clk: sunxi: introduce "modern" clock support
Subsystems (4)
cover clk: sunxi: introduce "modern" clock support
Hi,
This is an attempt at introducing clock support for the Allwinner SoCs following the current model used by pretty much all the other SoCs.
Such a conversion has been suggested on a regular basis by Mike and Stephen, and here is a first implementation.
This new approach has a good number of advantages, some due to the new binding itself, some due to the lessons learned with the current code we have.
Beside from having a binding similar to the other SoCs, which helps developper hopping from one SoC to the other, it also reduces the amount of binding review that needs to be done, something that Rob already complained about a few times.
Now that we are following the DT-as-an-ABI rule, the new binding will also make our life way easier, since we reduce the exposed surface greatly. The former binding, while making quite easy to mix and match clocks when bringing up new SoCs, was also exposing way too much implementation details that would hold us back when wanting to refactor, consolidate, or fix some shortcomings in the current implementation. In the new approach, the only thing that we're exposing is the clock index, meaning that we can change the implementation as much as we want.
This rewrite is also the occasion to layer things up quite differently in our clock core.
The current code had a bunch of shortcomings. Most of the code was relying on our clk-factor code, which was factoring away a few things like the clock registration, ie boilerplate, but didn't factor the logic to compute a clock rate, while the huge majority are computed from some variation of a formula, which could actually be shared.
Which meant that every time we had to add new code to help clk-factors compute the actual factors used, even though a clock with the same formual was probably already supported. This eventually lead to a huge number of clocks driver patches, and to review, which is also something Stephen complained about.
The new approach takes a different approach by adding a bunch of clock drivers based on the formula they use to compute their rate and / or the features they have (mux, gate, etc.). The SoC will only have to provide the data for the driver to know how many options it has, without adding any extra code.
To reduce the amount of code duplication between those drivers, a bunch of helpers have also been introduced to deal with the common features (pre-dividers, gate, muxes, etc.). This will also be very easy to extend to support new features missing for now (mostly the fractional stuff as of today).
Since this is a complete rewrite, it probably has a bunch of bugs and/or limitations not yet found. My plan would be to start using that approach on the A64, A83T and H3 which are in their early support stage to be the test-bed for this new framework, before switching the older and more featureful SoCs to it eventually.
Because of the DT ABI, the older drivers will remain in-tree obviously, otherwise things would break pretty badly.
The current code has been tested on the H3 and an Orange Pi PC, including making sure that MMC still works, so the general approach seems ok.
Let me know what you think,
Maxime
Maxime Ripard (16):
clk: fix critical clock locking
clk: sunxi-ng: Add common infrastructure
clk: sunxi-ng: Add fixed factor clock support
clk: sunxi-ng: Add gate clock support
clk: sunxi-ng: Add mux clock support
clk: sunxi-ng: Add divider table clock
clk: sunxi-ng: Add phase clock support
clk: sunxi-ng: Add M-factor clock support
clk: sunxi-ng: Add P-factor clock support
clk: sunxi-ng: Add M-P factor clock support
clk: sunxi-ng: Add N-K-factor clock support
clk: sunxi-ng: Add N-M-factor clock support
clk: sunxi-ng: Add N-K-M Factor clock
clk: sunxi-ng: Add N-K-M-P factor clock
clk: sunxi-ng: Add H3 clocks
ARM: dt: sun8i: switch the H3 to the new CCU driver
arch/arm/boot/dts/sun8i-h3.dtsi | 310 +++---------- drivers/clk/Makefile | 1 + drivers/clk/clk.c | 7 + drivers/clk/sunxi-ng/Makefile | 17 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 ++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_common.c | 108 +++++ drivers/clk/sunxi-ng/ccu_common.h | 74 ++++ drivers/clk/sunxi-ng/ccu_div_table.c | 117 +++++ drivers/clk/sunxi-ng/ccu_div_table.h | 75 ++++ drivers/clk/sunxi-ng/ccu_factor.h | 15 + drivers/clk/sunxi-ng/ccu_fixed_factor.c | 42 ++ drivers/clk/sunxi-ng/ccu_fixed_factor.h | 50 +++ drivers/clk/sunxi-ng/ccu_gate.c | 82 ++++ drivers/clk/sunxi-ng/ccu_gate.h | 53 +++ drivers/clk/sunxi-ng/ccu_m.c | 135 ++++++ drivers/clk/sunxi-ng/ccu_m.h | 101 +++++ drivers/clk/sunxi-ng/ccu_mp.c | 158 +++++++ drivers/clk/sunxi-ng/ccu_mp.h | 79 ++++ drivers/clk/sunxi-ng/ccu_mux.c | 187 ++++++++ drivers/clk/sunxi-ng/ccu_mux.h | 92 ++++ drivers/clk/sunxi-ng/ccu_nk.c | 147 +++++++ drivers/clk/sunxi-ng/ccu_nk.h | 44 ++ drivers/clk/sunxi-ng/ccu_nkm.c | 144 ++++++ drivers/clk/sunxi-ng/ccu_nkm.h | 42 ++ drivers/clk/sunxi-ng/ccu_nkmp.c | 157 +++++++ drivers/clk/sunxi-ng/ccu_nkmp.h | 43 ++ drivers/clk/sunxi-ng/ccu_nm.c | 103 +++++ drivers/clk/sunxi-ng/ccu_nm.h | 41 ++ drivers/clk/sunxi-ng/ccu_p.c | 141 ++++++ drivers/clk/sunxi-ng/ccu_p.h | 40 ++ drivers/clk/sunxi-ng/ccu_phase.c | 126 ++++++ drivers/clk/sunxi-ng/ccu_phase.h | 50 +++ drivers/clk/sunxi-ng/ccu_reset.c | 55 +++ drivers/clk/sunxi-ng/ccu_reset.h | 40 ++ include/dt-bindings/clock/sun8i-h3.h | 162 +++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 36 files changed, 3646 insertions(+), 252 deletions(-) create mode 100644 drivers/clk/sunxi-ng/Makefile create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 drivers/clk/sunxi-ng/ccu_common.c create mode 100644 drivers/clk/sunxi-ng/ccu_common.h create mode 100644 drivers/clk/sunxi-ng/ccu_div_table.c create mode 100644 drivers/clk/sunxi-ng/ccu_div_table.h create mode 100644 drivers/clk/sunxi-ng/ccu_factor.h create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.c create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.h create mode 100644 drivers/clk/sunxi-ng/ccu_gate.c create mode 100644 drivers/clk/sunxi-ng/ccu_gate.h create mode 100644 drivers/clk/sunxi-ng/ccu_m.c create mode 100644 drivers/clk/sunxi-ng/ccu_m.h create mode 100644 drivers/clk/sunxi-ng/ccu_mp.c create mode 100644 drivers/clk/sunxi-ng/ccu_mp.h create mode 100644 drivers/clk/sunxi-ng/ccu_mux.c create mode 100644 drivers/clk/sunxi-ng/ccu_mux.h create mode 100644 drivers/clk/sunxi-ng/ccu_nk.c create mode 100644 drivers/clk/sunxi-ng/ccu_nk.h create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.h create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.h create mode 100644 drivers/clk/sunxi-ng/ccu_nm.c create mode 100644 drivers/clk/sunxi-ng/ccu_nm.h create mode 100644 drivers/clk/sunxi-ng/ccu_p.c create mode 100644 drivers/clk/sunxi-ng/ccu_p.h create mode 100644 drivers/clk/sunxi-ng/ccu_phase.c create mode 100644 drivers/clk/sunxi-ng/ccu_phase.h create mode 100644 drivers/clk/sunxi-ng/ccu_reset.c create mode 100644 drivers/clk/sunxi-ng/ccu_reset.h create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.h
Signature · 1 line
2.8.2
PATCH 1/16 clk: fix critical clock locking
The critical clock handling in __clk_core_init isn't taking the enable lock before calling clk_core_enable, which in turns triggers the warning in the lockdep_assert_held call in that function when lockep is enabled.
Add the calls to clk_enable_lock/unlock to make sure it doesn't happen.
--- drivers/clk/clk.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/clk/clk.c +7 -0
@@ -2404,8 +2404,15 @@ static int __clk_core_init(struct clk_core *core) core->ops->init (core->hw);if (core->flags &CLK_IS_CRITICAL ) { +unsigned long flags; + +clk_prepare_lock ();clk_core_prepare (core); +clk_prepare_unlock (); + + flags =clk_enable_lock ();clk_core_enable (core); +clk_enable_unlock (flags); }kref_init (&core->ref);
Signature · 1 line
2.8.2
PATCH 1/16 clk: fix critical clock locking
Quoted 9 lines · Maxime Ripard
The critical clock handling in
__clk_core_initisn't taking the enable lock before callingclk_core_enable, which in turns triggers the warning in thelockdep_assert_heldcall in that function when lockep is enabled.Add the calls to clk_enable_lock/unlock to make sure it doesn't happen.
Fixes 32b9b1096186 ("clk: Allow clocks to be marked as CRITICAL")Signed-off-by Maxime Ripard <[email protected]>---
Why is this patch hiding in this series?
Quoted 8 lines
drivers/clk/clk.c | 7 +++++++ 1 file changed, 7 insertions(+)drivers/clk/clk.c +0
-0
drivers/clk/clk.c static int __clk_core_init(struct clk_core *core) · line 2411
Quoted 8 lines
drivers/clk/clk.c +4
-0@@ -2404,8 +2404,15 @@ static int __clk_core_init(struct clk_core *core) core->ops->init (core->hw);if (core->flags &CLK_IS_CRITICAL ) { +unsigned long flags; + +clk_prepare_lock ();clk_core_prepare (core); +clk_prepare_unlock ();
It looks like we already hold the prepare lock at this point.
drivers/clk/clk.c static int __clk_core_init(struct clk_core *core) · line 2415
Quoted 4 lines
drivers/clk/clk.c +3
-0+ + flags =clk_enable_lock ();clk_core_enable (core); +clk_enable_unlock (flags);
This seems correct though.
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH 1/16 clk: fix critical clock locking
Hi Stephen,
Quoted 5 lines · Stephen Boyd
Quoted 4 lines · Maxime Ripard
The critical clock handling in
__clk_core_initisn't taking the enable lock before callingclk_core_enable, which in turns triggers the warning in thelockdep_assert_heldcall in that function when lockep is enabled.
Quoted 7 lines
Quoted 5 lines
Add the calls to clk_enable_lock/unlock to make sure it doesn't happen.
Fixes 32b9b1096186 ("clk: Allow clocks to be marked as CRITICAL")Signed-off-by Maxime Ripard <[email protected]>---
Why is this patch hiding in this series?
Sorry, I discovered it while working on this, and somehow it slipped in there. I'll resend it separately.
Quoted 11 lines
Quoted 11 lines
drivers/clk/clk.c | 7 +++++++ 1 file changed, 7 insertions(+)drivers/clk/clk.c +0
-0@@ -2404,8 +2404,15 @@ static int __clk_core_init(struct clk_core *core) core->ops->init (core->hw);
Quoted 8 lines
drivers/clk/clk.c static int __clk_core_init(struct clk_core *core) · line 2411
Quoted 6 lines
drivers/clk/clk.c +4
-0if (core->flags &CLK_IS_CRITICAL ) { +unsigned long flags; + +clk_prepare_lock ();clk_core_prepare (core); +clk_prepare_unlock ();It looks like we already hold the prepare lock at this point.
You're right. I thought I removed it, but obviously I didn't.
I'll send a v2.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160513/b4592f8e/attachment.sig>
PATCH 2/16 clk: sunxi-ng: Add common infrastructure
In reply to Maxime RipardStart our new clock infrastructure by adding the registration code, common structure and common code.
--- drivers/clk/Makefile | 1 + drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu_common.c | 108 ++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_common.h | 74 ++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_factor.h | 15 ++++++ drivers/clk/sunxi-ng/ccu_mux.h | 20 +++++++ drivers/clk/sunxi-ng/ccu_reset.c | 55 +++++++++++++++++++ drivers/clk/sunxi-ng/ccu_reset.h | 40 ++++++++++++++ 8 files changed, 315 insertions(+) create mode 100644 drivers/clk/sunxi-ng/Makefile create mode 100644 drivers/clk/sunxi-ng/ccu_common.c create mode 100644 drivers/clk/sunxi-ng/ccu_common.h create mode 100644 drivers/clk/sunxi-ng/ccu_factor.h create mode 100644 drivers/clk/sunxi-ng/ccu_mux.h create mode 100644 drivers/clk/sunxi-ng/ccu_reset.c create mode 100644 drivers/clk/sunxi-ng/ccu_reset.h
drivers/clk/Makefile +1 -0
@@ -78,6 +78,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_STI) += st/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ +obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ obj-$(CONFIG_ARCH_U8500) += ux500/
drivers/clk/sunxi-ng/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +obj-y += ccu_common.o +obj-y += ccu_reset.o
drivers/clk/sunxi-ng/ccu_common.c new file +108 -0
108 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_common.h new file +74 -0
74 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_factor.h new file +15 -0
@@ -0,0 +1,15 @@ +#ifndef _CLK_FACTOR_H_ +#define _CLK_FACTOR_H_ + +struct ccu_factor { +u8 shift; +u8 width; +}; + +#define SUNXI_CLK_FACTOR (_shift, _width) \ + { \ + .shift = _shift, \ + .width = _width, \ + } + +#endif /* _CLK_FACTOR_H_ */
drivers/clk/sunxi-ng/ccu_mux.h new file +20 -0
@@ -0,0 +1,20 @@ +#ifndef _CCU_MUX_H_ +#define _CCU_MUX_H_ + +#include "common.h" + +struct ccu_mux_internal { +u8 shift; +u8 width; + +u8 *map; +}; + +#define SUNXI_CLK_MUX (_shift, _width, _map) \ + { \ + .map = _map, \ + .shift = _shift, \ + .width = _width, \ + } + +#endif /* _CCU_MUX_H_ */
drivers/clk/sunxi-ng/ccu_reset.c new file +55 -0
55 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_reset.h new file +40 -0
@@ -0,0 +1,40 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_RESET_H_ +#define _CCU_RESET_H_ + +#include <linux/reset-controller.h> + +struct ccu_reset_map { +u16 reg; +u32 bit; +}; + + +struct ccu_reset { +void __iomem *base; +struct ccu_reset_map *reset_map; +spinlock_t *lock; + +struct reset_controller_dev rcdev; +}; + +static inline struct ccu_reset *rcdev_to_ccu_reset (struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct ccu_reset, rcdev); +} + +extern const struct reset_control_ops ccu_reset_ops; + +#endif /* _CCU_RESET_H_ */
Signature · 1 line
2.8.2
PATCH 2/16 clk: sunxi-ng: Add common infrastructure
Quoted 73 lines · Maxime Ripard
Start our new clock infrastructure by adding the registration code, common structure and common code.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/Makefile | 1 + drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu_common.c | 108 ++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_common.h | 74 ++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_factor.h | 15 ++++++ drivers/clk/sunxi-ng/ccu_mux.h | 20 +++++++ drivers/clk/sunxi-ng/ccu_reset.c | 55 +++++++++++++++++++ drivers/clk/sunxi-ng/ccu_reset.h | 40 ++++++++++++++ 8 files changed, 315 insertions(+) create mode 100644 drivers/clk/sunxi-ng/Makefile create mode 100644 drivers/clk/sunxi-ng/ccu_common.c create mode 100644 drivers/clk/sunxi-ng/ccu_common.h create mode 100644 drivers/clk/sunxi-ng/ccu_factor.h create mode 100644 drivers/clk/sunxi-ng/ccu_mux.h create mode 100644 drivers/clk/sunxi-ng/ccu_reset.c create mode 100644 drivers/clk/sunxi-ng/ccu_reset.hdrivers/clk/Makefile +1
-0@@ -78,6 +78,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_STI) += st/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ +obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ obj-$(CONFIG_ARCH_U8500) += ux500/drivers/clk/sunxi-ng/Makefile new file +2
-0@@ -0,0 +1,2 @@ +obj-y += ccu_common.o +obj-y += ccu_reset.odrivers/clk/sunxi-ng/ccu_common.c new file +25
-0@@ -0,0 +1,108 @@ +/* +* Copyright 2016 Maxime Ripard +* +* Maxime Ripard <[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 <linux/clk-provider.h> +#include <linux/iopoll.h> +#include <linux/of_address.h> +#include <linux/slab.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +static DEFINE_SPINLOCK (ccu_lock);
drivers/clk/sunxi-ng/ccu_common.c line 35
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_common.c new file +10
-0+ +void ccu_helper_wait_for_lock (struct ccu_common *common,u32 lock) +{ +u32 reg; + +if (!(common->features &CCU_FEATURE_LOCK )) +return ; + +WARN_ON (readl_relaxed_poll_timeout (common->base + common->reg, reg, + !(reg & lock),0 ,500 ));
no delay between reads? ^
Quoted 4 lines
drivers/clk/sunxi-ng/ccu_common.c new file +4
-0+} + +int sunxi_ccu_probe (struct device_node *node, +const struct sunxi_ccu_desc *desc)
drivers/clk/sunxi-ng/ccu_common.c line 49
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_common.c new file +10
-0+{ +struct ccu_common **cclks = desc->clks; +size_t num_clks = desc->num_clks; +struct clk_onecell_data *data; +struct ccu_reset *reset; +struct clk **clks; +void __iomem *reg; +int i, ret; + + reg =of_iomap (node,0 );
Why not of_io_request_and_map?
drivers/clk/sunxi-ng/ccu_common.c line 50
Quoted 1 line
drivers/clk/sunxi-ng/ccu_common.c new file +1
-0+if (IS_ERR (reg)) {
And of_iomap returns NULL on error. This is for of_io_request_and_map.
Quoted 12 lines
drivers/clk/sunxi-ng/ccu_common.c new file +12
-0+pr_err ("%s: Could not map the clock registers\n" , +of_node_full_name (node)); +return PTR_ERR (reg); + } + + data =kzalloc (sizeof (*data),GFP_KERNEL ); +if (!data) +return -ENOMEM ; + + clks =kcalloc (num_clks,sizeof (struct clk *),GFP_KERNEL ); +if (!clks) +return -ENOMEM ;
drivers/clk/sunxi-ng/ccu_common.c line 72
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_common.c new file +10
-0+ + data->clks = clks; + data->clk_num = num_clks; + +for (i =0 ; i < num_clks; i++) { +struct ccu_common *cclk = cclks[i]; +struct clk *clk; + +if (!cclk) { + cclk =ERR_PTR (-ENOENT );
This seems redundant, unless you intended to use it elsewhere?
Quoted 53 lines
drivers/clk/sunxi-ng/ccu_common.c new file +36
-0+continue ; + } + + cclk->base = reg; + cclk->lock = &ccu_lock; + + clk =clk_register (NULL , &cclk->hw); +if (IS_ERR (clk)) +continue ; + + clks[i] = clk; + } + + ret =of_clk_add_provider (node, of_clk_src_onecell_get, data); +if (ret) + goto err_clk_unreg; + + reset =kzalloc (sizeof (*reset),GFP_KERNEL ); + reset->rcdev.of_node = node; + reset->rcdev.ops = &ccu_reset_ops; + reset->rcdev.owner =THIS_MODULE ; + reset->rcdev.nr_resets = desc->num_resets; + reset->base = reg; + reset->lock = &ccu_lock; + reset->reset_map = desc->resets; + + ret =reset_controller_register (&reset->rcdev); +if (ret) + goto err_of_clk_unreg; + +return 0 ; + +err_of_clk_unreg: +err_clk_unreg: +return ret; +}drivers/clk/sunxi-ng/ccu_common.h new file +11
-0@@ -0,0 +1,74 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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.
drivers/clk/sunxi-ng/ccu_common.h line 21
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_common.h new file +10
-0+*/ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include <linux/compiler.h> +#include <linux/clk-provider.h> + +#define CCU_FEATURE_GATE BIT(0) +#define CCU_FEATURE_LOCK BIT(1)
*_PLL_LOCK would be clearer that this implements a PLL lock indicator. Or maybe a comment.
Quoted 18 lines
drivers/clk/sunxi-ng/ccu_common.h new file +18
-0+#define CCU_FEATURE_FRACTIONAL BIT(2) +#define CCU_FEATURE_VARIABLE_PREDIV BIT(3) +#define CCU_FEATURE_FIXED_PREDIV BIT(4) +#define CCU_FEATURE_FIXED_POSTDIV BIT(5) + +struct device_node ; + +#define SUNXI_HW_INIT (_name, _parent, _ops, _flags) \ + &(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = (const char *[]) { _parent }, \ + .num_parents = 1, \ + .ops = _ops, \ + } + +#define SUNXI_HW_INIT_PARENTS (_name, _parents, _ops, _flags) \ + &(struct clk_init_data) { \
drivers/clk/sunxi-ng/ccu_common.h line 49
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_common.h new file +10
-0+ .flags = _flags, \ + .name = _name, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .ops = _ops, \ + } + +struct ccu_common { +void __iomem *base; +unsigned long reg;
This seems quite large, considering the address space of the CCU, and you using u16 or u32 for the same thing on the reset control side.
drivers/clk/sunxi-ng/ccu_mux.h
Quoted 51 lines
drivers/clk/sunxi-ng/ccu_common.h new file +25
-0+ +unsigned long features; +spinlock_t *lock; +struct clk_hw hw; +}; + +static inline struct ccu_common *hw_to_ccu_common (struct clk_hw *hw) +{ + return container_of(hw, struct ccu_common, hw); +} + +struct sunxi_ccu_desc { +struct ccu_common **clks; +unsigned long num_clks; + +struct ccu_reset_map *resets; +unsigned long num_resets; +}; + +void ccu_helper_wait_for_lock (struct ccu_common *common,u32 lock); + +int sunxi_ccu_probe (struct device_node *node, +const struct sunxi_ccu_desc *desc); + +#endif /* _COMMON_H_ */ drivers/clk/sunxi-ng/ccu_factor.h new file +15
-0@@ -0,0 +1,15 @@ +#ifndef _CLK_FACTOR_H_ +#define _CLK_FACTOR_H_ + +struct ccu_factor { +u8 shift; +u8 width; +}; + +#define SUNXI_CLK_FACTOR (_shift, _width) \ + { \ + .shift = _shift, \ + .width = _width, \ + } + +#endif /* _CLK_FACTOR_H_ */ drivers/clk/sunxi-ng/ccu_mux.h new file +0
-0
As far as I can tell there are no users of this file within this patch or the following patches before the mux clock support one. It'd be easier to understand if this part was moved to the mux clock patch.
drivers/clk/sunxi-ng/ccu_mux.h line 10
Quoted 11 lines
drivers/clk/sunxi-ng/ccu_mux.h new file +10
-0@@ -0,0 +1,20 @@ +#ifndef _CCU_MUX_H_ +#define _CCU_MUX_H_ + +#include "common.h" + +struct ccu_mux_internal { + u8 shift; + u8 width; + + u8 *map;
I assume map is a table?
Quoted 107 lines
drivers/clk/sunxi-ng/ccu_mux.h new file +10
-0+}; + +#define SUNXI_CLK_MUX (_shift, _width, _map) \ + { \ + .map = _map, \ + .shift = _shift, \ + .width = _width, \ + } + +#endif /* _CCU_MUX_H_ */ drivers/clk/sunxi-ng/ccu_reset.c new file +55
-0@@ -0,0 +1,55 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/io.h> +#include <linux/reset-controller.h> + +#include "ccu_reset.h" + +static int ccu_reset_assert (struct reset_controller_dev *rcdev, +unsigned long id) +{ +struct ccu_reset *ccu =rcdev_to_ccu_reset (rcdev); +const struct ccu_reset_map *map = &ccu->reset_map[id]; +unsigned long flags; +u32 reg; + +spin_lock_irqsave (ccu->lock, flags); + + reg =readl (ccu->base + map->reg); +writel (reg & ~map->bit, ccu->base + map->reg); + +spin_unlock_irqrestore (ccu->lock, flags); + +return 0 ; +} + +static int ccu_reset_deassert (struct reset_controller_dev *rcdev, +unsigned long id) +{ +struct ccu_reset *ccu =rcdev_to_ccu_reset (rcdev); +const struct ccu_reset_map *map = &ccu->reset_map[id]; +unsigned long flags; +u32 reg; + +spin_lock_irqsave (ccu->lock, flags); + + reg =readl (ccu->base + map->reg); +writel (reg | map->bit, ccu->base + map->reg); + +spin_unlock_irqrestore (ccu->lock, flags); + +return 0 ; +} + +const struct reset_control_ops ccu_reset_ops = { + .assert = ccu_reset_assert, + .deassert = ccu_reset_deassert, +};drivers/clk/sunxi-ng/ccu_reset.h new file +30
-0@@ -0,0 +1,40 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_RESET_H_ +#define _CCU_RESET_H_ + +#include <linux/reset-controller.h> + +struct ccu_reset_map { + u16 reg; + u32 bit; +}; + + +struct ccu_reset { + void __iomem *base; + struct ccu_reset_map *reset_map; + spinlock_t *lock; + + struct reset_controller_dev rcdev;
drivers/clk/sunxi-ng/ccu_reset.h line 40
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_reset.h new file +10
-0+}; + +static inline struct ccu_reset *rcdev_to_ccu_reset (struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct ccu_reset, rcdev); +} + +extern const struct reset_control_ops ccu_reset_ops; + +#endif /* _CCU_RESET_H_ */
The reset control code looks good.
Regards
ChenYu
Quoted 3 lines
--
2.8.2
PATCH 2/16 clk: sunxi-ng: Add common infrastructure
Hi,
Quoted 79 lines · Chen-Yu Tsai
Quoted 77 lines · Maxime Ripard
Start our new clock infrastructure by adding the registration code, common structure and common code.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/Makefile | 1 + drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu_common.c | 108 ++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_common.h | 74 ++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_factor.h | 15 ++++++ drivers/clk/sunxi-ng/ccu_mux.h | 20 +++++++ drivers/clk/sunxi-ng/ccu_reset.c | 55 +++++++++++++++++++ drivers/clk/sunxi-ng/ccu_reset.h | 40 ++++++++++++++ 8 files changed, 315 insertions(+) create mode 100644 drivers/clk/sunxi-ng/Makefile create mode 100644 drivers/clk/sunxi-ng/ccu_common.c create mode 100644 drivers/clk/sunxi-ng/ccu_common.h create mode 100644 drivers/clk/sunxi-ng/ccu_factor.h create mode 100644 drivers/clk/sunxi-ng/ccu_mux.h create mode 100644 drivers/clk/sunxi-ng/ccu_reset.c create mode 100644 drivers/clk/sunxi-ng/ccu_reset.hdrivers/clk/Makefile +1
-0@@ -78,6 +78,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_STI) += st/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ +obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ obj-$(CONFIG_ARCH_U8500) += ux500/drivers/clk/sunxi-ng/Makefile new file +2
-0@@ -0,0 +1,2 @@ +obj-y += ccu_common.o +obj-y += ccu_reset.odrivers/clk/sunxi-ng/ccu_common.c new file +29
-0@@ -0,0 +1,108 @@ +/* +* Copyright 2016 Maxime Ripard +* +* Maxime Ripard <[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 <linux/clk-provider.h> +#include <linux/iopoll.h> +#include <linux/of_address.h> +#include <linux/slab.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +static DEFINE_SPINLOCK (ccu_lock); + +void ccu_helper_wait_for_lock (struct ccu_common *common,u32 lock) +{ +u32 reg;
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_common.c line 35
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_common.c new file +6
-0+ +if (!(common->features &CCU_FEATURE_LOCK )) +return ; + +WARN_ON (readl_relaxed_poll_timeout (common->base + common->reg, reg, + !(reg & lock),0 ,500 ));no delay between reads? ^
Yes, I intended it to be a simple busy waiting loop since I don't expect it to be very long. Do yu have any more data on how much time it usually takes?
Quoted 15 lines
drivers/clk/sunxi-ng/ccu_common.c line 49
Quoted 13 lines
drivers/clk/sunxi-ng/ccu_common.c new file +12
-0+int sunxi_ccu_probe (struct device_node *node, +const struct sunxi_ccu_desc *desc) +{ +struct ccu_common **cclks = desc->clks; +size_t num_clks = desc->num_clks; +struct clk_onecell_data *data; +struct ccu_reset *reset; +struct clk **clks; +void __iomem *reg; +int i, ret; + + reg =of_iomap (node,0 );Why not
of_io_request_and_map?
Because initially I still had some old clocks that were probing, which was leading to some issues. This is obviously not the case anymore, I'll switch to it.
Quoted 21 lines
drivers/clk/sunxi-ng/ccu_common.c line 50
Quoted 2 lines
drivers/clk/sunxi-ng/ccu_common.c new file +1
-0+if (IS_ERR (reg)) {And
of_iomapreturns NULL on error. This is forof_io_request_and_map.Quoted 16 lines
drivers/clk/sunxi-ng/ccu_common.c new file +16
-0+pr_err ("%s: Could not map the clock registers\n" , +of_node_full_name (node)); +return PTR_ERR (reg); + } + + data =kzalloc (sizeof (*data),GFP_KERNEL ); +if (!data) +return -ENOMEM ; + + clks =kcalloc (num_clks,sizeof (struct clk *),GFP_KERNEL ); +if (!clks) +return -ENOMEM ; + + data->clks = clks; + data->clk_num = num_clks; +
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_common.c line 72
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_common.c new file +6
-0+for (i =0 ; i < num_clks; i++) { +struct ccu_common *cclk = cclks[i]; +struct clk *clk; + +if (!cclk) { + cclk =ERR_PTR (-ENOENT );This seems redundant, unless you intended to use it elsewhere?
Yeah, that was supposed to be clks[i] = ERR_PTR(..);
I'll fix it.
Quoted 59 lines
Quoted 59 lines
drivers/clk/sunxi-ng/ccu_common.c new file +36
-0+continue ; + } + + cclk->base = reg; + cclk->lock = &ccu_lock; + + clk =clk_register (NULL , &cclk->hw); +if (IS_ERR (clk)) +continue ; + + clks[i] = clk; + } + + ret =of_clk_add_provider (node, of_clk_src_onecell_get, data); +if (ret) + goto err_clk_unreg; + + reset =kzalloc (sizeof (*reset),GFP_KERNEL ); + reset->rcdev.of_node = node; + reset->rcdev.ops = &ccu_reset_ops; + reset->rcdev.owner =THIS_MODULE ; + reset->rcdev.nr_resets = desc->num_resets; + reset->base = reg; + reset->lock = &ccu_lock; + reset->reset_map = desc->resets; + + ret =reset_controller_register (&reset->rcdev); +if (ret) + goto err_of_clk_unreg; + +return 0 ; + +err_of_clk_unreg: +err_clk_unreg: +return ret; +}drivers/clk/sunxi-ng/ccu_common.h new file +16
-0@@ -0,0 +1,74 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _COMMON_H_ +#define _COMMON_H_ +
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_common.h line 21
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_common.h new file +5
-0+#include <linux/compiler.h> +#include <linux/clk-provider.h> + +#define CCU_FEATURE_GATE BIT(0) +#define CCU_FEATURE_LOCK BIT(1)
*_PLL_LOCKwould be clearer that this implements a PLL lock indicator. Or maybe a comment.
I'll change it for PLL_LOCK
Quoted 24 lines
Quoted 24 lines
drivers/clk/sunxi-ng/ccu_common.h new file +23
-0+#define CCU_FEATURE_FRACTIONAL BIT(2) +#define CCU_FEATURE_VARIABLE_PREDIV BIT(3) +#define CCU_FEATURE_FIXED_PREDIV BIT(4) +#define CCU_FEATURE_FIXED_POSTDIV BIT(5) + +struct device_node ; + +#define SUNXI_HW_INIT (_name, _parent, _ops, _flags) \ + &(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = (const char *[]) { _parent }, \ + .num_parents = 1, \ + .ops = _ops, \ + } + +#define SUNXI_HW_INIT_PARENTS (_name, _parents, _ops, _flags) \ + &(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .ops = _ops, \
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_common.h line 49
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_common.h new file +5
-0+ } + +struct ccu_common { +void __iomem *base; +unsigned long reg;This seems quite large, considering the address space of the CCU, and you using u16 or u32 for the same thing on the reset control side.
Indeed, what about u16?
Quoted 48 lines
Quoted 48 lines
drivers/clk/sunxi-ng/ccu_common.h new file +25
-0+ +unsigned long features; +spinlock_t *lock; +struct clk_hw hw; +}; + +static inline struct ccu_common *hw_to_ccu_common (struct clk_hw *hw) +{ + return container_of(hw, struct ccu_common, hw); +} + +struct sunxi_ccu_desc { +struct ccu_common **clks; +unsigned long num_clks; + +struct ccu_reset_map *resets; +unsigned long num_resets; +}; + +void ccu_helper_wait_for_lock (struct ccu_common *common,u32 lock); + +int sunxi_ccu_probe (struct device_node *node, +const struct sunxi_ccu_desc *desc); + +#endif /* _COMMON_H_ */ drivers/clk/sunxi-ng/ccu_factor.h new file +15
-0@@ -0,0 +1,15 @@ +#ifndef _CLK_FACTOR_H_ +#define _CLK_FACTOR_H_ + +struct ccu_factor { +u8 shift; +u8 width; +}; + +#define SUNXI_CLK_FACTOR (_shift, _width) \ + { \ + .shift = _shift, \ + .width = _width, \ + } + +#endif /* _CLK_FACTOR_H_ */ drivers/clk/sunxi-ng/ccu_mux.h +0
-0
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_mux.h
Quoted 4 lines
new file mode 100644
index 000000000000..17cedad4e433drivers/clk/sunxi-ng/ccu_mux.h new file +0
-0As far as I can tell there are no users of this file within this patch or the following patches before the mux clock support one. It'd be easier to understand if this part was moved to the mux clock patch.
Will do.
Quoted 126 lines
drivers/clk/sunxi-ng/ccu_mux.h line 10
Quoted 12 lines
drivers/clk/sunxi-ng/ccu_mux.h new file +10
-0@@ -0,0 +1,20 @@ +#ifndef _CCU_MUX_H_ +#define _CCU_MUX_H_ + +#include "common.h" + +struct ccu_mux_internal { + u8 shift; + u8 width; + + u8 *map;I assume map is a table?
Quoted 111 lines
drivers/clk/sunxi-ng/ccu_mux.h new file +10
-0+}; + +#define SUNXI_CLK_MUX (_shift, _width, _map) \ + { \ + .map = _map, \ + .shift = _shift, \ + .width = _width, \ + } + +#endif /* _CCU_MUX_H_ */ drivers/clk/sunxi-ng/ccu_reset.c new file +55
-0@@ -0,0 +1,55 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/io.h> +#include <linux/reset-controller.h> + +#include "ccu_reset.h" + +static int ccu_reset_assert (struct reset_controller_dev *rcdev, +unsigned long id) +{ +struct ccu_reset *ccu =rcdev_to_ccu_reset (rcdev); +const struct ccu_reset_map *map = &ccu->reset_map[id]; +unsigned long flags; +u32 reg; + +spin_lock_irqsave (ccu->lock, flags); + + reg =readl (ccu->base + map->reg); +writel (reg & ~map->bit, ccu->base + map->reg); + +spin_unlock_irqrestore (ccu->lock, flags); + +return 0 ; +} + +static int ccu_reset_deassert (struct reset_controller_dev *rcdev, +unsigned long id) +{ +struct ccu_reset *ccu =rcdev_to_ccu_reset (rcdev); +const struct ccu_reset_map *map = &ccu->reset_map[id]; +unsigned long flags; +u32 reg; + +spin_lock_irqsave (ccu->lock, flags); + + reg =readl (ccu->base + map->reg); +writel (reg | map->bit, ccu->base + map->reg); + +spin_unlock_irqrestore (ccu->lock, flags); + +return 0 ; +} + +const struct reset_control_ops ccu_reset_ops = { + .assert = ccu_reset_assert, + .deassert = ccu_reset_deassert, +};drivers/clk/sunxi-ng/ccu_reset.h new file +34
-0@@ -0,0 +1,40 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_RESET_H_ +#define _CCU_RESET_H_ + +#include <linux/reset-controller.h> + +struct ccu_reset_map { +u16 reg; +u32 bit; +}; + + +struct ccu_reset { +void __iomem *base; +struct ccu_reset_map *reset_map; +spinlock_t *lock; + +struct reset_controller_dev rcdev; +}; + +static inline struct ccu_reset *rcdev_to_ccu_reset (struct reset_controller_dev *rcdev) +{
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_reset.h line 40
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_reset.h new file +6
-0+ return container_of(rcdev, struct ccu_reset, rcdev); +} + +extern const struct reset_control_ops ccu_reset_ops; + +#endif /* _CCU_RESET_H_ */ The reset control code looks good.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160515/f96ad50b/attachment.sig>
PATCH 2/16 clk: sunxi-ng: Add common infrastructure
Quoted 252 lines · Maxime Ripard
Hi,
Quoted 79 lines · Chen-Yu Tsai
Quoted 77 lines · Maxime Ripard
Start our new clock infrastructure by adding the registration code, common structure and common code.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/Makefile | 1 + drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu_common.c | 108 ++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_common.h | 74 ++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_factor.h | 15 ++++++ drivers/clk/sunxi-ng/ccu_mux.h | 20 +++++++ drivers/clk/sunxi-ng/ccu_reset.c | 55 +++++++++++++++++++ drivers/clk/sunxi-ng/ccu_reset.h | 40 ++++++++++++++ 8 files changed, 315 insertions(+) create mode 100644 drivers/clk/sunxi-ng/Makefile create mode 100644 drivers/clk/sunxi-ng/ccu_common.c create mode 100644 drivers/clk/sunxi-ng/ccu_common.h create mode 100644 drivers/clk/sunxi-ng/ccu_factor.h create mode 100644 drivers/clk/sunxi-ng/ccu_mux.h create mode 100644 drivers/clk/sunxi-ng/ccu_reset.c create mode 100644 drivers/clk/sunxi-ng/ccu_reset.hdrivers/clk/Makefile +1
-0@@ -78,6 +78,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_STI) += st/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ +obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ obj-$(CONFIG_ARCH_U8500) += ux500/drivers/clk/sunxi-ng/Makefile new file +2
-0@@ -0,0 +1,2 @@ +obj-y += ccu_common.o +obj-y += ccu_reset.odrivers/clk/sunxi-ng/ccu_common.c new file +29
-0@@ -0,0 +1,108 @@ +/* +* Copyright 2016 Maxime Ripard +* +* Maxime Ripard <[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 <linux/clk-provider.h> +#include <linux/iopoll.h> +#include <linux/of_address.h> +#include <linux/slab.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +static DEFINE_SPINLOCK (ccu_lock); + +void ccu_helper_wait_for_lock (struct ccu_common *common,u32 lock) +{ +u32 reg;Quoted 8 lines
drivers/clk/sunxi-ng/ccu_common.c line 35
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_common.c new file +6
-0+ +if (!(common->features &CCU_FEATURE_LOCK )) +return ; + +WARN_ON (readl_relaxed_poll_timeout (common->base + common->reg, reg, + !(reg & lock),0 ,500 ));no delay between reads? ^
Yes, I intended it to be a simple busy waiting loop since I don't expect it to be very long. Do yu have any more data on how much time it usually takes?
Quoted 15 lines
drivers/clk/sunxi-ng/ccu_common.c line 49
Quoted 13 lines
drivers/clk/sunxi-ng/ccu_common.c new file +12
-0+int sunxi_ccu_probe (struct device_node *node, +const struct sunxi_ccu_desc *desc) +{ +struct ccu_common **cclks = desc->clks; +size_t num_clks = desc->num_clks; +struct clk_onecell_data *data; +struct ccu_reset *reset; +struct clk **clks; +void __iomem *reg; +int i, ret; + + reg =of_iomap (node,0 );Why not
of_io_request_and_map?Because initially I still had some old clocks that were probing, which was leading to some issues. This is obviously not the case anymore, I'll switch to it.
Quoted 21 lines
drivers/clk/sunxi-ng/ccu_common.c line 50
Quoted 2 lines
drivers/clk/sunxi-ng/ccu_common.c new file +1
-0+if (IS_ERR (reg)) {And
of_iomapreturns NULL on error. This is forof_io_request_and_map.Quoted 16 lines
drivers/clk/sunxi-ng/ccu_common.c new file +16
-0+pr_err ("%s: Could not map the clock registers\n" , +of_node_full_name (node)); +return PTR_ERR (reg); + } + + data =kzalloc (sizeof (*data),GFP_KERNEL ); +if (!data) +return -ENOMEM ; + + clks =kcalloc (num_clks,sizeof (struct clk *),GFP_KERNEL ); +if (!clks) +return -ENOMEM ; + + data->clks = clks; + data->clk_num = num_clks; +Quoted 8 lines
drivers/clk/sunxi-ng/ccu_common.c line 72
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_common.c new file +6
-0+for (i =0 ; i < num_clks; i++) { +struct ccu_common *cclk = cclks[i]; +struct clk *clk; + +if (!cclk) { + cclk =ERR_PTR (-ENOENT );This seems redundant, unless you intended to use it elsewhere?
Yeah, that was supposed to be clks[i] =
ERR_PTR(..);I'll fix it.
Quoted 59 lines
Quoted 59 lines
drivers/clk/sunxi-ng/ccu_common.c new file +36
-0+continue ; + } + + cclk->base = reg; + cclk->lock = &ccu_lock; + + clk =clk_register (NULL , &cclk->hw); +if (IS_ERR (clk)) +continue ; + + clks[i] = clk; + } + + ret =of_clk_add_provider (node, of_clk_src_onecell_get, data); +if (ret) + goto err_clk_unreg; + + reset =kzalloc (sizeof (*reset),GFP_KERNEL ); + reset->rcdev.of_node = node; + reset->rcdev.ops = &ccu_reset_ops; + reset->rcdev.owner =THIS_MODULE ; + reset->rcdev.nr_resets = desc->num_resets; + reset->base = reg; + reset->lock = &ccu_lock; + reset->reset_map = desc->resets; + + ret =reset_controller_register (&reset->rcdev); +if (ret) + goto err_of_clk_unreg; + +return 0 ; + +err_of_clk_unreg: +err_clk_unreg: +return ret; +}drivers/clk/sunxi-ng/ccu_common.h new file +16
-0@@ -0,0 +1,74 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _COMMON_H_ +#define _COMMON_H_ +Quoted 8 lines
drivers/clk/sunxi-ng/ccu_common.h line 21
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_common.h new file +5
-0+#include <linux/compiler.h> +#include <linux/clk-provider.h> + +#define CCU_FEATURE_GATE BIT(0) +#define CCU_FEATURE_LOCK BIT(1)
*_PLL_LOCKwould be clearer that this implements a PLL lock indicator. Or maybe a comment.I'll change it for
PLL_LOCKQuoted 24 lines
Quoted 24 lines
drivers/clk/sunxi-ng/ccu_common.h new file +23
-0+#define CCU_FEATURE_FRACTIONAL BIT(2) +#define CCU_FEATURE_VARIABLE_PREDIV BIT(3) +#define CCU_FEATURE_FIXED_PREDIV BIT(4) +#define CCU_FEATURE_FIXED_POSTDIV BIT(5) + +struct device_node ; + +#define SUNXI_HW_INIT (_name, _parent, _ops, _flags) \ + &(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = (const char *[]) { _parent }, \ + .num_parents = 1, \ + .ops = _ops, \ + } + +#define SUNXI_HW_INIT_PARENTS (_name, _parents, _ops, _flags) \ + &(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .ops = _ops, \Quoted 8 lines
drivers/clk/sunxi-ng/ccu_common.h line 49
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_common.h new file +5
-0+ } + +struct ccu_common { +void __iomem *base; +unsigned long reg;This seems quite large, considering the address space of the CCU, and you using u16 or u32 for the same thing on the reset control side.
Quoted 1 line
Indeed, what about u16?
Either u16 or u32 will do. I suspect u16 will get bumped up to u32 due to alignment issues of the struct.
ChenYu
Quoted 201 lines
Quoted 48 lines
Quoted 48 lines
drivers/clk/sunxi-ng/ccu_common.h new file +25
-0+ +unsigned long features; +spinlock_t *lock; +struct clk_hw hw; +}; + +static inline struct ccu_common *hw_to_ccu_common (struct clk_hw *hw) +{ + return container_of(hw, struct ccu_common, hw); +} + +struct sunxi_ccu_desc { +struct ccu_common **clks; +unsigned long num_clks; + +struct ccu_reset_map *resets; +unsigned long num_resets; +}; + +void ccu_helper_wait_for_lock (struct ccu_common *common,u32 lock); + +int sunxi_ccu_probe (struct device_node *node, +const struct sunxi_ccu_desc *desc); + +#endif /* _COMMON_H_ */ drivers/clk/sunxi-ng/ccu_factor.h new file +15
-0@@ -0,0 +1,15 @@ +#ifndef _CLK_FACTOR_H_ +#define _CLK_FACTOR_H_ + +struct ccu_factor { +u8 shift; +u8 width; +}; + +#define SUNXI_CLK_FACTOR (_shift, _width) \ + { \ + .shift = _shift, \ + .width = _width, \ + } + +#endif /* _CLK_FACTOR_H_ */ drivers/clk/sunxi-ng/ccu_mux.h +0
-0Quoted 8 lines
drivers/clk/sunxi-ng/ccu_mux.h
Quoted 4 lines
new file mode 100644
index 000000000000..17cedad4e433drivers/clk/sunxi-ng/ccu_mux.h new file +0
-0As far as I can tell there are no users of this file within this patch or the following patches before the mux clock support one. It'd be easier to understand if this part was moved to the mux clock patch.
Will do.
Quoted 126 lines
drivers/clk/sunxi-ng/ccu_mux.h line 10
Quoted 12 lines
drivers/clk/sunxi-ng/ccu_mux.h new file +10
-0@@ -0,0 +1,20 @@ +#ifndef _CCU_MUX_H_ +#define _CCU_MUX_H_ + +#include "common.h" + +struct ccu_mux_internal { + u8 shift; + u8 width; + + u8 *map;I assume map is a table?
Quoted 111 lines
drivers/clk/sunxi-ng/ccu_mux.h new file +10
-0+}; + +#define SUNXI_CLK_MUX (_shift, _width, _map) \ + { \ + .map = _map, \ + .shift = _shift, \ + .width = _width, \ + } + +#endif /* _CCU_MUX_H_ */ drivers/clk/sunxi-ng/ccu_reset.c new file +55
-0@@ -0,0 +1,55 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/io.h> +#include <linux/reset-controller.h> + +#include "ccu_reset.h" + +static int ccu_reset_assert (struct reset_controller_dev *rcdev, +unsigned long id) +{ +struct ccu_reset *ccu =rcdev_to_ccu_reset (rcdev); +const struct ccu_reset_map *map = &ccu->reset_map[id]; +unsigned long flags; +u32 reg; + +spin_lock_irqsave (ccu->lock, flags); + + reg =readl (ccu->base + map->reg); +writel (reg & ~map->bit, ccu->base + map->reg); + +spin_unlock_irqrestore (ccu->lock, flags); + +return 0 ; +} + +static int ccu_reset_deassert (struct reset_controller_dev *rcdev, +unsigned long id) +{ +struct ccu_reset *ccu =rcdev_to_ccu_reset (rcdev); +const struct ccu_reset_map *map = &ccu->reset_map[id]; +unsigned long flags; +u32 reg; + +spin_lock_irqsave (ccu->lock, flags); + + reg =readl (ccu->base + map->reg); +writel (reg | map->bit, ccu->base + map->reg); + +spin_unlock_irqrestore (ccu->lock, flags); + +return 0 ; +} + +const struct reset_control_ops ccu_reset_ops = { + .assert = ccu_reset_assert, + .deassert = ccu_reset_deassert, +};drivers/clk/sunxi-ng/ccu_reset.h new file +34
-0@@ -0,0 +1,40 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_RESET_H_ +#define _CCU_RESET_H_ + +#include <linux/reset-controller.h> + +struct ccu_reset_map { +u16 reg; +u32 bit; +}; + + +struct ccu_reset { +void __iomem *base; +struct ccu_reset_map *reset_map; +spinlock_t *lock; + +struct reset_controller_dev rcdev; +}; + +static inline struct ccu_reset *rcdev_to_ccu_reset (struct reset_controller_dev *rcdev) +{Quoted 8 lines
drivers/clk/sunxi-ng/ccu_reset.h line 40
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_reset.h new file +6
-0+ return container_of(rcdev, struct ccu_reset, rcdev); +} + +extern const struct reset_control_ops ccu_reset_ops; + +#endif /* _CCU_RESET_H_ */ The reset control code looks good.
Thanks!
Maxime--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
PATCH 2/16 clk: sunxi-ng: Add common infrastructure
In reply to Maxime RipardQuoted 12 lines · On Sun, 15 May 2016 20:31:22 +0200 Maxime Ripard…
Quoted 11 lines
drivers/clk/sunxi-ng/ccu_common.c line 35
Quoted 9 lines
drivers/clk/sunxi-ng/ccu_common.c new file +9
-0+void ccu_helper_wait_for_lock (struct ccu_common *common,u32 lock) +{ +u32 reg; + +if (!(common->features &CCU_FEATURE_LOCK )) +return ; + +WARN_ON (readl_relaxed_poll_timeout (common->base + common->reg, reg, + !(reg & lock),0 ,500 ));no delay between reads? ^
Quoted 3 lines
Yes, I intended it to be a simple busy waiting loop since I don't expect it to be very long. Do yu have any more data on how much time it usually takes?
I have a Soc in which the rate of the audio clock is stable after a good second.
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 2/16 clk: sunxi-ng: Add common infrastructure
Hi Jean-Francois,
Quoted 15 lines · Jean-Francois Moine
Quoted 12 lines · On Sun, 15 May 2016 20:31:22 +0200 Maxime Ripard…
Quoted 11 lines
drivers/clk/sunxi-ng/ccu_common.c line 35
Quoted 9 lines
drivers/clk/sunxi-ng/ccu_common.c new file +9
-0+void ccu_helper_wait_for_lock (struct ccu_common *common,u32 lock) +{ +u32 reg; + +if (!(common->features &CCU_FEATURE_LOCK )) +return ; + +WARN_ON (readl_relaxed_poll_timeout (common->base + common->reg, reg, + !(reg & lock),0 ,500 ));no delay between reads? ^
Quoted 6 lines
Quoted 3 lines
Yes, I intended it to be a simple busy waiting loop since I don't expect it to be very long. Do yu have any more data on how much time it usually takes?
I have a Soc in which the rate of the audio clock is stable after a good second.
You mean before the clock is actually stable, or before the lock bit is cleared?
Which SoC is it? As far as I've seen, only the H3 allows to configure the stable time, and while by default it will take 16us, you can configure as high as 66ms (which is still way higher than the current limit).
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160516/c43f8041/attachment.sig>
PATCH 2/16 clk: sunxi-ng: Add common infrastructure
Quoted 7 lines · On Mon, 16 May 2016 22:15:09 +0200 Maxime Ripard…
Quoted 6 lines
Quoted 3 lines
Yes, I intended it to be a simple busy waiting loop since I don't expect it to be very long. Do yu have any more data on how much time it usually takes?
I have a Soc in which the rate of the audio clock is stable after a good second.
Quoted 7 lines
You mean before the clock is actually stable, or before the lock bit is cleared?
Which SoC is it? As far as I've seen, only the H3 allows to configure the stable time, and while by default it will take 16us, you can configure as high as 66ms (which is still way higher than the current limit).
Hi Maxime,
Well, it is not a SoC, but an external chip, the SI5351 (in the Dove Cubox). There is no lock bit, but as it is used for audio, and as I did not set any delay at streaming start time, I can hear when the clock is stable.
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 2/16 clk: sunxi-ng: Add common infrastructure
Quoted 18 lines · Jean-Francois Moine
Quoted 7 lines · On Mon, 16 May 2016 22:15:09 +0200 Maxime Ripard…
Quoted 6 lines
Quoted 3 lines
Yes, I intended it to be a simple busy waiting loop since I don't expect it to be very long. Do yu have any more data on how much time it usually takes?
I have a Soc in which the rate of the audio clock is stable after a good second.
Quoted 7 lines
You mean before the clock is actually stable, or before the lock bit is cleared?
Which SoC is it? As far as I've seen, only the H3 allows to configure the stable time, and while by default it will take 16us, you can configure as high as 66ms (which is still way higher than the current limit).
Quoted 6 lines
Hi Maxime,
Well, it is not a SoC, but an external chip, the SI5351 (in the Dove Cubox). There is no lock bit, but as it is used for audio, and as I did not set any delay at streaming start time, I can hear when the clock is stable.
Ok. So I guess we set it high enough to cover the maximum we know for know (65ms), and we can always rise that up later if needed.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160518/a06a27a8/attachment.sig>
PATCH 3/16 clk: sunxi-ng: Add fixed factor clock support
In reply to Maxime RipardSome clocks in the Allwinner SoCs clock units are direct, fixed, multipliers or dividers from their parent.
Add support for such clocks.
--- drivers/clk/sunxi-ng/Makefile | 2 ++ drivers/clk/sunxi-ng/ccu_fixed_factor.c | 42 +++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_fixed_factor.h | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.c create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.h
drivers/clk/sunxi-ng/Makefile +2 -0
@@ -1,2 +1,4 @@ obj-y += ccu_common.o obj-y += ccu_reset.o + +obj-y += ccu_fixed_factor.o
drivers/clk/sunxi-ng/ccu_fixed_factor.c new file +42 -0
42 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_fixed_factor.h new file +50 -0
50 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 3/16 clk: sunxi-ng: Add fixed factor clock support
Hi,
Quoted 39 lines · Maxime Ripard
Some clocks in the Allwinner SoCs clock units are direct, fixed, multipliers or dividers from their parent.
Add support for such clocks.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 ++ drivers/clk/sunxi-ng/ccu_fixed_factor.c | 42 +++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_fixed_factor.h | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.c create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -1,2 +1,4 @@ obj-y += ccu_common.o obj-y += ccu_reset.o + +obj-y += ccu_fixed_factor.odrivers/clk/sunxi-ng/ccu_fixed_factor.c new file +10
-0@@ -0,0 +1,42 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ +
drivers/clk/sunxi-ng/ccu_fixed_factor.c line 20
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_fixed_factor.c new file +10
-0+#include <linux/clk-provider.h> + +#include "ccu_fixed_factor.h" + +static unsigned long ccu_fixed_factor_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +struct ccu_fixed_factor *fix =hw_to_ccu_fixed_factor (hw); + +return parent_rate * fix->mult / fix->div;
do_div (from include/asm-generic/div64.h) is better, since this is an 64 bit value.
drivers/clk/sunxi-ng/ccu_fixed_factor.c line 29
Quoted 9 lines
drivers/clk/sunxi-ng/ccu_fixed_factor.c new file +9
-0+} + +static long ccu_fixed_factor_round_rate (struct clk_hw *hw, +unsigned long rate, +unsigned long *parent_rate) +{ +struct ccu_fixed_factor *fix =hw_to_ccu_fixed_factor (hw); + +return *parent_rate / fix->div * fix->mult;
Why is this the other way around? With integer math it shouldn't be interchangeable. (Though it seems clk_fixed_factor does the same...)
Also, clk_fixed_factor handles CLK_SET_RATE_PARENT. Do we need to do the same here?
Quoted 70 lines
drivers/clk/sunxi-ng/ccu_fixed_factor.c new file +13
-0+} + +static int ccu_fixed_factor_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +return 0 ; +} + +const struct clk_ops ccu_fixed_factor_ops = { + .recalc_rate = ccu_fixed_factor_recalc_rate, + .round_rate = ccu_fixed_factor_round_rate, + .set_rate = ccu_fixed_factor_set_rate, +};drivers/clk/sunxi-ng/ccu_fixed_factor.h new file +50
-1@@ -0,0 +1,50 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_FIXED_FACTOR_H_ +#define _CCU_FIXED_FACTOR_H_ + +#include <linux/clk-provider.h> + +#include "ccu_common.h" + +struct ccu_fixed_factor { +u16 div; +u16 mult; + +struct ccu_common common; +}; + +#define SUNXI_CCU_FIXED_FACTOR (_struct, _name, _parent, \ + _div, _mult, _flags) \ + struct ccu_fixed_factor _struct = { \ + .div = _div, \ + .mult = _mult, \ + .common = { \ + .hw.init = SUNXI_HW_INIT(_name, \ + _parent, \ + &ccu_fixed_factor_ops, \ + _flags), \ + }, \ + } + +static inline struct ccu_fixed_factor *hw_to_ccu_fixed_factor (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_fixed_factor, common); +} + +extern const struct clk_ops ccu_fixed_factor_ops; + +#endif /* _CCU_FIXED_FACTOR_H_ */ --
Quoted 2 lines
2.8.2
Regards
ChenYu
PATCH 3/16 clk: sunxi-ng: Add fixed factor clock support
Quoted 13 lines · On Mon, 9 May 2016 18:05:20 +0800 Chen-Yu Tsai <[email protected]> wrote:
drivers/clk/sunxi-ng/ccu_fixed_factor.c line 29
Quoted 9 lines
drivers/clk/sunxi-ng/ccu_fixed_factor.c new file +9
-0+} + +static long ccu_fixed_factor_round_rate (struct clk_hw *hw, +unsigned long rate, +unsigned long *parent_rate) +{ +struct ccu_fixed_factor *fix =hw_to_ccu_fixed_factor (hw); + +return *parent_rate / fix->div * fix->mult;Why is this the other way around? With integer math it shouldn't be interchangeable. (Though it seems
clk_fixed_factordoes the same...)
Quoted 2 lines
Also,
clk_fixed_factorhandlesCLK_SET_RATE_PARENT. Do we need to do the same here?
Agree. Otherwise, sound in the H3 does not work.
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 3/16 clk: sunxi-ng: Add fixed factor clock support
In reply to Chen-Yu TsaiQuoted 48 lines · Chen-Yu Tsai
Hi,
Quoted 44 lines · Maxime Ripard
Some clocks in the Allwinner SoCs clock units are direct, fixed, multipliers or dividers from their parent.
Add support for such clocks.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 ++ drivers/clk/sunxi-ng/ccu_fixed_factor.c | 42 +++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_fixed_factor.h | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.c create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -1,2 +1,4 @@ obj-y += ccu_common.o obj-y += ccu_reset.o + +obj-y += ccu_fixed_factor.odrivers/clk/sunxi-ng/ccu_fixed_factor.c new file +15
-0@@ -0,0 +1,42 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> + +#include "ccu_fixed_factor.h" + +static unsigned long ccu_fixed_factor_recalc_rate(struct clk_hw *hw,
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_fixed_factor.c line 20
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_fixed_factor.c new file +5
-0+ unsigned long parent_rate) +{ +struct ccu_fixed_factor *fix =hw_to_ccu_fixed_factor (hw); + +return parent_rate * fix->mult / fix->div;
do_div(frominclude/asm-generic/div64.h) is better, since this is an 64 bit value.
unsigned long is 32 bits, but that's true.
Quoted 13 lines
drivers/clk/sunxi-ng/ccu_fixed_factor.c line 29
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_fixed_factor.c new file +9
-0+} + +static long ccu_fixed_factor_round_rate (struct clk_hw *hw, +unsigned long rate, +unsigned long *parent_rate) +{ +struct ccu_fixed_factor *fix =hw_to_ccu_fixed_factor (hw); + +return *parent_rate / fix->div * fix->mult;Why is this the other way around? With integer math it shouldn't be interchangeable. (Though it seems
clk_fixed_factordoes the same...)
I'm guessing this is so that it doesn't trip over UINT_MAX, but it doesn't really apply in our case. I'll make it consistant.
Quoted 3 lines
Also,
clk_fixed_factorhandlesCLK_SET_RATE_PARENT. Do we need to do the same here?
Indeed, I'll add it.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160516/4b467868/attachment.sig>
PATCH 4/16 clk: sunxi-ng: Add gate clock support
In reply to Maxime RipardSome clocks in the Allwinner SoCs clocks unit are just simple gates. Add support for those clocks.
Since it's a feature that can also be found in more complex clocks, provide a bunch of helpers that can be reused later on.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_gate.c | 82 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_gate.h | 53 ++++++++++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_gate.c create mode 100644 drivers/clk/sunxi-ng/ccu_gate.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -2,3 +2,4 @@ obj-y += ccu_common.o obj-y += ccu_reset.o obj-y += ccu_fixed_factor.o +obj-y += ccu_gate.o
drivers/clk/sunxi-ng/ccu_gate.c new file +82 -0
82 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_gate.h new file +53 -0
53 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 5/16 clk: sunxi-ng: Add mux clock support
In reply to Maxime RipardSome clocks in the Allwinner SoCs clocks unit are just muxes.
However, those muxes might also be found in some other complicated clocks that would benefit from the code in there to deal with "advanced" features, like pre-dividers.
Introduce a set of helpers to reduce the code duplication in such cases.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_mux.c | 187 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_mux.h | 80 +++++++++++++++++- 3 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 drivers/clk/sunxi-ng/ccu_mux.c
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -3,3 +3,4 @@ obj-y += ccu_reset.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o +obj-y += ccu_mux.o
drivers/clk/sunxi-ng/ccu_mux.c new file +187 -0
187 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_mux.h +76 -4
96 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 5/16 clk: sunxi-ng: Add mux clock support
Hi,
Quoted 92 lines · Maxime Ripard
Some clocks in the Allwinner SoCs clocks unit are just muxes.
However, those muxes might also be found in some other complicated clocks that would benefit from the code in there to deal with "advanced" features, like pre-dividers.
Introduce a set of helpers to reduce the code duplication in such cases.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_mux.c | 187 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_mux.h | 80 +++++++++++++++++- 3 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 drivers/clk/sunxi-ng/ccu_mux.cdrivers/clk/sunxi-ng/Makefile +1
-0@@ -3,3 +3,4 @@ obj-y += ccu_reset.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o +obj-y += ccu_mux.odrivers/clk/sunxi-ng/ccu_mux.c new file +61
-0@@ -0,0 +1,187 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> + +#include "ccu_gate.h" +#include "ccu_mux.h" + +void ccu_mux_helper_adjust_parent_for_prediv (struct ccu_common *common, +struct ccu_mux_internal *cm, +int parent_index, +unsigned long *parent_rate) +{ +u8 prediv =1 ; +u32 reg; + +if (!((common->features &CCU_FEATURE_FIXED_PREDIV ) || + (common->features &CCU_FEATURE_VARIABLE_PREDIV ))) +return ; + + reg =readl (common->base + common->reg); +if (parent_index <0 ) { + parent_index = reg >> cm->shift; + parent_index &= (1 << cm->width) -1 ; + } + +if (common->features &CCU_FEATURE_FIXED_PREDIV ) +if (parent_index == cm->fixed_prediv.index) + prediv = cm->fixed_prediv.div; + +if (common->features &CCU_FEATURE_VARIABLE_PREDIV ) +if (parent_index == cm->variable_prediv.index) { +u8 div; + + div = reg >> cm->variable_prediv.shift; + div &= (1 << cm->variable_prediv.width) -1 ; + prediv = div +1 ; + } + + *parent_rate = *parent_rate / prediv; +} + +int ccu_mux_helper_determine_rate (struct ccu_common *common, +struct ccu_mux_internal *cm, +struct clk_rate_request *req, +unsigned long (*round)(struct ccu_mux_internal *, +unsigned long , +unsigned long , +void *), +void *data) +{ +unsigned long best_parent_rate =0 , best_rate =0 ; +struct clk_hw *best_parent, *hw = &common->hw; +unsigned int i;
drivers/clk/sunxi-ng/ccu_mux.c line 71
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_mux.c new file +10
-0+ +for (i =0 ; i <clk_hw_get_num_parents (hw); i++) { +unsigned long tmp_rate, parent_rate; +struct clk_hw *parent; + + parent =clk_hw_get_parent_by_index (hw, i); +if (!parent) +continue ; + + parent_rate =clk_hw_get_rate (parent);
Using clk-mux.c as a reference, you should honor CLK_SET_RATE_PARENT here.
drivers/clk/sunxi-ng/ccu_mux.c line 73
Quoted 2 lines
drivers/clk/sunxi-ng/ccu_mux.c new file +2
-0+ccu_mux_helper_adjust_parent_for_prediv (common, cm, i, + &parent_rate);
ccu_mux_helper_adjust_parent_for_prediv can modify parent_rate. You should probably save a copy...
drivers/clk/sunxi-ng/ccu_mux.c line 78
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_mux.c new file +5
-0+ + tmp_rate =round (cm,clk_hw_get_rate (parent), req->rate, data); +if (tmp_rate == req->rate) { + best_parent = parent; + best_parent_rate = parent_rate;
... to assign to best_parent_rate. The returned best_parent_rate is used to change the parent clock rate. This happens if CLK_SET_RATE_PARENT is set. The CCF doesn't know about our predivs, so you should pass back the original rate, not the one after the prediv.
I suppose you didn't run into problems as CLK_SET_RATE_PARENT was not used anywhere?
Regards
ChenYu
Quoted 213 lines
drivers/clk/sunxi-ng/ccu_mux.c new file +109
-0+ best_rate = tmp_rate; + goto out; + } + +if ((req->rate - tmp_rate) < (req->rate - best_rate)) { + best_rate = tmp_rate; + best_parent_rate = parent_rate; + best_parent = parent; + } + } + +if (best_rate ==0 ) +return -EINVAL ; + +out: + req->best_parent_hw = best_parent; + req->best_parent_rate = best_parent_rate; + req->rate = best_rate; +return 0 ; +} + +u8 ccu_mux_helper_get_parent (struct ccu_common *common, +struct ccu_mux_internal *cm) +{ +u32 reg; +u8 parent; + + reg =readl (common->base + common->reg); + parent = reg >> cm->shift; + parent &= (1 << cm->width) -1 ; + +return parent; +} + +int ccu_mux_helper_set_parent (struct ccu_common *common, +struct ccu_mux_internal *cm, +u8 index) +{ +unsigned long flags; +u32 reg; + +spin_lock_irqsave (common->lock, flags); + + reg =readl (common->base + common->reg); + reg &= ~GENMASK (cm->width + cm->shift, cm->shift); +writel (reg | (index << cm->shift), common->base + common->reg); + +spin_unlock_irqrestore (common->lock, flags); + +return 0 ; +} + +static void ccu_mux_disable (struct clk_hw *hw) +{ +struct ccu_mux *cm =hw_to_ccu_mux (hw); + +return ccu_gate_helper_disable (&cm->common, cm->enable); +} + +static int ccu_mux_enable (struct clk_hw *hw) +{ +struct ccu_mux *cm =hw_to_ccu_mux (hw); + +return ccu_gate_helper_enable (&cm->common, cm->enable); +} + +static int ccu_mux_is_enabled (struct clk_hw *hw) +{ +struct ccu_mux *cm =hw_to_ccu_mux (hw); + +return ccu_gate_helper_is_enabled (&cm->common, cm->enable); +} + +static u8 ccu_mux_get_parent (struct clk_hw *hw) +{ +struct ccu_mux *cm =hw_to_ccu_mux (hw); + +return ccu_mux_helper_get_parent (&cm->common, &cm->mux); +} + +static int ccu_mux_set_parent (struct clk_hw *hw,u8 index) +{ +struct ccu_mux *cm =hw_to_ccu_mux (hw); + +return ccu_mux_helper_set_parent (&cm->common, &cm->mux, index); +} + +static unsigned long ccu_mux_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +struct ccu_mux *cm =hw_to_ccu_mux (hw); + +ccu_mux_helper_adjust_parent_for_prediv (&cm->common, &cm->mux,-1 , + &parent_rate); + +return parent_rate; +} + +const struct clk_ops ccu_mux_ops = { + .disable = ccu_mux_disable, + .enable = ccu_mux_enable, + .is_enabled = ccu_mux_is_enabled, + + .get_parent = ccu_mux_get_parent, + .set_parent = ccu_mux_set_parent, + + .determine_rate = __clk_mux_determine_rate, + .recalc_rate = ccu_mux_recalc_rate, +};drivers/clk/sunxi-ng/ccu_mux.h +76
-5@@ -1,20 +1,92 @@#ifndef _CCU_MUX_H_#define _CCU_MUX_H_ -#include "common.h" +#include <linux/clk-provider.h> + +#include "ccu_common.h" struct ccu_mux_internal {u8 shift;u8 width; -u8 *map; +struct { +u8 index; +u8 div; + } fixed_prediv; + +struct { +u8 index; +u8 shift; +u8 width; + } variable_prediv; }; -#define SUNXI_CLK_MUX (_shift, _width, _map) \ +#define SUNXI_CLK_MUX (_shift, _width) \ { \ - .map = _map, \ .shift = _shift, \ .width = _width, \ } +struct ccu_mux { +u16 reg; +u32 enable; + +struct ccu_mux_internal mux; +struct ccu_common common; +}; + +#define SUNXI_CCU_MUX (_struct, _name, _parents, _reg, _shift, _width, _flags) \ + struct ccu_mux _struct = { \ + .mux = SUNXI_CLK_MUX(_shift, _width), \ + .common = { \ + .reg = _reg, \ + .hw.init = SUNXI_HW_INIT_PARENTS(_name, \ + _parents, \ + &ccu_mux_ops, \ + _flags), \ + } \ + } + +#define SUNXI_CCU_MUX_WITH_GATE (_struct, _name, _parents, _reg, \ + _shift, _width, _gate, _flags) \ + struct ccu_mux _struct = { \ + .enable = _gate, \ + .mux = SUNXI_CLK_MUX(_shift, _width), \ + .common = { \ + .reg = _reg, \ + .features = CCU_FEATURE_GATE, \ + .hw.init = SUNXI_HW_INIT_PARENTS(_name, \ + _parents, \ + &ccu_mux_ops, \ + _flags), \ + } \ + } + +static inline struct ccu_mux *hw_to_ccu_mux (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_mux, common); +} + +extern const struct clk_ops ccu_mux_ops; + +void ccu_mux_helper_adjust_parent_for_prediv (struct ccu_common *common, +struct ccu_mux_internal *cm, +int parent_index, +unsigned long *parent_rate); +int ccu_mux_helper_determine_rate (struct ccu_common *common, +struct ccu_mux_internal *cm, +struct clk_rate_request *req, +unsigned long (*round)(struct ccu_mux_internal *, +unsigned long , +unsigned long , +void *), +void *data); +u8 ccu_mux_helper_get_parent (struct ccu_common *common, +struct ccu_mux_internal *cm); +int ccu_mux_helper_set_parent (struct ccu_common *common, +struct ccu_mux_internal *cm, +u8 index); +#endif /* _CCU_MUX_H_ */ --2.8.2
PATCH 5/16 clk: sunxi-ng: Add mux clock support
Hi,
Quoted 121 lines · Chen-Yu Tsai
Hi,
Quoted 92 lines · Maxime Ripard
Some clocks in the Allwinner SoCs clocks unit are just muxes.
However, those muxes might also be found in some other complicated clocks that would benefit from the code in there to deal with "advanced" features, like pre-dividers.
Introduce a set of helpers to reduce the code duplication in such cases.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_mux.c | 187 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_mux.h | 80 +++++++++++++++++- 3 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 drivers/clk/sunxi-ng/ccu_mux.cdrivers/clk/sunxi-ng/Makefile +1
-0@@ -3,3 +3,4 @@ obj-y += ccu_reset.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o +obj-y += ccu_mux.odrivers/clk/sunxi-ng/ccu_mux.c new file +61
-0@@ -0,0 +1,187 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> + +#include "ccu_gate.h" +#include "ccu_mux.h" + +void ccu_mux_helper_adjust_parent_for_prediv (struct ccu_common *common, +struct ccu_mux_internal *cm, +int parent_index, +unsigned long *parent_rate) +{ +u8 prediv =1 ; +u32 reg; + +if (!((common->features &CCU_FEATURE_FIXED_PREDIV ) || + (common->features &CCU_FEATURE_VARIABLE_PREDIV ))) +return ; + + reg =readl (common->base + common->reg); +if (parent_index <0 ) { + parent_index = reg >> cm->shift; + parent_index &= (1 << cm->width) -1 ; + } + +if (common->features &CCU_FEATURE_FIXED_PREDIV ) +if (parent_index == cm->fixed_prediv.index) + prediv = cm->fixed_prediv.div; + +if (common->features &CCU_FEATURE_VARIABLE_PREDIV ) +if (parent_index == cm->variable_prediv.index) { +u8 div; + + div = reg >> cm->variable_prediv.shift; + div &= (1 << cm->variable_prediv.width) -1 ; + prediv = div +1 ; + } + + *parent_rate = *parent_rate / prediv; +} + +int ccu_mux_helper_determine_rate (struct ccu_common *common, +struct ccu_mux_internal *cm, +struct clk_rate_request *req, +unsigned long (*round)(struct ccu_mux_internal *, +unsigned long , +unsigned long , +void *), +void *data) +{ +unsigned long best_parent_rate =0 , best_rate =0 ; +struct clk_hw *best_parent, *hw = &common->hw; +unsigned int i;drivers/clk/sunxi-ng/ccu_mux.c line 71
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_mux.c new file +10
-0+ +for (i =0 ; i <clk_hw_get_num_parents (hw); i++) { +unsigned long tmp_rate, parent_rate; +struct clk_hw *parent; + + parent =clk_hw_get_parent_by_index (hw, i); +if (!parent) +continue ; + + parent_rate =clk_hw_get_rate (parent);Using
clk-mux.cas a reference, you should honorCLK_SET_RATE_PARENThere.drivers/clk/sunxi-ng/ccu_mux.c line 73
Quoted 2 lines
drivers/clk/sunxi-ng/ccu_mux.c new file +2
-0+ccu_mux_helper_adjust_parent_for_prediv (common, cm, i, + &parent_rate);
ccu_mux_helper_adjust_parent_for_predivcan modifyparent_rate. You should probably save a copy...drivers/clk/sunxi-ng/ccu_mux.c line 78
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_mux.c new file +5
-0+ + tmp_rate =round (cm,clk_hw_get_rate (parent), req->rate, data); +if (tmp_rate == req->rate) { + best_parent = parent; + best_parent_rate = parent_rate;
Quoted 7 lines
... to assign to
best_parent_rate. The returnedbest_parent_rateis used to change the parent clock rate. This happens ifCLK_SET_RATE_PARENTis set. The CCF doesn't know about our predivs, so you should pass back the original rate, not the one after the prediv.I suppose you didn't run into problems as
CLK_SET_RATE_PARENTwas not used anywhere?
Probably, yes. You do have a good point, but I'm a bit unconfident merging some code that hasn't been tested, and will probably end up broken anyway. This is always something that we can add later.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160522/43ff552c/attachment.sig>
PATCH 6/16 clk: sunxi-ng: Add divider table clock
In reply to Maxime RipardAdd support for clocks based on a divider tables.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_div_table.c | 117 +++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_div_table.h | 75 ++++++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_div_table.c create mode 100644 drivers/clk/sunxi-ng/ccu_div_table.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -1,6 +1,7 @@ obj-y += ccu_common.o obj-y += ccu_reset.o +obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o obj-y += ccu_mux.o
drivers/clk/sunxi-ng/ccu_div_table.c new file +117 -0
117 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_div_table.h new file +75 -0
75 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 6/16 clk: sunxi-ng: Add divider table clock
Hi,
Quoted 56 lines · Maxime Ripard
Add support for clocks based on a divider tables.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_div_table.c | 117 +++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_div_table.h | 75 ++++++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_div_table.c create mode 100644 drivers/clk/sunxi-ng/ccu_div_table.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -1,6 +1,7 @@ obj-y += ccu_common.o obj-y += ccu_reset.o +obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o obj-y += ccu_mux.odrivers/clk/sunxi-ng/ccu_div_table.c new file +27
-0@@ -0,0 +1,117 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> + +#include "ccu_div_table.h" +#include "ccu_gate.h" + +static void ccu_div_table_find_best (unsigned long parent,unsigned long rate, +struct ccu_div_table *ct, +unsigned int *index) +{ +unsigned long best_rate =0 ; +unsigned int best_index =0 ; +unsigned int _index; + +for (_index =0 ; _index <= ct->num_divs; _index++) { +unsigned long tmp_rate = parent / ct->table[_index]; + +if (tmp_rate > rate)
drivers/clk/sunxi-ng/ccu_div_table.c line 37
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_div_table.c new file +10
-0+continue ; + +if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_index = _index; + } + } + + *index = best_index; +}
You can drop this function and use the CCF helpers (mentioned below) instead.
Quoted 25 lines
drivers/clk/sunxi-ng/ccu_div_table.c new file +25
-0+ +static void ccu_div_table_disable (struct clk_hw *hw) +{ +struct ccu_div_table *ct =hw_to_ccu_div_table (hw); + +return ccu_gate_helper_disable (&ct->common, ct->enable); +} + +static int ccu_div_table_enable (struct clk_hw *hw) +{ +struct ccu_div_table *ct =hw_to_ccu_div_table (hw); + +return ccu_gate_helper_enable (&ct->common, ct->enable); +} + +static int ccu_div_table_is_enabled (struct clk_hw *hw) +{ +struct ccu_div_table *ct =hw_to_ccu_div_table (hw); + +return ccu_gate_helper_is_enabled (&ct->common, ct->enable); +} + +static unsigned long ccu_div_table_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{
drivers/clk/sunxi-ng/ccu_div_table.c line 72
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_div_table.c new file +10
-0+struct ccu_div_table *ct =hw_to_ccu_div_table (hw); +unsigned long div; +u32 reg; + + reg =readl (ct->common.base + ct->common.reg); + + div = reg >> ct->div.shift; + div &= (1 << ct->div.width) -1 ; + +return parent_rate / ct->table[div];
CCF provides divider_recalc_rate().
drivers/clk/sunxi-ng/ccu_div_table.c line 84
Quoted 12 lines
drivers/clk/sunxi-ng/ccu_div_table.c new file +12
-0+} + +static long ccu_div_table_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *parent_rate) +{ +struct ccu_div_table *ct =hw_to_ccu_div_table (hw); +unsigned int index; + +ccu_div_table_find_best (*parent_rate, rate, + ct, &index); + +return *parent_rate / ct->table[index];
CCF provides divider_round_rate().
drivers/clk/sunxi-ng/ccu_div_table.c line 95
Quoted 11 lines
drivers/clk/sunxi-ng/ccu_div_table.c new file +11
-0+} + +static int ccu_div_table_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_div_table *ct =hw_to_ccu_div_table (hw); +unsigned long flags; +unsigned int index; +u32 reg; + +ccu_div_table_find_best (parent_rate, rate, ct, &index);
CCF provides divider_get_val().
Quoted 43 lines
drivers/clk/sunxi-ng/ccu_div_table.c new file +22
-0+ +spin_lock_irqsave (ct->common.lock, flags); + + reg =readl (ct->common.base + ct->common.reg); + reg &= ~GENMASK (ct->div.width + ct->div.shift, ct->div.shift); +writel (reg | ((ct->table[index]) << ct->div.shift), + ct->common.base + ct->common.reg); + +spin_unlock_irqrestore (ct->common.lock, flags); + +return 0 ; +} + +const struct clk_ops ccu_div_table_ops = { + .disable = ccu_div_table_disable, + .enable = ccu_div_table_enable, + .is_enabled = ccu_div_table_is_enabled, + + .recalc_rate = ccu_div_table_recalc_rate, + .round_rate = ccu_div_table_round_rate, + .set_rate = ccu_div_table_set_rate, +};drivers/clk/sunxi-ng/ccu_div_table.h new file +15
-0@@ -0,0 +1,75 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_DIV_TABLE_H_ +#define _CCU_DIV_TABLE_H_
drivers/clk/sunxi-ng/ccu_div_table.h line 25
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_div_table.h new file +10
-0+ +#include <linux/clk-provider.h> + +#include "ccu_common.h" +#include "ccu_factor.h" + +struct ccu_div_table { +u32 enable; + +u8 *table;
I suggest using struct clk_div_table instead, to be able to use the CCF helpers.
drivers/clk/sunxi-ng/ccu_div_table.h line 26
Quoted 1 line
drivers/clk/sunxi-ng/ccu_div_table.h new file +1
-0+int num_divs;
This field won't be needed then, but you should add a divider flags field.
Regards
ChenYu
Quoted 52 lines
drivers/clk/sunxi-ng/ccu_div_table.h new file +49
-1+ +struct ccu_factor div; +struct ccu_common common; +}; + +#define SUNXI_CCU_DIV_TABLE (_struct, _name, _parent, _reg, \ + _shift, _width, \ + _table, _flags) \ + struct ccu_div_table _struct = { \ + .table = _table, \ + .num_divs = ARRAY_SIZE(_table), \ + .div = SUNXI_CLK_FACTOR(_shift, _width), \ + .common = { \ + .reg = _reg, \ + .hw.init = SUNXI_HW_INIT(_name, \ + _parent, \ + &ccu_div_table_ops, \ + _flags), \ + } \ + } + +#define SUNXI_CCU_DIV_TABLE_WITH_GATE (_struct, _name, _parent, _reg, \ + _shift, _width, \ + _table, _gate, _flags) \ + struct ccu_div_table _struct = { \ + .enable = _gate, \ + .table = _table, \ + .num_divs = ARRAY_SIZE(_table), \ + .div = SUNXI_CLK_FACTOR(_shift, _width), \ + .common = { \ + .reg = _reg, \ + .features = CCU_FEATURE_GATE, \ + .hw.init = SUNXI_HW_INIT(_name, \ + _parent, \ + &ccu_div_table_ops, \ + _flags), \ + } \ + } + +static inline struct ccu_div_table *hw_to_ccu_div_table (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_div_table, common); +} + +extern const struct clk_ops ccu_div_table_ops; + +#endif /* _CCU_DIV_H_ */ --2.8.2
PATCH 7/16 clk: sunxi-ng: Add phase clock support
In reply to Maxime RipardAdd support for the clocks in the CCU that introduce a phase shift from their parent clock.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_phase.c | 126 +++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_phase.h | 50 ++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_phase.c create mode 100644 drivers/clk/sunxi-ng/ccu_phase.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -5,3 +5,4 @@ obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o obj-y += ccu_mux.o +obj-y += ccu_phase.o
drivers/clk/sunxi-ng/ccu_phase.c new file +126 -0
126 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_phase.h new file +50 -0
50 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 7/16 clk: sunxi-ng: Add phase clock support
Hi,
Quoted 47 lines · Maxime Ripard
Add support for the clocks in the CCU that introduce a phase shift from their parent clock.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_phase.c | 126 +++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_phase.h | 50 ++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_phase.c create mode 100644 drivers/clk/sunxi-ng/ccu_phase.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -5,3 +5,4 @@ obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o obj-y += ccu_mux.o +obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_phase.c new file +20
-0@@ -0,0 +1,126 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> +#include <linux/spinlock.h> + +#include "ccu_phase.h" + +static int ccu_phase_get_phase (struct clk_hw *hw) +{ +struct ccu_phase *phase =hw_to_ccu_phase (hw); +struct clk_hw *parent, *pparent; +unsigned int parent_rate, pparent_rate;
drivers/clk/sunxi-ng/ccu_phase.c line 30
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +10
-0+u16 step, parent_div; +u32 reg; +u8 delay; + + reg =readl (phase->common.base + phase->common.reg); + delay = (reg >> phase->shift); + delay &= (1 << phase->width) -1 ; + +if (!delay) +return 180 ;
I don't understand why a "no delay" would be 180 phase. More on this below.
Quoted 23 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +23
-0+ +/* Get our parent clock, it's the one that can adjust its rate */ + parent =clk_hw_get_parent (hw); +if (!parent) +return -EINVAL ; + +/* And its rate */ + parent_rate =clk_hw_get_rate (parent); +if (!parent_rate) +return -EINVAL ; + +/* Now, get our parent's parent (most likely some PLL) */ + pparent =clk_hw_get_parent (parent); +if (!pparent) +return -EINVAL ; + +/* And its rate */ + pparent_rate =clk_hw_get_rate (pparent); +if (!pparent_rate) +return -EINVAL ; + +/* Get our parent clock divider */ + parent_div = pparent_rate / parent_rate;
drivers/clk/sunxi-ng/ccu_phase.c line 63
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +10
-0+ + step =DIV_ROUND_CLOSEST (360 , parent_div); +return delay * step; +} + +static int ccu_phase_set_phase (struct clk_hw *hw,int degrees) +{ +struct ccu_phase *phase =hw_to_ccu_phase (hw); +struct clk_hw *parent, *pparent; +unsigned int parent_rate, pparent_rate;
grandparent(_rate) would be easier to understand.
Quoted 35 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +35
-0+unsigned long flags; +u32 reg; +u8 delay; + +/* Get our parent clock, it's the one that can adjust its rate */ + parent =clk_hw_get_parent (hw); +if (!parent) +return -EINVAL ; + +/* And its rate */ + parent_rate =clk_hw_get_rate (parent); +if (!parent_rate) +return -EINVAL ; + +/* Now, get our parent's parent (most likely some PLL) */ + pparent =clk_hw_get_parent (parent); +if (!pparent) +return -EINVAL ; + +/* And its rate */ + pparent_rate =clk_hw_get_rate (pparent); +if (!pparent_rate) +return -EINVAL ; + +if (degrees !=180 ) { +u16 step, parent_div; + +/* Get our parent divider */ + parent_div = pparent_rate / parent_rate; + +/* +* We can only outphase the clocks by multiple of the +* PLL's period. +* +* Since our parent clock is only a divider, and the
drivers/clk/sunxi-ng/ccu_phase.c line 108
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +10
-0+* formula to get the outphasing in degrees is deg = +* 360 * delta / period +* +* If we simplify this formula, we can see that the +* only thing that we're concerned about is the number +* of period we want to outphase our clock from, and +* the divider set by our parent clock. +*/ + step =DIV_ROUND_CLOSEST (360 , parent_div); + delay =DIV_ROUND_CLOSEST (degrees, step);
Doesn't this mean some delay values are impossible to set?
For instance, for PLL = 600 MHz and this clock = 50 MHz, div would be 12, and a step would be 30 degrees. This means we can't ask for a delay of 6, which is 180 degrees.
For PLL = 600 MHz, clock = 100 MHz, div would be 6, and a step is 60 degrees. Therefor we can't ask for a delay of 3.
Does this make sense?
Quoted 37 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +18
-0+ }else { + delay =0 ; + } + +spin_lock_irqsave (phase->common.lock, flags); + reg =readl (phase->common.base + phase->common.reg); + reg &= ~GENMASK (phase->width + phase->shift, phase->shift); +writel (reg | (delay << phase->shift), + phase->common.base + phase->common.reg); +spin_unlock_irqrestore (phase->common.lock, flags); + +return 0 ; +} + +const struct clk_ops ccu_phase_ops = { + .get_phase = ccu_phase_get_phase, + .set_phase = ccu_phase_set_phase, +};drivers/clk/sunxi-ng/ccu_phase.h new file +13
-0@@ -0,0 +1,50 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ +
drivers/clk/sunxi-ng/ccu_phase.h line 23
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_phase.h new file +10
-0+#ifndef _CCU_PHASE_H_ +#define _CCU_PHASE_H_ + +#include <linux/clk-provider.h> + +#include "ccu_common.h" + +struct ccu_phase { + u8 shift; + u8 width;
Not sure why you used struct ccu_factor in the divider table clock, but separate fields directly in ccu_phase here.
Regards
ChenYu
Quoted 30 lines
drivers/clk/sunxi-ng/ccu_phase.h new file +27
-1+ +struct ccu_common common; +}; + +#define SUNXI_CCU_PHASE (_struct, _name, _parent, _reg, _shift, _width, _flags) \ + struct ccu_phase _struct = { \ + .shift = _shift, \ + .width = _width, \ + .common = { \ + .reg = _reg, \ + .hw.init = SUNXI_HW_INIT(_name, \ + _parent, \ + &ccu_phase_ops, \ + _flags), \ + } \ + } + +static inline struct ccu_phase *hw_to_ccu_phase (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_phase, common); +} + +extern const struct clk_ops ccu_phase_ops; + +#endif /* _CCU_PHASE_H_ */ --2.8.2
PATCH 7/16 clk: sunxi-ng: Add phase clock support
Hi,
Quoted 7 lines · Chen-Yu Tsai
drivers/clk/sunxi-ng/ccu_phase.c line 63
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +5
-0+static int ccu_phase_set_phase (struct clk_hw *hw,int degrees) +{ +struct ccu_phase *phase =hw_to_ccu_phase (hw); +struct clk_hw *parent, *pparent; +unsigned int parent_rate, pparent_rate;
grandparent(_rate)would be easier to understand.
Ack.
Quoted 49 lines
Quoted 36 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +35
-0+unsigned long flags; +u32 reg; +u8 delay; + +/* Get our parent clock, it's the one that can adjust its rate */ + parent =clk_hw_get_parent (hw); +if (!parent) +return -EINVAL ; + +/* And its rate */ + parent_rate =clk_hw_get_rate (parent); +if (!parent_rate) +return -EINVAL ; + +/* Now, get our parent's parent (most likely some PLL) */ + pparent =clk_hw_get_parent (parent); +if (!pparent) +return -EINVAL ; + +/* And its rate */ + pparent_rate =clk_hw_get_rate (pparent); +if (!pparent_rate) +return -EINVAL ; + +if (degrees !=180 ) { +u16 step, parent_div; + +/* Get our parent divider */ + parent_div = pparent_rate / parent_rate; + +/* +* We can only outphase the clocks by multiple of the +* PLL's period. +* +* Since our parent clock is only a divider, and the drivers/clk/sunxi-ng/ccu_phase.c line 108
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +10
-0+* formula to get the outphasing in degrees is deg = +* 360 * delta / period +* +* If we simplify this formula, we can see that the +* only thing that we're concerned about is the number +* of period we want to outphase our clock from, and +* the divider set by our parent clock. +*/ + step =DIV_ROUND_CLOSEST (360 , parent_div); + delay =DIV_ROUND_CLOSEST (degrees, step);Doesn't this mean some delay values are impossible to set?
Quoted 6 lines
For instance, for PLL = 600 MHz and this clock = 50 MHz, div would be 12, and a step would be 30 degrees. This means we can't ask for a delay of 6, which is 180 degrees.
For PLL = 600 MHz, clock = 100 MHz, div would be 6, and a step is 60 degrees. Therefor we can't ask for a delay of 3.
You don't ask for a delay, you ask for an outphasing in degrees. In the hardware, in the register 0 means an outphasing of 180 degrees (and this has been confirmed by Allwinner a while back). In the two cases you point out, we would have two ways of achieving the same thing, we prefer one over another, but I don't see how it's problematic.
It's also a direct copy of the current code we have, which didn't raise any objection, or had any known bugs.
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_phase.h line 23
Quoted 3 lines
drivers/clk/sunxi-ng/ccu_phase.h new file +3
-0+struct ccu_phase { +u8 shift; +u8 width;Not sure why you used struct
ccu_factorin the divider table clock, but separate fields directly inccu_phasehere.
Because this is not meant for the same thing. ccu_factor is probably going to go away anyway because of the dividers consolidation.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160523/2ae847cb/attachment-0001.sig>
PATCH 7/16 clk: sunxi-ng: Add phase clock support
Quoted 69 lines · Maxime Ripard
Hi,
Quoted 7 lines · Chen-Yu Tsai
drivers/clk/sunxi-ng/ccu_phase.c line 63
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +5
-0+static int ccu_phase_set_phase (struct clk_hw *hw,int degrees) +{ +struct ccu_phase *phase =hw_to_ccu_phase (hw); +struct clk_hw *parent, *pparent; +unsigned int parent_rate, pparent_rate;
grandparent(_rate)would be easier to understand.Ack.
Quoted 49 lines
Quoted 36 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +35
-0+unsigned long flags; +u32 reg; +u8 delay; + +/* Get our parent clock, it's the one that can adjust its rate */ + parent =clk_hw_get_parent (hw); +if (!parent) +return -EINVAL ; + +/* And its rate */ + parent_rate =clk_hw_get_rate (parent); +if (!parent_rate) +return -EINVAL ; + +/* Now, get our parent's parent (most likely some PLL) */ + pparent =clk_hw_get_parent (parent); +if (!pparent) +return -EINVAL ; + +/* And its rate */ + pparent_rate =clk_hw_get_rate (pparent); +if (!pparent_rate) +return -EINVAL ; + +if (degrees !=180 ) { +u16 step, parent_div; + +/* Get our parent divider */ + parent_div = pparent_rate / parent_rate; + +/* +* We can only outphase the clocks by multiple of the +* PLL's period. +* +* Since our parent clock is only a divider, and the drivers/clk/sunxi-ng/ccu_phase.c line 108
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_phase.c new file +10
-0+* formula to get the outphasing in degrees is deg = +* 360 * delta / period +* +* If we simplify this formula, we can see that the +* only thing that we're concerned about is the number +* of period we want to outphase our clock from, and +* the divider set by our parent clock. +*/ + step =DIV_ROUND_CLOSEST (360 , parent_div); + delay =DIV_ROUND_CLOSEST (degrees, step);Doesn't this mean some delay values are impossible to set?
Quoted 6 lines
For instance, for PLL = 600 MHz and this clock = 50 MHz, div would be 12, and a step would be 30 degrees. This means we can't ask for a delay of 6, which is 180 degrees.
For PLL = 600 MHz, clock = 100 MHz, div would be 6, and a step is 60 degrees. Therefor we can't ask for a delay of 3.
Quoted 6 lines
You don't ask for a delay, you ask for an outphasing in degrees. In the hardware, in the register 0 means an outphasing of 180 degrees (and this has been confirmed by Allwinner a while back). In the two cases you point out, we would have two ways of achieving the same thing, we prefer one over another, but I don't see how it's problematic.
I guess I find the outphasing degrees not being increasing somewhat odd...
Quoted 2 lines
It's also a direct copy of the current code we have, which didn't raise any objection, or had any known bugs.
I had a hard time wrapping this around my head when I was working on the MMC DDR stuff. Allwinner's code directly asks for a delay, not a outphasing. I just checked and it seems I converted some values incorrectly. I need to do some more tests for the A80...
Thanks for the explanation.
Regards
ChenYu
Quoted 18 lines
Quoted 7 lines
drivers/clk/sunxi-ng/ccu_phase.h line 23
Quoted 4 lines
drivers/clk/sunxi-ng/ccu_phase.h new file +3
-0+struct ccu_phase { +u8 shift; +u8 width;Not sure why you used struct
ccu_factorin the divider table clock, but separate fields directly inccu_phasehere.Because this is not meant for the same thing.
ccu_factoris probably going to go away anyway because of the dividers consolidation.Thanks!
Maxime--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
PATCH 8/16 clk: sunxi-ng: Add M-factor clock support
In reply to Maxime RipardIntroduce support for clocks that divide by a linear factor.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_m.c | 135 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_m.h | 101 +++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_m.c create mode 100644 drivers/clk/sunxi-ng/ccu_m.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -4,5 +4,6 @@ obj-y += ccu_reset.o obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o +obj-y += ccu_m.o obj-y += ccu_mux.o obj-y += ccu_phase.o
drivers/clk/sunxi-ng/ccu_m.c new file +135 -0
135 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_m.h new file +101 -0
101 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 8/16 clk: sunxi-ng: Add M-factor clock support
Quoted 28 lines · On Sun, 8 May 2016 22:01:43 +0200 Maxime Ripard…
Introduce support for clocks that divide by a linear factor.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_m.c | 135 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_m.h | 101 +++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_m.c create mode 100644 drivers/clk/sunxi-ng/ccu_m.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -4,5 +4,6 @@ obj-y += ccu_reset.o obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o +obj-y += ccu_m.o obj-y += ccu_mux.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_m.c new file +0
-0
drivers/clk/sunxi-ng/ccu_m.c line 9
Quoted 9 lines
drivers/clk/sunxi-ng/ccu_m.c new file +9
-0@@ -0,0 +1,135 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/
[snip]
Quoted 4 lines
drivers/clk/sunxi-ng/ccu_m.c new file +4
-0+static int ccu_m_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_m *cm =hw_to_ccu_m (hw);
drivers/clk/sunxi-ng/ccu_m.c line 100
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_m.c new file +10
-0+unsigned long flags; +unsigned int m; +u32 reg; + +ccu_m_find_best (parent_rate, rate,1 << cm->m.width, &m); + +spin_lock_irqsave (cm->common.lock, flags); + + reg =readl (cm->common.base + cm->common.reg); + reg &= ((1 << cm->m.width) -1 ) << cm->m.shift;
Bug:
reg &= ~GENMASK(cm->m.width + cm->m.shift, cm->m.shift);
drivers/clk/sunxi-ng/ccu_m.c line 108
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_m.c new file +8
-0+ +writel (reg | ((m -1 ) << cm->m.shift), + cm->common.base + cm->common.reg); + +spin_unlock_irqrestore (cm->common.lock, flags); + +return 0 ; +}
[snip]
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 8/16 clk: sunxi-ng: Add M-factor clock support
Quoted 57 lines · Jean-Francois Moine
Quoted 28 lines · On Sun, 8 May 2016 22:01:43 +0200 Maxime Ripard…
Introduce support for clocks that divide by a linear factor.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_m.c | 135 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_m.h | 101 +++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_m.c create mode 100644 drivers/clk/sunxi-ng/ccu_m.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -4,5 +4,6 @@ obj-y += ccu_reset.o obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o +obj-y += ccu_m.o obj-y += ccu_mux.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_m.c new file +0
-0drivers/clk/sunxi-ng/ccu_m.c line 9
Quoted 9 lines
drivers/clk/sunxi-ng/ccu_m.c new file +9
-0@@ -0,0 +1,135 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ [snip]Quoted 4 lines
drivers/clk/sunxi-ng/ccu_m.c new file +4
-0+static int ccu_m_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_m *cm =hw_to_ccu_m (hw);drivers/clk/sunxi-ng/ccu_m.c line 100
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_m.c new file +10
-0+unsigned long flags; +unsigned int m; +u32 reg; + +ccu_m_find_best (parent_rate, rate,1 << cm->m.width, &m); + +spin_lock_irqsave (cm->common.lock, flags); + + reg =readl (cm->common.base + cm->common.reg); + reg &= ((1 << cm->m.width) -1 ) << cm->m.shift;Bug:
Quoted 1 line
reg &= ~GENMASK(cm->m.width + cm->m.shift, cm->m.shift);
Indeed, this one slipped in, thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160515/4a3c02f5/attachment.sig>
PATCH 8/16 clk: sunxi-ng: Add M-factor clock support
In reply to Maxime RipardHi,
Quoted 1 line · Maxime Ripard
Introduce support for clocks that divide by a linear factor.
I think we can have just one implementation for single divide factor (either P or M)
clocks, using the CCF divider helpers. Even the divider table clock could be merged
in.
Quoted 43 lines
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_m.c | 135 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_m.h | 101 +++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_m.c create mode 100644 drivers/clk/sunxi-ng/ccu_m.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -4,5 +4,6 @@ obj-y += ccu_reset.o obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o +obj-y += ccu_m.o obj-y += ccu_mux.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_m.c new file +16
-0@@ -0,0 +1,135 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> + +#include "ccu_gate.h" +#include "ccu_m.h" +#include "ccu_mux.h" +
drivers/clk/sunxi-ng/ccu_m.c line 26
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_m.c new file +10
-0+static void ccu_m_find_best (unsigned long parent,unsigned long rate, +unsigned int max_m,unsigned int *m) +{ +unsigned int _m = parent / rate; + +if (_m > max_m) + _m = max_m; + + *m = _m; +}
This can go.
drivers/clk/sunxi-ng/ccu_m.c line 38
Quoted 12 lines
drivers/clk/sunxi-ng/ccu_m.c new file +12
-0+ +static unsigned long ccu_m_round_rate (struct ccu_mux_internal *mux, +unsigned long parent_rate, +unsigned long rate, +void *data) +{ +struct ccu_m *cm = data; +unsigned int m; + +ccu_m_find_best (parent_rate, rate,1 << cm->m.width, &m); + +return parent_rate / m;
Use divider_round_rate() helper instead.
Quoted 27 lines
drivers/clk/sunxi-ng/ccu_m.c new file +27
-0+} + + +static void ccu_m_disable (struct clk_hw *hw) +{ +struct ccu_m *cm =hw_to_ccu_m (hw); + +return ccu_gate_helper_disable (&cm->common, cm->enable); +} + +static int ccu_m_enable (struct clk_hw *hw) +{ +struct ccu_m *cm =hw_to_ccu_m (hw); + +return ccu_gate_helper_enable (&cm->common, cm->enable); +} + +static int ccu_m_is_enabled (struct clk_hw *hw) +{ +struct ccu_m *cm =hw_to_ccu_m (hw); + +return ccu_gate_helper_is_enabled (&cm->common, cm->enable); +} + +static unsigned long ccu_m_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{
drivers/clk/sunxi-ng/ccu_m.c line 75
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_m.c new file +10
-0+struct ccu_m *cm =hw_to_ccu_m (hw); +unsigned long m; +u32 reg; + + reg =readl (cm->common.base + cm->common.reg); + + m = reg >> cm->m.shift; + m &= (1 << cm->m.width) -1 ; + +return parent_rate / (m +1 );
Use divider_recalc_rate() helper.
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_m.c new file +10
-0+} + +static int ccu_m_determine_rate (struct clk_hw *hw, +struct clk_rate_request *req) +{ +struct ccu_m *cm =hw_to_ccu_m (hw); + +return ccu_mux_helper_determine_rate (&cm->common, &cm->mux, + req, ccu_m_round_rate, cm); +}
drivers/clk/sunxi-ng/ccu_m.c line 95
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_m.c new file +10
-0+ +static int ccu_m_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_m *cm =hw_to_ccu_m (hw); +unsigned long flags; +unsigned int m; +u32 reg; + +ccu_m_find_best (parent_rate, rate,1 << cm->m.width, &m);
Use divider_get_val() helper.
Quoted 60 lines
drivers/clk/sunxi-ng/ccu_m.c new file +40
-0+ +spin_lock_irqsave (cm->common.lock, flags); + + reg =readl (cm->common.base + cm->common.reg); + reg &= ((1 << cm->m.width) -1 ) << cm->m.shift; + +writel (reg | ((m -1 ) << cm->m.shift), + cm->common.base + cm->common.reg); + +spin_unlock_irqrestore (cm->common.lock, flags); + +return 0 ; +} + +static u8 ccu_m_get_parent (struct clk_hw *hw) +{ +struct ccu_m *cm =hw_to_ccu_m (hw); + +return ccu_mux_helper_get_parent (&cm->common, &cm->mux); +} + +static int ccu_m_set_parent (struct clk_hw *hw,u8 index) +{ +struct ccu_m *cm =hw_to_ccu_m (hw); + +return ccu_mux_helper_set_parent (&cm->common, &cm->mux, index); +} + +const struct clk_ops ccu_m_ops = { + .disable = ccu_m_disable, + .enable = ccu_m_enable, + .is_enabled = ccu_m_is_enabled, + + .get_parent = ccu_m_get_parent, + .set_parent = ccu_m_set_parent, + + .determine_rate = ccu_m_determine_rate, + .recalc_rate = ccu_m_recalc_rate, + .set_rate = ccu_m_set_rate, +};drivers/clk/sunxi-ng/ccu_m.h new file +14
-0@@ -0,0 +1,101 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_M_H_
drivers/clk/sunxi-ng/ccu_m.h line 24
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_m.h new file +10
-0+#define _CCU_M_H_ + +#include <linux/clk-provider.h> + +#include "ccu_common.h" +#include "ccu_factor.h" +#include "ccu_mux.h" + +struct ccu_m { +u32 enable;
Add a field for divider flags, such as CLK_DIVIDER_ONE_BASED and CLK_DIVIDER_POWER_OF_TWO. With these we can merge P & M factor clocks, and also be able to handle M factors starting from both 1 and 0.
Also add a field for divider tables to merge the divider table clock.
Quoted 39 lines
drivers/clk/sunxi-ng/ccu_m.h new file +39
-0+ +struct ccu_factor m; +struct ccu_mux_internal mux; +struct ccu_common common; +}; + +#define SUNXI_CCU_M (_struct, _name, _parent, _reg, _mshift, _mwidth, \ + _flags) \ + struct ccu_m _struct = { \ + .m = SUNXI_CLK_FACTOR(_mshift, _mwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init = SUNXI_HW_INIT(_name, \ + _parent, \ + &ccu_m_ops, \ + _flags), \ + }, \ + } + +#define SUNXI_CCU_M_WITH_GATE (_struct, _name, _parent, _reg, \ + _mshift, _mwidth, _gate, \ + _flags) \ + struct ccu_m _struct = { \ + .enable = _gate, \ + .m = SUNXI_CLK_FACTOR(_mshift, _mwidth), \ + .common = { \ + .reg = _reg, \ + .features = CCU_FEATURE_GATE, \ + .hw.init = SUNXI_HW_INIT(_name, \ + _parent, \ + &ccu_m_ops, \ + _flags), \ + }, \ + } + +#define SUNXI_CCU_M_WITH_MUX (_struct, _name, _parents, _reg, \ + _mshift, _mwidth, _muxshift, _muxwidth, \ + _flags) \ + struct ccu_m _struct = { \
drivers/clk/sunxi-ng/ccu_m.h line 73
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_m.h new file +10
-0+ .m = SUNXI_CLK_FACTOR(_mshift, _mwidth), \ + .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init =SUNXI_HW_INIT_PARENTS (_name, \ + _parents, \ + &ccu_m_ops, \ + _flags), \ + }, \ + }
Maybe you could use the full macro below to simplify the above 3, with the unused fields set to 0?
Regards
ChenYu
Quoted 31 lines
drivers/clk/sunxi-ng/ccu_m.h new file +28
-1+ +#define SUNXI_CCU_M_WITH_MUX_GATE (_struct, _name, _parents, _reg, \ + _mshift, _mwidth, _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_m _struct = { \ + .enable = _gate, \ + .m = SUNXI_CLK_FACTOR(_mshift, _mwidth), \ + .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .features = CCU_FEATURE_GATE, \ + .hw.init = SUNXI_HW_INIT_PARENTS(_name, \ + _parents, \ + &ccu_m_ops, \ + _flags), \ + }, \ + } + +static inline struct ccu_m *hw_to_ccu_m (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_m, common); +} + +extern const struct clk_ops ccu_m_ops; + +#endif /* _CCU_M_H_ */ --2.8.2
PATCH 8/16 clk: sunxi-ng: Add M-factor clock support
Quoted 11 lines · Chen-Yu Tsai
Hi,
Quoted 1 line · Maxime Ripard
Introduce support for clocks that divide by a linear factor.
I think we can have just one implementation for single divide factor (either P or M)
clocks, using the CCF divider helpers. Even the divider table clock could be merged
in.
This is a good point, I'll merge the drivers.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160522/0aa79e59/attachment.sig>
PATCH 9/16 clk: sunxi-ng: Add P-factor clock support
In reply to Maxime RipardIntroduce support for clocks that divide using a power of two factor.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_p.c | 141 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_p.h | 40 ++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_p.c create mode 100644 drivers/clk/sunxi-ng/ccu_p.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -6,4 +6,5 @@ obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o obj-y += ccu_m.o obj-y += ccu_mux.o +obj-y += ccu_p.o obj-y += ccu_phase.o
drivers/clk/sunxi-ng/ccu_p.c new file +141 -0
141 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_p.h new file +40 -0
@@ -0,0 +1,40 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_P_H_ +#define _CCU_P_H_ + +#include <linux/clk-provider.h> + +#include "ccu_common.h" +#include "ccu_factor.h" +#include "ccu_mux.h" + +struct ccu_p { +u32 enable; + +struct ccu_factor p; +struct ccu_mux_internal mux; +struct ccu_common common; +}; + +static inline struct ccu_p *hw_to_ccu_p (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_p, common); +} + +extern const struct clk_ops ccu_p_ops; + +#endif /* _CCU_P_H_ */
Signature · 1 line
2.8.2
PATCH 10/16 clk: sunxi-ng: Add M-P factor clock support
In reply to Maxime RipardIntroduce support for the clocks that combine a linear divider and a power-of-two based one.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_mp.c | 158 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_mp.h | 79 +++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_mp.c create mode 100644 drivers/clk/sunxi-ng/ccu_mp.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -5,6 +5,7 @@ obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o obj-y += ccu_m.o +obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_p.o obj-y += ccu_phase.o
drivers/clk/sunxi-ng/ccu_mp.c new file +158 -0
158 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_mp.h new file +79 -0
79 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 10/16 clk: sunxi-ng: Add M-P factor clock support
Hi,
Quoted 2 lines · Maxime Ripard
Introduce support for the clocks that combine a linear divider and a power-of-two based one.
A description or formula in the source code (for those of us that forget) would be nice. :)
Quoted 141 lines
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_mp.c | 158 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_mp.h | 79 +++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_mp.c create mode 100644 drivers/clk/sunxi-ng/ccu_mp.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -5,6 +5,7 @@ obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o obj-y += ccu_m.o +obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_mp.c new file +113
-0@@ -0,0 +1,158 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> + +#include "ccu_gate.h" +#include "ccu_mp.h" + +static void ccu_mp_find_best (unsigned long parent,unsigned long rate, +unsigned int max_m,unsigned int max_p, +unsigned int *m,unsigned int *p) +{ +unsigned long best_rate =0 ; +unsigned int best_m =0 , best_p =0 ; +unsigned int _m, _p; + +for (_p =0 ; _p <= max_p; _p++) { +for (_m =1 ; _m <= max_m; _m++) { +unsigned long tmp_rate = (parent >> _p) / _m; + +if (tmp_rate > rate) +continue ; + +if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_m = _m; + best_p = _p; + } + } + } + + *m = best_m; + *p = best_p; +} + +static unsigned long ccu_mp_round_rate (struct ccu_mux_internal *mux, +unsigned long parent_rate, +unsigned long rate, +void *data) +{ +struct ccu_mp *cmp = data; +unsigned int m, p; + +ccu_mp_find_best (parent_rate, rate, +1 << cmp->m.width, (1 << cmp->p.width) -1 , + &m, &p); + +return (parent_rate >> p) / m; +} + +static void ccu_mp_disable (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_gate_helper_disable (&cmp->common, cmp->enable); +} + +static int ccu_mp_enable (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_gate_helper_enable (&cmp->common, cmp->enable); +} + +static int ccu_mp_is_enabled (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_gate_helper_is_enabled (&cmp->common, cmp->enable); +} + +static unsigned long ccu_mp_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); +unsigned int m, p; +u32 reg; + + reg =readl (cmp->common.base + cmp->common.reg); + + m = reg >> cmp->m.shift; + m &= (1 << cmp->m.width) -1 ; + + p = reg >> cmp->p.shift; + p &= (1 << cmp->p.width) -1 ; + +return (parent_rate >> p) / (m +1 ); +} + +static int ccu_mp_determine_rate (struct clk_hw *hw, +struct clk_rate_request *req) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_mux_helper_determine_rate (&cmp->common, &cmp->mux, + req, ccu_mp_round_rate, cmp); +} + +static int ccu_mp_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); +unsigned long flags; +unsigned int m, p; +u32 reg; +
drivers/clk/sunxi-ng/ccu_mp.c line 123
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_mp.c new file +10
-0+ccu_mp_find_best (parent_rate, rate, +1 << cmp->m.width, (1 << cmp->p.width) -1 , + &m, &p); + + +spin_lock_irqsave (cmp->common.lock, flags); + + reg =readl (cmp->common.base + cmp->common.reg); + reg &= ~GENMASK (cmp->m.width + cmp->m.shift, cmp->m.shift); + reg &= ~GENMASK (cmp->p.width + cmp->p.shift, cmp->p.shift);
width + shift - 1 ? IIRC GENMASK is inclusive at both ends.
Quoted 79 lines
drivers/clk/sunxi-ng/ccu_mp.c new file +35
-0+ +writel (reg | (p << cmp->p.shift) | ((m -1 ) << cmp->m.shift), + cmp->common.base + cmp->common.reg); + +spin_unlock_irqrestore (cmp->common.lock, flags); + +return 0 ; +} + +static u8 ccu_mp_get_parent (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_mux_helper_get_parent (&cmp->common, &cmp->mux); +} + +static int ccu_mp_set_parent (struct clk_hw *hw,u8 index) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_mux_helper_set_parent (&cmp->common, &cmp->mux, index); +} + +const struct clk_ops ccu_mp_ops = { + .disable = ccu_mp_disable, + .enable = ccu_mp_enable, + .is_enabled = ccu_mp_is_enabled, + + .get_parent = ccu_mp_get_parent, + .set_parent = ccu_mp_set_parent, + + .determine_rate = ccu_mp_determine_rate, + .recalc_rate = ccu_mp_recalc_rate, + .set_rate = ccu_mp_set_rate, +};drivers/clk/sunxi-ng/ccu_mp.h new file +38
-0@@ -0,0 +1,79 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_MP_H_ +#define _CCU_MP_H_ + +#include <linux/clk-provider.h> + +#include "ccu_common.h" +#include "ccu_factor.h" +#include "ccu_mux.h" + +struct ccu_mp { +u32 enable; + +struct ccu_factor m; +struct ccu_factor p; +struct ccu_mux_internal mux; +struct ccu_common common; +}; + +#define SUNXI_CCU_MP_WITH_MUX (_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _flags) \ + struct ccu_mp _struct = { \ + .m = SUNXI_CLK_FACTOR(_mshift, _mwidth), \
drivers/clk/sunxi-ng/ccu_mp.h line 48
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +10
-0+ .p = SUNXI_CLK_FACTOR(_pshift, _pwidth), \ + .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init =SUNXI_HW_INIT_PARENTS (_name, \ + _parents, \ + &ccu_mp_ops, \ + _flags), \ + } \ + }
Use the latter to simplify this one?
drivers/clk/sunxi-ng/ccu_mp.h line 50
Quoted 2 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +2
-0+ +#define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
We could merge _struct with _name ...
drivers/clk/sunxi-ng/ccu_mp.h line 55
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +5
-0+ _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_mp _struct = { \
and have struct ccu_mp _name##_clk = {
drivers/clk/sunxi-ng/ccu_mp.h line 63
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +8
-0+ .enable = _gate, \ + .m = SUNXI_CLK_FACTOR(_mshift, _mwidth), \ + .p = SUNXI_CLK_FACTOR(_pshift, _pwidth), \ + .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .features = CCU_FEATURE_GATE, \ + .hw.init = SUNXI_HW_INIT_PARENTS(_name, \
and #_name, \
to try to squeeze the users each on a single line. It's a just minor thing though.
Regards
ChenYu
Quoted 19 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +16
-1+ _parents, \ + &ccu_mp_ops, \ + _flags), \ + } \ + } + +static inline struct ccu_mp *hw_to_ccu_mp (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_mp, common); +} + +extern const struct clk_ops ccu_mp_ops; + +#endif /* _CCU_MP_H_ */ --2.8.2
PATCH 10/16 clk: sunxi-ng: Add M-P factor clock support
Hi,
Quoted 9 lines · Chen-Yu Tsai
Hi,
Quoted 2 lines · Maxime Ripard
Introduce support for the clocks that combine a linear divider and a power-of-two based one.
A description or formula in the source code (for those of us that forget) would be nice. :)
Ack :)
Quoted 146 lines
Quoted 146 lines
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_mp.c | 158 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_mp.h | 79 +++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_mp.c create mode 100644 drivers/clk/sunxi-ng/ccu_mp.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -5,6 +5,7 @@ obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o obj-y += ccu_m.o +obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_mp.c new file +117
-0@@ -0,0 +1,158 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> + +#include "ccu_gate.h" +#include "ccu_mp.h" + +static void ccu_mp_find_best (unsigned long parent,unsigned long rate, +unsigned int max_m,unsigned int max_p, +unsigned int *m,unsigned int *p) +{ +unsigned long best_rate =0 ; +unsigned int best_m =0 , best_p =0 ; +unsigned int _m, _p; + +for (_p =0 ; _p <= max_p; _p++) { +for (_m =1 ; _m <= max_m; _m++) { +unsigned long tmp_rate = (parent >> _p) / _m; + +if (tmp_rate > rate) +continue ; + +if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_m = _m; + best_p = _p; + } + } + } + + *m = best_m; + *p = best_p; +} + +static unsigned long ccu_mp_round_rate (struct ccu_mux_internal *mux, +unsigned long parent_rate, +unsigned long rate, +void *data) +{ +struct ccu_mp *cmp = data; +unsigned int m, p; + +ccu_mp_find_best (parent_rate, rate, +1 << cmp->m.width, (1 << cmp->p.width) -1 , + &m, &p); + +return (parent_rate >> p) / m; +} + +static void ccu_mp_disable (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_gate_helper_disable (&cmp->common, cmp->enable); +} + +static int ccu_mp_enable (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_gate_helper_enable (&cmp->common, cmp->enable); +} + +static int ccu_mp_is_enabled (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_gate_helper_is_enabled (&cmp->common, cmp->enable); +} + +static unsigned long ccu_mp_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); +unsigned int m, p; +u32 reg; + + reg =readl (cmp->common.base + cmp->common.reg); + + m = reg >> cmp->m.shift; + m &= (1 << cmp->m.width) -1 ; + + p = reg >> cmp->p.shift; + p &= (1 << cmp->p.width) -1 ; + +return (parent_rate >> p) / (m +1 ); +} + +static int ccu_mp_determine_rate (struct clk_hw *hw, +struct clk_rate_request *req) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_mux_helper_determine_rate (&cmp->common, &cmp->mux, + req, ccu_mp_round_rate, cmp); +} + +static int ccu_mp_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); +unsigned long flags; +unsigned int m, p; +u32 reg; + +ccu_mp_find_best (parent_rate, rate, +1 << cmp->m.width, (1 << cmp->p.width) -1 , + &m, &p); +
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_mp.c line 123
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_mp.c new file +6
-0+ +spin_lock_irqsave (cmp->common.lock, flags); + + reg =readl (cmp->common.base + cmp->common.reg); + reg &= ~GENMASK (cmp->m.width + cmp->m.shift, cmp->m.shift); + reg &= ~GENMASK (cmp->p.width + cmp->p.shift, cmp->p.shift);width + shift - 1 ? IIRC GENMASK is inclusive at both ends.
Indeed, will fix.
Quoted 98 lines
Quoted 80 lines
drivers/clk/sunxi-ng/ccu_mp.c new file +35
-0+ +writel (reg | (p << cmp->p.shift) | ((m -1 ) << cmp->m.shift), + cmp->common.base + cmp->common.reg); + +spin_unlock_irqrestore (cmp->common.lock, flags); + +return 0 ; +} + +static u8 ccu_mp_get_parent (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_mux_helper_get_parent (&cmp->common, &cmp->mux); +} + +static int ccu_mp_set_parent (struct clk_hw *hw,u8 index) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_mux_helper_set_parent (&cmp->common, &cmp->mux, index); +} + +const struct clk_ops ccu_mp_ops = { + .disable = ccu_mp_disable, + .enable = ccu_mp_enable, + .is_enabled = ccu_mp_is_enabled, + + .get_parent = ccu_mp_get_parent, + .set_parent = ccu_mp_set_parent, + + .determine_rate = ccu_mp_determine_rate, + .recalc_rate = ccu_mp_recalc_rate, + .set_rate = ccu_mp_set_rate, +};drivers/clk/sunxi-ng/ccu_mp.h new file +38
-0@@ -0,0 +1,79 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_MP_H_ +#define _CCU_MP_H_ + +#include <linux/clk-provider.h> + +#include "ccu_common.h" +#include "ccu_factor.h" +#include "ccu_mux.h" + +struct ccu_mp { +u32 enable; + +struct ccu_factor m; +struct ccu_factor p; +struct ccu_mux_internal mux; +struct ccu_common common; +}; + +#define SUNXI_CCU_MP_WITH_MUX (_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _flags) \ + struct ccu_mp _struct = { \ + .m = SUNXI_CLK_FACTOR(_mshift, _mwidth), \drivers/clk/sunxi-ng/ccu_mp.h line 48
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +10
-0+ .p = SUNXI_CLK_FACTOR(_pshift, _pwidth), \ + .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init =SUNXI_HW_INIT_PARENTS (_name, \ + _parents, \ + &ccu_mp_ops, \ + _flags), \ + } \ + }Use the latter to simplify this one?
drivers/clk/sunxi-ng/ccu_mp.h line 50
Quoted 2 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +2
-0+ +#define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \We could merge
_structwith_name...
Quoted 7 lines
drivers/clk/sunxi-ng/ccu_mp.h line 55
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +5
-0+ _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_mp _struct = { \and have struct
ccu_mp_name##_clk = {
Unfortunately, that prevents to use dashes as clock names, which is something we've done in the past. Having a separate name allows us to use whatever we want.
Maxime
---
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160523/f648848f/attachment-0001.sig>
PATCH 10/16 clk: sunxi-ng: Add M-P factor clock support
Hi,
Quoted 276 lines · Maxime Ripard
Hi,
Quoted 9 lines · Chen-Yu Tsai
Hi,
Quoted 2 lines · Maxime Ripard
Introduce support for the clocks that combine a linear divider and a power-of-two based one.
A description or formula in the source code (for those of us that forget) would be nice. :)
Ack :)
Quoted 146 lines
Quoted 146 lines
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_mp.c | 158 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_mp.h | 79 +++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_mp.c create mode 100644 drivers/clk/sunxi-ng/ccu_mp.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -5,6 +5,7 @@ obj-y += ccu_div_table.o obj-y += ccu_fixed_factor.o obj-y += ccu_gate.o obj-y += ccu_m.o +obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_mp.c new file +117
-0@@ -0,0 +1,158 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> + +#include "ccu_gate.h" +#include "ccu_mp.h" + +static void ccu_mp_find_best (unsigned long parent,unsigned long rate, +unsigned int max_m,unsigned int max_p, +unsigned int *m,unsigned int *p) +{ +unsigned long best_rate =0 ; +unsigned int best_m =0 , best_p =0 ; +unsigned int _m, _p; + +for (_p =0 ; _p <= max_p; _p++) { +for (_m =1 ; _m <= max_m; _m++) { +unsigned long tmp_rate = (parent >> _p) / _m; + +if (tmp_rate > rate) +continue ; + +if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_m = _m; + best_p = _p; + } + } + } + + *m = best_m; + *p = best_p; +} + +static unsigned long ccu_mp_round_rate (struct ccu_mux_internal *mux, +unsigned long parent_rate, +unsigned long rate, +void *data) +{ +struct ccu_mp *cmp = data; +unsigned int m, p; + +ccu_mp_find_best (parent_rate, rate, +1 << cmp->m.width, (1 << cmp->p.width) -1 , + &m, &p); + +return (parent_rate >> p) / m; +} + +static void ccu_mp_disable (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_gate_helper_disable (&cmp->common, cmp->enable); +} + +static int ccu_mp_enable (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_gate_helper_enable (&cmp->common, cmp->enable); +} + +static int ccu_mp_is_enabled (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_gate_helper_is_enabled (&cmp->common, cmp->enable); +} + +static unsigned long ccu_mp_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); +unsigned int m, p; +u32 reg; + + reg =readl (cmp->common.base + cmp->common.reg); + + m = reg >> cmp->m.shift; + m &= (1 << cmp->m.width) -1 ; + + p = reg >> cmp->p.shift; + p &= (1 << cmp->p.width) -1 ; + +return (parent_rate >> p) / (m +1 ); +} + +static int ccu_mp_determine_rate (struct clk_hw *hw, +struct clk_rate_request *req) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_mux_helper_determine_rate (&cmp->common, &cmp->mux, + req, ccu_mp_round_rate, cmp); +} + +static int ccu_mp_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); +unsigned long flags; +unsigned int m, p; +u32 reg; + +ccu_mp_find_best (parent_rate, rate, +1 << cmp->m.width, (1 << cmp->p.width) -1 , + &m, &p); +Quoted 8 lines
drivers/clk/sunxi-ng/ccu_mp.c line 123
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_mp.c new file +6
-0+ +spin_lock_irqsave (cmp->common.lock, flags); + + reg =readl (cmp->common.base + cmp->common.reg); + reg &= ~GENMASK (cmp->m.width + cmp->m.shift, cmp->m.shift); + reg &= ~GENMASK (cmp->p.width + cmp->p.shift, cmp->p.shift);width + shift - 1 ? IIRC GENMASK is inclusive at both ends.
Indeed, will fix.
Quoted 104 lines
Quoted 80 lines
drivers/clk/sunxi-ng/ccu_mp.c new file +35
-0+ +writel (reg | (p << cmp->p.shift) | ((m -1 ) << cmp->m.shift), + cmp->common.base + cmp->common.reg); + +spin_unlock_irqrestore (cmp->common.lock, flags); + +return 0 ; +} + +static u8 ccu_mp_get_parent (struct clk_hw *hw) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_mux_helper_get_parent (&cmp->common, &cmp->mux); +} + +static int ccu_mp_set_parent (struct clk_hw *hw,u8 index) +{ +struct ccu_mp *cmp =hw_to_ccu_mp (hw); + +return ccu_mux_helper_set_parent (&cmp->common, &cmp->mux, index); +} + +const struct clk_ops ccu_mp_ops = { + .disable = ccu_mp_disable, + .enable = ccu_mp_enable, + .is_enabled = ccu_mp_is_enabled, + + .get_parent = ccu_mp_get_parent, + .set_parent = ccu_mp_set_parent, + + .determine_rate = ccu_mp_determine_rate, + .recalc_rate = ccu_mp_recalc_rate, + .set_rate = ccu_mp_set_rate, +};drivers/clk/sunxi-ng/ccu_mp.h new file +38
-0@@ -0,0 +1,79 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_MP_H_ +#define _CCU_MP_H_ + +#include <linux/clk-provider.h> + +#include "ccu_common.h" +#include "ccu_factor.h" +#include "ccu_mux.h" + +struct ccu_mp { +u32 enable; + +struct ccu_factor m; +struct ccu_factor p; +struct ccu_mux_internal mux; +struct ccu_common common; +}; + +#define SUNXI_CCU_MP_WITH_MUX (_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _flags) \ + struct ccu_mp _struct = { \ + .m = SUNXI_CLK_FACTOR(_mshift, _mwidth), \drivers/clk/sunxi-ng/ccu_mp.h line 48
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +10
-0+ .p = SUNXI_CLK_FACTOR(_pshift, _pwidth), \ + .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init =SUNXI_HW_INIT_PARENTS (_name, \ + _parents, \ + &ccu_mp_ops, \ + _flags), \ + } \ + }Use the latter to simplify this one?
drivers/clk/sunxi-ng/ccu_mp.h line 50
Quoted 2 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +2
-0+ +#define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \We could merge
_structwith_name...Quoted 5 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +5
-0+ _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_mp _struct = { \
Quoted 5 lines
Quoted 1 line
and have struct
ccu_mp_name##_clk = {Unfortunately, that prevents to use dashes as clock names, which is something we've done in the past. Having a separate name allows us to use whatever we want.
We could do some replacement in the register function, but that seems hackish. Also I noticed we aren't using clock-output-names from the DT anymore?
ChenYu
PATCH 10/16 clk: sunxi-ng: Add M-P factor clock support
Hi,
Quoted 10 lines · Chen-Yu Tsai
Quoted 10 lines
Quoted 10 lines
Quoted 1 line
+#define SUNXI_CCU_MP_WITH_MUX_GATE(_struct,
_name,_parents,_reg, \We could merge
_structwith_name...Quoted 5 lines
drivers/clk/sunxi-ng/ccu_mp.h new file +5
-0+ _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_mp _struct = { \
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
and have struct
ccu_mp_name##_clk = {Unfortunately, that prevents to use dashes as clock names, which is something we've done in the past. Having a separate name allows us to use whatever we want.
We could do some replacement in the register function, but that seems hackish
Indeed
Quoted 2 lines
Also I noticed we aren't using clock-output-names from the DT anymore?
Yep, there's just too many clocks to be practical, and you have to have the name in the source code anyway for the parenting relationships.
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160524/3297fc91/attachment.sig>
PATCH 11/16 clk: sunxi-ng: Add N-K-factor clock support
In reply to Maxime RipardIntroduce support for clocks that use a combination of two linear multipliers.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nk.c | 147 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nk.h | 44 +++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nk.c create mode 100644 drivers/clk/sunxi-ng/ccu_nk.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -7,5 +7,6 @@ obj-y += ccu_gate.o obj-y += ccu_m.o obj-y += ccu_mp.o obj-y += ccu_mux.o +obj-y += ccu_nk.o obj-y += ccu_p.o obj-y += ccu_phase.o
drivers/clk/sunxi-ng/ccu_nk.c new file +147 -0
147 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_nk.h new file +44 -0
44 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 11/16 clk: sunxi-ng: Add N-K-factor clock support
Hi,
Quoted 2 lines · Maxime Ripard
Introduce support for clocks that use a combination of two linear multipliers.
Mostly the same comments as the previous patch.
Quoted 31 lines
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nk.c | 147 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nk.h | 44 +++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nk.c create mode 100644 drivers/clk/sunxi-ng/ccu_nk.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -7,5 +7,6 @@ obj-y += ccu_gate.o obj-y += ccu_m.o obj-y += ccu_mp.o obj-y += ccu_mux.o +obj-y += ccu_nk.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_nk.c new file +5
-0@@ -0,0 +1,147 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[email protected]> +* +* This program is free software; you can redistribute it and/or
drivers/clk/sunxi-ng/ccu_nk.c line 15
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nk.c new file +10
-0+* 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. +*/ + +#include <linux/clk-provider.h> +#include <linux/rational.h> + +#include "ccu_gate.h" +#include "ccu_nk.h"
A formula to check against would be nice.
drivers/clk/sunxi-ng/ccu_nk.c line 26
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nk.c new file +10
-0+void ccu_nk_find_best (unsigned long parent,unsigned long rate, +unsigned int max_n,unsigned int max_k, +unsigned int *n,unsigned int *k) +{ +unsigned long best_rate =0 ; +unsigned int best_k =0 , best_n =0 ; +unsigned int _k, _n; + +for (_k =0 ; _k <= max_k; _k++) { +for (_n =0 ; _n <= max_n; _n++) {
I don't think 0 is a valid multiplier, regardless whether the N value in the register starts from 0 or 1.
Quoted 47 lines
drivers/clk/sunxi-ng/ccu_nk.c new file +47
-0+unsigned long tmp_rate = parent * _n * _k; + +if (tmp_rate > rate) +continue ; + +if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_k = _k; + best_n = _n; + } + } + } + + *k = best_k; + *n = best_n; +} + +static void ccu_nk_disable (struct clk_hw *hw) +{ +struct ccu_nk *nk =hw_to_ccu_nk (hw); + +return ccu_gate_helper_disable (&nk->common, nk->enable); +} + +static int ccu_nk_enable (struct clk_hw *hw) +{ +struct ccu_nk *nk =hw_to_ccu_nk (hw); + +return ccu_gate_helper_enable (&nk->common, nk->enable); +} + +static int ccu_nk_is_enabled (struct clk_hw *hw) +{ +struct ccu_nk *nk =hw_to_ccu_nk (hw); + +return ccu_gate_helper_is_enabled (&nk->common, nk->enable); +} + +static unsigned long ccu_nk_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +struct ccu_nk *nk =hw_to_ccu_nk (hw); +unsigned long rate, n, k; +u32 reg; + + reg =readl (nk->common.base + nk->common.reg); +
drivers/clk/sunxi-ng/ccu_nk.c line 83
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nk.c new file +10
-0+ n = reg >> nk->n.shift; + n &= (1 << nk->n.width) -1 ; + + k = reg >> nk->k.shift; + k &= (1 << nk->k.width) -1 ; + + rate = parent_rate * (n +1 ) * (k +1 ); + +if (nk->common.features &CCU_FEATURE_FIXED_POSTDIV ) + rate = rate / nk->fixed_post_div;
I would go with "rate /= nk->fixed_post_div", but it's purely aesthetics.
Quoted 34 lines
drivers/clk/sunxi-ng/ccu_nk.c new file +34
-0+ +return rate; +} + +static long ccu_nk_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *parent_rate) +{ +struct ccu_nk *nk =hw_to_ccu_nk (hw); +unsigned int n, k; + +if (nk->common.features &CCU_FEATURE_FIXED_POSTDIV ) + rate = rate * nk->fixed_post_div; + +ccu_nk_find_best (*parent_rate, rate, +1 << nk->n.width,1 << nk->k.width, + &n, &k); + + rate = *parent_rate * n * k; +if (nk->common.features &CCU_FEATURE_FIXED_POSTDIV ) + rate = rate / nk->fixed_post_div; + +return rate; +} + +static int ccu_nk_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_nk *nk =hw_to_ccu_nk (hw); +unsigned long flags; +unsigned int n, k; +u32 reg; + +if (nk->common.features &CCU_FEATURE_FIXED_POSTDIV ) + rate = rate * nk->fixed_post_div;
drivers/clk/sunxi-ng/ccu_nk.c line 127
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nk.c new file +10
-0+ +ccu_nk_find_best (parent_rate, rate, +1 << nk->n.width,1 << nk->k.width, + &n, &k); + +spin_lock_irqsave (nk->common.lock, flags); + + reg =readl (nk->common.base + nk->common.reg); + reg &= ~GENMASK (nk->n.width + nk->n.shift, nk->n.shift); + reg &= ~GENMASK (nk->k.width + nk->k.shift, nk->k.shift);
width + shift - 1
Quoted 58 lines
drivers/clk/sunxi-ng/ccu_nk.c new file +20
-0+ +writel (reg | ((k -1 ) << nk->k.shift) | ((n -1 ) << nk->n.shift), + nk->common.base + nk->common.reg); + +spin_unlock_irqrestore (nk->common.lock, flags); + +ccu_helper_wait_for_lock (&nk->common, nk->lock); + +return 0 ; +} + +const struct clk_ops ccu_nk_ops = { + .disable = ccu_nk_disable, + .enable = ccu_nk_enable, + .is_enabled = ccu_nk_is_enabled, + + .recalc_rate = ccu_nk_recalc_rate, + .round_rate = ccu_nk_round_rate, + .set_rate = ccu_nk_set_rate, +};drivers/clk/sunxi-ng/ccu_nk.h new file +32
-0@@ -0,0 +1,44 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_NK_H_ +#define _CCU_NK_H_ + +#include <linux/clk-provider.h> + +#include "ccu_common.h" +#include "ccu_factor.h" + +struct ccu_nk { + u16 reg; + u32 enable; + u32 lock; + + struct ccu_factor n; + struct ccu_factor k; + + unsigned int fixed_post_div; + + struct ccu_common common;
drivers/clk/sunxi-ng/ccu_nk.h line 42
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nk.h new file +10
-0+}; + +static inline struct ccu_nk *hw_to_ccu_nk (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_nk, common); +} + +extern const struct clk_ops ccu_nk_ops;
No macros for this one?
Regards
ChenYu
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_nk.h new file +2
-1+ +#endif /* _CCU_NK_H_ */ --2.8.2
PATCH 12/16 clk: sunxi-ng: Add N-M-factor clock support
In reply to Maxime RipardIntroduce support for clocks that multiply and divide using linear factors.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nm.c | 103 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nm.h | 41 +++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nm.c create mode 100644 drivers/clk/sunxi-ng/ccu_nm.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -8,5 +8,6 @@ obj-y += ccu_m.o obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_nk.o +obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o
drivers/clk/sunxi-ng/ccu_nm.c new file +103 -0
103 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_nm.h new file +41 -0
41 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 12/16 clk: sunxi-ng: Add N-M-factor clock support
Quoted 10 lines · On Sun, 8 May 2016 22:01:47 +0200 Maxime Ripard…
Introduce support for clocks that multiply and divide using linear factors.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nm.c | 103 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nm.h | 41 +++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nm.c create mode 100644 drivers/clk/sunxi-ng/ccu_nm.h
[snip]
drivers/clk/sunxi-ng/ccu_nm.c
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +0
-0@@ -0,0 +1,103 @@
[snip]
drivers/clk/sunxi-ng/ccu_nm.c line 63
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +8
-0+static long ccu_nm_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *parent_rate) +{ +struct ccu_nm *nm =hw_to_ccu_nm (hw); +unsigned long n, m; + +rational_best_approximation (rate, *parent_rate, + nm->n.width, nm->m.width, &n, &m);
Should be
1 << nm->n.width, 1 << nm->m.width, &n, &m);
Quoted 4 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +4
-0+ +return *parent_rate * n / m; +} +
drivers/clk/sunxi-ng/ccu_nm.c line 77
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +10
-0+static int ccu_nm_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_nm *nm =hw_to_ccu_nm (hw); +unsigned long flags; +unsigned long n, m; +u32 reg; + +rational_best_approximation (rate, parent_rate, + nm->n.width, nm->m.width, &n, &m);
Idem
Quoted 16 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +16
-0+ +spin_lock_irqsave (nm->common.lock, flags); + + reg =readl (nm->common.base + nm->common.reg); + reg &= ~GENMASK (nm->n.width + nm->n.shift, nm->n.shift); + reg &= ~GENMASK (nm->m.width + nm->m.shift, nm->m.shift); + +writel (reg | ((m -1 ) << nm->m.shift) | ((n -1 ) << nm->n.shift), + nm->common.base + nm->common.reg); + +spin_unlock_irqrestore (nm->common.lock, flags); + +ccu_helper_wait_for_lock (&nm->common, nm->lock); + +return 0 ; +}
drivers/clk/sunxi-ng/ccu_nm.c line 103
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +10
-0+ +const struct clk_ops ccu_nm_ops = { + .disable = ccu_nm_disable, + .enable = ccu_nm_enable, + .is_enabled = ccu_nm_is_enabled, + + .recalc_rate = ccu_nm_recalc_rate, + .round_rate = ccu_nm_round_rate, + .set_rate = ccu_nm_set_rate, +};
[snip]
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 12/16 clk: sunxi-ng: Add N-M-factor clock support
Hi,
Quoted 33 lines · Jean-Francois Moine
Quoted 10 lines · On Sun, 8 May 2016 22:01:47 +0200 Maxime Ripard…
Introduce support for clocks that multiply and divide using linear factors.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nm.c | 103 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nm.h | 41 +++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nm.c create mode 100644 drivers/clk/sunxi-ng/ccu_nm.h[snip]drivers/clk/sunxi-ng/ccu_nm.c
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +0
-0@@ -0,0 +1,103 @@[snip]drivers/clk/sunxi-ng/ccu_nm.c line 63
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +8
-0+static long ccu_nm_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *parent_rate) +{ +struct ccu_nm *nm =hw_to_ccu_nm (hw); +unsigned long n, m; + +rational_best_approximation (rate, *parent_rate, + nm->n.width, nm->m.width, &n, &m);Should be
1 << nm->n.width, 1 << nm->m.width, &n, &m);
Quoted 16 lines
Quoted 4 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +4
-0+ +return *parent_rate * n / m; +} +drivers/clk/sunxi-ng/ccu_nm.c line 77
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nm.c new file +10
-0+static int ccu_nm_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_nm *nm =hw_to_ccu_nm (hw); +unsigned long flags; +unsigned long n, m; +u32 reg; + +rational_best_approximation (rate, parent_rate, + nm->n.width, nm->m.width, &n, &m);Idem
Indeed, fixed.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160515/3b0e96e4/attachment.sig>
PATCH 13/16 clk: sunxi-ng: Add N-K-M Factor clock
In reply to Maxime RipardIntroduce support for clocks that multiply and divide using two linear multipliers and one linear divider.
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nkm.c | 144 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nkm.h | 42 ++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -8,6 +8,7 @@ obj-y += ccu_m.o obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_nk.o +obj-y += ccu_nkm.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o
drivers/clk/sunxi-ng/ccu_nkm.c new file +144 -0
144 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_nkm.h new file +42 -0
42 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 13/16 clk: sunxi-ng: Add N-K-M Factor clock
drivers/clk/sunxi-ng/ccu_nkm.c
Quoted 29 lines · On Sun, 8 May 2016 22:01:48 +0200 Maxime Ripard…
Introduce support for clocks that multiply and divide using two linear multipliers and one linear divider.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nkm.c | 144 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nkm.h | 42 ++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -8,6 +8,7 @@ obj-y += ccu_m.o obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_nk.o +obj-y += ccu_nkm.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_nkm.c new file +0
-0
[snip]
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +9
-0@@ -0,0 +1,144 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/
drivers/clk/sunxi-ng/ccu_nkm.c line 19
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +10
-0+ +#include <linux/clk-provider.h> +#include <linux/rational.h> + +#include "ccu_gate.h" +#include "ccu_nkm.h" + +void ccu_nkm_find_best (unsigned long parent,unsigned long rate, +unsigned long max_n,unsigned long max_k,unsigned long max_m, +unsigned long *n,unsigned long *k,unsigned long *m)
Should be static
[snip]
Quoted 12 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +12
-0+static int ccu_nkm_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_nkm *nkm =hw_to_ccu_nkm (hw); +unsigned long n, k, m; +unsigned long flags; +u32 reg; + +ccu_nkm_find_best (parent_rate, rate,1 << nkm->n.width, +1 << nkm->k.width,1 << nkm->m.width, + &n, &k, &m); +
drivers/clk/sunxi-ng/ccu_nkm.c line 125
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +10
-0+spin_lock_irqsave (nkm->common.lock, flags); + + reg =readl (nkm->common.base + nkm->common.reg); + reg &= ~GENMASK (nkm->n.width + nkm->n.shift, nkm->n.shift); + reg &= ~GENMASK (nkm->k.width + nkm->k.shift, nkm->k.shift); + reg &= ~GENMASK (nkm->m.width + nkm->m.shift, nkm->m.shift); + + reg |= (n -1 ) << nkm->m.shift; + reg |= (k -1 ) << nkm->m.shift; + reg |= (m -1 ) << nkm->m.shift;
reg |= (n - 1) << nkm->n.shift; reg |= (k - 1) << nkm->k.shift;
drivers/clk/sunxi-ng/ccu_nkm.c line 134
Quoted 9 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +9
-0+ +writel (reg, nkm->common.base + nkm->common.reg); + +spin_unlock_irqrestore (nkm->common.lock, flags); + +ccu_helper_wait_for_lock (&nkm->common, nkm->lock); + +return 0 ; +}
[snip]
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 13/16 clk: sunxi-ng: Add N-K-M Factor clock
Quoted 75 lines · Jean-Francois Moine
drivers/clk/sunxi-ng/ccu_nkm.c
Quoted 29 lines · On Sun, 8 May 2016 22:01:48 +0200 Maxime Ripard…
Introduce support for clocks that multiply and divide using two linear multipliers and one linear divider.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nkm.c | 144 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nkm.h | 42 ++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -8,6 +8,7 @@ obj-y += ccu_m.o obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_nk.o +obj-y += ccu_nkm.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_nkm.c new file +0
-0[snip]Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +9
-0@@ -0,0 +1,144 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ drivers/clk/sunxi-ng/ccu_nkm.c line 19
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +10
-0+ +#include <linux/clk-provider.h> +#include <linux/rational.h> + +#include "ccu_gate.h" +#include "ccu_nkm.h" + +void ccu_nkm_find_best (unsigned long parent,unsigned long rate, +unsigned long max_n,unsigned long max_k,unsigned long max_m, +unsigned long *n,unsigned long *k,unsigned long *m)Should be static
[snip]Quoted 17 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +17
-0+static int ccu_nkm_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_nkm *nkm =hw_to_ccu_nkm (hw); +unsigned long n, k, m; +unsigned long flags; +u32 reg; + +ccu_nkm_find_best (parent_rate, rate,1 << nkm->n.width, +1 << nkm->k.width,1 << nkm->m.width, + &n, &k, &m); + +spin_lock_irqsave (nkm->common.lock, flags); + + reg =readl (nkm->common.base + nkm->common.reg); + reg &= ~GENMASK (nkm->n.width + nkm->n.shift, nkm->n.shift); + reg &= ~GENMASK (nkm->k.width + nkm->k.shift, nkm->k.shift);
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_nkm.c line 125
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +5
-0+ reg &= ~GENMASK (nkm->m.width + nkm->m.shift, nkm->m.shift); + + reg |= (n -1 ) << nkm->m.shift; + reg |= (k -1 ) << nkm->m.shift; + reg |= (m -1 ) << nkm->m.shift;reg |= (n - 1) << nkm->n.shift; reg |= (k - 1) << nkm->k.shift;
Good catches, thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160515/2cefa15f/attachment.sig>
PATCH 13/16 clk: sunxi-ng: Add N-K-M Factor clock
In reply to Maxime RipardHi,
Quoted 39 lines · Maxime Ripard
Introduce support for clocks that multiply and divide using two linear multipliers and one linear divider.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nkm.c | 144 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nkm.h | 42 ++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkm.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -8,6 +8,7 @@ obj-y += ccu_m.o obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_nk.o +obj-y += ccu_nkm.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_nkm.c new file +9
-0@@ -0,0 +1,144 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/
drivers/clk/sunxi-ng/ccu_nkm.c line 19
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +10
-0+ +#include <linux/clk-provider.h> +#include <linux/rational.h> + +#include "ccu_gate.h" +#include "ccu_nkm.h" + +void ccu_nkm_find_best (unsigned long parent,unsigned long rate, +unsigned long max_n,unsigned long max_k,unsigned long max_m, +unsigned long *n,unsigned long *k,unsigned long *m)
Would it be easier to just pass struct ccu_nkm* here?
Quoted 92 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +92
-0+{ +unsigned long best_rate =0 ; +unsigned long best_n =0 , best_k =0 , best_m =0 ; +unsigned long _n, _k, _m; + +for (_k =1 ; _k <= max_k; _k++) { +unsigned long tmp_rate; + +rational_best_approximation (rate / _k, parent, + max_n, max_m, &_n, &_m); + + tmp_rate = parent * _n * _k / _m; + +if (tmp_rate > rate) +continue ; + +if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_n = _n; + best_k = _k; + best_m = _m; + } + } + + *n = best_n; + *k = best_k; + *m = best_m; +} + +static void ccu_nkm_disable (struct clk_hw *hw) +{ +struct ccu_nkm *nkm =hw_to_ccu_nkm (hw); + +return ccu_gate_helper_disable (&nkm->common, nkm->enable); +} + +static int ccu_nkm_enable (struct clk_hw *hw) +{ +struct ccu_nkm *nkm =hw_to_ccu_nkm (hw); + +return ccu_gate_helper_enable (&nkm->common, nkm->enable); +} + +static int ccu_nkm_is_enabled (struct clk_hw *hw) +{ +struct ccu_nkm *nkm =hw_to_ccu_nkm (hw); + +return ccu_gate_helper_is_enabled (&nkm->common, nkm->enable); +} + +static unsigned long ccu_nkm_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +struct ccu_nkm *nkm =hw_to_ccu_nkm (hw); +unsigned long n, m, k; +u32 reg; + + reg =readl (nkm->common.base + nkm->common.reg); + + n = reg >> nkm->n.shift; + n &= (1 << nkm->n.width) -1 ; + + k = reg >> nkm->k.shift; + k &= (1 << nkm->k.width) -1 ; + + m = reg >> nkm->m.shift; + m &= (1 << nkm->m.width) -1 ; + +return parent_rate * (n +1 ) * (k +1 ) / (m +1 ); +} + +static long ccu_nkm_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *parent_rate) +{ +struct ccu_nkm *nkm =hw_to_ccu_nkm (hw); +unsigned long n, k, m; + +ccu_nkm_find_best (*parent_rate, rate,1 << nkm->n.width, +1 << nkm->k.width,1 << nkm->m.width, + &n, &k, &m); + +return *parent_rate * n * k / m; +} + +static int ccu_nkm_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_nkm *nkm =hw_to_ccu_nkm (hw); +unsigned long n, k, m; +unsigned long flags; +u32 reg; +
drivers/clk/sunxi-ng/ccu_nkm.c line 121
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +10
-0+ccu_nkm_find_best (parent_rate, rate,1 << nkm->n.width, +1 << nkm->k.width,1 << nkm->m.width, + &n, &k, &m); + +spin_lock_irqsave (nkm->common.lock, flags); + + reg =readl (nkm->common.base + nkm->common.reg); + reg &= ~GENMASK (nkm->n.width + nkm->n.shift, nkm->n.shift); + reg &= ~GENMASK (nkm->k.width + nkm->k.shift, nkm->k.shift); + reg &= ~GENMASK (nkm->m.width + nkm->m.shift, nkm->m.shift);
GENMASK(width + shift - 1, shift)
Quoted 59 lines
drivers/clk/sunxi-ng/ccu_nkm.c new file +23
-0+ + reg |= (n -1 ) << nkm->m.shift; + reg |= (k -1 ) << nkm->m.shift; + reg |= (m -1 ) << nkm->m.shift; + +writel (reg, nkm->common.base + nkm->common.reg); + +spin_unlock_irqrestore (nkm->common.lock, flags); + +ccu_helper_wait_for_lock (&nkm->common, nkm->lock); + +return 0 ; +} + +const struct clk_ops ccu_nkm_ops = { + .disable = ccu_nkm_disable, + .enable = ccu_nkm_enable, + .is_enabled = ccu_nkm_is_enabled, + + .recalc_rate = ccu_nkm_recalc_rate, + .round_rate = ccu_nkm_round_rate, + .set_rate = ccu_nkm_set_rate, +};drivers/clk/sunxi-ng/ccu_nkm.h new file +30
-0@@ -0,0 +1,42 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_NKM_H_ +#define _CCU_NKM_H_ + +#include <linux/clk-provider.h> + +#include "ccu_factor.h" +#include "ccu_common.h" + +struct ccu_nkm { + u32 enable; + u32 lock; + + struct ccu_factor n; + struct ccu_factor k; + struct ccu_factor m; + + struct ccu_common common;
drivers/clk/sunxi-ng/ccu_nkm.h line 40
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkm.h new file +10
-0+}; + +static inline struct ccu_nkm *hw_to_ccu_nkm (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_nkm, common); +} + +extern const struct clk_ops ccu_nkm_ops;
No macro? I like the macros as they give the actual driver a more table-like look.
Regards
ChenYu
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_nkm.h new file +2
-1+ +#endif /* _CCU_NKM_H_ */ --2.8.2
PATCH 14/16 clk: sunxi-ng: Add N-K-M-P factor clock
In reply to Maxime RipardIntroduce support for clocks that use a combination of two linear multipliers (N and K factors), one linear divider (M) and one power of two divider (P).
--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nkmp.c | 157 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nkmp.h | 43 +++++++++++ 3 files changed, 201 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.h
drivers/clk/sunxi-ng/Makefile +1 -0
@@ -9,6 +9,7 @@ obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_nk.o obj-y += ccu_nkm.o +obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o
drivers/clk/sunxi-ng/ccu_nkmp.c new file +157 -0
157 lines not on this page · raw message
drivers/clk/sunxi-ng/ccu_nkmp.h new file +43 -0
43 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 14/16 clk: sunxi-ng: Add N-K-M-P factor clock
drivers/clk/sunxi-ng/ccu_nkmp.c
Quoted 30 lines · On Sun, 8 May 2016 22:01:49 +0200 Maxime Ripard…
Introduce support for clocks that use a combination of two linear multipliers (N and K factors), one linear divider (M) and one power of two divider (P).
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nkmp.c | 157 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nkmp.h | 43 +++++++++++ 3 files changed, 201 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -9,6 +9,7 @@ obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_nk.o obj-y += ccu_nkm.o +obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_nkmp.c new file +0
-0
[snip]
drivers/clk/sunxi-ng/ccu_nkmp.c
Quoted 1 line
drivers/clk/sunxi-ng/ccu_nkmp.c new file +0
-0@@ -0,0 +1,157 @@
[snip]
Quoted 13 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +13
-0+static int ccu_nkmp_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_nkmp *nkmp =hw_to_ccu_nkmp (hw); +unsigned long n, k, m, p; +unsigned long flags; +u32 reg; + +ccu_nkmp_find_best (parent_rate, rate, +1 << nkmp->n.width,1 << nkmp->k.width, +1 << nkmp->m.width, (1 << nkmp->p.width) -1 , + &n, &k, &m, &p); +
drivers/clk/sunxi-ng/ccu_nkmp.c line 136
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +10
-0+spin_lock_irqsave (nkmp->common.lock, flags); + + reg =readl (nkmp->common.base + nkmp->common.reg); + reg &= ~GENMASK (nkmp->n.width + nkmp->n.shift, nkmp->n.shift); + reg &= ~GENMASK (nkmp->k.width + nkmp->k.shift, nkmp->k.shift); + reg &= ~GENMASK (nkmp->m.width + nkmp->m.shift, nkmp->m.shift); + reg &= ~GENMASK (nkmp->p.width + nkmp->p.shift, nkmp->p.shift); + + reg |= (n -1 ) << nkmp->m.shift; + reg |= (k -1 ) << nkmp->m.shift;
reg |= (n - 1) << nkmp->n.shift; reg |= (k - 1) << nkmp->k.shift;
drivers/clk/sunxi-ng/ccu_nkmp.c line 147
Quoted 11 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +11
-0+ reg |= (m -1 ) << nkmp->m.shift; + reg |= p << nkmp->p.shift; + +writel (reg, nkmp->common.base + nkmp->common.reg); + +spin_unlock_irqrestore (nkmp->common.lock, flags); + +ccu_helper_wait_for_lock (&nkmp->common, nkmp->lock); + +return 0 ; +}
[snip]
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 14/16 clk: sunxi-ng: Add N-K-M-P factor clock
In reply to Maxime RipardHi,
Quoted 42 lines · Maxime Ripard
Introduce support for clocks that use a combination of two linear multipliers (N and K factors), one linear divider (M) and one power of two divider (P).
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nkmp.c | 157 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nkmp.h | 43 +++++++++++ 3 files changed, 201 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -9,6 +9,7 @@ obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_nk.o obj-y += ccu_nkm.o +obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_nkmp.c new file +11
-0@@ -0,0 +1,157 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h>
drivers/clk/sunxi-ng/ccu_nkmp.c line 21
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +10
-0+#include <linux/rational.h> + +#include "ccu_gate.h" +#include "ccu_nkmp.h" + +void ccu_nkmp_find_best (unsigned long parent,unsigned long rate, +unsigned long max_n,unsigned long max_k, +unsigned long max_m,unsigned long max_p, +unsigned long *n,unsigned long *k, +unsigned long *m,unsigned long *p)
We definitely should just pass struct ccu_nkmp* here.
drivers/clk/sunxi-ng/ccu_nkmp.c line 31
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +10
-0+{ +unsigned long best_rate =0 ; +unsigned long best_n =0 , best_k =0 , best_m =0 , best_p =0 ; +unsigned long _n, _k, _m, _p; + +for (_k =1 ; _k <= max_k; _k++) { +for (_p =0 ; _p <= max_p; _p++) { +unsigned long tmp_rate; + + rational_best_approximation(rate / _k, parent << _p,
I think you mean "parent >> _p" ?
In general we might lose some precision if parent is too small or _p is too large. But the only place we see this type of clock is the CPU PLL, and parent (24 MHz) are divisible by all the possible values of P.
This brings up another issue: P does not go all the way up to (1 << width - 1). A register value of 3, or P = 8 is not valid, and it's not restricted in the driver. This is not true for all the SoCs though.
The manual also says P should only be used when rate < 288 MHz. Moving P to the outer loop, and maybe adding a short circuit exit when the rate matches exactly would help.
Quoted 92 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +92
-0+ max_n, max_m, &_n, &_m); + + tmp_rate = (parent * _n * _k >> _p) / _m; + +if (tmp_rate > rate) +continue ; + +if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_n = _n; + best_k = _k; + best_m = _m; + best_p = _p; + } + } + } + + *n = best_n; + *k = best_k; + *m = best_m; + *p = best_p; +} + +static void ccu_nkmp_disable (struct clk_hw *hw) +{ +struct ccu_nkmp *nkmp =hw_to_ccu_nkmp (hw); + +return ccu_gate_helper_disable (&nkmp->common, nkmp->enable); +} + +static int ccu_nkmp_enable (struct clk_hw *hw) +{ +struct ccu_nkmp *nkmp =hw_to_ccu_nkmp (hw); + +return ccu_gate_helper_enable (&nkmp->common, nkmp->enable); +} + +static int ccu_nkmp_is_enabled (struct clk_hw *hw) +{ +struct ccu_nkmp *nkmp =hw_to_ccu_nkmp (hw); + +return ccu_gate_helper_is_enabled (&nkmp->common, nkmp->enable); +} + +static unsigned long ccu_nkmp_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +struct ccu_nkmp *nkmp =hw_to_ccu_nkmp (hw); +unsigned long n, m, k, p; +u32 reg; + + reg =readl (nkmp->common.base + nkmp->common.reg); + + n = reg >> nkmp->n.shift; + n &= (1 << nkmp->n.width) -1 ; + + k = reg >> nkmp->k.shift; + k &= (1 << nkmp->k.width) -1 ; + + m = reg >> nkmp->m.shift; + m &= (1 << nkmp->m.width) -1 ; + + p = reg >> nkmp->p.shift; + p &= (1 << nkmp->p.width) -1 ; + +return (parent_rate * (n +1 ) * (k +1 ) >> p) / (m +1 ); +} + +static long ccu_nkmp_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *parent_rate) +{ +struct ccu_nkmp *nkmp =hw_to_ccu_nkmp (hw); +unsigned long n, k, m, p; + +ccu_nkmp_find_best (*parent_rate, rate, +1 << nkmp->n.width,1 << nkmp->k.width, +1 << nkmp->m.width, (1 << nkmp->p.width) -1 , + &n, &k, &m, &p); + +return (*parent_rate * n * k >> p) / m; +} + +static int ccu_nkmp_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct ccu_nkmp *nkmp =hw_to_ccu_nkmp (hw); +unsigned long n, k, m, p; +unsigned long flags; +u32 reg; + + ccu_nkmp_find_best(parent_rate, rate, + 1 << nkmp->n.width, 1 << nkmp->k.width,
drivers/clk/sunxi-ng/ccu_nkmp.c line 133
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +10
-0+1 << nkmp->m.width, (1 << nkmp->p.width) -1 , + &n, &k, &m, &p); + +spin_lock_irqsave (nkmp->common.lock, flags); + + reg =readl (nkmp->common.base + nkmp->common.reg); + reg &= ~GENMASK (nkmp->n.width + nkmp->n.shift, nkmp->n.shift); + reg &= ~GENMASK (nkmp->k.width + nkmp->k.shift, nkmp->k.shift); + reg &= ~GENMASK (nkmp->m.width + nkmp->m.shift, nkmp->m.shift); + reg &= ~GENMASK (nkmp->p.width + nkmp->p.shift, nkmp->p.shift);
GENMASK(width + shift - 1, shift)
Quoted 61 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +24
-0+ + reg |= (n -1 ) << nkmp->m.shift; + reg |= (k -1 ) << nkmp->m.shift; + reg |= (m -1 ) << nkmp->m.shift; + reg |= p << nkmp->p.shift; + +writel (reg, nkmp->common.base + nkmp->common.reg); + +spin_unlock_irqrestore (nkmp->common.lock, flags); + +ccu_helper_wait_for_lock (&nkmp->common, nkmp->lock); + +return 0 ; +} + +const struct clk_ops ccu_nkmp_ops = { + .disable = ccu_nkmp_disable, + .enable = ccu_nkmp_enable, + .is_enabled = ccu_nkmp_is_enabled, + + .recalc_rate = ccu_nkmp_recalc_rate, + .round_rate = ccu_nkmp_round_rate, + .set_rate = ccu_nkmp_set_rate, +};drivers/clk/sunxi-ng/ccu_nkmp.h new file +31
-0@@ -0,0 +1,43 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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 _CCU_NKMP_H_ +#define _CCU_NKMP_H_ + +#include <linux/clk-provider.h> + +#include "ccu_factor.h" +#include "ccu_common.h" + +struct ccu_nkmp { + u32 enable; + u32 lock; + + struct ccu_factor n; + struct ccu_factor k; + struct ccu_factor m; + struct ccu_factor p; + + struct ccu_common common;
drivers/clk/sunxi-ng/ccu_nkmp.h line 41
Quoted 10 lines
drivers/clk/sunxi-ng/ccu_nkmp.h new file +10
-0+}; + +static inline struct ccu_nkmp *hw_to_ccu_nkmp (struct clk_hw *hw) +{ +struct ccu_common *common =hw_to_ccu_common (hw); + + return container_of(common, struct ccu_nkmp, common); +} + +extern const struct clk_ops ccu_nkmp_ops;
Macro please. :)
Regards
ChenYu
Quoted 5 lines
drivers/clk/sunxi-ng/ccu_nkmp.h new file +2
-1+ +#endif /* _CCU_NKMP_H_ */ --2.8.2
PATCH 14/16 clk: sunxi-ng: Add N-K-M-P factor clock
Hi Chen-Yu,
Quoted 48 lines · Chen-Yu Tsai
Quoted 46 lines · Maxime Ripard
Introduce support for clocks that use a combination of two linear multipliers (N and K factors), one linear divider (M) and one power of two divider (P).
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu_nkmp.c | 157 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu_nkmp.h | 43 +++++++++++ 3 files changed, 201 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.c create mode 100644 drivers/clk/sunxi-ng/ccu_nkmp.hdrivers/clk/sunxi-ng/Makefile +1
-0@@ -9,6 +9,7 @@ obj-y += ccu_mp.o obj-y += ccu_mux.o obj-y += ccu_nk.o obj-y += ccu_nkm.o +obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.odrivers/clk/sunxi-ng/ccu_nkmp.c new file +15
-0@@ -0,0 +1,157 @@ +/* +* Copyright (C) 2016 Maxime Ripard +* Maxime Ripard <[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. +*/ + +#include <linux/clk-provider.h> +#include <linux/rational.h> + +#include "ccu_gate.h" +#include "ccu_nkmp.h"
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_nkmp.c line 21
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +6
-0+ +void ccu_nkmp_find_best (unsigned long parent,unsigned long rate, +unsigned long max_n,unsigned long max_k, +unsigned long max_m,unsigned long max_p, +unsigned long *n,unsigned long *k, +unsigned long *m,unsigned long *p)We definitely should just pass struct ccu_nkmp* here.
Ok
Quoted 4 lines
Quoted 4 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +4
-0+{ +unsigned long best_rate =0 ; +unsigned long best_n =0 , best_k =0 , best_m =0 , best_p =0 ; +unsigned long _n, _k, _m, _p;
Quoted 8 lines
drivers/clk/sunxi-ng/ccu_nkmp.c line 31
Quoted 6 lines
drivers/clk/sunxi-ng/ccu_nkmp.c new file +6
-0+ +for (_k =1 ; _k <= max_k; _k++) { +for (_p =0 ; _p <= max_p; _p++) { +unsigned long tmp_rate; + + rational_best_approximation(rate / _k, parent << _p,I think you mean "parent >> _p" ?
Indeed :/
Quoted 11 lines
In general we might lose some precision if parent is too small or _p is too large. But the only place we see this type of clock is the CPU PLL, and parent (24 MHz) are divisible by all the possible values of P.
This brings up another issue: P does not go all the way up to (1 << width - 1). A register value of 3, or P = 8 is not valid, and it's not restricted in the driver. This is not true for all the SoCs though.
The manual also says P should only be used when rate < 288 MHz. Moving P to the outer loop, and maybe adding a short circuit exit when the rate matches exactly would help.
This is already something that was already reported by Jean-Francois. Apart from the P limitation this is the current logic used in the clock driver. We should probably fix that, but without any user (ie, cpufreq), it's just wild guesses in the middle of a massive and very intrusive changes.
So I don't really want to actually try to figure that out for now (and this is exactly why I don't want to convert the SoCs with a good support for now, since we'll pretty much uncover a whole lot of bugs that would turn into regressions).
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160530/4a242ac9/attachment.sig>
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
In reply to Maxime RipardAdd the list of clocks and resets found in the H3 CCU.
--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.h
drivers/clk/sunxi-ng/Makefile +2 -0
@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.o
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +757 -0
757 lines not on this page · raw message
include/dt-bindings/clock/sun8i-h3.h new file +162 -0
162 lines not on this page · raw message
include/dt-bindings/reset/sun8i-h3.h new file +103 -0
103 lines not on this page · raw message
Signature · 1 line
2.8.2
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
Quoted 18 lines · On Sun, 8 May 2016 22:01:50 +0200 Maxime Ripard…
Add the list of clocks and resets found in the H3 CCU.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +0
-0
drivers/clk/sunxi-ng/Makefile obj-y += ccu_nkmp.o · line 17
Quoted 5 lines
drivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.o
+obj-$(CONFIG_MACH_SUN8I) += ccu-sun8i-h3.o
should be better.
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
Quoted 29 lines · Jean-Francois Moine
Quoted 18 lines · On Sun, 8 May 2016 22:01:50 +0200 Maxime Ripard…
Add the list of clocks and resets found in the H3 CCU.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +0
-0drivers/clk/sunxi-ng/Makefile obj-y += ccu_nkmp.o · line 17
Quoted 5 lines
drivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.o+obj-$(CONFIG_MACH_SUN8I) += ccu-sun8i-h3.o
Quoted 1 line
should be better.
Indeed, changed.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160515/bfedb768/attachment-0001.sig>
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
In reply to Maxime RipardQuoted 1 line · On Sun, 8 May 2016 22:01:50 +0200 Maxime Ripard…
Add the list of clocks and resets found in the H3 CCU.
Hi Maxime,
Nice job. I like this new way for defining the sunxi clocks. But it does not yet fully work for the H3 (apart the other already signalled errors). See below.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
Quoted 27 lines
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.odrivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +0
-0@@ -0,0 +1,757 @@
[snip]
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 46
Quoted 12 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +12
-0+static struct ccu_nkmp pll_cpux_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,2 ), + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .p =SUNXI_CLK_FACTOR (16 ,2 ), + + .common = { + .reg =0x000 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK ,
It seems to me that these flags are redondant with the .enable and .lock fields (always != 0 when used).
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 52
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ .hw.init = SUNXI_HW_INIT("pll-cpux", +"osc24M" , + &ccu_nkmp_ops, + 0), + }, +};
The 'p' factor must be used only for very low rates (< 288MHz). I think that it should be ignored.
Quoted 17 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +17
-0+ +static struct ccu_nm pll_audio_base_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,5 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x008 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-audio-base" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +};
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 79
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ +static SUNXI_CCU_M(pll_audio_clk, "pll-audio", "pll-audio-base", + 0x008, 16, 4, 0); + +static SUNXI_CCU_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, 0);
Forcing the post divider 'p' to 4 would simplify this PLL.
Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +7
-0+ +static struct ccu_nm pll_video_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ),
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 96
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ + .common = { + .reg = 0x010, + .features = CCU_FEATURE_GATE | CCU_FEATURE_LOCK, + .hw.init =SUNXI_HW_INIT ("pll-video" , +"osc24M" , + &ccu_nm_ops, + 0), + }, +};
The legacy u-boot I use (lichee) forces this PLL to 297MHz in fractional mode (FRAC_CLK_OUT = 1 and PLL_MODE_SEL = 0).
As these bits are not managed, getting the rate is false and setting it is not possible.
[snip]
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ +static struct ccu_nk pll_periph0_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .fixed_post_div =2 , + + .common = {
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 151
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ .reg = 0x028, + .features = (CCU_FEATURE_GATE | +CCU_FEATURE_LOCK | + CCU_FEATURE_FIXED_POSTDIV), + .hw.init =SUNXI_HW_INIT ("pll-periph0" , +"osc24M" , + &ccu_nk_ops, + 0), + }, +};
As told previously, the H3 documentation says:
Note: The PLL Output should be fixed to 600MHz, it is not recommended to vary this value arbitrarily.
So, is it useful to offer the possibility to change the rate of this PLL (and same for pll-periph1)?
(I force the rate in the DT with assigned-clock-rates to avoid any problem)
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 155
Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+ +static SUNXI_CCU_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", + "pll-periph0", 1, 2, 0); +
[snip]
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 389
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +8
-0+static const char *const nand_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", nand_parents, 0x080, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0);
The mux width is 2, meaning there may be 4 parents. Then, there may be an access out of the parent array (and same for mmcx and spix).
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 392
Quoted 3 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +3
-0+ +static const char *const mmc0_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" };
The parent tables of nand, mmcx and spix are the same. One table should be enough.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 403
Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +11
-0+static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_parents, 0x088, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0", + 0x088, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0", + 0x088, 8, 3, 0);
[snip]
Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+static const char *const i2s0_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s0_parents, + 0x0b0, 16, 2, BIT(31), 0);
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 481
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ +static const char *const i2s1_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s1_parents, + 0x0b4, 16, 2, BIT(31), 0); + +static const char *const i2s2_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", i2s2_parents, + 0x0b8, 16, 2, BIT(31), 0);
[snip]
Same parent tables.
This occurs for other clocks.
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
Hi Jean-Francois,
Quoted 10 lines · Jean-Francois Moine
Quoted 1 line · On Sun, 8 May 2016 22:01:50 +0200 Maxime Ripard…
Add the list of clocks and resets found in the H3 CCU.
Hi Maxime,
Nice job. I like this new way for defining the sunxi clocks. But it does not yet fully work for the H3 (apart the other already signalled errors). See below.
I'm glad you like it, it should make everyone's life easier.
And I was kind of expecting you'd uncover a bunch of bugs testing that with the HDMI audio patches you have.
Quoted 29 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
Quoted 28 lines
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.odrivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +0
-0@@ -0,0 +1,757 @@[snip]
Quoted 15 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 46
Quoted 12 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +12
-0+static struct ccu_nkmp pll_cpux_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,2 ), + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .p =SUNXI_CLK_FACTOR (16 ,2 ), + + .common = { + .reg =0x000 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK ,It seems to me that these flags are redondant with the .enable and .lock fields (always != 0 when used).
Yes, kind of, but not exactly. The features flags describe in a generic manner what the clock can and cannot do, while the fields themselves are per-structure.
This will allow the core if we ever need it to probe what each clock implements. And since we are using it for other features that can be shared by multiple clock classes (muxes, post-div, pre-div and so on), I think it would be best to keep it consitent and use it here.
But I agree that it's not really a strong argument.
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 52
Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ .hw.init = SUNXI_HW_INIT("pll-cpux", +"osc24M" , + &ccu_nkmp_ops, + 0), + }, +};The 'p' factor must be used only for very low rates (< 288MHz). I think that it should be ignored.
Yeah, I noticed it as well during the development. I just re-used the current behaviour of the A23 PLL1 that uses P as well. I was not really willing to change any behaviour here at first, this patch set is already quite intrusive.
But we can definitely change that later.
Quoted 21 lines
Quoted 21 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +21
-0+ +static struct ccu_nm pll_audio_base_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,5 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x008 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-audio-base" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; + +static SUNXI_CCU_M(pll_audio_clk, "pll-audio", "pll-audio-base", + 0x008, 16, 4, 0); +
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 79
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+static SUNXI_CCU_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, 0);Forcing the post divider 'p' to 4 would simplify this PLL.
Yes and no. It would simplify the clock rate computation and propagation across the tree, but it would also add more code in there, and we would not be able to read the clock rate properly.
Chaining clocks like that should also be supported and working, so I'd still be very much in favour of implementing it as it is supposed to be, and fixing whatever bug there might be in there.
Quoted 13 lines
Quoted 13 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +13
-0+static struct ccu_nm pll_video_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x010 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init = SUNXI_HW_INIT("pll-video", + "osc24M", + &ccu_nm_ops,
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 52
Quoted 3 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +3
-0+ 0), + }, +};The legacy u-boot I use (lichee) forces this PLL to 297MHz in fractional mode (
FRAC_CLK_OUT= 1 andPLL_MODE_SEL= 0).
As these bits are not managed, getting the rate is false and setting it is not possible.
Ah, interesting.
I'll add support for fractional clocks in the next version then.
Just out of curiosity, is there any particular reason for sticking with Allwinner's U-Boot over using mainline U-Boot?
Quoted 22 lines
Quoted 9 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +9
-0+static struct ccu_nk pll_periph0_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .fixed_post_div =2 , + + .common = {drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 151
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ .reg = 0x028, + .features = (CCU_FEATURE_GATE | +CCU_FEATURE_LOCK | + CCU_FEATURE_FIXED_POSTDIV), + .hw.init =SUNXI_HW_INIT ("pll-periph0" , +"osc24M" , + &ccu_nk_ops, + 0), + }, +};As told previously, the H3 documentation says:
Quoted 6 lines
Note: The PLL Output should be fixed to 600MHz, it is not recommended to vary this value arbitrarily.
So, is it useful to offer the possibility to change the rate of this PLL (and same for pll-periph1)?
(I force the rate in the DT with assigned-clock-rates to avoid any problem)
assigned-clock-rates will not change anything unfortunately. It sets a default rate at boot time, but it doesn't prevent the rate from being changed.
Fortunately, that rate will never be modified, since none of the child clock have CLK_SET_RATE_PARENT.
If that was to change, and when that time comes, we can always use the clk boundaries to deal with it nicely.
Quoted 5 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 155
Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+ +static SUNXI_CCU_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", + "pll-periph0", 1, 2, 0); +[snip]
Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 389
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +8
-0+static const char *const nand_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", nand_parents, 0x080, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0);The mux width is 2, meaning there may be 4 parents. Then, there may be an access out of the parent array (and same for mmcx and spix).
The mux relies on the number of parents registered in the clock framework, which is 3 in this case, so that won't happen.
Or am I missing what you're saying?
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 392
Quoted 3 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +3
-0+ +static const char *const mmc0_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" };The parent tables of nand, mmcx and spix are the same. One table should be enough.
Ack.
Quoted 28 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 403
Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +11
-0+static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_parents, 0x088, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0", + 0x088, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0", + 0x088, 8, 3, 0);[snip]Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+static const char *const i2s0_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s0_parents, + 0x0b0, 16, 2, BIT(31), 0);drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 481
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ +static const char *const i2s1_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s1_parents, + 0x0b4, 16, 2, BIT(31), 0); + +static const char *const i2s2_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", i2s2_parents, + 0x0b8, 16, 2, BIT(31), 0);[snip]
Quoted 2 lines
Same parent tables.
This occurs for other clocks.
Ack.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160518/dec7f73c/attachment-0001.sig>
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
Quoted 1 line · On Wed, 18 May 2016 16:02:00 +0200 Maxime Ripard…
On Fri, May 13, 2016 at 11:45:59AM +0200, Jean-Francois Moine wrote:
[snip]
Quoted 30 lines
Quoted 21 lines
Quoted 21 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +21
-0+ +static struct ccu_nm pll_audio_base_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,5 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x008 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-audio-base" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; + +static SUNXI_CCU_M(pll_audio_clk, "pll-audio", "pll-audio-base", + 0x008, 16, 4, 0); +Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 79
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+static SUNXI_CCU_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, 0);Forcing the post divider 'p' to 4 would simplify this PLL.
Quoted 7 lines
Yes and no. It would simplify the clock rate computation and propagation across the tree, but it would also add more code in there, and we would not be able to read the clock rate properly.
Chaining clocks like that should also be supported and working, so I'd still be very much in favour of implementing it as it is supposed to be, and fixing whatever bug there might be in there.
See my next mail:
static SUNXI_CCU_FIXED_FACTOR(pll_audio, "pll-audio",
"pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
Quoted 22 lines
Quoted 13 lines
Quoted 13 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +13
-0+static struct ccu_nm pll_video_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x010 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init = SUNXI_HW_INIT("pll-video", + "osc24M", + &ccu_nm_ops,Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 52
Quoted 3 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +3
-0+ 0), + }, +};The legacy u-boot I use (lichee) forces this PLL to 297MHz in fractional mode (
FRAC_CLK_OUT= 1 andPLL_MODE_SEL= 0).
As these bits are not managed, getting the rate is false and setting it is not possible.
Quoted 6 lines
Ah, interesting.
I'll add support for fractional clocks in the next version then.
Just out of curiosity, is there any particular reason for sticking with Allwinner's U-Boot over using mainline U-Boot?
Allwinner's U_Boot works fine enough for me, and with it, I am sure that the hidden/unknown parts of the SoC (dram, prcm) are correctly initialized.
Quoted 110 lines
Quoted 22 lines
Quoted 9 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +9
-0+static struct ccu_nk pll_periph0_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .fixed_post_div =2 , + + .common = {drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 151
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ .reg = 0x028, + .features = (CCU_FEATURE_GATE | +CCU_FEATURE_LOCK | + CCU_FEATURE_FIXED_POSTDIV), + .hw.init =SUNXI_HW_INIT ("pll-periph0" , +"osc24M" , + &ccu_nk_ops, + 0), + }, +};As told previously, the H3 documentation says:
Quoted 6 lines
Note: The PLL Output should be fixed to 600MHz, it is not recommended to vary this value arbitrarily.
So, is it useful to offer the possibility to change the rate of this PLL (and same for pll-periph1)?
(I force the rate in the DT with assigned-clock-rates to avoid any problem)assigned-clock-rates will not change anything unfortunately. It sets a default rate at boot time, but it doesn't prevent the rate from being changed.
Fortunately, that rate will never be modified, since none of the child clock have
CLK_SET_RATE_PARENT.If that was to change, and when that time comes, we can always use the clk boundaries to deal with it nicely.
Quoted 5 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 155
Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+ +static SUNXI_CCU_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", + "pll-periph0", 1, 2, 0); +[snip]Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 389
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +8
-0+static const char *const nand_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", nand_parents, 0x080, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0);The mux width is 2, meaning there may be 4 parents. Then, there may be an access out of the parent array (and same for mmcx and spix).
The mux relies on the number of parents registered in the clock framework, which is 3 in this case, so that won't happen.
Or am I missing what you're saying?
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 392
Quoted 3 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +3
-0+ +static const char *const mmc0_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" };The parent tables of nand, mmcx and spix are the same. One table should be enough.
Ack.
Quoted 28 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 403
Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +11
-0+static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_parents, 0x088, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0", + 0x088, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0", + 0x088, 8, 3, 0);[snip]Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+static const char *const i2s0_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s0_parents, + 0x0b0, 16, 2, BIT(31), 0);drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 481
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ +static const char *const i2s1_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s1_parents, + 0x0b4, 16, 2, BIT(31), 0); + +static const char *const i2s2_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", i2s2_parents, + 0x0b8, 16, 2, BIT(31), 0);[snip]Quoted 2 lines
Same parent tables.
This occurs for other clocks.Ack.
Thanks!
MaximeSignature · 3 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
In reply to Maxime RipardHi Maxime,
Sorry, my previous mail was sent while not finished!
Quoted 1 line · On Wed, 18 May 2016 16:02:00 +0200 Maxime Ripard…
On Fri, May 13, 2016 at 11:45:59AM +0200, Jean-Francois Moine wrote:
[snip]
Quoted 12 lines
Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 389
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +8
-0+static const char *const nand_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", nand_parents, 0x080, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0);The mux width is 2, meaning there may be 4 parents. Then, there may be an access out of the parent array (and same for mmcx and spix).
Quoted 4 lines
The mux relies on the number of parents registered in the clock framework, which is 3 in this case, so that won't happen.
Or am I missing what you're saying?
Sorry, at this time, I did not look yet at the macros. There is no problem here.
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
In reply to Maxime Riparddrivers/clk/sunxi-ng/ccu-sun8i-h3.c
Quoted 29 lines · On Sun, 8 May 2016 22:01:50 +0200 Maxime Ripard…
Add the list of clocks and resets found in the H3 CCU.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.odrivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +0
-0@@ -0,0 +1,757 @@
[snip]
Quoted 17 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +17
-0+static struct ccu_nm pll_audio_base_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,5 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x008 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-audio-base" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; +
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 80
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+static SUNXI_CCU_M(pll_audio_clk, "pll-audio", "pll-audio-base", + 0x008, 16, 4, 0); + +static SUNXI_CCU_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, 0); +
[snip]
The pll-audio-{2,4,8}x clocks lack the CLK_SET_RATE_PARENT.
Also, in my implementation of the sound on HDMI, I set pll-audio as the parent of the i2s2 clock. Then, as the pll-audio clock is defined here, setting its rate is always wrong (only 'M' is changed, and with a bad value - BTW, DIV_ROUND_UP would be welcome in ccu_m_find_best()).
As the pre-divider 'M' is set to 4 by default, there is no need to change it. Then, audio works fine for me with:
static SUNXI_CCU_FIXED_FACTOR(pll_audio, "pll-audio",
"pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
Signature · 2 lines
Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
Hi,
Quoted 69 lines · Jean-Francois Moine
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
Quoted 29 lines · On Sun, 8 May 2016 22:01:50 +0200 Maxime Ripard…
Add the list of clocks and resets found in the H3 CCU.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.odrivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +0
-0@@ -0,0 +1,757 @@[snip]Quoted 17 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +17
-0+static struct ccu_nm pll_audio_base_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,5 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x008 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-audio-base" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; +drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 80
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+static SUNXI_CCU_M(pll_audio_clk, "pll-audio", "pll-audio-base", + 0x008, 16, 4, 0); + +static SUNXI_CCU_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, 0); +[snip]The pll-audio-{2,4,8}x clocks lack the
CLK_SET_RATE_PARENT.Also, in my implementation of the sound on HDMI, I set pll-audio as the parent of the i2s2 clock. Then, as the pll-audio clock is defined here, setting its rate is always wrong (only 'M' is changed, and with a bad value - BTW,
DIV_ROUND_UPwould be welcome inccu_m_find_best()).
Quoted 6 lines
As the pre-divider 'M' is set to 4 by default, there is no need to change it. Then, audio works fine for me with:
static SUNXI_CCU_FIXED_FACTOR(pll_audio, "pll-audio",
"pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
OK. I just changed it, we can always change it later if needs be.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160518/197395b9/attachment.sig>
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
In reply to Maxime RipardQuoted 61 lines · Maxime Ripard
Add the list of clocks and resets found in the H3 CCU.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.odrivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +32
-0@@ -0,0 +1,757 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/clk-provider.h> + +#include <dt-bindings/clock/sun8i-h3.h> +#include <dt-bindings/reset/sun8i-h3.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div_table.h" +#include "ccu_factor.h" +#include "ccu_fixed_factor.h" +#include "ccu_gate.h" +#include "ccu_m.h" +#include "ccu_mp.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" +#include "ccu_p.h"
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 42
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+#include "ccu_phase.h" + +static struct ccu_nkmp pll_cpux_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,2 ), + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .p =SUNXI_CLK_FACTOR (16 ,2 ),
We should find a way to specify a table for p.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 48
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ + .common = { + .reg = 0x000, + .features = CCU_FEATURE_GATE | CCU_FEATURE_LOCK, + .hw.init = SUNXI_HW_INIT("pll-cpux", + "osc24M",
osc24M is an outside reference. Shouldn't we use put it in a "clocks" property in the DT, and use of_clk_get_parent_name()?
osc24M can be controlled from the PRCM on other chips. I suspect the same with the H3. osc32k might also be from the PRCM.
Quoted 63 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +63
-0+ &ccu_nkmp_ops, + 0), + }, +}; + +static struct ccu_nm pll_audio_base_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,5 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x008 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-audio-base" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; + +static SUNXI_CCU_M(pll_audio_clk, "pll-audio", "pll-audio-base", + 0x008, 16, 4, 0); + +static SUNXI_CCU_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, 0); + +static struct ccu_nm pll_video_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x010 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-video" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; + +static struct ccu_nm pll_ve_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x018 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-ve" , +"osc24M" , + &ccu_nm_ops, +0 ),
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 121
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ }, +}; + +static struct ccu_nkm pll_ddr_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .m =SUNXI_CLK_FACTOR (0 ,2 ),
We need a special "update" bit (bit 20) for this clock, otherwise changes don't really take effect.
Quoted 81 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +81
-0+ + .common = { + .reg = 0x020, + .features = CCU_FEATURE_GATE | CCU_FEATURE_LOCK, + .hw.init =SUNXI_HW_INIT ("pll-ddr" , +"osc24M" , + &ccu_nkm_ops, + 0), + }, +}; + +static struct ccu_nk pll_periph0_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .fixed_post_div =2 , + + .common = { + .reg =0x028 , + .features = (CCU_FEATURE_GATE | +CCU_FEATURE_LOCK | +CCU_FEATURE_FIXED_POSTDIV ), + .hw.init =SUNXI_HW_INIT ("pll-periph0" , +"osc24M" , + &ccu_nk_ops, +0 ), + }, +}; + +static SUNXI_CCU_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", + "pll-periph0", 1, 2, 0); + +static struct ccu_nm pll_gpu_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x038 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-gpu" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; + +static struct ccu_nk pll_periph1_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .fixed_post_div =2 , + + .common = { + .reg =0x044 , + .features = (CCU_FEATURE_GATE | +CCU_FEATURE_LOCK | +CCU_FEATURE_FIXED_POSTDIV ), + .hw.init =SUNXI_HW_INIT ("pll-periph1" , +"osc24M" , + &ccu_nk_ops, +0 ), + }, +}; + +static struct ccu_nm pll_de_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x048 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK ,
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 212
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ .hw.init = SUNXI_HW_INIT("pll-de", +"osc24M" , + &ccu_nm_ops, + 0), + }, +}; + +static const char *const cpux_parents[] = {"osc32k" ,"osc24M" ,"pll-cpux" ,"pll-cpux" }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, + 0x050, 16, 2, CLK_IS_CRITICAL);
Nit: Is it necessary to split this line?
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 214
Quoted 2 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +2
-0+ +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x050, 0, 2, 0);
This register also has a "System APB" clock. Any idea what that is?
Quoted 77 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +77
-0+ +static const char *const ahb1_parents[] = {"osc32k" ,"osc24M" ,"axi" ,"pll-periph0" }; +static struct ccu_p ahb1_clk = { + .p =SUNXI_CLK_FACTOR (4 ,2 ), + + .mux = { + .shift =12 , + .width =2 , + + .variable_prediv = { + .index =3 , + .shift =6 , + .width =2 , + }, + }, + + .common = { + .reg =0x054 , + .features =CCU_FEATURE_VARIABLE_PREDIV , + .hw.init =SUNXI_HW_INIT_PARENTS ("ahb1" , + ahb1_parents, + &ccu_p_ops, +0 ), + }, +}; + +static u8 apb1_div_table [] = {2 ,2 ,4 ,8 }; +static SUNXI_CCU_DIV_TABLE(apb1_clk, "apb1", "ahb1", + 0x054, 8, 2, apb1_div_table, 0); + +static const char *const apb2_parents[] = {"osc32k" ,"osc24M" , +"pll-periph0" ,"pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058, +0 ,5 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ + 0); + +static const char *const ahb2_parents[] = {"ahb1" ,"pll-periph0" }; +static struct ccu_mux ahb2_clk = { + .mux = { + .shift =0 , + .width =1 , + + .fixed_prediv = { + .index =1 , + .div =2 , + }, + }, + + .common = { + .reg =0x05c , + .features =CCU_FEATURE_FIXED_PREDIV , + .hw.init =SUNXI_HW_INIT_PARENTS ("ahb2" , + ahb2_parents, + &ccu_mux_ops, +0 ), + }, +}; + +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "ahb1", + 0x060, BIT(5), 0); +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "ahb1", + 0x060, BIT(6), 0); +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb1", + 0x060, BIT(8), 0); +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb1", + 0x060, BIT(9), 0); +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb1", + 0x060, BIT(10), 0); +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb1", + 0x060, BIT(13), 0); +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "ahb1", + 0x060, BIT(14), 0); +static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb2", + 0x060, BIT(17), 0); +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb1",
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 301
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ 0x060, BIT(18), 0); +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1", + 0x060, BIT(19), 0); +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb1", + 0x060, BIT(20), 0); +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb1", + 0x060, BIT(21), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb1", + 0x060, BIT(23), 0); +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb2",
Clock diagram says ?HCI 1/2/3 are on ahb2, while otg (I assume it includes both the OTG controller and the associated ?HCI) is on ahb1.
Quoted 65 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +65
-0+ 0x060, BIT(24), 0); +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb2", + 0x060, BIT(25), 0); +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb2", + 0x060, BIT(26), 0); +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb2", + 0x060, BIT(27), 0); +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb2", + 0x060, BIT(28), 0); +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb2", + 0x060, BIT(29), 0); +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb2", + 0x060, BIT(30), 0); +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb2", + 0x060, BIT(31), 0); + +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "ahb1", + 0x064, BIT(0), 0); +static SUNXI_CCU_GATE(bus_tcon0_clk, "bus-tcon0", "ahb1", + 0x064, BIT(3), 0); +static SUNXI_CCU_GATE(bus_tcon1_clk, "bus-tcon1", "ahb1", + 0x064, BIT(4), 0); +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "ahb1", + 0x064, BIT(5), 0); +static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb1", + 0x064, BIT(8), 0); +static SUNXI_CCU_GATE(bus_tve_clk, "bus-tve", "ahb1", + 0x064, BIT(9), 0); +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb1", + 0x064, BIT(11), 0); +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1", + 0x064, BIT(12), 0); +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1", + 0x064, BIT(20), 0); +static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1", + 0x064, BIT(21), 0); +static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1", + 0x064, BIT(22), 0); + +static SUNXI_CCU_GATE(bus_codec_clk, "bus-codec", "apb1", + 0x068, BIT(0), 0); +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", + 0x068, BIT(1), 0); +static SUNXI_CCU_GATE(bus_pio_clk, "bus-pio", "apb1", + 0x068, BIT(5), 0); +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", + 0x068, BIT(8), 0); +static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1", + 0x068, BIT(12), 0); +static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1", + 0x068, BIT(13), 0); +static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1", + 0x068, BIT(14), 0); + +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", + 0x06c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", + 0x06c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", + 0x06c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", + 0x06c, BIT(16), 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", + 0x06c, BIT(17), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2",
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 376
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+ 0x06c, BIT(18), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", + 0x06c, BIT(19), 0); +static SUNXI_CCU_GATE(bus_scr_clk, "bus-scr", "apb2", + 0x06c, BIT(20), 0); + +static SUNXI_CCU_GATE(bus_ephy_clk, "bus-ephy", "ahb1", + 0x070, BIT(0), 0); +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "ahb1", + 0x070, BIT(7), 0);
Maybe not split these lines? IMHO it's easier to read as table.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 380
Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+ +static u8 ths_div_table [] = {1 ,2 ,4 ,6 }; +static SUNXI_CCU_DIV_TABLE_WITH_GATE(ths_clk, "ths", "osc24M", + 0x074, 0, 2, ths_div_table, BIT(31), 0);
The clock actually has a mux, which has only one valid parent. Should we include it?
Quoted 47 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +47
-0+ +static const char *const nand_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", nand_parents, 0x080, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static const char *const mmc0_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_parents, 0x088, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0", + 0x088, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0", + 0x088, 8, 3, 0); + +static const char *const mmc1_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc1_parents, 0x08c, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1_sample", "mmc1", + 0x08c, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1_output", "mmc1", + 0x08c, 8, 3, 0); + +static const char *const mmc2_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc2_parents, 0x090, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); +
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 437
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+static SUNXI_CCU_PHASE(mmc2_sample_clk, "mmc2_sample", "mmc2", + 0x090, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc2_output_clk, "mmc2_output", "mmc2", + 0x090, 8, 3, 0); + +static const char *const ts_parents[] = {"osc24M" ,"pll-periph0" , }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x098, +0 ,4 ,/* M */ +16 ,2 ,/* P */ + 24, 1, /* mux */
The mux is 4 bits wide with only 2 valid parents.
Quoted 58 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +58
-0+BIT (31 ),/* gate */ + 0); + +static const char *const ce_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x09c, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static const char *const spi0_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", spi0_parents, 0x0a0, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static const char *const spi1_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", spi1_parents, 0x0a4, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static const char *const i2s0_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s0_parents, + 0x0b0, 16, 2, BIT(31), 0); + +static const char *const i2s1_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s1_parents, + 0x0b4, 16, 2, BIT(31), 0); + +static const char *const i2s2_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", i2s2_parents, + 0x0b8, 16, 2, BIT(31), 0); + +static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio", + 0x0c0, 0, 4, BIT(31), 0); + +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", + 0x0cc, BIT(8), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", + 0x0cc, BIT(9), 0); +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", + 0x0cc, BIT(10), 0); +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc24M", + 0x0cc, BIT(11), 0); +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M", + 0x0cc, BIT(16), 0);
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 505
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc24M", + 0x0cc, BIT(17), 0); +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc24M", + 0x0cc, BIT(18), 0); +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc24M", + 0x0cc, BIT(19), 0); + +static const char *const dram_parents[] = {"pll-ddr" ,"pll-periph0-2x" }; +static SUNXI_CCU_M_WITH_MUX(dram_clk, "dram", dram_parents, + 0x0f4, 0, 4, 20, 1, 0);
Mux is 2 bits wide. Also need an update bit setting for this clock. (or mark it read-only?)
Quoted 14 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +14
-0+ +static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "dram", + 0x100, BIT(0), 0); +static SUNXI_CCU_GATE(dram_csi_clk, "dram-csi", "dram", + 0x100, BIT(1), 0); +static SUNXI_CCU_GATE(dram_deinterlace_clk, "dram-deinterlace", "dram", + 0x100, BIT(2), 0); +static SUNXI_CCU_GATE(dram_ts_clk, "dram-ts", "dram", + 0x100, BIT(3), 0); + +static const char *const de_parents[] = {"pll-periph0-2x" ,"pll-de" }; +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, + 0x104, 0, 4, 24, 1, BIT(31), 0); +
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 529
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+static SUNXI_CCU_M_WITH_GATE(tcon_clk, "tcon", "pll-video", + 0x118, 0, 4, BIT(31), 0); + +static const char *const tve_parents[] = {"pll-de" ,"pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(tve_clk, "tve", tve_parents, + 0x120, 0, 4, 24, 1, BIT(31), 0); + +static const char *const deinterlace_parents[] = {"pll-periph0" ,"pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", deinterlace_parents, + 0x124, 0, 4, 24, 1, BIT(31), 0);
Mux is 3 bits wide for DE, TCON, TVE, and DEINTERLACE clocks.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 536
Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +7
-0+ +static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", + 0x130, BIT(31), 0); + +static const char *const csi_sclk_parents[] = {"pll-periph0" ,"pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_sclk_clk, "csi-sclk", csi_sclk_parents, + 0x134, 16, 4, 24, 1, BIT(31), 0);
Mux is 3 bits wide.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 540
Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+ +static const char *const csi_mclk_parents[] = {"osc24M" ,"pll-video" ,"pll-periph0" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents, + 0x134, 0, 5, 8, 2, BIT(15), 0);
Same here.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 551
Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +11
-0+ +static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", + 0x13c, 16, 3, BIT(31), 0); + +static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio", + 0x140, BIT(31), 0); +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", + 0x144, BIT(31), 0); + +static SUNXI_CCU_M_WITH_GATE(hdmi_clk, "hdmi", "pll-video", + 0x150, 0, 4, BIT(31), 0);
2 bit mux?
Quoted 484 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +206
-0+ +static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", + 0x154, BIT(31), 0); + +static const char *const mbus_parents[] = {"osc24M" ,"pll-periph0-2x" ,"pll-ddr" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, + 0x15c, 0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL); + +static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu", + 0x1a0, 0, 3, BIT(31), 0); + +static struct ccu_common *sun8i_h3_ccu_clks[] = { + [CLK_PLL_CPUX ] = &pll_cpux_clk.common, + [CLK_PLL_AUDIO_BASE ] = &pll_audio_base_clk.common, + [CLK_PLL_AUDIO ] = &pll_audio_clk.common, + [CLK_PLL_AUDIO_2X ] = &pll_audio_2x_clk.common, + [CLK_PLL_AUDIO_4X ] = &pll_audio_4x_clk.common, + [CLK_PLL_AUDIO_8X ] = &pll_audio_8x_clk.common, + [CLK_PLL_VIDEO ] = &pll_video_clk.common, + [CLK_PLL_VE ] = &pll_ve_clk.common, + [CLK_PLL_DDR ] = &pll_ddr_clk.common, + [CLK_PLL_PERIPH0 ] = &pll_periph0_clk.common, + [CLK_PLL_PERIPH0_2X ] = &pll_periph0_2x_clk.common, + [CLK_PLL_GPU ] = &pll_gpu_clk.common, + [CLK_PLL_PERIPH1 ] = &pll_periph1_clk.common, + [CLK_PLL_DE ] = &pll_de_clk.common, + [CLK_CPUX ] = &cpux_clk.common, + [CLK_AXI ] = &axi_clk.common, + [CLK_AHB1 ] = &ahb1_clk.common, + [CLK_APB1 ] = &apb1_clk.common, + [CLK_APB2 ] = &apb2_clk.common, + [CLK_AHB2 ] = &ahb2_clk.common, + [CLK_BUS_CE ] = &bus_ce_clk.common, + [CLK_BUS_DMA ] = &bus_dma_clk.common, + [CLK_BUS_MMC0 ] = &bus_mmc0_clk.common, + [CLK_BUS_MMC1 ] = &bus_mmc1_clk.common, + [CLK_BUS_MMC2 ] = &bus_mmc2_clk.common, + [CLK_BUS_NAND ] = &bus_nand_clk.common, + [CLK_BUS_DRAM ] = &bus_dram_clk.common, + [CLK_BUS_EMAC ] = &bus_emac_clk.common, + [CLK_BUS_TS ] = &bus_ts_clk.common, + [CLK_BUS_HSTIMER ] = &bus_hstimer_clk.common, + [CLK_BUS_SPI0 ] = &bus_spi0_clk.common, + [CLK_BUS_SPI1 ] = &bus_spi1_clk.common, + [CLK_BUS_OTG ] = &bus_otg_clk.common, + [CLK_BUS_EHCI0 ] = &bus_ehci0_clk.common, + [CLK_BUS_EHCI1 ] = &bus_ehci1_clk.common, + [CLK_BUS_EHCI2 ] = &bus_ehci2_clk.common, + [CLK_BUS_EHCI3 ] = &bus_ehci3_clk.common, + [CLK_BUS_OHCI0 ] = &bus_ohci0_clk.common, + [CLK_BUS_OHCI1 ] = &bus_ohci1_clk.common, + [CLK_BUS_OHCI2 ] = &bus_ohci2_clk.common, + [CLK_BUS_OHCI3 ] = &bus_ohci3_clk.common, + [CLK_BUS_VE ] = &bus_ve_clk.common, + [CLK_BUS_TCON0 ] = &bus_tcon0_clk.common, + [CLK_BUS_TCON1 ] = &bus_tcon1_clk.common, + [CLK_BUS_DEINTERLACE ] = &bus_deinterlace_clk.common, + [CLK_BUS_CSI ] = &bus_csi_clk.common, + [CLK_BUS_TVE ] = &bus_tve_clk.common, + [CLK_BUS_HDMI ] = &bus_hdmi_clk.common, + [CLK_BUS_DE ] = &bus_de_clk.common, + [CLK_BUS_GPU ] = &bus_gpu_clk.common, + [CLK_BUS_MSGBOX ] = &bus_msgbox_clk.common, + [CLK_BUS_SPINLOCK ] = &bus_spinlock_clk.common, + [CLK_BUS_CODEC ] = &bus_codec_clk.common, + [CLK_BUS_SPDIF ] = &bus_spdif_clk.common, + [CLK_BUS_PIO ] = &bus_pio_clk.common, + [CLK_BUS_THS ] = &bus_ths_clk.common, + [CLK_BUS_I2S0 ] = &bus_i2s0_clk.common, + [CLK_BUS_I2S1 ] = &bus_i2s1_clk.common, + [CLK_BUS_I2S2 ] = &bus_i2s2_clk.common, + [CLK_BUS_I2C0 ] = &bus_i2c0_clk.common, + [CLK_BUS_I2C1 ] = &bus_i2c1_clk.common, + [CLK_BUS_I2C2 ] = &bus_i2c2_clk.common, + [CLK_BUS_UART0 ] = &bus_uart0_clk.common, + [CLK_BUS_UART1 ] = &bus_uart1_clk.common, + [CLK_BUS_UART2 ] = &bus_uart2_clk.common, + [CLK_BUS_UART3 ] = &bus_uart3_clk.common, + [CLK_BUS_SCR ] = &bus_scr_clk.common, + [CLK_BUS_EPHY ] = &bus_ephy_clk.common, + [CLK_BUS_DBG ] = &bus_dbg_clk.common, + [CLK_THS ] = &ths_clk.common, + [CLK_NAND ] = &nand_clk.common, + [CLK_MMC0 ] = &mmc0_clk.common, + [CLK_MMC0_SAMPLE ] = &mmc0_sample_clk.common, + [CLK_MMC0_OUTPUT ] = &mmc0_output_clk.common, + [CLK_MMC1 ] = &mmc1_clk.common, + [CLK_MMC1_SAMPLE ] = &mmc1_sample_clk.common, + [CLK_MMC1_OUTPUT ] = &mmc1_output_clk.common, + [CLK_MMC2 ] = &mmc2_clk.common, + [CLK_MMC2_SAMPLE ] = &mmc2_sample_clk.common, + [CLK_MMC2_OUTPUT ] = &mmc2_output_clk.common, + [CLK_TS ] = &ts_clk.common, + [CLK_CE ] = &ce_clk.common, + [CLK_SPI0 ] = &spi0_clk.common, + [CLK_SPI1 ] = &spi1_clk.common, + [CLK_I2S0 ] = &i2s0_clk.common, + [CLK_I2S1 ] = &i2s1_clk.common, + [CLK_I2S2 ] = &i2s2_clk.common, + [CLK_SPDIF ] = &spdif_clk.common, + [CLK_USB_PHY0 ] = &usb_phy0_clk.common, + [CLK_USB_PHY1 ] = &usb_phy1_clk.common, + [CLK_USB_PHY2 ] = &usb_phy2_clk.common, + [CLK_USB_PHY3 ] = &usb_phy3_clk.common, + [CLK_USB_OHCI0 ] = &usb_ohci0_clk.common, + [CLK_USB_OHCI1 ] = &usb_ohci1_clk.common, + [CLK_USB_OHCI2 ] = &usb_ohci2_clk.common, + [CLK_USB_OHCI3 ] = &usb_ohci3_clk.common, + [CLK_DRAM ] = &dram_clk.common, + [CLK_DRAM_VE ] = &dram_ve_clk.common, + [CLK_DRAM_CSI ] = &dram_csi_clk.common, + [CLK_DRAM_DEINTERLACE ] = &dram_deinterlace_clk.common, + [CLK_DRAM_TS ] = &dram_ts_clk.common, + [CLK_DE ] = &de_clk.common, + [CLK_TCON0 ] = &tcon_clk.common, + [CLK_TVE ] = &tve_clk.common, + [CLK_DEINTERLACE ] = &deinterlace_clk.common, + [CLK_CSI_MISC ] = &csi_misc_clk.common, + [CLK_CSI_SCLK ] = &csi_sclk_clk.common, + [CLK_CSI_MCLK ] = &csi_mclk_clk.common, + [CLK_VE ] = &ve_clk.common, + [CLK_AC_DIG ] = &ac_dig_clk.common, + [CLK_AVS ] = &avs_clk.common, + [CLK_HDMI ] = &hdmi_clk.common, + [CLK_HDMI_DDC ] = &hdmi_ddc_clk.common, + [CLK_MBUS ] = &mbus_clk.common, + [CLK_GPU ] = &gpu_clk.common, +}; + +static struct ccu_reset_map sun8i_h3_ccu_resets[] = { + [RST_USB_PHY0 ] = {0x0cc ,BIT (0 ) }, + [RST_USB_PHY1 ] = {0x0cc ,BIT (1 ) }, + [RST_USB_PHY2 ] = {0x0cc ,BIT (2 ) }, + [RST_USB_PHY3 ] = {0x0cc ,BIT (3 ) }, + + [RST_MBUS ] = {0x0fc ,BIT (31 ) }, + + [RST_BUS_CE ] = {0x2c0 ,BIT (5 ) }, + [RST_BUS_DMA ] = {0x2c0 ,BIT (6 ) }, + [RST_BUS_MMC0 ] = {0x2c0 ,BIT (8 ) }, + [RST_BUS_MMC1 ] = {0x2c0 ,BIT (9 ) }, + [RST_BUS_MMC2 ] = {0x2c0 ,BIT (10 ) }, + [RST_BUS_NAND ] = {0x2c0 ,BIT (13 ) }, + [RST_BUS_DRAM ] = {0x2c0 ,BIT (14 ) }, + [RST_BUS_EMAC ] = {0x2c0 ,BIT (17 ) }, + [RST_BUS_TS ] = {0x2c0 ,BIT (18 ) }, + [RST_BUS_HSTIMER ] = {0x2c0 ,BIT (19 ) }, + [RST_BUS_SPI0 ] = {0x2c0 ,BIT (20 ) }, + [RST_BUS_SPI1 ] = {0x2c0 ,BIT (21 ) }, + [RST_BUS_OTG ] = {0x2c0 ,BIT (23 ) }, + [RST_BUS_EHCI0 ] = {0x2c0 ,BIT (24 ) }, + [RST_BUS_EHCI1 ] = {0x2c0 ,BIT (25 ) }, + [RST_BUS_EHCI2 ] = {0x2c0 ,BIT (26 ) }, + [RST_BUS_EHCI3 ] = {0x2c0 ,BIT (27 ) }, + [RST_BUS_OHCI0 ] = {0x2c0 ,BIT (28 ) }, + [RST_BUS_OHCI1 ] = {0x2c0 ,BIT (29 ) }, + [RST_BUS_OHCI2 ] = {0x2c0 ,BIT (30 ) }, + [RST_BUS_OHCI3 ] = {0x2c0 ,BIT (31 ) }, + + [RST_BUS_VE ] = {0x2c4 ,BIT (0 ) }, + [RST_BUS_TCON0 ] = {0x2c4 ,BIT (3 ) }, + [RST_BUS_TCON1 ] = {0x2c4 ,BIT (4 ) }, + [RST_BUS_DEINTERLACE ] = {0x2c4 ,BIT (5 ) }, + [RST_BUS_CSI ] = {0x2c4 ,BIT (8 ) }, + [RST_BUS_TVE ] = {0x2c4 ,BIT (9 ) }, + [RST_BUS_HDMI0 ] = {0x2c4 ,BIT (10 ) }, + [RST_BUS_HDMI1 ] = {0x2c4 ,BIT (11 ) }, + [RST_BUS_DE ] = {0x2c4 ,BIT (12 ) }, + [RST_BUS_GPU ] = {0x2c4 ,BIT (20 ) }, + [RST_BUS_MSGBOX ] = {0x2c4 ,BIT (21 ) }, + [RST_BUS_SPINLOCK ] = {0x2c4 ,BIT (22 ) }, + [RST_BUS_DBG ] = {0x2c4 ,BIT (31 ) }, + + [RST_BUS_EPHY ] = {0x2c8 ,BIT (2 ) }, + + [RST_BUS_CODEC ] = {0x2d0 ,BIT (0 ) }, + [RST_BUS_SPDIF ] = {0x2d0 ,BIT (1 ) }, + [RST_BUS_THS ] = {0x2d0 ,BIT (8 ) }, + [RST_BUS_I2S0 ] = {0x2d0 ,BIT (12 ) }, + [RST_BUS_I2S1 ] = {0x2d0 ,BIT (13 ) }, + [RST_BUS_I2S2 ] = {0x2d0 ,BIT (14 ) }, + + [RST_BUS_I2C0 ] = {0x2d4 ,BIT (0 ) }, + [RST_BUS_I2C1 ] = {0x2d4 ,BIT (1 ) }, + [RST_BUS_I2C2 ] = {0x2d4 ,BIT (2 ) }, + [RST_BUS_UART0 ] = {0x2d4 ,BIT (16 ) }, + [RST_BUS_UART1 ] = {0x2d4 ,BIT (17 ) }, + [RST_BUS_UART2 ] = {0x2d4 ,BIT (18 ) }, + [RST_BUS_UART3 ] = {0x2d4 ,BIT (19 ) }, + [RST_BUS_SCR ] = {0x2d4 ,BIT (20 ) }, +}; + +static const struct sunxi_ccu_desc sun8i_h3_ccu_desc = { + .clks = sun8i_h3_ccu_clks, + .num_clks =ARRAY_SIZE (sun8i_h3_ccu_clks), + + .resets = sun8i_h3_ccu_resets, + .num_resets =ARRAY_SIZE (sun8i_h3_ccu_resets), +}; + +static void __init sun8i_h3_ccu_setup (struct device_node *node) +{ +sunxi_ccu_probe (node, &sun8i_h3_ccu_desc); +} +CLK_OF_DECLARE (sun8i_h3_ccu,"allwinner,sun8i-h3-ccu" , + sun8i_h3_ccu_setup);include/dt-bindings/clock/sun8i-h3.h new file +162
-0@@ -0,0 +1,162 @@ +/* +* Copyright (C) 2016 Maxime Ripard <[email protected]> +* +* This file is dual-licensed: you can use it either under the terms +* of the GPL or the X11 license, at your option. Note that this dual +* licensing only applies to this file, and not this project as a +* whole. +* +* a) This file 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 file 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. +* +* Or, alternatively, +* +* b) Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _DT_BINDINGS_CLK_SUN8I_H3_H_ +#define _DT_BINDINGS_CLK_SUN8I_H3_H_ + +#define CLK_PLL_CPUX 0 +#define CLK_PLL_AUDIO_BASE 1 +#define CLK_PLL_AUDIO 2 +#define CLK_PLL_AUDIO_2X 3 +#define CLK_PLL_AUDIO_4X 4 +#define CLK_PLL_AUDIO_8X 5 +#define CLK_PLL_VIDEO 6 +#define CLK_PLL_VE 7 +#define CLK_PLL_DDR 8 +#define CLK_PLL_PERIPH0 9 +#define CLK_PLL_PERIPH0_2X 10 +#define CLK_PLL_GPU 11 +#define CLK_PLL_PERIPH1 12 +#define CLK_PLL_DE 13 +#define CLK_CPUX 14 +#define CLK_AXI 15 +#define CLK_AHB1 16 +#define CLK_APB1 17 +#define CLK_APB2 18 +#define CLK_AHB2 19 +#define CLK_BUS_CE 20 +#define CLK_BUS_DMA 21 +#define CLK_BUS_MMC0 22 +#define CLK_BUS_MMC1 23 +#define CLK_BUS_MMC2 24 +#define CLK_BUS_NAND 25 +#define CLK_BUS_DRAM 26 +#define CLK_BUS_EMAC 27 +#define CLK_BUS_TS 28 +#define CLK_BUS_HSTIMER 29 +#define CLK_BUS_SPI0 30 +#define CLK_BUS_SPI1 31 +#define CLK_BUS_OTG 32 +#define CLK_BUS_EHCI0 33 +#define CLK_BUS_EHCI1 34 +#define CLK_BUS_EHCI2 35 +#define CLK_BUS_EHCI3 36 +#define CLK_BUS_OHCI0 37 +#define CLK_BUS_OHCI1 38 +#define CLK_BUS_OHCI2 39 +#define CLK_BUS_OHCI3 40 +#define CLK_BUS_VE 41 +#define CLK_BUS_TCON0 42 +#define CLK_BUS_TCON1 43 +#define CLK_BUS_DEINTERLACE 44 +#define CLK_BUS_CSI 45 +#define CLK_BUS_TVE 46 +#define CLK_BUS_HDMI 47 +#define CLK_BUS_DE 48 +#define CLK_BUS_GPU 49 +#define CLK_BUS_MSGBOX 50 +#define CLK_BUS_SPINLOCK 51 +#define CLK_BUS_CODEC 52 +#define CLK_BUS_SPDIF 53 +#define CLK_BUS_PIO 54 +#define CLK_BUS_THS 55 +#define CLK_BUS_I2S0 56 +#define CLK_BUS_I2S1 57 +#define CLK_BUS_I2S2 58 +#define CLK_BUS_I2C0 59 +#define CLK_BUS_I2C1 60 +#define CLK_BUS_I2C2 61 +#define CLK_BUS_UART0 62 +#define CLK_BUS_UART1 63 +#define CLK_BUS_UART2 64 +#define CLK_BUS_UART3 65 +#define CLK_BUS_SCR 66 +#define CLK_BUS_EPHY 67 +#define CLK_BUS_DBG 68 +#define CLK_THS 69 +#define CLK_NAND 70 +#define CLK_MMC0 71 +#define CLK_MMC0_SAMPLE 72 +#define CLK_MMC0_OUTPUT 73 +#define CLK_MMC1 74 +#define CLK_MMC1_SAMPLE 75 +#define CLK_MMC1_OUTPUT 76 +#define CLK_MMC2 77 +#define CLK_MMC2_SAMPLE 78 +#define CLK_MMC2_OUTPUT 79 +#define CLK_TS 80 +#define CLK_CE 81 +#define CLK_SPI0 82 +#define CLK_SPI1 83 +#define CLK_I2S0 84 +#define CLK_I2S1 85 +#define CLK_I2S2 86 +#define CLK_SPDIF 87 +#define CLK_USB_PHY0 88 +#define CLK_USB_PHY1 89 +#define CLK_USB_PHY2 90 +#define CLK_USB_PHY3 91 +#define CLK_USB_OHCI0 92 +#define CLK_USB_OHCI1 93 +#define CLK_USB_OHCI2 94 +#define CLK_USB_OHCI3 95 +#define CLK_DRAM 96 +#define CLK_DRAM_VE 97 +#define CLK_DRAM_CSI 98 +#define CLK_DRAM_DEINTERLACE 99 +#define CLK_DRAM_TS 100 +#define CLK_DE 101 +#define CLK_TCON0 102 +#define CLK_TVE 103 +#define CLK_DEINTERLACE 104 +#define CLK_CSI_MISC 105 +#define CLK_CSI_SCLK 106 +#define CLK_CSI_MCLK 107 +#define CLK_VE 108 +#define CLK_AC_DIG 109 +#define CLK_AVS 110 +#define CLK_HDMI 111 +#define CLK_HDMI_DDC 112 +#define CLK_MBUS 113 +#define CLK_GPU 114 + +#endif /* _DT_BINDINGS_CLK_SUN8I_H3_H_ */ include/dt-bindings/reset/sun8i-h3.h new file +103
-1@@ -0,0 +1,103 @@ +/* +* Copyright (C) 2016 Maxime Ripard <[email protected]> +* +* This file is dual-licensed: you can use it either under the terms +* of the GPL or the X11 license, at your option. Note that this dual +* licensing only applies to this file, and not this project as a +* whole. +* +* a) This file 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 file 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. +* +* Or, alternatively, +* +* b) Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _DT_BINDINGS_RST_SUN8I_H3_H_ +#define _DT_BINDINGS_RST_SUN8I_H3_H_ + +#define RST_USB_PHY0 0 +#define RST_USB_PHY1 1 +#define RST_USB_PHY2 2 +#define RST_USB_PHY3 3 + +#define RST_MBUS 4 + +#define RST_BUS_CE 5 +#define RST_BUS_DMA 6 +#define RST_BUS_MMC0 7 +#define RST_BUS_MMC1 8 +#define RST_BUS_MMC2 9 +#define RST_BUS_NAND 10 +#define RST_BUS_DRAM 11 +#define RST_BUS_EMAC 12 +#define RST_BUS_TS 13 +#define RST_BUS_HSTIMER 14 +#define RST_BUS_SPI0 15 +#define RST_BUS_SPI1 16 +#define RST_BUS_OTG 17 +#define RST_BUS_EHCI0 18 +#define RST_BUS_EHCI1 19 +#define RST_BUS_EHCI2 20 +#define RST_BUS_EHCI3 21 +#define RST_BUS_OHCI0 22 +#define RST_BUS_OHCI1 23 +#define RST_BUS_OHCI2 24 +#define RST_BUS_OHCI3 25 +#define RST_BUS_VE 26 +#define RST_BUS_TCON0 27 +#define RST_BUS_TCON1 28 +#define RST_BUS_DEINTERLACE 29 +#define RST_BUS_CSI 30 +#define RST_BUS_TVE 31 +#define RST_BUS_HDMI0 32 +#define RST_BUS_HDMI1 33 +#define RST_BUS_DE 34 +#define RST_BUS_GPU 35 +#define RST_BUS_MSGBOX 36 +#define RST_BUS_SPINLOCK 37 +#define RST_BUS_DBG 38 +#define RST_BUS_EPHY 39 +#define RST_BUS_CODEC 40 +#define RST_BUS_SPDIF 41 +#define RST_BUS_THS 42 +#define RST_BUS_I2S0 43 +#define RST_BUS_I2S1 44 +#define RST_BUS_I2S2 45 +#define RST_BUS_I2C0 46 +#define RST_BUS_I2C1 47 +#define RST_BUS_I2C2 48 +#define RST_BUS_UART0 49 +#define RST_BUS_UART1 50 +#define RST_BUS_UART2 51 +#define RST_BUS_UART3 52 +#define RST_BUS_SCR 53 + +#endif /* _DT_BINDINGS_RST_SUN8I_H3_H_ */ --
Quoted 2 lines
2.8.2
The rest looks good. Sorry it took so long.
About the mux widths, I prefer to have the full width, even if only the first few values are valid. It would prevent someone playing with the registers (or bad code) and the values sticking, before the kernel loads. Then the kernel won't think that it set a valid parent, but the high bit was not cleared, and whatever peripheral ended up not working.
Regards
ChenYu
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
Hi Chen-Yu,
Quoted 67 lines · Chen-Yu Tsai
Quoted 65 lines · Maxime Ripard
Add the list of clocks and resets found in the H3 CCU.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.odrivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +36
-0@@ -0,0 +1,757 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/clk-provider.h> + +#include <dt-bindings/clock/sun8i-h3.h> +#include <dt-bindings/reset/sun8i-h3.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div_table.h" +#include "ccu_factor.h" +#include "ccu_fixed_factor.h" +#include "ccu_gate.h" +#include "ccu_m.h" +#include "ccu_mp.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" +#include "ccu_p.h" +#include "ccu_phase.h" + +static struct ccu_nkmp pll_cpux_clk = { + .enable =BIT (31 ),
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 42
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ .lock = BIT(28), + + .m = SUNXI_CLK_FACTOR(0, 2), + .k = SUNXI_CLK_FACTOR(4, 2), + .n = SUNXI_CLK_FACTOR(8, 5), + .p = SUNXI_CLK_FACTOR(16, 2),We should find a way to specify a table for p.
A table for P? Why?
Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 48
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ + .common = { + .reg = 0x000, + .features = CCU_FEATURE_GATE | CCU_FEATURE_LOCK, + .hw.init = SUNXI_HW_INIT("pll-cpux", + "osc24M",
Quoted 5 lines
osc24M is an outside reference. Shouldn't we use put it in a "clocks" property in the DT, and use
of_clk_get_parent_name()?osc24M can be controlled from the PRCM on other chips. I suspect the same with the H3. osc32k might also be from the PRCM.
I was discussing exactly this the other day with Mike. He has a bunch of patches to address exactly that issue. He plans on posting it and merge it by 4.8. Until then, we should rely on the hardcoded clock string like it's done there, and we should obviously add the clocks in the DT node for when we will actually use them.
Quoted 68 lines
Quoted 68 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +68
-0+ &ccu_nkmp_ops, + 0), + }, +}; + +static struct ccu_nm pll_audio_base_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,5 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x008 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-audio-base" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; + +static SUNXI_CCU_M(pll_audio_clk, "pll-audio", "pll-audio-base", + 0x008, 16, 4, 0); + +static SUNXI_CCU_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, 0); +static SUNXI_CCU_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, 0); + +static struct ccu_nm pll_video_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x010 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-video" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; + +static struct ccu_nm pll_ve_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x018 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-ve" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; + +static struct ccu_nkm pll_ddr_clk = { + .enable = BIT(31),
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 121
Quoted 5 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +5
-0+ .lock = BIT(28), + + .n = SUNXI_CLK_FACTOR(8, 5), + .k = SUNXI_CLK_FACTOR(4, 2), + .m = SUNXI_CLK_FACTOR(0, 2),We need a special "update" bit (bit 20) for this clock, otherwise changes don't really take effect.
Yeah, I know, but I feel like it's a feature here, since Linux should never modify that clock anyway.
I can add a comment though.
Quoted 85 lines
Quoted 85 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +85
-0+ + .common = { + .reg = 0x020, + .features = CCU_FEATURE_GATE | CCU_FEATURE_LOCK, + .hw.init =SUNXI_HW_INIT ("pll-ddr" , +"osc24M" , + &ccu_nkm_ops, + 0), + }, +}; + +static struct ccu_nk pll_periph0_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .fixed_post_div =2 , + + .common = { + .reg =0x028 , + .features = (CCU_FEATURE_GATE | +CCU_FEATURE_LOCK | +CCU_FEATURE_FIXED_POSTDIV ), + .hw.init =SUNXI_HW_INIT ("pll-periph0" , +"osc24M" , + &ccu_nk_ops, +0 ), + }, +}; + +static SUNXI_CCU_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", + "pll-periph0", 1, 2, 0); + +static struct ccu_nm pll_gpu_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x038 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-gpu" , +"osc24M" , + &ccu_nm_ops, +0 ), + }, +}; + +static struct ccu_nk pll_periph1_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .fixed_post_div =2 , + + .common = { + .reg =0x044 , + .features = (CCU_FEATURE_GATE | +CCU_FEATURE_LOCK | +CCU_FEATURE_FIXED_POSTDIV ), + .hw.init =SUNXI_HW_INIT ("pll-periph1" , +"osc24M" , + &ccu_nk_ops, +0 ), + }, +}; + +static struct ccu_nm pll_de_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .m =SUNXI_CLK_FACTOR (0 ,4 ), + .n =SUNXI_CLK_FACTOR (8 ,7 ), + + .common = { + .reg =0x048 , + .features =CCU_FEATURE_GATE |CCU_FEATURE_LOCK , + .hw.init =SUNXI_HW_INIT ("pll-de" , +"osc24M" , + &ccu_nm_ops, +0 ),
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 212
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ }, +}; + +static const char *const cpux_parents[] = {"osc32k" ,"osc24M" ,"pll-cpux" ,"pll-cpux" }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, + 0x050, 16, 2, CLK_IS_CRITICAL);Nit: Is it necessary to split this line?
I liked the similar layout across all the clocks, comparing to other clocks that have a longer name or parent name.
Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 214
Quoted 2 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +2
-0+ +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x050, 0, 2, 0);This register also has a "System APB" clock. Any idea what that is?
None, and it seems like it's not used by any downstream device either.
Quoted 83 lines
Quoted 83 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +82
-0+ +static const char *const ahb1_parents[] = {"osc32k" ,"osc24M" ,"axi" ,"pll-periph0" }; +static struct ccu_p ahb1_clk = { + .p =SUNXI_CLK_FACTOR (4 ,2 ), + + .mux = { + .shift =12 , + .width =2 , + + .variable_prediv = { + .index =3 , + .shift =6 , + .width =2 , + }, + }, + + .common = { + .reg =0x054 , + .features =CCU_FEATURE_VARIABLE_PREDIV , + .hw.init =SUNXI_HW_INIT_PARENTS ("ahb1" , + ahb1_parents, + &ccu_p_ops, +0 ), + }, +}; + +static u8 apb1_div_table [] = {2 ,2 ,4 ,8 }; +static SUNXI_CCU_DIV_TABLE(apb1_clk, "apb1", "ahb1", + 0x054, 8, 2, apb1_div_table, 0); + +static const char *const apb2_parents[] = {"osc32k" ,"osc24M" , +"pll-periph0" ,"pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058, +0 ,5 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ + 0); + +static const char *const ahb2_parents[] = {"ahb1" ,"pll-periph0" }; +static struct ccu_mux ahb2_clk = { + .mux = { + .shift =0 , + .width =1 , + + .fixed_prediv = { + .index =1 , + .div =2 , + }, + }, + + .common = { + .reg =0x05c , + .features =CCU_FEATURE_FIXED_PREDIV , + .hw.init =SUNXI_HW_INIT_PARENTS ("ahb2" , + ahb2_parents, + &ccu_mux_ops, +0 ), + }, +}; + +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "ahb1", + 0x060, BIT(5), 0); +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "ahb1", + 0x060, BIT(6), 0); +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb1", + 0x060, BIT(8), 0); +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb1", + 0x060, BIT(9), 0); +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb1", + 0x060, BIT(10), 0); +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb1", + 0x060, BIT(13), 0); +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "ahb1", + 0x060, BIT(14), 0); +static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb2", + 0x060, BIT(17), 0); +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb1", + 0x060, BIT(18), 0); +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1", + 0x060, BIT(19), 0); +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb1", + 0x060, BIT(20), 0);
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 301
Quoted 5 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +5
-0+static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb1", + 0x060, BIT(21), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb1", + 0x060, BIT(23), 0); +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb2",Clock diagram says ?HCI 1/2/3 are on ahb2, while otg (I assume it includes both the OTG controller and the associated ?HCI) is on ahb1.
Indeed, I'll fix it.
Quoted 69 lines
Quoted 69 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +69
-0+ 0x060, BIT(24), 0); +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb2", + 0x060, BIT(25), 0); +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb2", + 0x060, BIT(26), 0); +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb2", + 0x060, BIT(27), 0); +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb2", + 0x060, BIT(28), 0); +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb2", + 0x060, BIT(29), 0); +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb2", + 0x060, BIT(30), 0); +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb2", + 0x060, BIT(31), 0); + +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "ahb1", + 0x064, BIT(0), 0); +static SUNXI_CCU_GATE(bus_tcon0_clk, "bus-tcon0", "ahb1", + 0x064, BIT(3), 0); +static SUNXI_CCU_GATE(bus_tcon1_clk, "bus-tcon1", "ahb1", + 0x064, BIT(4), 0); +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "ahb1", + 0x064, BIT(5), 0); +static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb1", + 0x064, BIT(8), 0); +static SUNXI_CCU_GATE(bus_tve_clk, "bus-tve", "ahb1", + 0x064, BIT(9), 0); +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb1", + 0x064, BIT(11), 0); +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1", + 0x064, BIT(12), 0); +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1", + 0x064, BIT(20), 0); +static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1", + 0x064, BIT(21), 0); +static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1", + 0x064, BIT(22), 0); + +static SUNXI_CCU_GATE(bus_codec_clk, "bus-codec", "apb1", + 0x068, BIT(0), 0); +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", + 0x068, BIT(1), 0); +static SUNXI_CCU_GATE(bus_pio_clk, "bus-pio", "apb1", + 0x068, BIT(5), 0); +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", + 0x068, BIT(8), 0); +static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1", + 0x068, BIT(12), 0); +static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1", + 0x068, BIT(13), 0); +static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1", + 0x068, BIT(14), 0); + +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", + 0x06c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", + 0x06c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", + 0x06c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", + 0x06c, BIT(16), 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", + 0x06c, BIT(17), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", + 0x06c, BIT(18), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", + 0x06c, BIT(19), 0); +static SUNXI_CCU_GATE(bus_scr_clk, "bus-scr", "apb2",
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 376
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ 0x06c, BIT(20), 0); + +static SUNXI_CCU_GATE(bus_ephy_clk, "bus-ephy", "ahb1", + 0x070, BIT(0), 0); +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "ahb1", + 0x070, BIT(7), 0);Maybe not split these lines? IMHO it's easier to read as table.
Maybe yes, I'll give it a try.
Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 380
Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+ +static u8 ths_div_table [] = {1 ,2 ,4 ,6 }; +static SUNXI_CCU_DIV_TABLE_WITH_GATE(ths_clk, "ths", "osc24M", + 0x074, 0, 2, ths_div_table, BIT(31), 0);The clock actually has a mux, which has only one valid parent. Should we include it?
If it has a single parent, it's not a mux, is it ? :)
Quoted 51 lines
Quoted 51 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +51
-0+ +static const char *const nand_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", nand_parents, 0x080, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static const char *const mmc0_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_parents, 0x088, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0", + 0x088, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0", + 0x088, 8, 3, 0); + +static const char *const mmc1_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc1_parents, 0x08c, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1_sample", "mmc1", + 0x08c, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1_output", "mmc1", + 0x08c, 8, 3, 0); + +static const char *const mmc2_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc2_parents, 0x090, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc2_sample_clk, "mmc2_sample", "mmc2", + 0x090, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc2_output_clk, "mmc2_output", "mmc2", + 0x090, 8, 3, 0);
Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 437
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ +static const char *const ts_parents[] = {"osc24M" ,"pll-periph0" , }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x098, +0 ,4 ,/* M */ +16 ,2 ,/* P */ + 24, 1, /* mux */The mux is 4 bits wide with only 2 valid parents.
I'm not sure what to do with all of these. There's two valid parents, so it doesn't really make any kind of difference, does it?
Quoted 619 lines
Quoted 58 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +58
-0+BIT (31 ),/* gate */ + 0); + +static const char *const ce_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x09c, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static const char *const spi0_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", spi0_parents, 0x0a0, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static const char *const spi1_parents[] = {"osc24M" ,"pll-periph0" , +"pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", spi1_parents, 0x0a4, +0 ,4 ,/* M */ +16 ,2 ,/* P */ +24 ,2 ,/* mux */ +BIT (31 ),/* gate */ + 0); + +static const char *const i2s0_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s0_parents, + 0x0b0, 16, 2, BIT(31), 0); + +static const char *const i2s1_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s1_parents, + 0x0b4, 16, 2, BIT(31), 0); + +static const char *const i2s2_parents[] = {"pll-audio-8x" ,"pll-audio-4x" , +"pll-audio-2x" ,"pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", i2s2_parents, + 0x0b8, 16, 2, BIT(31), 0); + +static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio", + 0x0c0, 0, 4, BIT(31), 0); + +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", + 0x0cc, BIT(8), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", + 0x0cc, BIT(9), 0); +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", + 0x0cc, BIT(10), 0); +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc24M", + 0x0cc, BIT(11), 0); +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M", + 0x0cc, BIT(16), 0);drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 505
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc24M", + 0x0cc, BIT(17), 0); +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc24M", + 0x0cc, BIT(18), 0); +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc24M", + 0x0cc, BIT(19), 0); + +static const char *const dram_parents[] = {"pll-ddr" ,"pll-periph0-2x" }; +static SUNXI_CCU_M_WITH_MUX(dram_clk, "dram", dram_parents, + 0x0f4, 0, 4, 20, 1, 0);Mux is 2 bits wide. Also need an update bit setting for this clock. (or mark it read-only?)
Quoted 14 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +14
-0+ +static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "dram", + 0x100, BIT(0), 0); +static SUNXI_CCU_GATE(dram_csi_clk, "dram-csi", "dram", + 0x100, BIT(1), 0); +static SUNXI_CCU_GATE(dram_deinterlace_clk, "dram-deinterlace", "dram", + 0x100, BIT(2), 0); +static SUNXI_CCU_GATE(dram_ts_clk, "dram-ts", "dram", + 0x100, BIT(3), 0); + +static const char *const de_parents[] = {"pll-periph0-2x" ,"pll-de" }; +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, + 0x104, 0, 4, 24, 1, BIT(31), 0); +drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 529
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +10
-0+static SUNXI_CCU_M_WITH_GATE(tcon_clk, "tcon", "pll-video", + 0x118, 0, 4, BIT(31), 0); + +static const char *const tve_parents[] = {"pll-de" ,"pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(tve_clk, "tve", tve_parents, + 0x120, 0, 4, 24, 1, BIT(31), 0); + +static const char *const deinterlace_parents[] = {"pll-periph0" ,"pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", deinterlace_parents, + 0x124, 0, 4, 24, 1, BIT(31), 0);Mux is 3 bits wide for DE, TCON, TVE, and DEINTERLACE clocks.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 536
Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +7
-0+ +static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", + 0x130, BIT(31), 0); + +static const char *const csi_sclk_parents[] = {"pll-periph0" ,"pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_sclk_clk, "csi-sclk", csi_sclk_parents, + 0x134, 16, 4, 24, 1, BIT(31), 0);Mux is 3 bits wide.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 540
Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +4
-0+ +static const char *const csi_mclk_parents[] = {"osc24M" ,"pll-video" ,"pll-periph0" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents, + 0x134, 0, 5, 8, 2, BIT(15), 0);Same here.
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 551
Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +11
-0+ +static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", + 0x13c, 16, 3, BIT(31), 0); + +static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio", + 0x140, BIT(31), 0); +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", + 0x144, BIT(31), 0); + +static SUNXI_CCU_M_WITH_GATE(hdmi_clk, "hdmi", "pll-video", + 0x150, 0, 4, BIT(31), 0);2 bit mux?
Quoted 484 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +206
-0+ +static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", + 0x154, BIT(31), 0); + +static const char *const mbus_parents[] = {"osc24M" ,"pll-periph0-2x" ,"pll-ddr" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, + 0x15c, 0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL); + +static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu", + 0x1a0, 0, 3, BIT(31), 0); + +static struct ccu_common *sun8i_h3_ccu_clks[] = { + [CLK_PLL_CPUX ] = &pll_cpux_clk.common, + [CLK_PLL_AUDIO_BASE ] = &pll_audio_base_clk.common, + [CLK_PLL_AUDIO ] = &pll_audio_clk.common, + [CLK_PLL_AUDIO_2X ] = &pll_audio_2x_clk.common, + [CLK_PLL_AUDIO_4X ] = &pll_audio_4x_clk.common, + [CLK_PLL_AUDIO_8X ] = &pll_audio_8x_clk.common, + [CLK_PLL_VIDEO ] = &pll_video_clk.common, + [CLK_PLL_VE ] = &pll_ve_clk.common, + [CLK_PLL_DDR ] = &pll_ddr_clk.common, + [CLK_PLL_PERIPH0 ] = &pll_periph0_clk.common, + [CLK_PLL_PERIPH0_2X ] = &pll_periph0_2x_clk.common, + [CLK_PLL_GPU ] = &pll_gpu_clk.common, + [CLK_PLL_PERIPH1 ] = &pll_periph1_clk.common, + [CLK_PLL_DE ] = &pll_de_clk.common, + [CLK_CPUX ] = &cpux_clk.common, + [CLK_AXI ] = &axi_clk.common, + [CLK_AHB1 ] = &ahb1_clk.common, + [CLK_APB1 ] = &apb1_clk.common, + [CLK_APB2 ] = &apb2_clk.common, + [CLK_AHB2 ] = &ahb2_clk.common, + [CLK_BUS_CE ] = &bus_ce_clk.common, + [CLK_BUS_DMA ] = &bus_dma_clk.common, + [CLK_BUS_MMC0 ] = &bus_mmc0_clk.common, + [CLK_BUS_MMC1 ] = &bus_mmc1_clk.common, + [CLK_BUS_MMC2 ] = &bus_mmc2_clk.common, + [CLK_BUS_NAND ] = &bus_nand_clk.common, + [CLK_BUS_DRAM ] = &bus_dram_clk.common, + [CLK_BUS_EMAC ] = &bus_emac_clk.common, + [CLK_BUS_TS ] = &bus_ts_clk.common, + [CLK_BUS_HSTIMER ] = &bus_hstimer_clk.common, + [CLK_BUS_SPI0 ] = &bus_spi0_clk.common, + [CLK_BUS_SPI1 ] = &bus_spi1_clk.common, + [CLK_BUS_OTG ] = &bus_otg_clk.common, + [CLK_BUS_EHCI0 ] = &bus_ehci0_clk.common, + [CLK_BUS_EHCI1 ] = &bus_ehci1_clk.common, + [CLK_BUS_EHCI2 ] = &bus_ehci2_clk.common, + [CLK_BUS_EHCI3 ] = &bus_ehci3_clk.common, + [CLK_BUS_OHCI0 ] = &bus_ohci0_clk.common, + [CLK_BUS_OHCI1 ] = &bus_ohci1_clk.common, + [CLK_BUS_OHCI2 ] = &bus_ohci2_clk.common, + [CLK_BUS_OHCI3 ] = &bus_ohci3_clk.common, + [CLK_BUS_VE ] = &bus_ve_clk.common, + [CLK_BUS_TCON0 ] = &bus_tcon0_clk.common, + [CLK_BUS_TCON1 ] = &bus_tcon1_clk.common, + [CLK_BUS_DEINTERLACE ] = &bus_deinterlace_clk.common, + [CLK_BUS_CSI ] = &bus_csi_clk.common, + [CLK_BUS_TVE ] = &bus_tve_clk.common, + [CLK_BUS_HDMI ] = &bus_hdmi_clk.common, + [CLK_BUS_DE ] = &bus_de_clk.common, + [CLK_BUS_GPU ] = &bus_gpu_clk.common, + [CLK_BUS_MSGBOX ] = &bus_msgbox_clk.common, + [CLK_BUS_SPINLOCK ] = &bus_spinlock_clk.common, + [CLK_BUS_CODEC ] = &bus_codec_clk.common, + [CLK_BUS_SPDIF ] = &bus_spdif_clk.common, + [CLK_BUS_PIO ] = &bus_pio_clk.common, + [CLK_BUS_THS ] = &bus_ths_clk.common, + [CLK_BUS_I2S0 ] = &bus_i2s0_clk.common, + [CLK_BUS_I2S1 ] = &bus_i2s1_clk.common, + [CLK_BUS_I2S2 ] = &bus_i2s2_clk.common, + [CLK_BUS_I2C0 ] = &bus_i2c0_clk.common, + [CLK_BUS_I2C1 ] = &bus_i2c1_clk.common, + [CLK_BUS_I2C2 ] = &bus_i2c2_clk.common, + [CLK_BUS_UART0 ] = &bus_uart0_clk.common, + [CLK_BUS_UART1 ] = &bus_uart1_clk.common, + [CLK_BUS_UART2 ] = &bus_uart2_clk.common, + [CLK_BUS_UART3 ] = &bus_uart3_clk.common, + [CLK_BUS_SCR ] = &bus_scr_clk.common, + [CLK_BUS_EPHY ] = &bus_ephy_clk.common, + [CLK_BUS_DBG ] = &bus_dbg_clk.common, + [CLK_THS ] = &ths_clk.common, + [CLK_NAND ] = &nand_clk.common, + [CLK_MMC0 ] = &mmc0_clk.common, + [CLK_MMC0_SAMPLE ] = &mmc0_sample_clk.common, + [CLK_MMC0_OUTPUT ] = &mmc0_output_clk.common, + [CLK_MMC1 ] = &mmc1_clk.common, + [CLK_MMC1_SAMPLE ] = &mmc1_sample_clk.common, + [CLK_MMC1_OUTPUT ] = &mmc1_output_clk.common, + [CLK_MMC2 ] = &mmc2_clk.common, + [CLK_MMC2_SAMPLE ] = &mmc2_sample_clk.common, + [CLK_MMC2_OUTPUT ] = &mmc2_output_clk.common, + [CLK_TS ] = &ts_clk.common, + [CLK_CE ] = &ce_clk.common, + [CLK_SPI0 ] = &spi0_clk.common, + [CLK_SPI1 ] = &spi1_clk.common, + [CLK_I2S0 ] = &i2s0_clk.common, + [CLK_I2S1 ] = &i2s1_clk.common, + [CLK_I2S2 ] = &i2s2_clk.common, + [CLK_SPDIF ] = &spdif_clk.common, + [CLK_USB_PHY0 ] = &usb_phy0_clk.common, + [CLK_USB_PHY1 ] = &usb_phy1_clk.common, + [CLK_USB_PHY2 ] = &usb_phy2_clk.common, + [CLK_USB_PHY3 ] = &usb_phy3_clk.common, + [CLK_USB_OHCI0 ] = &usb_ohci0_clk.common, + [CLK_USB_OHCI1 ] = &usb_ohci1_clk.common, + [CLK_USB_OHCI2 ] = &usb_ohci2_clk.common, + [CLK_USB_OHCI3 ] = &usb_ohci3_clk.common, + [CLK_DRAM ] = &dram_clk.common, + [CLK_DRAM_VE ] = &dram_ve_clk.common, + [CLK_DRAM_CSI ] = &dram_csi_clk.common, + [CLK_DRAM_DEINTERLACE ] = &dram_deinterlace_clk.common, + [CLK_DRAM_TS ] = &dram_ts_clk.common, + [CLK_DE ] = &de_clk.common, + [CLK_TCON0 ] = &tcon_clk.common, + [CLK_TVE ] = &tve_clk.common, + [CLK_DEINTERLACE ] = &deinterlace_clk.common, + [CLK_CSI_MISC ] = &csi_misc_clk.common, + [CLK_CSI_SCLK ] = &csi_sclk_clk.common, + [CLK_CSI_MCLK ] = &csi_mclk_clk.common, + [CLK_VE ] = &ve_clk.common, + [CLK_AC_DIG ] = &ac_dig_clk.common, + [CLK_AVS ] = &avs_clk.common, + [CLK_HDMI ] = &hdmi_clk.common, + [CLK_HDMI_DDC ] = &hdmi_ddc_clk.common, + [CLK_MBUS ] = &mbus_clk.common, + [CLK_GPU ] = &gpu_clk.common, +}; + +static struct ccu_reset_map sun8i_h3_ccu_resets[] = { + [RST_USB_PHY0 ] = {0x0cc ,BIT (0 ) }, + [RST_USB_PHY1 ] = {0x0cc ,BIT (1 ) }, + [RST_USB_PHY2 ] = {0x0cc ,BIT (2 ) }, + [RST_USB_PHY3 ] = {0x0cc ,BIT (3 ) }, + + [RST_MBUS ] = {0x0fc ,BIT (31 ) }, + + [RST_BUS_CE ] = {0x2c0 ,BIT (5 ) }, + [RST_BUS_DMA ] = {0x2c0 ,BIT (6 ) }, + [RST_BUS_MMC0 ] = {0x2c0 ,BIT (8 ) }, + [RST_BUS_MMC1 ] = {0x2c0 ,BIT (9 ) }, + [RST_BUS_MMC2 ] = {0x2c0 ,BIT (10 ) }, + [RST_BUS_NAND ] = {0x2c0 ,BIT (13 ) }, + [RST_BUS_DRAM ] = {0x2c0 ,BIT (14 ) }, + [RST_BUS_EMAC ] = {0x2c0 ,BIT (17 ) }, + [RST_BUS_TS ] = {0x2c0 ,BIT (18 ) }, + [RST_BUS_HSTIMER ] = {0x2c0 ,BIT (19 ) }, + [RST_BUS_SPI0 ] = {0x2c0 ,BIT (20 ) }, + [RST_BUS_SPI1 ] = {0x2c0 ,BIT (21 ) }, + [RST_BUS_OTG ] = {0x2c0 ,BIT (23 ) }, + [RST_BUS_EHCI0 ] = {0x2c0 ,BIT (24 ) }, + [RST_BUS_EHCI1 ] = {0x2c0 ,BIT (25 ) }, + [RST_BUS_EHCI2 ] = {0x2c0 ,BIT (26 ) }, + [RST_BUS_EHCI3 ] = {0x2c0 ,BIT (27 ) }, + [RST_BUS_OHCI0 ] = {0x2c0 ,BIT (28 ) }, + [RST_BUS_OHCI1 ] = {0x2c0 ,BIT (29 ) }, + [RST_BUS_OHCI2 ] = {0x2c0 ,BIT (30 ) }, + [RST_BUS_OHCI3 ] = {0x2c0 ,BIT (31 ) }, + + [RST_BUS_VE ] = {0x2c4 ,BIT (0 ) }, + [RST_BUS_TCON0 ] = {0x2c4 ,BIT (3 ) }, + [RST_BUS_TCON1 ] = {0x2c4 ,BIT (4 ) }, + [RST_BUS_DEINTERLACE ] = {0x2c4 ,BIT (5 ) }, + [RST_BUS_CSI ] = {0x2c4 ,BIT (8 ) }, + [RST_BUS_TVE ] = {0x2c4 ,BIT (9 ) }, + [RST_BUS_HDMI0 ] = {0x2c4 ,BIT (10 ) }, + [RST_BUS_HDMI1 ] = {0x2c4 ,BIT (11 ) }, + [RST_BUS_DE ] = {0x2c4 ,BIT (12 ) }, + [RST_BUS_GPU ] = {0x2c4 ,BIT (20 ) }, + [RST_BUS_MSGBOX ] = {0x2c4 ,BIT (21 ) }, + [RST_BUS_SPINLOCK ] = {0x2c4 ,BIT (22 ) }, + [RST_BUS_DBG ] = {0x2c4 ,BIT (31 ) }, + + [RST_BUS_EPHY ] = {0x2c8 ,BIT (2 ) }, + + [RST_BUS_CODEC ] = {0x2d0 ,BIT (0 ) }, + [RST_BUS_SPDIF ] = {0x2d0 ,BIT (1 ) }, + [RST_BUS_THS ] = {0x2d0 ,BIT (8 ) }, + [RST_BUS_I2S0 ] = {0x2d0 ,BIT (12 ) }, + [RST_BUS_I2S1 ] = {0x2d0 ,BIT (13 ) }, + [RST_BUS_I2S2 ] = {0x2d0 ,BIT (14 ) }, + + [RST_BUS_I2C0 ] = {0x2d4 ,BIT (0 ) }, + [RST_BUS_I2C1 ] = {0x2d4 ,BIT (1 ) }, + [RST_BUS_I2C2 ] = {0x2d4 ,BIT (2 ) }, + [RST_BUS_UART0 ] = {0x2d4 ,BIT (16 ) }, + [RST_BUS_UART1 ] = {0x2d4 ,BIT (17 ) }, + [RST_BUS_UART2 ] = {0x2d4 ,BIT (18 ) }, + [RST_BUS_UART3 ] = {0x2d4 ,BIT (19 ) }, + [RST_BUS_SCR ] = {0x2d4 ,BIT (20 ) }, +}; + +static const struct sunxi_ccu_desc sun8i_h3_ccu_desc = { + .clks = sun8i_h3_ccu_clks, + .num_clks =ARRAY_SIZE (sun8i_h3_ccu_clks), + + .resets = sun8i_h3_ccu_resets, + .num_resets =ARRAY_SIZE (sun8i_h3_ccu_resets), +}; + +static void __init sun8i_h3_ccu_setup (struct device_node *node) +{ +sunxi_ccu_probe (node, &sun8i_h3_ccu_desc); +} +CLK_OF_DECLARE (sun8i_h3_ccu,"allwinner,sun8i-h3-ccu" , + sun8i_h3_ccu_setup);include/dt-bindings/clock/sun8i-h3.h new file +162
-0@@ -0,0 +1,162 @@ +/* +* Copyright (C) 2016 Maxime Ripard <[email protected]> +* +* This file is dual-licensed: you can use it either under the terms +* of the GPL or the X11 license, at your option. Note that this dual +* licensing only applies to this file, and not this project as a +* whole. +* +* a) This file 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 file 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. +* +* Or, alternatively, +* +* b) Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _DT_BINDINGS_CLK_SUN8I_H3_H_ +#define _DT_BINDINGS_CLK_SUN8I_H3_H_ + +#define CLK_PLL_CPUX 0 +#define CLK_PLL_AUDIO_BASE 1 +#define CLK_PLL_AUDIO 2 +#define CLK_PLL_AUDIO_2X 3 +#define CLK_PLL_AUDIO_4X 4 +#define CLK_PLL_AUDIO_8X 5 +#define CLK_PLL_VIDEO 6 +#define CLK_PLL_VE 7 +#define CLK_PLL_DDR 8 +#define CLK_PLL_PERIPH0 9 +#define CLK_PLL_PERIPH0_2X 10 +#define CLK_PLL_GPU 11 +#define CLK_PLL_PERIPH1 12 +#define CLK_PLL_DE 13 +#define CLK_CPUX 14 +#define CLK_AXI 15 +#define CLK_AHB1 16 +#define CLK_APB1 17 +#define CLK_APB2 18 +#define CLK_AHB2 19 +#define CLK_BUS_CE 20 +#define CLK_BUS_DMA 21 +#define CLK_BUS_MMC0 22 +#define CLK_BUS_MMC1 23 +#define CLK_BUS_MMC2 24 +#define CLK_BUS_NAND 25 +#define CLK_BUS_DRAM 26 +#define CLK_BUS_EMAC 27 +#define CLK_BUS_TS 28 +#define CLK_BUS_HSTIMER 29 +#define CLK_BUS_SPI0 30 +#define CLK_BUS_SPI1 31 +#define CLK_BUS_OTG 32 +#define CLK_BUS_EHCI0 33 +#define CLK_BUS_EHCI1 34 +#define CLK_BUS_EHCI2 35 +#define CLK_BUS_EHCI3 36 +#define CLK_BUS_OHCI0 37 +#define CLK_BUS_OHCI1 38 +#define CLK_BUS_OHCI2 39 +#define CLK_BUS_OHCI3 40 +#define CLK_BUS_VE 41 +#define CLK_BUS_TCON0 42 +#define CLK_BUS_TCON1 43 +#define CLK_BUS_DEINTERLACE 44 +#define CLK_BUS_CSI 45 +#define CLK_BUS_TVE 46 +#define CLK_BUS_HDMI 47 +#define CLK_BUS_DE 48 +#define CLK_BUS_GPU 49 +#define CLK_BUS_MSGBOX 50 +#define CLK_BUS_SPINLOCK 51 +#define CLK_BUS_CODEC 52 +#define CLK_BUS_SPDIF 53 +#define CLK_BUS_PIO 54 +#define CLK_BUS_THS 55 +#define CLK_BUS_I2S0 56 +#define CLK_BUS_I2S1 57 +#define CLK_BUS_I2S2 58 +#define CLK_BUS_I2C0 59 +#define CLK_BUS_I2C1 60 +#define CLK_BUS_I2C2 61 +#define CLK_BUS_UART0 62 +#define CLK_BUS_UART1 63 +#define CLK_BUS_UART2 64 +#define CLK_BUS_UART3 65 +#define CLK_BUS_SCR 66 +#define CLK_BUS_EPHY 67 +#define CLK_BUS_DBG 68 +#define CLK_THS 69 +#define CLK_NAND 70 +#define CLK_MMC0 71 +#define CLK_MMC0_SAMPLE 72 +#define CLK_MMC0_OUTPUT 73 +#define CLK_MMC1 74 +#define CLK_MMC1_SAMPLE 75 +#define CLK_MMC1_OUTPUT 76 +#define CLK_MMC2 77 +#define CLK_MMC2_SAMPLE 78 +#define CLK_MMC2_OUTPUT 79 +#define CLK_TS 80 +#define CLK_CE 81 +#define CLK_SPI0 82 +#define CLK_SPI1 83 +#define CLK_I2S0 84 +#define CLK_I2S1 85 +#define CLK_I2S2 86 +#define CLK_SPDIF 87 +#define CLK_USB_PHY0 88 +#define CLK_USB_PHY1 89 +#define CLK_USB_PHY2 90 +#define CLK_USB_PHY3 91 +#define CLK_USB_OHCI0 92 +#define CLK_USB_OHCI1 93 +#define CLK_USB_OHCI2 94 +#define CLK_USB_OHCI3 95 +#define CLK_DRAM 96 +#define CLK_DRAM_VE 97 +#define CLK_DRAM_CSI 98 +#define CLK_DRAM_DEINTERLACE 99 +#define CLK_DRAM_TS 100 +#define CLK_DE 101 +#define CLK_TCON0 102 +#define CLK_TVE 103 +#define CLK_DEINTERLACE 104 +#define CLK_CSI_MISC 105 +#define CLK_CSI_SCLK 106 +#define CLK_CSI_MCLK 107 +#define CLK_VE 108 +#define CLK_AC_DIG 109 +#define CLK_AVS 110 +#define CLK_HDMI 111 +#define CLK_HDMI_DDC 112 +#define CLK_MBUS 113 +#define CLK_GPU 114 + +#endif /* _DT_BINDINGS_CLK_SUN8I_H3_H_ */ include/dt-bindings/reset/sun8i-h3.h new file +103
-1@@ -0,0 +1,103 @@ +/* +* Copyright (C) 2016 Maxime Ripard <[email protected]> +* +* This file is dual-licensed: you can use it either under the terms +* of the GPL or the X11 license, at your option. Note that this dual +* licensing only applies to this file, and not this project as a +* whole. +* +* a) This file 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 file 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. +* +* Or, alternatively, +* +* b) Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _DT_BINDINGS_RST_SUN8I_H3_H_ +#define _DT_BINDINGS_RST_SUN8I_H3_H_ + +#define RST_USB_PHY0 0 +#define RST_USB_PHY1 1 +#define RST_USB_PHY2 2 +#define RST_USB_PHY3 3 + +#define RST_MBUS 4 + +#define RST_BUS_CE 5 +#define RST_BUS_DMA 6 +#define RST_BUS_MMC0 7 +#define RST_BUS_MMC1 8 +#define RST_BUS_MMC2 9 +#define RST_BUS_NAND 10 +#define RST_BUS_DRAM 11 +#define RST_BUS_EMAC 12 +#define RST_BUS_TS 13 +#define RST_BUS_HSTIMER 14 +#define RST_BUS_SPI0 15 +#define RST_BUS_SPI1 16 +#define RST_BUS_OTG 17 +#define RST_BUS_EHCI0 18 +#define RST_BUS_EHCI1 19 +#define RST_BUS_EHCI2 20 +#define RST_BUS_EHCI3 21 +#define RST_BUS_OHCI0 22 +#define RST_BUS_OHCI1 23 +#define RST_BUS_OHCI2 24 +#define RST_BUS_OHCI3 25 +#define RST_BUS_VE 26 +#define RST_BUS_TCON0 27 +#define RST_BUS_TCON1 28 +#define RST_BUS_DEINTERLACE 29 +#define RST_BUS_CSI 30 +#define RST_BUS_TVE 31 +#define RST_BUS_HDMI0 32 +#define RST_BUS_HDMI1 33 +#define RST_BUS_DE 34 +#define RST_BUS_GPU 35 +#define RST_BUS_MSGBOX 36 +#define RST_BUS_SPINLOCK 37 +#define RST_BUS_DBG 38 +#define RST_BUS_EPHY 39 +#define RST_BUS_CODEC 40 +#define RST_BUS_SPDIF 41 +#define RST_BUS_THS 42 +#define RST_BUS_I2S0 43 +#define RST_BUS_I2S1 44 +#define RST_BUS_I2S2 45 +#define RST_BUS_I2C0 46 +#define RST_BUS_I2C1 47 +#define RST_BUS_I2C2 48 +#define RST_BUS_UART0 49 +#define RST_BUS_UART1 50 +#define RST_BUS_UART2 51 +#define RST_BUS_UART3 52 +#define RST_BUS_SCR 53 + +#endif /* _DT_BINDINGS_RST_SUN8I_H3_H_ */ --Quoted 2 lines
2.8.2
The rest looks good. Sorry it took so long.
Quoted 5 lines
About the mux widths, I prefer to have the full width, even if only the first few values are valid. It would prevent someone playing with the registers (or bad code) and the values sticking, before the kernel loads. Then the kernel won't think that it set a valid parent, but the high bit was not cleared, and whatever peripheral ended up not working.
Good point. I'll change it.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160601/b0c99760/attachment-0001.sig>
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
Hi,
Quoted 91 lines · Maxime Ripard
Hi Chen-Yu,
Quoted 67 lines · Chen-Yu Tsai
Quoted 65 lines · Maxime Ripard
Add the list of clocks and resets found in the H3 CCU.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.odrivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +36
-0@@ -0,0 +1,757 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/clk-provider.h> + +#include <dt-bindings/clock/sun8i-h3.h> +#include <dt-bindings/reset/sun8i-h3.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div_table.h" +#include "ccu_factor.h" +#include "ccu_fixed_factor.h" +#include "ccu_gate.h" +#include "ccu_m.h" +#include "ccu_mp.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" +#include "ccu_p.h" +#include "ccu_phase.h" + +static struct ccu_nkmp pll_cpux_clk = { + .enable =BIT (31 ),Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 42
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ .lock = BIT(28), + + .m = SUNXI_CLK_FACTOR(0, 2), + .k = SUNXI_CLK_FACTOR(4, 2), + .n = SUNXI_CLK_FACTOR(8, 5), + .p = SUNXI_CLK_FACTOR(16, 2),We should find a way to specify a table for p.
A table for P? Why?
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 48
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ + .common = { + .reg = 0x000, + .features = CCU_FEATURE_GATE | CCU_FEATURE_LOCK, + .hw.init = SUNXI_HW_INIT("pll-cpux", + "osc24M",osc24M is an outside reference. Shouldn't we use put it in a "clocks" property in the DT, and use
of_clk_get_parent_name()?
Quoted 8 lines
Quoted 2 lines
osc24M can be controlled from the PRCM on other chips. I suspect the same with the H3. osc32k might also be from the PRCM.
I was discussing exactly this the other day with Mike. He has a bunch of patches to address exactly that issue. He plans on posting it and merge it by 4.8. Until then, we should rely on the hardcoded clock string like it's done there, and we should obviously add the clocks in the DT node for when we will actually use them.
OK. Let's wait and see.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +5
-0+ &ccu_nkmp_ops, + 0), + }, +}; +
[...]
Quoted 11 lines
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 121
Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +7
-0+static struct ccu_nkm pll_ddr_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .m =SUNXI_CLK_FACTOR (0 ,2 ),We need a special "update" bit (bit 20) for this clock, otherwise changes don't really take effect.
Quoted 4 lines
Yeah, I know, but I feel like it's a feature here, since Linux should never modify that clock anyway.
I can add a comment though.
Maybe we should do a read-only variant, or a feature flag?
[...]
Thanks
ChenYu
PATCH 15/16 clk: sunxi-ng: Add H3 clocks
Quoted 84 lines · Chen-Yu Tsai
Hi,
Quoted 80 lines · Maxime Ripard
Hi Chen-Yu,
Quoted 67 lines · Chen-Yu Tsai
Quoted 65 lines · Maxime Ripard
Add the list of clocks and resets found in the H3 CCU.
Signed-off-by Maxime Ripard <[email protected]>--- drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 757 +++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/sun8i-h3.h | 162 ++++++++ include/dt-bindings/reset/sun8i-h3.h | 103 +++++ 4 files changed, 1024 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-h3.c create mode 100644 include/dt-bindings/clock/sun8i-h3.h create mode 100644 include/dt-bindings/reset/sun8i-h3.hdrivers/clk/sunxi-ng/Makefile +2
-0@@ -13,3 +13,5 @@ obj-y += ccu_nkmp.o obj-y += ccu_nm.o obj-y += ccu_p.o obj-y += ccu_phase.o + +obj-y += ccu-sun8i-h3.odrivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +36
-0@@ -0,0 +1,757 @@ +/* +* Copyright (c) 2016 Maxime Ripard. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/clk-provider.h> + +#include <dt-bindings/clock/sun8i-h3.h> +#include <dt-bindings/reset/sun8i-h3.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div_table.h" +#include "ccu_factor.h" +#include "ccu_fixed_factor.h" +#include "ccu_gate.h" +#include "ccu_m.h" +#include "ccu_mp.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" +#include "ccu_p.h" +#include "ccu_phase.h" + +static struct ccu_nkmp pll_cpux_clk = { + .enable =BIT (31 ),Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 42
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ .lock = BIT(28), + + .m = SUNXI_CLK_FACTOR(0, 2), + .k = SUNXI_CLK_FACTOR(4, 2), + .n = SUNXI_CLK_FACTOR(8, 5), + .p = SUNXI_CLK_FACTOR(16, 2),We should find a way to specify a table for p.
A table for P? Why?
Missed this one. The datasheet says P = 0x3 is not valid.
ChenYu
Quoted 53 lines
Quoted 11 lines
Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 48
Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +6
-0+ + .common = { + .reg = 0x000, + .features = CCU_FEATURE_GATE | CCU_FEATURE_LOCK, + .hw.init = SUNXI_HW_INIT("pll-cpux", + "osc24M",osc24M is an outside reference. Shouldn't we use put it in a "clocks" property in the DT, and use
of_clk_get_parent_name()?Quoted 8 lines
Quoted 2 lines
osc24M can be controlled from the PRCM on other chips. I suspect the same with the H3. osc32k might also be from the PRCM.
I was discussing exactly this the other day with Mike. He has a bunch of patches to address exactly that issue. He plans on posting it and merge it by 4.8. Until then, we should rely on the hardcoded clock string like it's done there, and we should obviously add the clocks in the DT node for when we will actually use them.
OK. Let's wait and see.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +5
-0+ &ccu_nkmp_ops, + 0), + }, +}; +[...]
Quoted 11 lines
Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c line 121
Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun8i-h3.c new file +7
-0+static struct ccu_nkm pll_ddr_clk = { + .enable =BIT (31 ), + .lock =BIT (28 ), + + .n =SUNXI_CLK_FACTOR (8 ,5 ), + .k =SUNXI_CLK_FACTOR (4 ,2 ), + .m =SUNXI_CLK_FACTOR (0 ,2 ),We need a special "update" bit (bit 20) for this clock, otherwise changes don't really take effect.
Quoted 4 lines
Yeah, I know, but I feel like it's a feature here, since Linux should never modify that clock anyway.
I can add a comment though.
Maybe we should do a read-only variant, or a feature flag?
[...]
Thanks
ChenYu
PATCH 16/16 ARM: dt: sun8i: switch the H3 to the new CCU driver
In reply to Maxime RipardNow that we have a different clock representation, switch to it.
--- arch/arm/boot/dts/sun8i-h3.dtsi | 310 ++++++++-------------------------------- 1 file changed, 58 insertions(+), 252 deletions(-)
arch/arm/boot/dts/sun8i-h3.dtsi +58 -252
@@ -42,8 +42,10 @@ #include "skeleton.dtsi" +#include <dt-bindings/clock/sun8i-h3.h> #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/pinctrl/sun4i-a10.h> +#include <dt-bindings/reset/sun8i-h3.h> / { interrupt-parent = <&gic>;
@@ -104,191 +106,6 @@ clock-output-names = "osc32k"; }; - pll1: clk at 01c20000 { - #clock-cells = <0>; - compatible = "allwinner,sun8i-a23-pll1-clk"; - reg = <0x01c20000 0x4>; - clocks = <&osc24M>; - clock-output-names = "pll1"; - }; - - /* dummy clock until actually implemented */ - pll5: pll5_clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <0>; - clock-output-names = "pll5"; - }; - - pll6: clk at 01c20028 { - #clock-cells = <1>; - compatible = "allwinner,sun6i-a31-pll6-clk"; - reg = <0x01c20028 0x4>; - clocks = <&osc24M>; - clock-output-names = "pll6", "pll6x2"; - }; - - pll6d2: pll6d2_clk { - #clock-cells = <0>; - compatible = "fixed-factor-clock"; - clock-div = <2>; - clock-mult = <1>; - clocks = <&pll6 0>; - clock-output-names = "pll6d2"; - }; - - /* dummy clock until pll6 can be reused */ - pll8: pll8_clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <1>; - clock-output-names = "pll8"; - }; - - cpu: cpu_clk at 01c20050 { - #clock-cells = <0>; - compatible = "allwinner,sun4i-a10-cpu-clk"; - reg = <0x01c20050 0x4>; - clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>; - clock-output-names = "cpu"; - }; - - axi: axi_clk at 01c20050 { - #clock-cells = <0>; - compatible = "allwinner,sun4i-a10-axi-clk"; - reg = <0x01c20050 0x4>; - clocks = <&cpu>; - clock-output-names = "axi"; - }; - - ahb1: ahb1_clk at 01c20054 { - #clock-cells = <0>; - compatible = "allwinner,sun6i-a31-ahb1-clk"; - reg = <0x01c20054 0x4>; - clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>; - clock-output-names = "ahb1"; - }; - - ahb2: ahb2_clk at 01c2005c { - #clock-cells = <0>; - compatible = "allwinner,sun8i-h3-ahb2-clk"; - reg = <0x01c2005c 0x4>; - clocks = <&ahb1>, <&pll6d2>; - clock-output-names = "ahb2"; - }; - - apb1: apb1_clk at 01c20054 { - #clock-cells = <0>; - compatible = "allwinner,sun4i-a10-apb0-clk"; - reg = <0x01c20054 0x4>; - clocks = <&ahb1>; - clock-output-names = "apb1"; - }; - - apb2: apb2_clk at 01c20058 { - #clock-cells = <0>; - compatible = "allwinner,sun4i-a10-apb1-clk"; - reg = <0x01c20058 0x4>; - clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>; - clock-output-names = "apb2"; - }; - - bus_gates: clk at 01c20060 { - #clock-cells = <1>; - compatible = "allwinner,sun8i-h3-bus-gates-clk"; - reg = <0x01c20060 0x14>; - clocks = <&ahb1>, <&ahb2>, <&apb1>, <&apb2>; - clock-names = "ahb1", "ahb2", "apb1", "apb2"; - clock-indices = <5>, <6>, <8>, - <9>, <10>, <13>, - <14>, <17>, <18>, - <19>, <20>, - <21>, <23>, - <24>, <25>, - <26>, <27>, - <28>, <29>, - <30>, <31>, <32>, - <35>, <36>, <37>, - <40>, <41>, <43>, - <44>, <52>, <53>, - <54>, <64>, - <65>, <69>, <72>, - <76>, <77>, <78>, - <96>, <97>, <98>, - <112>, <113>, - <114>, <115>, - <116>, <128>, <135>; - clock-output-names = "bus_ce", "bus_dma", "bus_mmc0", - "bus_mmc1", "bus_mmc2", "bus_nand", - "bus_sdram", "bus_gmac", "bus_ts", - "bus_hstimer", "bus_spi0", - "bus_spi1", "bus_otg", - "bus_otg_ehci0", "bus_ehci1", - "bus_ehci2", "bus_ehci3", - "bus_otg_ohci0", "bus_ohci1", - "bus_ohci2", "bus_ohci3", "bus_ve", - "bus_lcd0", "bus_lcd1", "bus_deint", - "bus_csi", "bus_tve", "bus_hdmi", - "bus_de", "bus_gpu", "bus_msgbox", - "bus_spinlock", "bus_codec", - "bus_spdif", "bus_pio", "bus_ths", - "bus_i2s0", "bus_i2s1", "bus_i2s2", - "bus_i2c0", "bus_i2c1", "bus_i2c2", - "bus_uart0", "bus_uart1", - "bus_uart2", "bus_uart3", - "bus_scr", "bus_ephy", "bus_dbg"; - }; - - mmc0_clk: clk at 01c20088 { - #clock-cells = <1>; - compatible = "allwinner,sun4i-a10-mmc-clk"; - reg = <0x01c20088 0x4>; - clocks = <&osc24M>, <&pll6 0>, <&pll8>; - clock-output-names = "mmc0", - "mmc0_output", - "mmc0_sample"; - }; - - mmc1_clk: clk at 01c2008c { - #clock-cells = <1>; - compatible = "allwinner,sun4i-a10-mmc-clk"; - reg = <0x01c2008c 0x4>; - clocks = <&osc24M>, <&pll6 0>, <&pll8>; - clock-output-names = "mmc1", - "mmc1_output", - "mmc1_sample"; - }; - - mmc2_clk: clk at 01c20090 { - #clock-cells = <1>; - compatible = "allwinner,sun4i-a10-mmc-clk"; - reg = <0x01c20090 0x4>; - clocks = <&osc24M>, <&pll6 0>, <&pll8>; - clock-output-names = "mmc2", - "mmc2_output", - "mmc2_sample"; - }; - - usb_clk: clk at 01c200cc { - #clock-cells = <1>; - #reset-cells = <1>; - compatible = "allwinner,sun8i-h3-usb-clk"; - reg = <0x01c200cc 0x4>; - clocks = <&osc24M>; - clock-output-names = "usb_phy0", "usb_phy1", - "usb_phy2", "usb_phy3", - "usb_ohci0", "usb_ohci1", - "usb_ohci2", "usb_ohci3"; - }; - - mbus_clk: clk at 01c2015c { - #clock-cells = <0>; - compatible = "allwinner,sun8i-a23-mbus-clk"; - reg = <0x01c2015c 0x4>; - clocks = <&osc24M>, <&pll6 1>, <&pll5>; - clock-output-names = "mbus"; - }; - apb0: apb0_clk { compatible = "fixed-factor-clock"; #clock-cells = <0>;
@@ -327,23 +144,23 @@ compatible = "allwinner,sun8i-h3-dma"; reg = <0x01c02000 0x1000>; interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&bus_gates 6>; - resets = <&ahb_rst 6>; + clocks = <&ccu CLK_BUS_DMA>; + resets = <&ccu RST_BUS_DMA>; #dma-cells = <1>; }; mmc0: mmc at 01c0f000 { compatible = "allwinner,sun5i-a13-mmc"; reg = <0x01c0f000 0x1000>; - clocks = <&bus_gates 8>, - <&mmc0_clk 0>, - <&mmc0_clk 1>, - <&mmc0_clk 2>; + clocks = <&ccu CLK_BUS_MMC0>, + <&ccu CLK_MMC0>, + <&ccu CLK_MMC0_OUTPUT>, + <&ccu CLK_MMC0_SAMPLE>; clock-names = "ahb", "mmc", "output", "sample"; - resets = <&ahb_rst 8>; + resets = <&ccu RST_BUS_MMC0>; reset-names = "ahb"; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; status = "disabled";
@@ -354,15 +171,15 @@ mmc1: mmc at 01c10000 { compatible = "allwinner,sun5i-a13-mmc"; reg = <0x01c10000 0x1000>; - clocks = <&bus_gates 9>, - <&mmc1_clk 0>, - <&mmc1_clk 1>, - <&mmc1_clk 2>; + clocks = <&ccu CLK_BUS_MMC1>, + <&ccu CLK_MMC1>, + <&ccu CLK_MMC1_OUTPUT>, + <&ccu CLK_MMC1_SAMPLE>; clock-names = "ahb", "mmc", "output", "sample"; - resets = <&ahb_rst 9>; + resets = <&ccu RST_BUS_MMC1>; reset-names = "ahb"; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; status = "disabled";
@@ -373,15 +190,15 @@ mmc2: mmc at 01c11000 { compatible = "allwinner,sun5i-a13-mmc"; reg = <0x01c11000 0x1000>; - clocks = <&bus_gates 10>, - <&mmc2_clk 0>, - <&mmc2_clk 1>, - <&mmc2_clk 2>; + clocks = <&ccu CLK_BUS_MMC2>, + <&ccu CLK_MMC2>, + <&ccu CLK_MMC2_OUTPUT>, + <&ccu CLK_MMC2_SAMPLE>; clock-names = "ahb", "mmc", "output", "sample"; - resets = <&ahb_rst 10>; + resets = <&ccu RST_BUS_MMC2>; reset-names = "ahb"; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; status = "disabled";
@@ -401,18 +218,18 @@ "pmu1", "pmu2", "pmu3"; - clocks = <&usb_clk 8>, - <&usb_clk 9>, - <&usb_clk 10>, - <&usb_clk 11>; + clocks = <&ccu CLK_USB_PHY0>, + <&ccu CLK_USB_PHY1>, + <&ccu CLK_USB_PHY2>, + <&ccu CLK_USB_PHY3>; clock-names = "usb0_phy", "usb1_phy", "usb2_phy", "usb3_phy"; - resets = <&usb_clk 0>, - <&usb_clk 1>, - <&usb_clk 2>, - <&usb_clk 3>; + resets = <&ccu RST_USB_PHY0>, + <&ccu RST_USB_PHY1>, + <&ccu RST_USB_PHY2>, + <&ccu RST_USB_PHY3>; reset-names = "usb0_reset", "usb1_reset", "usb2_reset",
@@ -425,8 +242,8 @@ compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; reg = <0x01c1b000 0x100>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&bus_gates 25>, <&bus_gates 29>; - resets = <&ahb_rst 25>, <&ahb_rst 29>; + clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>; + resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>; phys = <&usbphy 1>; phy-names = "usb"; status = "disabled";
@@ -436,9 +253,9 @@ compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; reg = <0x01c1b400 0x100>; interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&bus_gates 29>, <&bus_gates 25>, - <&usb_clk 17>; - resets = <&ahb_rst 29>, <&ahb_rst 25>; + clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>, + <&ccu CLK_USB_OHCI1>; + resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>; phys = <&usbphy 1>; phy-names = "usb"; status = "disabled";
@@ -448,8 +265,8 @@ compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; reg = <0x01c1c000 0x100>; interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&bus_gates 26>, <&bus_gates 30>; - resets = <&ahb_rst 26>, <&ahb_rst 30>; + clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>; + resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>; phys = <&usbphy 2>; phy-names = "usb"; status = "disabled";
@@ -459,9 +276,9 @@ compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; reg = <0x01c1c400 0x100>; interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&bus_gates 30>, <&bus_gates 26>, - <&usb_clk 18>; - resets = <&ahb_rst 30>, <&ahb_rst 26>; + clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>, + <&ccu CLK_USB_OHCI2>; + resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>; phys = <&usbphy 2>; phy-names = "usb"; status = "disabled";
@@ -471,8 +288,8 @@ compatible = "allwinner,sun8i-h3-ehci", "generic-ehci"; reg = <0x01c1d000 0x100>; interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&bus_gates 27>, <&bus_gates 31>; - resets = <&ahb_rst 27>, <&ahb_rst 31>; + clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>; + resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>; phys = <&usbphy 3>; phy-names = "usb"; status = "disabled";
@@ -482,20 +299,27 @@ compatible = "allwinner,sun8i-h3-ohci", "generic-ohci"; reg = <0x01c1d400 0x100>; interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&bus_gates 31>, <&bus_gates 27>, - <&usb_clk 19>; - resets = <&ahb_rst 31>, <&ahb_rst 27>; + clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>, + <&ccu CLK_USB_OHCI3>; + resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>; phys = <&usbphy 3>; phy-names = "usb"; status = "disabled"; }; + ccu: clock at 01c20000 { + compatible = "allwinner,sun8i-h3-ccu"; + reg = <0x01c20000 0x400>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + pio: pinctrl at 01c20800 { compatible = "allwinner,sun8i-h3-pinctrl"; reg = <0x01c20800 0x400>; interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&bus_gates 69>; + clocks = <&ccu CLK_BUS_PIO>; gpio-controller; #gpio-cells = <3>; interrupt-controller;
@@ -542,24 +366,6 @@ }; }; - ahb_rst: reset at 01c202c0 { - #reset-cells = <1>; - compatible = "allwinner,sun6i-a31-ahb1-reset"; - reg = <0x01c202c0 0xc>; - }; - - apb1_rst: reset at 01c202d0 { - #reset-cells = <1>; - compatible = "allwinner,sun6i-a31-clock-reset"; - reg = <0x01c202d0 0x4>; - }; - - apb2_rst: reset at 01c202d8 { - #reset-cells = <1>; - compatible = "allwinner,sun6i-a31-clock-reset"; - reg = <0x01c202d8 0x4>; - }; - timer at 01c20c00 { compatible = "allwinner,sun4i-a10-timer"; reg = <0x01c20c00 0xa0>;
@@ -580,8 +386,8 @@ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; - clocks = <&bus_gates 112>; - resets = <&apb2_rst 16>; + clocks = <&ccu CLK_BUS_UART0>; + resets = <&ccu RST_BUS_UART0>; dmas = <&dma 6>, <&dma 6>; dma-names = "rx", "tx"; status = "disabled";
@@ -593,8 +399,8 @@ interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; - clocks = <&bus_gates 113>; - resets = <&apb2_rst 17>; + clocks = <&ccu CLK_BUS_UART1>; + resets = <&ccu RST_BUS_UART1>; dmas = <&dma 7>, <&dma 7>; dma-names = "rx", "tx"; status = "disabled";
@@ -606,8 +412,8 @@ interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; - clocks = <&bus_gates 114>; - resets = <&apb2_rst 18>; + clocks = <&ccu CLK_BUS_UART2>; + resets = <&ccu RST_BUS_UART2>; dmas = <&dma 8>, <&dma 8>; dma-names = "rx", "tx"; status = "disabled";
@@ -619,8 +425,8 @@ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; - clocks = <&bus_gates 115>; - resets = <&apb2_rst 19>; + clocks = <&ccu CLK_BUS_UART3>; + resets = <&ccu RST_BUS_UART3>; dmas = <&dma 9>, <&dma 9>; dma-names = "rx", "tx"; status = "disabled";
Signature · 1 line
2.8.2