sanitizing crazy clock data files
Subsystems (7)
Sascha Hauer
maintainerThe following tries to solve the chicken-egg problem we have with the common struct clk support and its users. It switches i.MX51 clock support to the new API. Included are some generic clock helpers for dividers and multiplexer. I first made them i.MX specific but after looking round in the other architectures I found them useful enough for other architectures aswell. If you could use the helpers but missing some bits please speak up.
There is one thing missing in Jeremys series and this series does not fix it. Once I add the new (un)prepare calls to drivers they won't compile without common struct clk support anymore. Maybe a
#ifndef CONFIG_USE_COMMON_STRUCT_CLK
#define clk_prepare()
#define clk_unprepare()
#endif
will do.
Sascha
The following changes since commit de4a95bc9025f0566ade64dc35e5e3014e640b85:
clk: Generic support for fixed-rate clocks (2011-04-15 20:39:48 +0200)
are available in the git repository at:
git://git.pengutronix.de/git/imx/linux-2.6.git clk-common
Sascha Hauer (8):
clk: Make NULL a valid clock again
clk: implement parent pass through functions
clk: Add support for simple dividers
clk: Add support for a generic clock multiplexer ARM i.MX: Support for clock building blocks. ARM i.MX: Add generic support for pllv2 ARM i.MX51/53: reimplement clock support ARM i.MX51/53: remove old clock support
arch/arm/mach-mx5/Kconfig | 6 + arch/arm/mach-mx5/Makefile | 2 +- arch/arm/mach-mx5/clock-imx51-imx53.c | 420 ++++++++ arch/arm/mach-mx5/clock-mx51-mx53.c | 1579 ------------------------------- arch/arm/mach-mx5/crm_regs.h | 249 +----- arch/arm/plat-mxc/Makefile | 1 + arch/arm/plat-mxc/clock.c | 182 ++++ arch/arm/plat-mxc/include/mach/clkdev.h | 2 + arch/arm/plat-mxc/include/mach/clock.h | 153 +++- arch/arm/plat-mxc/pllv2.c | 228 +++++ drivers/clk/Kconfig | 6 + drivers/clk/Makefile | 2 + drivers/clk/clk-divider.c | 132 +++ drivers/clk/clk-mux.c | 92 ++ drivers/clk/clk.c | 104 ++ include/linux/clk.h | 68 ++ 16 files changed, 1395 insertions(+), 1831 deletions(-) create mode 100644 arch/arm/mach-mx5/clock-imx51-imx53.c delete mode 100644 arch/arm/mach-mx5/clock-mx51-mx53.c create mode 100644 arch/arm/plat-mxc/pllv2.c create mode 100644 drivers/clk/clk-divider.c create mode 100644 drivers/clk/clk-mux.c
Sascha Hauer
maintainerPATCH 1/10 Add a common struct clk
From: Jeremy Kerr <[email protected]>
We currently have ~21 definitions of struct clk in the ARM architecture, each defined on a per-platform basis. This makes it difficult to define platform- (or architecture-) independent clock sources without making assumptions about struct clk, and impossible to compile two platforms with different struct clks into a single image.
This change is an effort to unify struct clk where possible, by defining a common struct clk, containing a set of clock operations. Different clock implementations can set their own operations, and have a standard interface for generic code. The callback interface is exposed to the kernel proper, while the clock implementations only need to be seen by the platform internals.
This allows us to share clock code among platforms, and makes it possible to dynamically create clock devices in platform-independent code.
Platforms can enable the generic struct clock through CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure consists of a common struct clk:
struct clk {
const struct clk_ops *ops;
unsigned int enable_count;
unsigned int prepare_count;
spinlock_t enable_lock;
struct mutex prepare_lock;
};And a set of clock operations (defined per type of clock):
struct clk_ops {
int (*enable)(struct clk *);
void (*disable)(struct clk *);
unsigned long (*get_rate)(struct clk *);
[...]
};To define a hardware-specific clock, machine code can "subclass" the struct clock into a new struct (adding any device-specific data), and provide a set of operations:
struct clk_foo {
struct clk clk;
void __iomem *some_register;
};struct clk_ops clk_foo_ops = {
.get_rate = clk_foo_get_rate,
};
The common clock definitions are based on a development patch from Ben Herrenschmidt <[email protected]>.
--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk.c | 132 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/clkdev.c | 7 ++ include/linux/clk.h | 164 +++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 298 insertions(+), 9 deletions(-) create mode 100644 drivers/clk/clk.c
drivers/clk/Kconfig +3 -0
@@ -2,3 +2,6 @@ config CLKDEV_LOOKUP bool select HAVE_CLK + +config USE_COMMON_STRUCT_CLK + bool
drivers/clk/Makefile +1 -0
@@ -1,2 +1,3 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
drivers/clk/clk.c new file +132 -0
132 lines not on this page · raw message
drivers/clk/clkdev.c +7 -0
@@ -23,6 +23,13 @@static LIST_HEAD (clocks);static DEFINE_MUTEX (clocks_mutex); +/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported +* through other headers; we don't want them used anywhere but here. */ +#ifdef CONFIG_USE_COMMON_STRUCT_CLK +extern int __clk_get (struct clk *clk); +extern void __clk_put (struct clk *clk); +#endif +/* * Find the correct struct clk for the device and connection ID. * We do slightly fuzzy matching here:
include/linux/clk.h +155 -9
197 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 1/10 Add a common struct clk
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.
These callbacks are completely pointless. There are only two non empty implementations in tree:
One does a try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go to clk->prepare().
Thanks,
tglx
PATCH 1/10 Add a common struct clk
Hi Thomas,
Quoted 8 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.
Quoted 6 lines
These callbacks are completely pointless. There are only two non empty implementations in tree:
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().
You forget mach-u300 __clk_get. It updates some registers.
The ops get/put let arch clock driver have a chance to do special things at the time when a user begins to use the clock.
Thanks
Richard
Quoted 9 lines
Thanks,
tglx
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH 1/10 Add a common struct clk
Quoted 14 lines · Richard Zhao
Hi Thomas,
Quoted 11 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.These callbacks are completely pointless. There are only two non empty implementations in tree:
Quoted 6 lines
Quoted 3 lines
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().You forget mach-u300
__clk_get. It updates some registers.
The ops get/put let arch clock driver have a chance to do special things at the time when a user begins to use the clock.
No I did not forget. It's exactly the code which wants to go into clk->prepare. Which you have to call _before_ doing anything with the clock, so there is no need for an extra callback.
Thanks,
tglx
PATCH 1/10 Add a common struct clk
Quoted 18 lines · Thomas Gleixner
Quoted 17 lines · Richard Zhao
Hi Thomas,
Quoted 14 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.These callbacks are completely pointless. There are only two non empty implementations in tree:
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().
Quoted 7 lines
Quoted 3 lines
You forget mach-u300
__clk_get. It updates some registers.
The ops get/put let arch clock driver have a chance to do special things at the time when a user begins to use the clock.No I did not forget. It's exactly the code which wants to go into
clk->prepare. Which you have to call _before_ doing anything with the clock, so there is no need for an extra callback.
No. clk_prepare only have to be called before clk_enable, but not have to for other operations, set_rate/set_parent etc.
Thanks
Richard
Quoted 4 lines
Thanks,
tglx
PATCH 1/10 Add a common struct clk
Quoted 23 lines · Richard Zhao
Quoted 22 lines · Thomas Gleixner
Quoted 20 lines · Richard Zhao
Hi Thomas,
Quoted 8 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.Quoted 6 lines
These callbacks are completely pointless. There are only two non empty implementations in tree:
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().You forget mach-u300
__clk_get. It updates some registers.
The ops get/put let arch clock driver have a chance to do special things at the time when a user begins to use the clock.
Quoted 5 lines
Quoted 3 lines
No I did not forget. It's exactly the code which wants to go into
clk->prepare. Which you have to call _before_ doing anything with the clock, so there is no need for an extra callback.No.
clk_prepareonly have to be called beforeclk_enable, but not have to for other operations, set_rate/set_parent etc.
And why do you need those registers set before you actually prepare/enable the clock? Just to set the rate register? You can store that information and set it on prepare. Before prepare/enable the value of the rate register is totally irrelevant.
The point of anything whats named get and put in the kernel is to obtain or drop a reference to an object.
Putting arbitrary initialization into such functions is a really bad hack.
And looking at that u300 code, it's borken:
user1: clk_get("MCLK");
clk_set_rate(.....);
user2: clk_get("MCLK");The second clk_get() call will overwrite what ?
The fact that you decided to put that into the absolutely wrong function is not an argument for keeping those callbacks.
The only real usecase for __clk_get() is the try_module_get()/module_put() code which will become part of the generic code. It does exaclty what get and put are meant for: dealing with refcounts.
Thanks,
tglx
PATCH 1/10 Add a common struct clk
Quoted 27 lines · Thomas Gleixner
Quoted 26 lines · Richard Zhao
Quoted 25 lines · Thomas Gleixner
Quoted 14 lines · Richard Zhao
Hi Thomas,
Quoted 11 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.These callbacks are completely pointless. There are only two non empty implementations in tree:
Quoted 6 lines
Quoted 3 lines
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().You forget mach-u300
__clk_get. It updates some registers.
The ops get/put let arch clock driver have a chance to do special things at the time when a user begins to use the clock.No I did not forget. It's exactly the code which wants to go into
clk->prepare. Which you have to call _before_ doing anything with the clock, so there is no need for an extra callback.
Quoted 7 lines
Quoted 2 lines
No.
clk_prepareonly have to be called beforeclk_enable, but not have to for other operations, set_rate/set_parent etc.And why do you need those registers set before you actually prepare/enable the clock? Just to set the rate register? You can store that information and set it on prepare. Before prepare/enable the value of the rate register is totally irrelevant.
Generally, the divider and enable registers can be set seperately.
Quoted 14 lines
The point of anything whats named get and put in the kernel is to obtain or drop a reference to an object.
Putting arbitrary initialization into such functions is a really bad hack.
And looking at that u300 code, it's borken:
user1: clk_get("MCLK"); clk_set_rate(.....); user2: clk_get("MCLK");
Quoted 4 lines
The second
clk_get()call will overwrite what ?The fact that you decided to put that into the absolutely wrong function is not an argument for keeping those callbacks.
Better ask u300 maintainer whether the _clk_get/put stuff may be moved to other functions. If yes, I agree to remove get/put from ops.
Quoted 5 lines
The only real usecase for
__clk_get()is the try_module_get()/module_put() code which will become part of the generic code. It does exaclty what get and put are meant for: dealing with refcounts.
It might be usefull for loadable clock module. But do we already have such use case? Even clock module is loadable, it'll never unloaded unless clock hw module support hot plug.
Thanks
Richard
Quoted 4 lines
Thanks,
tglx
PATCH 1/10 Add a common struct clk
In reply to Thomas Gleixner2011/4/23 Thomas Gleixner <[email protected]>:
Quoted 29 lines · Richard Zhao
Quoted 10 lines · Thomas Gleixner
Quoted 9 lines · Richard Zhao
Quoted 7 lines
Quoted 4 lines
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().You forget mach-u300
__clk_get. It updates some registers.
The ops get/put let arch clock driver have a chance to do special things at the time when a user begins to use the clock.Quoted 6 lines
Quoted 3 lines
No I did not forget. It's exactly the code which wants to go into
clk->prepare. Which you have to call _before_ doing anything with the clock, so there is no need for an extra callback.No.
clk_prepareonly have to be called beforeclk_enable, but not have to for other operations, set_rate/set_parent etc.And why do you need those registers set before you actually prepare/enable the clock? Just to set the rate register? You can store that information and set it on prepare. Before prepare/enable the value of the rate register is totally irrelevant.
The point of anything whats named get and put in the kernel is to obtain or drop a reference to an object.
Putting arbitrary initialization into such functions is a really bad hack.
Quoted 8 lines
And looking at that u300 code, it's borken:
? ?user1:
clk_get("MCLK");
? ? ? ? ?clk_set_rate(.....);? ?user2:
clk_get("MCLK");The second
clk_get()call will overwrite what ?
Heh yeah that is the case, and this code can just as well live in the ->prepare() function.
The clock that goes to "MCLK" and "MSPRO" is utilizing a common clock divider, which sounds backwards, but in practice this is because it's and MMC or Memory Stick Pro block clock, and you cannot pinmux in both in the ASIC, they are connected to the same pins and either function need its own support electronics. So naturally only one of them is ever active at the same time.
This should be *properly* reflected by creating the pin/padmux framework and have the clock prepare() call hook back into that, so that when you try to activate say "mclk" you need to mux in these pins and if the mspro is muxed in at that time you return -ENODEV and the clock code bails out.
We should just move it to prepare() and I'll fix it up if need be.
Linus Walleij
PATCH 1/10 Add a common struct clk
Quoted 49 lines · Linus Walleij
2011/4/23 Thomas Gleixner <[email protected]>:
Quoted 29 lines · Richard Zhao
Quoted 10 lines · Thomas Gleixner
Quoted 9 lines · Richard Zhao
Quoted 7 lines
Quoted 4 lines
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().You forget mach-u300
__clk_get. It updates some registers.
The ops get/put let arch clock driver have a chance to do special things at the time when a user begins to use the clock.Quoted 6 lines
Quoted 3 lines
No I did not forget. It's exactly the code which wants to go into
clk->prepare. Which you have to call _before_ doing anything with the clock, so there is no need for an extra callback.No.
clk_prepareonly have to be called beforeclk_enable, but not have to for other operations, set_rate/set_parent etc.And why do you need those registers set before you actually prepare/enable the clock? Just to set the rate register? You can store that information and set it on prepare. Before prepare/enable the value of the rate register is totally irrelevant.
The point of anything whats named get and put in the kernel is to obtain or drop a reference to an object.
Putting arbitrary initialization into such functions is a really bad hack.
Quoted 8 lines
And looking at that u300 code, it's borken:
? ?user1:
clk_get("MCLK");
? ? ? ? ?clk_set_rate(.....);? ?user2:
clk_get("MCLK");The second
clk_get()call will overwrite what ?Heh yeah that is the case, and this code can just as well live in the ->prepare() function.
The clock that goes to "MCLK" and "MSPRO" is utilizing a common clock divider, which sounds backwards, but in practice this is because it's and MMC or Memory Stick Pro block clock, and you cannot pinmux in both in the ASIC, they are connected to the same pins and either function need its own support electronics. So naturally only one of them is ever active at the same time.
Quoted 7 lines
This should be *properly* reflected by creating the pin/padmux framework and have the clock
prepare()call hook back into that, so that when you try to activate say "mclk" you need to mux in these pins and if the mspro is muxed in at that time you return-ENODEVand the clock code bails out.We should just move it to
prepare()and I'll fix it up if need be.
Great, so we don't need __clk_get/put. The only purpose of clk_get is to return pointer of clk.
Thanks
Richard
Quoted 2 lines
Linus Walleij
PATCH 1/10 Add a common struct clk
In reply to Thomas GleixnerQuoted 8 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr<[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.
Quoted 6 lines
These callbacks are completely pointless. There are only two non empty implementations in tree:
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().
Aren't you kinda contradicting yourself? In the other thread you say that when we implement a generic framework, you will have to implement more than what a specific arch would need. This seems to be exactly one of those cases. What's wrong with it?
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 1/10 Add a common struct clk
Quoted 12 lines · Saravana Kannan
Quoted 11 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr<[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.These callbacks are completely pointless. There are only two non empty implementations in tree:
Quoted 8 lines
Quoted 3 lines
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().Aren't you kinda contradicting yourself? In the other thread you say that when we implement a generic framework, you will have to implement more than what a specific arch would need. This seems to be exactly one of those cases. What's wrong with it?
Errm, that's why the try_module_get() goes into generic code. Simply because we can have loadable clock modules and we want proper module refcounts on them.
The clock enabling magic in mach-u300/ is setting up some registers, which can be done in the clk->prepare() callback as well. So there is no point for having an extra step and an extra indirection.
So how am I contradicting myself? By moving useful stuff to the core and moving hardware specific code to a different callback where it actually belongs?
And yes a framework will always have more functionality than most users need, but that's not an excuse to implement arbitrary and pointless crap.
Thanks,
tglx
PATCH 1/10 Add a common struct clk
In reply to Thomas GleixnerQuoted 8 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.
Quoted 6 lines
These callbacks are completely pointless. There are only two non empty implementations in tree:
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().
I disagree. Most clocks don't live in a module - there's only one platform which does at present. To force every clock to have an owner field is rediculous. We already know that the OMAP tree represents a significant amount of data, and for every additional unnecessary word, it gobbles up another 4K of data space.
If we go down the route of separating clock stuff into bite-size pieces, OMAP is going to end up with yet more struct clks, which is going to add to the bloat even more.
PATCH 1/10 Add a common struct clk
Quoted 12 lines · Russell King - ARM Linux
Quoted 11 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.These callbacks are completely pointless. There are only two non empty implementations in tree:
Quoted 7 lines
Quoted 3 lines
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().I disagree. Most clocks don't live in a module - there's only one platform which does at present. To force every clock to have an owner field is rediculous. We already know that the OMAP tree represents a
So we trade an owner field (which can be NULL) versus two function pointers in the clk_ops struct, which are of course subject to be abused for all kind of crap which does not belong there at all.
Quoted 2 lines
significant amount of data, and for every additional unnecessary word, it gobbles up another 4K of data space.
What are we talking about?
arch/arm/mach-omap2/clock2420_data.c:117arch/arm/mach-omap2/clock2430_data.c:126arch/arm/mach-omap2/clock3xxx_data.c:235arch/arm/mach-omap2/clock44xx_data.c:228
So even if we could build a common kernel for all these omaps, then adding owner to struct clk will consume ~2800 bytes.
Quoted 3 lines
If we go down the route of separating clock stuff into bite-size pieces, OMAP is going to end up with yet more struct clks, which is going to add to the bloat even more.
Make it 8k then and it's still not any significant number.
Abstractions and I mean abstractions which encapsulate common functionality have always a tradeoff in larger data size. And one lesson I learned the hard way is that if you make abstractions and frameworks by design permissive, then you end up with tons of extra private code because people prefer to hack their "special needs" into their private code instead of talking to the people who maintain the core code where it could be solved in a generalized way.
Yes, we want to avoid unneccesary data size growth, but at the same time we have to make it as hard as it gets for users of an abstraction/framework to tinker around the core code as they see fit. Otherwise you wont get any consolidation and reduction of over and over copied and modified code doing basically the same thing.
If I can trade 2800 bytes of data vs. 280 lines of duplicated code and a can of worms opened by interfaces which are an invitation for abuse, then I chose the 2800 bytes any time.
Thanks,
tglx
PATCH 1/10 Add a common struct clk
Quoted 31 lines · Thomas Gleixner
Quoted 12 lines · Russell King - ARM Linux
Quoted 11 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.These callbacks are completely pointless. There are only two non empty implementations in tree:
Quoted 7 lines
Quoted 3 lines
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().I disagree. Most clocks don't live in a module - there's only one platform which does at present. To force every clock to have an owner field is rediculous. We already know that the OMAP tree represents a
So we trade an owner field (which can be NULL) versus two function pointers in the
clk_opsstruct, which are of course subject to be abused for all kind of crap which does not belong there at all.Quoted 2 lines
significant amount of data, and for every additional unnecessary word, it gobbles up another 4K of data space.
What are we talking about?
Quoted 7 lines
arch/arm/mach-omap2/clock2420_data.c:117arch/arm/mach-omap2/clock2430_data.c:126arch/arm/mach-omap2/clock3xxx_data.c:235arch/arm/mach-omap2/clock44xx_data.c:228So even if we could build a common kernel for all these omaps, then adding owner to struct clk will consume ~2800 bytes.
Just to correct something, we are already building a common kernel for all these, see omap2plus_defconfig.
For the size, device tree will shrink down that data where only only one set of clock data is passed to the kernel. So I don't think the size is such a big issue.
Regards,
Tony
PATCH 1/10 Add a common struct clk
In reply to Thomas GleixnerQuoted 18 lines · Thomas Gleixner
Quoted 16 lines · Russell King - ARM Linux
Quoted 14 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.These callbacks are completely pointless. There are only two non empty implementations in tree:
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().
Quoted 7 lines
Quoted 3 lines
I disagree. Most clocks don't live in a module - there's only one platform which does at present. To force every clock to have an owner field is rediculous. We already know that the OMAP tree represents a
So we trade an owner field (which can be NULL) versus two function pointers in the
clk_opsstruct, which are of course subject to be abused for all kind of crap which does not belong there at all.
And the current __clk_get/__clk_put stuff has been abused to hell and back hasn't it with just three implementations. While I agree with your sentiment, lets agree to address that _if_ it becomes a problem. At the moment, we have _enough_ problems to deal with, we don't need to invent new ones which really don't matter at this stage.
PATCH 1/10 Add a common struct clk
Quoted 27 lines · Russell King - ARM Linux
Quoted 18 lines · Thomas Gleixner
Quoted 16 lines · Russell King - ARM Linux
Quoted 14 lines · Thomas Gleixner
Quoted 6 lines · Sascha Hauer
From: Jeremy Kerr <[email protected]>
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock viaclk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock viaclk_put(). Optional.These callbacks are completely pointless. There are only two non empty implementations in tree:
One does a
try_module_get(clk->owner), which should be done in generic code. The other does special clock enabling magic which wants to go toclk->prepare().Quoted 7 lines
Quoted 3 lines
I disagree. Most clocks don't live in a module - there's only one platform which does at present. To force every clock to have an owner field is rediculous. We already know that the OMAP tree represents a
So we trade an owner field (which can be NULL) versus two function pointers in the
clk_opsstruct, which are of course subject to be abused for all kind of crap which does not belong there at all.
Quoted 5 lines
And the current __clk_get/__clk_put stuff has been abused to hell and back hasn't it with just three implementations. While I agree with your sentiment, lets agree to address that _if_ it becomes a problem. At the moment, we have _enough_ problems to deal with, we don't need to invent new ones which really don't matter at this stage.
So lets.. add the pointer and see if 4K lost is a problem for someone...?
It should be 'nice abstractions first, optimalizations later'...
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH 1/10 Add a common struct clk
In reply to Sascha Hauer2011/4/15 Sascha Hauer <[email protected]>:
Quoted 7 lines
From: Jeremy Kerr <[email protected]>
We currently have ~21 definitions of struct clk in the ARM architecture, each defined on a per-platform basis. This makes it difficult to define platform- (or architecture-) independent clock sources without making assumptions about struct clk, and impossible to compile two platforms with different struct clks into a single image.
Sorry for this late comment, maybe already adressed:
Review
Quoted 10 lines
(quoted diff) +10
-0+int clk_enable(struct clk *clk) +{ + ? ? ? unsigned long flags; + ? ? ? int ret = 0; + + ? ? ? WARN_ON(clk->prepare_count == 0); + + ? ? ? spin_lock_irqsave(&clk->enable_lock, flags); + ? ? ? if (clk->enable_count == 0 && clk->ops->enable) + ? ? ? ? ? ? ? ret = clk->ops->enable(clk);
Here the spinlock is held requiring the clock implementation to be non-sleeping, something that has been discussed at no end, without addressing that eternal debate, please just drop the spinlock during the ->enable() call, what is it protecting during that time anyway...
Quoted 9 lines
drivers/clk/clk.c new file +9
-0+ + ? ? ? if (!ret) + ? ? ? ? ? ? ? clk->enable_count++; + ? ? ? spin_unlock_irqrestore(&clk->enable_lock, flags); + + ? ? ? return ret; +} +EXPORT_SYMBOL_GPL (clk_enable); +
drivers/clk/clk.c
Quoted 10 lines
drivers/clk/clk.c new file +10
-0+void clk_disable (struct clk *clk) +{ + ? ? ? unsigned long flags; + + ? ? ? spin_lock_irqsave(&clk->enable_lock, flags); + + ? ? ? WARN_ON(clk->enable_count == 0); + + ? ? ? if (!--clk->enable_count == 0 && clk->ops->disable) + ? ? ? ? ? ? ? clk->ops->disable(clk);
Same here.
drivers/clk/clk.c line 77
Quoted 4 lines
drivers/clk/clk.c new file +4
-0+ + ? ? ? spin_unlock_irqrestore(&clk->enable_lock, flags); +} +EXPORT_SYMBOL_GPL (clk_disable);
Apart from that I need to add that I really like the spirit this patch.
Yours,
Linus Walleij
PATCH 1/10 Add a common struct clk
Quoted 11 lines · Linus Walleij
2011/4/15 Sascha Hauer <[email protected]>:
Quoted 7 lines
From: Jeremy Kerr <[email protected]>
We currently have ~21 definitions of struct clk in the ARM architecture, each defined on a per-platform basis. This makes it difficult to define platform- (or architecture-) independent clock sources without making assumptions about struct clk, and impossible to compile two platforms with different struct clks into a single image.
Sorry for this late comment, maybe already adressed:
Quoted 16 lines
Review
Quoted 10 lines
(quoted diff) +10
-0+int clk_enable(struct clk *clk) +{ + ? ? ? unsigned long flags; + ? ? ? int ret = 0; + + ? ? ? WARN_ON(clk->prepare_count == 0); + + ? ? ? spin_lock_irqsave(&clk->enable_lock, flags); + ? ? ? if (clk->enable_count == 0 && clk->ops->enable) + ? ? ? ? ? ? ? ret = clk->ops->enable(clk);Here the spinlock is held requiring the clock implementation to be non-sleeping, something that has been discussed at no end, without addressing that eternal debate, please just drop the spinlock during the ->enable() call, what is it protecting during that time anyway...
clk->enable_count and two concurrent enables passing each other (eg, while one enable is in progress, another enable may pass it unless the spinlock is held.)
That's not going to change; we decided that the enable call shall be non-sleeping for everything. That's why we introduced the prepare call for the sleeping part of the problem.
PATCH 1/10 Add a common struct clk
2011/4/30 Russell King - ARM Linux <[email protected]>:
Quoted 3 lines
we decided that the enable call shall be
non-sleeping for everything. ?That's why we introduced the prepare call for the sleeping part of the problem.
Ah, that makes perfect sense. Let's go ahead with this.
Yours,
Linus Walleij
PATCH 1/10 Add a common struct clk
In reply to Sascha HauerJeremy,
Quoted 99 lines · Sascha Hauer
From: Jeremy Kerr<[email protected]>
We currently have ~21 definitions of struct clk in the ARM architecture, each defined on a per-platform basis. This makes it difficult to define platform- (or architecture-) independent clock sources without making assumptions about struct clk, and impossible to compile two platforms with different struct clks into a single image.
This change is an effort to unify struct clk where possible, by defining a common struct clk, containing a set of clock operations. Different clock implementations can set their own operations, and have a standard interface for generic code. The callback interface is exposed to the kernel proper, while the clock implementations only need to be seen by the platform internals.
This allows us to share clock code among platforms, and makes it possible to dynamically create clock devices in platform-independent code.
Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure consists of a common struct clk:struct clk { const struct clk_ops *ops; unsigned int enable_count; unsigned int prepare_count; spinlock_t enable_lock; struct mutex prepare_lock; };And a set of clock operations (defined per type of clock):
struct clk_ops { int (*enable)(struct clk *); void (*disable)(struct clk *); unsigned long (*get_rate)(struct clk *); [...] };To define a hardware-specific clock, machine code can "subclass" the struct clock into a new struct (adding any device-specific data), and provide a set of operations:
struct clk_foo { struct clk clk; void __iomem *some_register; };struct
clk_opsclk_foo_ops= {
.get_rate =clk_foo_get_rate,
};The common clock definitions are based on a development patch from Ben Herrenschmidt<[email protected]>.
Signed-off-by Jeremy Kerr<[email protected]>Signed-off-by Uwe Kleine-K?nig<[email protected]>--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk.c | 132 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/clkdev.c | 7 ++ include/linux/clk.h | 164 +++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 298 insertions(+), 9 deletions(-)create mode 100644
drivers/clk/clk.cdrivers/clk/Kconfig +3
-0@@ -2,3 +2,6 @@ config CLKDEV_LOOKUP bool select HAVE_CLK + +config USE_COMMON_STRUCT_CLK + booldrivers/clk/Makefile +1
-0@@ -1,2 +1,3 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.odrivers/clk/clk.c new file +7
-0@@ -0,0 +1,132 @@ +/* +* Copyright (C) 2010-2011 Canonical Ltd<[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*
drivers/clk/clk.c line 17
Quoted 10 lines
drivers/clk/clk.c new file +10
-0+* Standard functionality for the common clock API. +*/ + +#include <linux/clk.h> +#include <linux/module.h> + +int clk_prepare (struct clk *clk) +{ +int ret =0 ; +
Shouldn't all these functions have some clk pointer checks:
if (IS_ERR_OR_NULL(clk)) return -EINVAL;
Rob
PATCH 1/10 Add a common struct clk
Hi Rob,
Quoted 10 lines
drivers/clk/clk.c line 17
Quoted 4 lines
drivers/clk/clk.c new file +4
-0+int clk_prepare (struct clk *clk) +{ +int ret =0 ; +Shouldn't all these functions have some clk pointer checks:
if (IS_ERR_OR_NULL(clk)) return -EINVAL;
No, I'd prefer not to. The driver code should be responsible for passing a valid pointer here, by doing this check once (where the clock is initially acquired through clk_get), rather than the core code doing it on each function call.
Cheers,
Jeremy
PATCH 1/10 Add a common struct clk
Jeremy,
Quoted 9 lines · Jeremy Kerr
Hi Rob,
Quoted 7 lines
drivers/clk/clk.c line 17
Quoted 4 lines
drivers/clk/clk.c new file +4
-0+int clk_prepare (struct clk *clk) +{ +int ret =0 ; +Shouldn't all these functions have some clk pointer checks:
Quoted 8 lines
Quoted 3 lines
if (IS_ERR_OR_NULL(clk)) return -EINVAL;No, I'd prefer not to. The driver code should be responsible for passing a valid pointer here, by doing this check once (where the clock is initially acquired through
clk_get), rather than the core code doing it on each function call.
I think you will find many examples in the kernel where that is not done by drivers. It is also common that the same driver is used on platforms with and without clock support. Adding NULL ptr checks around every clk api function makes for ugly and duplicated code.
Every implementation of clk_enable that I looked at does this check in their implementation. I looked at omap, imx, spear, and samsung. Seems like we should try to minimize breakage from switching to common struct clk.
Rob
PATCH 1/10 Add a common struct clk
Hi Rob,
Quoted 2 lines
I think you will find many examples in the kernel where that is not done by drivers.
Drivers should be checking the return value of clk_get - if they don't, it's a bug. This is the logical place to check, rather than before all clock API calls.
For cases where there is no clock provided for the device (but is a valid clock on some machines), the platform code should return a no-op clock from the clk_get call. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, like clk_fixed.
Cheers,
Jeremy
PATCH 1/10 Add a common struct clk
Quoted 8 lines · Jeremy Kerr
Hi Rob,
Quoted 2 lines
I think you will find many examples in the kernel where that is not done by drivers.
Drivers should be checking the return value of
clk_get- if they don't, it's a bug. This is the logical place to check, rather than before all clock API calls.
Maybe so, but it's common practice. Why not allow it, but add a warning? Or allow NULL, but not an error value.
Quoted 5 lines
For cases where there is no clock provided for the device (but is a valid clock on some machines), the platform code should return a no-op clock from the
clk_getcall. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, likeclk_fixed.
There could be cases where the driver wants to know if there is no clock. A cpufreq driver for example would be pointless to register if no clock is available. Making the every platform clk_get code have to handle the 2 cases would require the platform code to know what the driver wants. Also, it would require at least some platform clock code to enable a new platform if you have existing drivers with both cases.
You could do something like this:
clk = clk_get(mydev, NULL);
if (IS_ERR(clk))
clk = noop_clk;
Or add a variation of clk_get like clk_get_or_fail where clk_get returns noop clk and clk_get_or_fail returns nothing if the clock is not found.
Rob
PATCH 1/10 Add a common struct clk
Quoted 6 lines · Rob Herring
Quoted 5 lines · Jeremy Kerr
Hi Rob,
Quoted 2 lines
I think you will find many examples in the kernel where that is not done by drivers.
Quoted 6 lines
Quoted 3 lines
Drivers should be checking the return value of
clk_get- if they don't, it's a bug. This is the logical place to check, rather than before all clock API calls.Maybe so, but it's common practice. Why not allow it, but add a warning? Or allow NULL, but not an error value.
If drivers don't check the return value of clk_get() then they'll suffer kernel oopses. What's to say that if the driver doesn't check the return value from clk_get() that they'll bother checking the return value from any of the other clk_* API functions. Nothing.
So, checking for ERR values inside the clk_* functions is silly, and just means that buggy drivers continue with undiscovered bugs because they happen not to fail.
Quoted 7 lines
Quoted 4 lines
For cases where there is no clock provided for the device (but is a valid clock on some machines), the platform code should return a no-op clock from the
clk_getcall. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, likeclk_fixed.There could be cases where the driver wants to know if there is no clock.
How exactly would a driver know that the clock it has is a no-op clock with it being a pointer to some random data structure? A better question would be in the case of a cpufreq driver, how would such a driver know that it's pointless trying to set the rate on a fixed rate clock?
There's soo many combinations here where you can say "if a clock has property X, then maybe the driver doesn't want to do Y". So, instead of trying to cover all the possibilities, take a step back and look at the bigger picture.
1. in a cpufreq driver, if it gets a clock, one would hope that the clock it has been provided with is adjustable - in other words, clk_set_rate() stands a chance of succeeding. If it fails, then it has the wrong clock.
2. if the clock it has does not support adjustments in this way, then there is a bug in the data involved in selecting that clock, and that's what's at fault. You find this out when you try to change its rate via clk_set_rate() which should fail.
3. (to head off something that I can see being proposed) no, I don't think we need a system of properties.
A cpufreq driver which obtains clks should be no different from any other driver. It should get a clk via clk_get(), and report errors if that fails. If clk_set_rate() fails, then it should report that error too. There's really nothing "special" here.
This does bring us to an interesting question though: should clk_set_rate() succeed or fail with a NULL clk? There is no clock to control, so my feeling is that it should fail, just like clk_get_rate() should return zero because the rate is meaningless. There is no rate to get and no rate to set.
PATCH 1/10 Add a common struct clk
Quoted 59 lines · Russell King - ARM Linux
Quoted 6 lines · Rob Herring
Quoted 5 lines · Jeremy Kerr
Hi Rob,
Quoted 2 lines
I think you will find many examples in the kernel where that is not done by drivers.
Quoted 6 lines
Quoted 3 lines
Drivers should be checking the return value of
clk_get- if they don't, it's a bug. This is the logical place to check, rather than before all clock API calls.Maybe so, but it's common practice. Why not allow it, but add a warning? Or allow NULL, but not an error value.
If drivers don't check the return value of
clk_get()then they'll suffer kernel oopses. What's to say that if the driver doesn't check the return value fromclk_get()that they'll bother checking the return value from any of the other clk_* API functions. Nothing.So, checking for ERR values inside the clk_* functions is silly, and just means that buggy drivers continue with undiscovered bugs because they happen not to fail.
Quoted 7 lines
Quoted 4 lines
For cases where there is no clock provided for the device (but is a valid clock on some machines), the platform code should return a no-op clock from the
clk_getcall. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, likeclk_fixed.There could be cases where the driver wants to know if there is no clock.
How exactly would a driver know that the clock it has is a no-op clock with it being a pointer to some random data structure? A better question would be in the case of a cpufreq driver, how would such a driver know that it's pointless trying to set the rate on a fixed rate clock?
There's soo many combinations here where you can say "if a clock has property X, then maybe the driver doesn't want to do Y". So, instead of trying to cover all the possibilities, take a step back and look at the bigger picture.
1. in a cpufreq driver, if it gets a clock, one would hope that the clock it has been provided with is adjustable - in other words,
clk_set_rate()stands a chance of succeeding. If it fails, then it has the wrong clock.2. if the clock it has does not support adjustments in this way, then there is a bug in the data involved in selecting that clock, and that's what's at fault. You find this out when you try to change its rate via
clk_set_rate()which should fail.3. (to head off something that I can see being proposed) no, I don't think we need a system of properties.
A cpufreq driver which obtains clks should be no different from any other driver. It should get a clk via
clk_get(), and report errors if that fails. Ifclk_set_rate()fails, then it should report that error too. There's really nothing "special" here.
Quoted 5 lines
This does bring us to an interesting question though: should
clk_set_rate()succeed or fail with a NULL clk? There is no clock to control, so my feeling is that it should fail, just likeclk_get_rate()should return zero because the rate is meaningless. There is no rate to get and no rate to set.
I think having NULL clocks return success on set_rate() would be more useful. The most common use case for NULL clocks is when a clocks is present in some soc/arch/mach but is not present in another. Instead of having the consumers having an "if" around every clk_* calls on that clk, they would get a NULL clk. If NULL clk starts failing for clk_set_rate(), I think the point of a NULL clk will get defeated.
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Sascha Hauer
maintainerPATCH 1/10 Add a common struct clk
Quoted 13 lines · Saravana Kannan
Quoted 5 lines
This does bring us to an interesting question though: should
clk_set_rate()succeed or fail with a NULL clk? There is no clock to control, so my feeling is that it should fail, just likeclk_get_rate()should return zero because the rate is meaningless. There is no rate to get and no rate to set.I think having NULL clocks return success on
set_rate()would be more useful. The most common use case for NULL clocks is when a clocks is present in some soc/arch/mach but is not present in another. Instead of having the consumers having an "if" around every clk_* calls on that clk, they would get a NULL clk. If NULL clk starts failing forclk_set_rate(), I think the point of a NULL clk will get defeated.
PATCH 1/10 Add a common struct clk
Quoted 15 lines · Sascha Hauer
Quoted 6 lines · Saravana Kannan
Quoted 5 lines
This does bring us to an interesting question though: should
clk_set_rate()succeed or fail with a NULL clk? There is no clock to control, so my feeling is that it should fail, just likeclk_get_rate()should return zero because the rate is meaningless. There is no rate to get and no rate to set.Quoted 7 lines
I think having NULL clocks return success on
set_rate()would be more useful. The most common use case for NULL clocks is when a clocks is present in some soc/arch/mach but is not present in another. Instead of having the consumers having an "if" around every clk_* calls on that clk, they would get a NULL clk. If NULL clk starts failing forclk_set_rate(), I think the point of a NULL clk will get defeated.
Quoted 6 lines
From my experience when a clock is present on one SoC but not on another
the actual rate does not matter, only enabling/disabling the clock for register accesses is important. When a driver sets a rate on a clock it does it on purpose and if this clock is not even present on other SoCs it looks like a bug or at least a very special case for me. So I thinkclk_set_ratefor a NULL clock should fail.
Good point.
Quoted 3 lines
Other than that it's not a good behaviour when
clk_get_rate()returns 0 for clock which rate has been successfully set to another rate usingclk_set_rate().
It's a NULL clock, so it hopefully shouldn't matter.
I think you have convinced my about set_rate() returning error is not catastrophic. But if it doesn't hurt to return success, I think we should go ahead and do that in case someone cares about it?
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 1/10 Add a common struct clk
In reply to Russell King - ARM LinuxHi
Quoted 5 lines · Russell King - ARM Linux
This does bring us to an interesting question though: should
clk_set_rate()succeed or fail with a NULL clk? There is no clock to control, so my feeling is that it should fail, just likeclk_get_rate()should return zero because the rate is meaningless. There is no rate to get and no rate to set.
Returning an error would be my preference when a NULL or bogus clock pointer is passed to any clk_* operation, especially since those operations will need to dereference the clock pointer.
- Paul
PATCH 1/10 Add a common struct clk
Quoted 10 lines · Paul Walmsley
Hi
Quoted 5 lines · Russell King - ARM Linux
This does bring us to an interesting question though: should
clk_set_rate()succeed or fail with a NULL clk? There is no clock to control, so my feeling is that it should fail, just likeclk_get_rate()should return zero because the rate is meaningless. There is no rate to get and no rate to set.
Quoted 3 lines
Returning an error would be my preference when a NULL or bogus clock pointer is passed to any clk_* operation, especially since those operations will need to dereference the clock pointer.
Wouldn't returning an error for all clk_* ops for a NULL clock make it meaningless? It would be the same as -ENOENT in that case.
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 1/10 Add a common struct clk
In reply to Jeremy KerrQuoted 5 lines · Jeremy Kerr
Hi Rob,
Quoted 2 lines
I think you will find many examples in the kernel where that is not done by drivers.
Quoted 8 lines
Drivers should be checking the return value of
clk_get- if they don't, it's a bug. This is the logical place to check, rather than before all clock API calls.For cases where there is no clock provided for the device (but is a valid clock on some machines), the platform code should return a no-op clock from the
clk_getcall. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, likeclk_fixed.
Having a general fixed clock is a good idea. There seem to be several 'dummy' clocks under various subarchs, and Stephen Boyd posted one for MSM on March 24.
Most of the MSM drivers check the clk_get and fail to probe the driver if the clock is unavailable.
David
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 1/10 Add a common struct clk
Quoted 14 lines · David Brown
Quoted 4 lines · Jeremy Kerr
Hi Rob,
Quoted 2 lines
I think you will find many examples in the kernel where that is not done by drivers.
Quoted 8 lines
Drivers should be checking the return value of
clk_get- if they don't, it's a bug. This is the logical place to check, rather than before all clock API calls.For cases where there is no clock provided for the device (but is a valid clock on some machines), the platform code should return a no-op clock from the
clk_getcall. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, likeclk_fixed.
Quoted 6 lines
Having a general fixed clock is a good idea. There seem to be several 'dummy' clocks under various subarchs, and Stephen Boyd posted one for MSM on March 24.
Most of the MSM drivers check the
clk_getand fail to probe the driver if the clock is unavailable.
Actually I would like to build the dummy clock into the core and just have the dummy clock be a NULL pointer. I didn't do this in the MSM code because clkdev wasn't properly handling the NULL clock case. That has since been fixed by Russell elsewhere in this thread.
Subject: Re: [PATCH 06/10] clk: Add support for a generic clock multiplexer
Message-ID: <[email protected]>
http://lkml.kernel.org/n/20110418184138.GE25671 at n2100.arm.linux.org.uk
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Sascha Hauer
maintainerPATCH 2/10 clk: Generic support for fixed-rate clocks
In reply to Sascha HauerFrom: Jeremy Kerr <[email protected]>
Since most platforms will need a fixed-rate clock, add one. This will also serve as a basic example of an implementation of struct clk.
--- drivers/clk/clk.c | 14 ++++++++++++++ include/linux/clk.h | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 0 deletions(-)
drivers/clk/clk.c +14 -0
@@ -130,3 +130,17 @@ void __clk_put(struct clk *clk)if (clk->ops->put) clk->ops->put (clk); } + +/* clk_fixed support */ + +#define to_clk_fixed (clk) (container_of(clk, struct clk_fixed, clk)) + +static unsigned long clk_fixed_get_rate (struct clk *clk) +{ +return to_clk_fixed (clk)->rate; +} + +struct clk_ops clk_fixed_ops = { + .get_rate = clk_fixed_get_rate, +}; +EXPORT_SYMBOL_GPL (clk_fixed_ops);
include/linux/clk.h +16 -0
@@ -155,6 +155,22 @@ static inline void clk_common_init(struct clk *clk) mutex_init(&clk->prepare_lock); } +/* Simple fixed-rate clock */ +struct clk_fixed { +struct clk clk; +unsigned long rate; +}; + +extern struct clk_ops clk_fixed_ops; + +#define INIT_CLK_FIXED (name, r) { \ + .clk = INIT_CLK(name.clk, clk_fixed_ops), \ + .rate = (r) \ +} + +#define DEFINE_CLK_FIXED (name, r) \ + struct clk_fixed name = INIT_CLK_FIXED(name, r) +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */ /*
Signature · 1 line
1.7.4.1
Sascha Hauer
maintainerPATCH 3/10 clk: Make NULL a valid clock again
In reply to Sascha HauerNULL used to be a valid clock. This patch makes the common struct clk stuff work with this. Instead of crashing we return sane default values for this dummy clock, that is: can always be prepared, enabled, rate unkown and no set rate.
--- drivers/clk/clk.c | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+), 0 deletions(-)
drivers/clk/clk.c +27 -0
@@ -15,6 +15,9 @@ int clk_prepare(struct clk *clk) {int ret =0 ; +if (!clk) +return 0 ; +mutex_lock (&clk->prepare_lock);if (clk->prepare_count ==0 && clk->ops->prepare) ret = clk->ops->prepare (clk);
@@ -29,6 +32,9 @@ EXPORT_SYMBOL_GPL(clk_prepare);void clk_unprepare (struct clk *clk) { +if (!clk) +return ; +mutex_lock (&clk->prepare_lock);WARN_ON (clk->prepare_count ==0 );
@@ -47,6 +53,9 @@ int clk_enable(struct clk *clk)unsigned long flags;int ret =0 ; +if (!clk) +return 0 ; +WARN_ON (clk->prepare_count ==0 );spin_lock_irqsave (&clk->enable_lock, flags);
@@ -65,6 +74,9 @@ void clk_disable(struct clk *clk) {unsigned long flags; +if (!clk) +return ; +spin_lock_irqsave (&clk->enable_lock, flags);WARN_ON (clk->enable_count ==0 );
@@ -78,6 +90,9 @@ EXPORT_SYMBOL_GPL(clk_disable);unsigned long clk_get_rate (struct clk *clk) { +if (!clk) +return 0 ; +if (clk->ops->get_rate)return clk->ops->get_rate (clk);return 0 ;
@@ -86,6 +101,9 @@ EXPORT_SYMBOL_GPL(clk_get_rate);long clk_round_rate (struct clk *clk,unsigned long rate) { +if (!clk) +return -ENOSYS ; +if (clk->ops->round_rate)return clk->ops->round_rate (clk, rate);return -ENOSYS ;
@@ -94,6 +112,9 @@ EXPORT_SYMBOL_GPL(clk_round_rate);int clk_set_rate (struct clk *clk,unsigned long rate) { +if (!clk) +return -ENOSYS ; +might_sleep ();if (clk->ops->set_rate)
@@ -104,6 +125,9 @@ EXPORT_SYMBOL_GPL(clk_set_rate);int clk_set_parent (struct clk *clk,struct clk *parent) { +if (!clk) +return -ENOSYS ; +if (clk->ops->set_parent)return clk->ops->set_parent (clk, parent);return -ENOSYS ;
@@ -112,6 +136,9 @@ EXPORT_SYMBOL_GPL(clk_set_parent);struct clk *clk_get_parent (struct clk *clk) { +if (!clk) +return ERR_PTR (-ENOSYS ); +if (clk->ops->get_parent)return clk->ops->get_parent (clk);return ERR_PTR (-ENOSYS );
Signature · 1 line
1.7.4.1
PATCH 3/10 clk: Make NULL a valid clock again
Hi Sascha,
Quoted 4 lines
NULL used to be a valid clock. This patch makes the common struct clk stuff work with this. Instead of crashing we return sane default values for this dummy clock, that is: can always be prepared, enabled, rate unkown and no set rate.
Although I'm not totally averse to this change, I've been trying to avoid allowing NULL clocks - it seems to be a little 'messy' to allows clocks that don't have any possible operations on them, and could hide error cases where clock pointers have not been correctly initialised.
However, I understand that this may be required for flexibility between machines, and in that case would make sense. Is that what you're intending this for?
Cheers,
Jeremy
Sascha Hauer
maintainerPATCH 3/10 clk: Make NULL a valid clock again
Hi Jeremy,
Quoted 7 lines · Jeremy Kerr
Hi Sascha,
Quoted 4 lines
NULL used to be a valid clock. This patch makes the common struct clk stuff work with this. Instead of crashing we return sane default values for this dummy clock, that is: can always be prepared, enabled, rate unkown and no set rate.
Quoted 8 lines
Although I'm not totally averse to this change, I've been trying to avoid allowing NULL clocks - it seems to be a little 'messy' to allows clocks that don't have any possible operations on them, and could hide error cases where clock pointers have not been correctly initialised.
However, I understand that this may be required for flexibility between machines, and in that case would make sense. Is that what you're intending this for?
I intended to use NULL clocks but didn't do it then. The patch was already created, so I posted it. I think We could equally well create a dummy clock which can be used by all architectures. People (including me) never really got used to NULL clocks and it's been a source of confusion since they have been introduced.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 3/10 clk: Make NULL a valid clock again
In reply to Sascha HauerQuoted 56 lines · Sascha Hauer
NULL used to be a valid clock. This patch makes the common struct clk stuff work with this. Instead of crashing we return sane default values for this dummy clock, that is: can always be prepared, enabled, rate unkown and no set rate.
Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>--- drivers/clk/clk.c | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+), 0 deletions(-)drivers/clk/clk.c +12
-0@@ -15,6 +15,9 @@ int clk_prepare(struct clk *clk) {int ret =0 ; +if (!clk) +return 0 ; +mutex_lock (&clk->prepare_lock);if (clk->prepare_count ==0 && clk->ops->prepare) ret = clk->ops->prepare (clk);@@ -29,6 +32,9 @@ EXPORT_SYMBOL_GPL(clk_prepare);void clk_unprepare (struct clk *clk) { +if (!clk) +return ; +mutex_lock (&clk->prepare_lock);WARN_ON (clk->prepare_count ==0 );@@ -47,6 +53,9 @@ int clk_enable(struct clk *clk)unsigned long flags;int ret =0 ; +if (!clk) +return 0 ; +WARN_ON (clk->prepare_count ==0 );spin_lock_irqsave (&clk->enable_lock, flags);@@ -65,6 +74,9 @@ void clk_disable(struct clk *clk) {unsigned long flags; +if (!clk) +return ; +spin_lock_irqsave (&clk->enable_lock, flags);WARN_ON (clk->enable_count ==0 );
drivers/clk/clk.c EXPORT_SYMBOL_GPL(clk_disable); · line 98
Quoted 9 lines
drivers/clk/clk.c +3
-0@@ -78,6 +90,9 @@ EXPORT_SYMBOL_GPL(clk_disable);unsigned long clk_get_rate (struct clk *clk) { +if (!clk) +return 0 ; +if (clk->ops->get_rate)return clk->ops->get_rate (clk);return 0 ;
How about writing that as:
if (clk && clk->ops->get_rate) return clk->ops->get_rate(clk); return 0;
? Ditto for some of the other functions.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Sascha Hauer
maintainerPATCH 4/10 clk: implement parent pass through functions
In reply to Sascha HauerA common case for clocks is that certain operations are not implemented and shall be passed through to the parent. Add convenience functions for this purpose
--- drivers/clk/clk.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 9 ++++++ 2 files changed, 86 insertions(+), 0 deletions(-)
drivers/clk/clk.c +77 -0
@@ -171,3 +171,80 @@ struct clk_ops clk_fixed_ops = { .get_rate = clk_fixed_get_rate, };EXPORT_SYMBOL_GPL (clk_fixed_ops); + +int clk_parent_prepare (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return -ENOSYS ; + +return clk_prepare (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_prepare); + +void clk_parent_unprepare (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return ; + +clk_unprepare (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_unprepare); + +int clk_parent_enable (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return 0 ; + +return clk_enable (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_enable); + +void clk_parent_disable (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return ; + +clk_disable (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_disable); + +unsigned long clk_parent_get_rate (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return 0 ; + +return clk_get_rate (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_get_rate); + +long clk_parent_round_rate (struct clk *clk,unsigned long rate) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return -ENOSYS ; + +return clk_round_rate (parent, rate); +} +EXPORT_SYMBOL_GPL (clk_parent_round_rate); + +int clk_parent_set_rate (struct clk *clk,unsigned long rate) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return -ENOSYS ; + +return clk_set_rate (parent, rate); +} +EXPORT_SYMBOL_GPL (clk_parent_set_rate);
include/linux/clk.h +9 -0
@@ -171,6 +171,15 @@ extern struct clk_ops clk_fixed_ops;#define DEFINE_CLK_FIXED (name, r) \ struct clk_fixed name = INIT_CLK_FIXED(name, r) +/* generic pass-through-to-parent functions */ +int clk_parent_prepare (struct clk *clk); +void clk_parent_unprepare (struct clk *clk); +int clk_parent_enable (struct clk *clk); +void clk_parent_disable (struct clk *clk); +unsigned long clk_parent_get_rate (struct clk *clk); +long clk_parent_round_rate (struct clk *clk,unsigned long rate); +int clk_parent_set_rate (struct clk *clk,unsigned long rate); +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */ /*
Signature · 1 line
1.7.4.1
PATCH 4/10 clk: implement parent pass through functions
Quoted 38 lines · Sascha Hauer
A common case for clocks is that certain operations are not implemented and shall be passed through to the parent. Add convenience functions for this purpose
Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>--- drivers/clk/clk.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 9 ++++++ 2 files changed, 86 insertions(+), 0 deletions(-)drivers/clk/clk.c +19
-0@@ -171,3 +171,80 @@ struct clk_ops clk_fixed_ops = { .get_rate = clk_fixed_get_rate, };EXPORT_SYMBOL_GPL (clk_fixed_ops); + +int clk_parent_prepare (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return -ENOSYS ; + +return clk_prepare (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_prepare); + +void clk_parent_unprepare (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return ; +
drivers/clk/clk.c struct clk_ops clk_fixed_ops = { · line 202
Quoted 10 lines
drivers/clk/clk.c +10
-0+clk_unprepare (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_unprepare); + +int clk_parent_enable (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return 0 ;
Do you really want to return 0 here? IMHO something is fishy if a clock has .enable = clk_parent_enable but has no parent.
Quoted 55 lines
drivers/clk/clk.c +48
-0+ +return clk_enable (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_enable); + +void clk_parent_disable (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return ; + +clk_disable (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_disable); + +unsigned long clk_parent_get_rate (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return 0 ; + +return clk_get_rate (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_get_rate); + +long clk_parent_round_rate (struct clk *clk,unsigned long rate) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return -ENOSYS ; + +return clk_round_rate (parent, rate); +} +EXPORT_SYMBOL_GPL (clk_parent_round_rate); + +int clk_parent_set_rate (struct clk *clk,unsigned long rate) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return -ENOSYS ; + +return clk_set_rate (parent, rate); +} +EXPORT_SYMBOL_GPL (clk_parent_set_rate);include/linux/clk.h +0
-0@@ -171,6 +171,15 @@ extern struct clk_ops clk_fixed_ops;#define DEFINE_CLK_FIXED (name, r) \ struct clk_fixed name = INIT_CLK_FIXED(name, r)
include/linux/clk.h extern struct clk_ops clk_fixed_ops; · line 182
Quoted 10 lines
include/linux/clk.h +9
-0+/* generic pass-through-to-parent functions */ +int clk_parent_prepare (struct clk *clk); +void clk_parent_unprepare (struct clk *clk); +int clk_parent_enable (struct clk *clk); +void clk_parent_disable (struct clk *clk); +unsigned long clk_parent_get_rate (struct clk *clk); +long clk_parent_round_rate (struct clk *clk,unsigned long rate); +int clk_parent_set_rate (struct clk *clk,unsigned long rate); +
Technically they don't need to depend on USE_COMMON_STRUCT_CLK.
Quoted 12 lines
include/linux/clk.h +0
-0#else /* !CONFIG_USE_COMMON_STRUCT_CLK */ /* Signature · 7 lines
1.7.4.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel at lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Sascha Hauer
maintainerPATCH 4/10 clk: implement parent pass through functions
Quoted 43 lines · Uwe Kleine-K?nig
Quoted 42 lines · Sascha Hauer
A common case for clocks is that certain operations are not implemented and shall be passed through to the parent. Add convenience functions for this purpose
Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>--- drivers/clk/clk.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 9 ++++++ 2 files changed, 86 insertions(+), 0 deletions(-)drivers/clk/clk.c +23
-0@@ -171,3 +171,80 @@ struct clk_ops clk_fixed_ops = { .get_rate = clk_fixed_get_rate, };EXPORT_SYMBOL_GPL (clk_fixed_ops); + +int clk_parent_prepare (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return -ENOSYS ; + +return clk_prepare (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_prepare); + +void clk_parent_unprepare (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return ; + +clk_unprepare (parent); +} +EXPORT_SYMBOL_GPL (clk_parent_unprepare); +
Quoted 8 lines
drivers/clk/clk.c struct clk_ops clk_fixed_ops = { · line 202
Quoted 6 lines
drivers/clk/clk.c +6
-0+int clk_parent_enable (struct clk *clk) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return 0 ;Do you really want to return 0 here? IMHO something is fishy if a clock has .enable =
clk_parent_enablebut has no parent.
However we decide, it should return the same value as clk_parent_prepare above. Yes, -ENOSYS seems better here.
Quoted 11 lines
drivers/clk/clk.c struct clk_ops clk_fixed_ops = { · line 211
Quoted 10 lines
drivers/clk/clk.c +9
-0+/* generic pass-through-to-parent functions */ +int clk_parent_prepare (struct clk *clk); +void clk_parent_unprepare (struct clk *clk); +int clk_parent_enable (struct clk *clk); +void clk_parent_disable (struct clk *clk); +unsigned long clk_parent_get_rate (struct clk *clk); +long clk_parent_round_rate (struct clk *clk,unsigned long rate); +int clk_parent_set_rate (struct clk *clk,unsigned long rate); +Technically they don't need to depend on
USE_COMMON_STRUCT_CLK.
Indeed. Maybe this dependency can add some motivation to switch to common struct clk.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 4/10 clk: implement parent pass through functions
In reply to Sascha HauerQuoted 7 lines · Sascha Hauer
A common case for clocks is that certain operations are not implemented and shall be passed through to the parent. Add convenience functions for this purpose
Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>
I was hoping we could just build the parent handling into the core instead of having every clk_ops->enable call the parent ops.
Something like: if the clk_ops doesn't have a get_parent, clk_get_parent() would return NULL, and if the clk_ops doesn't have a set_parent, clk_set_parent() would do nothing.
Then clk_enable()/clk_disable() would call clk_get_parent() and then clk_enable() on that (whatever it is) before calling down into the ops->enable() function. Of course this means NULL is now the "no parent" value as opposed to ERR_PTR(-ENOSYS) but I'm willing to live with that since it makes things a bit simpler when you only have to check for NULL in the clk_enable()/clk_disable() path as opposed to NULL and IS_ERR.
I'm afraid this patch means every time the clk_ops wants to enable its parent (which is almost always the case), it has to do so explicitly when we really just want to concentrate on what enabling means for that clock (namely setting some bits in some registers). Thoughts?
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Sascha Hauer
maintainerPATCH 4/10 clk: implement parent pass through functions
Quoted 9 lines · Stephen Boyd
Quoted 7 lines · Sascha Hauer
A common case for clocks is that certain operations are not implemented and shall be passed through to the parent. Add convenience functions for this purpose
Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>
Quoted 6 lines
I was hoping we could just build the parent handling into the core instead of having every
clk_ops->enablecall the parent ops.Something like: if the
clk_opsdoesn't have aget_parent,clk_get_parent()would return NULL, and if theclk_opsdoesn't have aset_parent,clk_set_parent()would do nothing.
That's the current behaviour (except that ERR_PTR(-ENOSYS) is returned instead of NULL).
Quoted 8 lines
Then clk_enable()/clk_disable() would call
clk_get_parent()and thenclk_enable()on that (whatever it is) before calling down into theops->enable()function. Of course this means NULL is now the "no parent" value as opposed toERR_PTR(-ENOSYS)but I'm willing to live with that since it makes things a bit simpler when you only have to check for NULL in the clk_enable()/clk_disable() path as opposed to NULL andIS_ERR.
Quoted 4 lines
I'm afraid this patch means every time the
clk_opswants to enable its parent (which is almost always the case), it has to do so explicitly when we really just want to concentrate on what enabling means for that clock (namely setting some bits in some registers). Thoughts?
+1 for letting the core enable/disable and prepare/unprepare the parent clocks. I scanned the different arm clock implementations and they all do it, except the ones which do not implement parents at all.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 4/10 clk: implement parent pass through functions
Hello,
Quoted 28 lines · Sascha Hauer
Quoted 9 lines · Stephen Boyd
Quoted 7 lines · Sascha Hauer
A common case for clocks is that certain operations are not implemented and shall be passed through to the parent. Add convenience functions for this purpose
Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>Quoted 6 lines
I was hoping we could just build the parent handling into the core instead of having every
clk_ops->enablecall the parent ops.Something like: if the
clk_opsdoesn't have aget_parent,clk_get_parent()would return NULL, and if theclk_opsdoesn't have aset_parent,clk_set_parent()would do nothing.That's the current behaviour (except that
ERR_PTR(-ENOSYS)is returned instead of NULL).Quoted 8 lines
Then clk_enable()/clk_disable() would call
clk_get_parent()and thenclk_enable()on that (whatever it is) before calling down into theops->enable()function. Of course this means NULL is now the "no parent" value as opposed toERR_PTR(-ENOSYS)but I'm willing to live with that since it makes things a bit simpler when you only have to check for NULL in the clk_enable()/clk_disable() path as opposed to NULL andIS_ERR.
Quoted 8 lines
Quoted 4 lines
I'm afraid this patch means every time the
clk_opswants to enable its parent (which is almost always the case), it has to do so explicitly when we really just want to concentrate on what enabling means for that clock (namely setting some bits in some registers). Thoughts?+1 for letting the core enable/disable and prepare/unprepare the parent clocks. I scanned the different arm clock implementations and they all do it, except the ones which do not implement parents at all.
Then the question is if all do handle parents in the same way. (i.e. in enable do parent first, in disable do child first?)
If one layer of indirection is acceptable this can easily be accomplished (unless I oversee something):
struct clk_with_parent {
struct clk clk;
const struct clk_ops *ops;
struct clk *parent;
}Then the callbacks in clk_with_parent.clk would handle the parent and then call the respective callbacks in clk_with_parent.ops.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Sascha Hauer
maintainerPATCH 4/10 clk: implement parent pass through functions
Quoted 8 lines · Uwe Kleine-K?nig
Hello,
Quoted 4 lines
+1 for letting the core enable/disable and prepare/unprepare the parent clocks. I scanned the different arm clock implementations and they all do it, except the ones which do not implement parents at all.
Then the question is if all do handle parents in the same way. (i.e. in enable do parent first, in disable do child first?)
Yes, they do.
Quoted 4 lines
If one layer of indirection is acceptable this can easily be accomplished (unless I oversee something):
Quoted 8 lines
struct clk_with_parent { struct clk clk; const struct clk_ops *ops; struct clk *parent; }Then the callbacks in clk_with_parent.clk would handle the parent and then call the respective callbacks in clk_with_parent.ops.
I fail to see what you are trying to archieve. struct clk already has a ops pointer, what's the purpose of the additional *ops here?
Other than that I prefer not to hardcode parent pointers. Often enough I have looked at clock trees and wondered if the clock tree is in sync with the hardware. When we read the mux values back from the hardware in clk_get_parent the trees are in sync by definition (modulo refcounting when you play with the registers somewhere else).
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 4/10 clk: implement parent pass through functions
In reply to Uwe Kleine-KönigQuoted 5 lines · Uwe Kleine-K?nig
Quoted 3 lines
+1 for letting the core enable/disable and prepare/unprepare the parent clocks. I scanned the different arm clock implementations and they all do it, except the ones which do not implement parents at all.
Then the question is if all do handle parents in the same way. (i.e. in enable do parent first, in disable do child first?)
That's not a question at all. Anything which does it the other way round is broken. Period.
Quoted 11 lines
If one layer of indirection is acceptable this can easily be accomplished (unless I oversee something):
struct clk_with_parent { struct clk clk; const struct clk_ops *ops; struct clk *parent; }Then the callbacks in clk_with_parent.clk would handle the parent and then call the respective callbacks in clk_with_parent.ops.
Why the heck do you want to do that? That's a complete and utter failure. You invent indirections for no value at all which just violate any sense of abstraction and layering.
clk_en/disable should just do (simplified):
clk_enable(clk)
{
if (!clk)
return 0;
ret = clk_enable(clk->parent);
if (ret)
return ret;
clk_refcnt++;
if (!clk->enable)
return 0;ret = clk->enable(); if (!ret) return 0; clk_refcnt--; clk_disable(clk->parent); return ret; }
Now go figure how clk_disable should look like.
No clk should care about the parent at all, except for handing down the pointer. And it should not even check for the pointer being NULL or not. It does not matter at all, as long as clk_enable/disable return sensible error codes.
Anything else is just overengineered clusterfuck for no value at all, which makes error handling way more complex than it needs to be.
Thanks,
tglx
PATCH 4/10 clk: implement parent pass through functions
Quoted 9 lines · Thomas Gleixner
Quoted 5 lines · Uwe Kleine-K?nig
Quoted 3 lines
+1 for letting the core enable/disable and prepare/unprepare the parent clocks. I scanned the different arm clock implementations and they all do it, except the ones which do not implement parents at all.
Then the question is if all do handle parents in the same way. (i.e. in enable do parent first, in disable do child first?)
That's not a question at all. Anything which does it the other way round is broken. Period.
I havn't checked, but I remember Jeremy not wanting to handle parents in the generic part because he saw some differences.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
PATCH 4/10 clk: implement parent pass through functions
Quoted 5 lines · Uwe Kleine-K?nig
Quoted 4 lines · Thomas Gleixner
Quoted 3 lines · Uwe Kleine-K?nig
Quoted 3 lines
+1 for letting the core enable/disable and prepare/unprepare the parent clocks. I scanned the different arm clock implementations and they all do it, except the ones which do not implement parents at all.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
Then the question is if all do handle parents in the same way. (i.e. in enable do parent first, in disable do child first?)
That's not a question at all. Anything which does it the other way round is broken. Period.
I havn't checked, but I remember Jeremy not wanting to handle parents in the generic part because he saw some differences.
It does not matter whether you checked or not. And it does not matter whether Jeremy found code which does it the other way round.
The only safe way is parent first on enable and child first on disable. That's a matter of hardware and not a question of random Joe hacker got it wrong and it happens to work.
Sure it works on a simple divider which is connected to the parent clock, but think "child is a PLL".
So having a strict ordering enforced is the only sane way, unless you can prove that a particular piece of hardware requires it the other way round. And I doubt that you can find one.
So the framework should be coded for the sane case in the first place. If the unlikely case of reverse ordering surfaces one day, then it's not rocket science to deal with that with a flag in struct clk which tells clk_enable/disable or prepare/unprepare to do it the other way round.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Thomas Gleixner---
Hello,
only compile tested so far.
Best regards
Uwe
drivers/clk/clk.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 8 ++++++++ 2 files changed, 51 insertions(+), 0 deletions(-)
drivers/clk/clk.c +43 -0
@@ -14,10 +14,23 @@int clk_prepare (struct clk *clk) {int ret =0 ; +struct clk *parent =ERR_PTR (-ENOSYS );if (!clk)return 0 ; +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) { + parent =clk_get_parent (clk); + +if (!IS_ERR (parent)) { + ret =clk_prepare (parent); +if (ret) +return ret; + }else if (PTR_ERR (parent) != -ENOSYS ) +/* -ENOSYS means no parent and is OK */ +return PTR_ERR (parent); + } +mutex_lock (&clk->prepare_lock);if (clk->prepare_count ==0 && clk->ops->prepare) ret = clk->ops->prepare (clk);
@@ -26,6 +39,9 @@ int clk_prepare(struct clk *clk) clk->prepare_count++;mutex_unlock (&clk->prepare_lock); +if (ret && !IS_ERR (parent)) +clk_unprepare (parent); +return ret; }EXPORT_SYMBOL_GPL (clk_prepare);
@@ -45,6 +61,12 @@ void clk_unprepare(struct clk *clk) }mutex_unlock (&clk->prepare_lock); + +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) { +struct clk *parent =clk_get_parent (clk); +if (!IS_ERR (parent)) +clk_unprepare (parent); + } }EXPORT_SYMBOL_GPL (clk_unprepare);
@@ -52,10 +74,22 @@ int clk_enable(struct clk *clk) {unsigned long flags;int ret =0 ; +struct clk *parent =ERR_PTR (-ENOSYS );if (!clk)return 0 ; +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) { + parent =clk_get_parent (clk); +if (!IS_ERR (parent)) { + ret =clk_enable (parent); +if (ret) +return ret; + }else if (PTR_ERR (parent) != -ENOSYS ) +/* -ENOSYS means no parent and is OK */ +return PTR_ERR (parent); + } +WARN_ON (clk->prepare_count ==0 );spin_lock_irqsave (&clk->enable_lock, flags);
@@ -66,6 +100,9 @@ int clk_enable(struct clk *clk) clk->enable_count++;spin_unlock_irqrestore (&clk->enable_lock, flags); +if (ret && !IS_ERR (parent)) +clk_disable (parent); +return ret; }EXPORT_SYMBOL_GPL (clk_enable);
@@ -85,6 +122,12 @@ void clk_disable(struct clk *clk) clk->ops->disable (clk);spin_unlock_irqrestore (&clk->enable_lock, flags); + +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) { +struct clk *parent =clk_get_parent (clk); +if (!IS_ERR (parent)) +clk_disable (parent); + } }EXPORT_SYMBOL_GPL (clk_disable);
include/linux/clk.h +8 -0
@@ -62,6 +62,11 @@ struct clk { .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \ } +/* bit definitions for struct clk_ops.flags */ +#define CLK_OPS_GENERIC_PARENT 1/* automatically handle parent in +enable, disable, prepare and +unprepare functions */ +/** * struct clk_ops - Callback operations for clocks; these are to be provided * by the clock implementation, and will be called by drivers through the clk_*
@@ -91,6 +96,8 @@ struct clk {* @put: Called by the core clock code when a devices driver releases a * clock via clk_put(). Optional. * +* @flags: see above for possible values. +* * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * implementations to split any work between atomic (enable) and sleepable * (prepare) contexts. If a clock requires sleeping code to be turned on, this
@@ -119,6 +126,7 @@ struct clk_ops {int (*set_rate)(struct clk *,unsigned long );int (*set_parent)(struct clk *,struct clk *);struct clk * (*get_parent)(struct clk *); +unsigned int flags; };/**
Signature · 1 line
1.7.4.1
RFC PATCH 1/1 clk: add support for automatic parent handling
On Wed, 20 Apr 2011, Uwe Kleine-K?nig wrote:
Very useful changelog.
Quoted 5 lines
Signed-off-by Uwe Kleine-K?nig <[email protected]>---
Hello,only compile tested so far.
You are not listening at all, right?
Quoted 5 lines
drivers/clk/clk.c +0
-0
drivers/clk/clk.c line 22
Quoted 9 lines
drivers/clk/clk.c +2
-0@@ -14,10 +14,23 @@int clk_prepare (struct clk *clk) {int ret =0 ; +struct clk *parent =ERR_PTR (-ENOSYS );if (!clk)return 0 ; +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) {
Why the hell is this conditional? I told you that a proper abstraction is for the sane cases which are the majority of the hardware and we don't code for the buggy HW case unless we have evidence that it exists. Once we have that evidence we can decide what to do - add a flag or a separate function.
drivers/clk/clk.c line 32
Quoted 10 lines
drivers/clk/clk.c +10
-0+ parent =clk_get_parent (clk); + +if (!IS_ERR (parent)) { + ret =clk_prepare (parent); +if (ret) +return ret; + }else if (PTR_ERR (parent) != -ENOSYS ) +/* -ENOSYS means no parent and is OK */ +return PTR_ERR (parent); + }
And this whole mess should be written:
ret = clk_prepare(clk->parent);
if (ret)
return ret;Which returns 0 when there is no parent and it also returns 0 when there is no prepare callback for the parent. Why the hell do we need all this ERRPTR checking mess and all this conditional crap ?
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 3 lines · Thomas Gleixner
On Wed, 20 Apr 2011, Uwe Kleine-K?nig wrote:
Very useful changelog.
IMHO OK for a RFC patch.
Quoted 18 lines
Quoted 5 lines
Signed-off-by Uwe Kleine-K?nig <[email protected]>---
Hello,only compile tested so far.
You are not listening at all, right?
Quoted 10 lines
drivers/clk/clk.c +1
-0@@ -14,10 +14,23 @@int clk_prepare (struct clk *clk) {int ret =0 ; +struct clk *parent =ERR_PTR (-ENOSYS );
Quoted 6 lines
drivers/clk/clk.c line 22
Quoted 4 lines
drivers/clk/clk.c +1
-0if (!clk)return 0 ; +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) {Why the hell is this conditional? I told you that a proper abstraction
I made it conditional because the new behaviour is new and so minimizes surprises. OK for me to drop this flag.
Quoted 18 lines
is for the sane cases which are the majority of the hardware and we don't code for the buggy HW case unless we have evidence that it exists. Once we have that evidence we can decide what to do - add a flag or a separate function.
drivers/clk/clk.c line 32
Quoted 10 lines
drivers/clk/clk.c +10
-0+ parent =clk_get_parent (clk); + +if (!IS_ERR (parent)) { + ret =clk_prepare (parent); +if (ret) +return ret; + }else if (PTR_ERR (parent) != -ENOSYS ) +/* -ENOSYS means no parent and is OK */ +return PTR_ERR (parent); + }And this whole mess should be written:
Quoted 7 lines
ret = clk_prepare(clk->parent); if (ret) return ret;Which returns 0 when there is no parent and it also returns 0 when there is no prepare callback for the parent. Why the hell do we need all this ERRPTR checking mess and all this conditional crap ?
struct clk has no parent member, there is only clk_get_parent(). If there is no parent it returns ERR_PTR(-ENOSYS) and if you pass that to clk_prepare it tries to dereference it. So either it must not be called with an error pointer or clk_prepare et al. need adaption to handle these error pointers. I choosed the former. Ah, or clk_get_parent must be changed that it cannot fail and returns NULL to signal that there is no parent.
I found some problems with my patch, so I will try if I can make you more happy with a v2.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 5 lines · Uwe Kleine-K?nig
Quoted 3 lines · Thomas Gleixner
On Wed, 20 Apr 2011, Uwe Kleine-K?nig wrote:
Very useful changelog.
IMHO OK for a RFC patch.
Not at all.
Quoted 7 lines
Quoted 7 lines
And this whole mess should be written:
ret = clk_prepare(clk->parent); if (ret) return ret;
Quoted 5 lines
Quoted 3 lines
Which returns 0 when there is no parent and it also returns 0 when there is no prepare callback for the parent. Why the hell do we need all this ERRPTR checking mess and all this conditional crap ?
struct clk has no parent member, there is only
clk_get_parent(). If
Which is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Because someone claimed, that you need a callback to make it safe from changing? Or what's the reason for this?
Quoted 4 lines
there is no parent it returns
ERR_PTR(-ENOSYS)and if you pass that toclk_prepareit tries to dereference it. So either it must not be called with an error pointer orclk_prepareet al. need adaption to handle
The whole clk struct is an utter failure.
It's simply the least common denominator of all clk madness in the tree. Which results in a half documented data structure and a handful helper functions of which most of them are exported, though the functionality in them is less than the overhead of the EXPORT_SYMBOL.
That's not an abstraction and neither it's a framework. It's a half arsed conglomorate of primitives w/o the minimal documentation how those primitives should be used and why they are there in the first place.
This is new code and it should be aimed to cleanup things not to shuffle things around in a frenzy.
So what's wrong with that code:
1) struct clk is just a collection of function pointers and two locks
It lacks:
- a flag field for properties
- a field for the parent
- a field for the current clock rate
- a field for the base register
- a struct for the offsets of the most common registers relative to base
optionally a set of common register accessor functions like I did for the generic irq chip.
2) The "framework" API is just a set of low level primitive helper functions
It lacks:
- proper refcounting. clk_get() / clk_put() should do that at the framework level.
- the ability to propagate enable/disable/prepare/unprepare down through the parent tree
- proper mechanisms to sanity check clk_set_parent(), clk_set_rate() et. al.
This is not a implementation detail inside a specific clock. It's a problem which is common at least on the tree level:
rootclk
/ \
clk1 clk2
/ \
clk3 clk4
/
clk5
So now you want to change the rate of clk1. Can you do that?
No, but where is the sanity check which prevents that ?
In the clk1->set_rate() callback ?
Great, that's the wrong place.
So now you want to switch the parent of clk3 from clk1 to clk2. Can you do that?
No, but where is the sanity check which prevents that ?
In the clk3->set_parent() callback ?
Again, the wrong place.
And these are not problems of a particular clk implementation, these are general problems and those want to be addressed in a real framework.
It's debatable, whether you want to be able to change clocks which have active childs or not. If not the decision function is pretty simple. If yes, you need a list of child clks which you want to consult first before committing the change.
So unless you fix this stuff you should not even think about converting anything to this "framework". That's just waste of time and effort. Aside of declaring it stable and useful ....
The least thing which we need now are half baken "abstractions" which just shuffle code around for no value.
Thanks,
tglx
Re: [PATCH RFC] clk: add support for automatic parent handling
Like most of what you had to say. Although, I think Jeremy did a pretty good job of trying to push things along in the right direction. So, I wouldn't call this an utter failure. I hope you aren't confusing Jeremy's patches with the additional patches that Sascha is adding on top. I haven't looked much at Sascha's patch series -- so I can't comment on them.
More comments follow.
Quoted 48 lines · Thomas Gleixner
Quoted 5 lines · Uwe Kleine-K?nig
Quoted 3 lines · Thomas Gleixner
On Wed, 20 Apr 2011, Uwe Kleine-K?nig wrote:
Very useful changelog.
IMHO OK for a RFC patch.
Not at all.
Quoted 7 lines
Quoted 7 lines
And this whole mess should be written:
ret = clk_prepare(clk->parent); if (ret) return ret;Quoted 5 lines
Quoted 3 lines
Which returns 0 when there is no parent and it also returns 0 when there is no prepare callback for the parent. Why the hell do we need all this ERRPTR checking mess and all this conditional crap ?
struct clk has no parent member, there is only
clk_get_parent(). IfWhich is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Because someone claimed, that you need a callback to make it safe from changing? Or what's the reason for this?
Quoted 4 lines
there is no parent it returns
ERR_PTR(-ENOSYS)and if you pass that toclk_prepareit tries to dereference it. So either it must not be called with an error pointer orclk_prepareet al. need adaption to handleThe whole clk struct is an utter failure.
It's simply the least common denominator of all clk madness in the tree. Which results in a half documented data structure and a handful helper functions of which most of them are exported, though the functionality in them is less than the overhead of the
EXPORT_SYMBOL.That's not an abstraction and neither it's a framework. It's a half arsed conglomorate of primitives w/o the minimal documentation how those primitives should be used and why they are there in the first place.
This is new code and it should be aimed to cleanup things not to shuffle things around in a frenzy.
Quoted 7 lines
So what's wrong with that code:
1) struct clk is just a collection of function pointers and two locks
It lacks:
- a flag field for properties
Agree. I would very much like it.
Quoted 1 line
- a field for the parent
Agree.
Quoted 1 line
- a field for the current clock rate
Meh! Not a big deal. Some clocks don't have the concept of setting their rate since they share a parent with another unrelated clock (Ah, looks like you talk about with the tree diagram). So, it might be easier to have the rate inside each implementation if they need it. I shouldn't add too much code.
Quoted 1 line
- a field for the base register
Definitely no. It's completely useless for clocks whose registers don't all line up with fixed offsets from the base register. Now I will have to put one register here and the rest of the registers in the internal data?
Quoted 2 lines
- a struct for the offsets of the most common registers relative to base
Ok, you thought about rest of the registers. But, how can this fit in the common code? Each clock h/w implementation has totally different set of registers. Sometimes different even within the same SoC. This would be quite wasteful and doesn't even make sense to store at the top level. Also, storing offsets is a pain in the neck when the register space is not clean (happens more often than we would like :-().
Quoted 2 lines
optionally a set of common register accessor functions like I did for the generic irq chip.
Again, I don't see the point in having this in the common code. May be I'm missing something?
IMO, a better option instead of the base register and the offsets would be an option to have a priv_data pointer. I forgot the exact use case, but we thought that would have been helpful when we tried to port the msm clock driver in our tree on top of Jeremy's patches.
Quoted 7 lines
2) The "framework" API is just a set of low level primitive helper functions
It lacks:
- proper refcounting.
clk_get()/clk_put()should do that at the framework level.
This has nothing to do with the patches Jeremy made. clk_get()/_put() is in clkdev. Also, I'm not sure if clk_get()/put() needs refcounting. That's like asking kalloc/kfree to have refcounting.
Quoted 2 lines
- the ability to propagate enable/disable/prepare/unprepare down through the parent tree
Agree. That would be nice. I think the main reason people were not pushing for it was to do things in manageable steps. It took a long time for people to agree on even the current framework Jeremy added.
Quoted 14 lines
- proper mechanisms to sanity check
clk_set_parent(),clk_set_rate()et. al.This is not a implementation detail inside a specific clock. It's a problem which is common at least on the tree level:
rootclk
/ \
clk1 clk2
/ \
clk3 clk4
/
clk5
Quoted 7 lines
So now you want to change the rate of clk1. Can you do that?
No, but where is the sanity check which prevents that ?
In the
clk1->set_rate()callback ?Great, that's the wrong place.
Ah! Nice to see that this bothers you too. This has been a point of contention with in our internal team too. I keep pushing back on requests to make child clock's set rate propagate up to the patent when the parent has two unrelated child clocks going to different devices.
IMO, the set rate should only work on the parent clock and if there really in a need to change the child clock rates, then the users of those child clocks will have to co-ordinate it amongst themselves. Although, our use case is a bit simpler in that most of the time the child clocks are direct branches (no dividers) of the parent.
To handle, more complex cases like these, I think a clk_set_divider(div)
and/orclk_set_frac_mult(numerator, denominator)
might be an API that we should add. If a child clock cares only about a ratio with the parent clock, clk_set_divider() is a much better API that clk_set_rate(). And we have real use cases of for these in MSM.
Quoted 2 lines
So now you want to switch the parent of clk3 from clk1 to clk2. Can you do that?
At least in h/w I have seen so far, all the clocks that can really change parents fall under one of these categories:
1. A clock with a mux for input from several PLLs running at fixed rates (fixed at least after boot). So, these clocks can actually generate frequencies that they can guarantee won't change from underneath.
2. Clocks with are a mux from a bunch of external inputs that's completely end user/board defined.
For (1) the parent is really changed as part of "clk_set_rate()". For
(2) I think we should just let set_parent() control the mux.
I'm not sure how realistic/common your example of switching parents for clk3 is. May be it is -- I would interested in what people have to say.
So, between clk_set_divider(), clk_set_parent() and clk_set_rate(), I think we should be able to cover most clock trees as long as we don't propagate clk_set_rate() to parents with more than one children. In those case, the children should just implement clk_set_divider() (or not even that if there is no divider) and not allow clk_set_rate().
Quoted 10 lines
No, but where is the sanity check which prevents that ?
In the
clk3->set_parent()callback ?Again, the wrong place.
And these are not problems of a particular clk implementation, these are general problems and those want to be addressed in a real framework.
Quoted 8 lines
It's debatable, whether you want to be able to change clocks which have active childs or not. If not the decision function is pretty simple. If yes, you need a list of child clks which you want to consult first before committing the change.
So unless you fix this stuff you should not even think about converting anything to this "framework". That's just waste of time and effort. Aside of declaring it stable and useful ....
I think you haven't seen all the repetition of refcounting and each mach's implementation of some variant of clock ops. The current patch set from Jeremy will certainly help cut down some of that. If we get the "enable parent before you enable child, etc" in now, I don't think there will be much churn when we try to add code to enforce the tree restrictions you mention above.
Quoted 2 lines
The least thing which we need now are half baken "abstractions" which just shuffle code around for no value.
While a lot of your points are correct, I don't think the current patches from Jeremy are useless. May be I'm completely mistaken in assuming that you are referring to Jeremy's patches?
Btw, on a slight tangent, there is also the problem of clk_round_rate() not being sufficient when a driver is trying to work across different mach's. I think we need a clk_set_rate_range(min, ideal, max) but I can start a separate thread on that if you want. I talked about it a bit in another thread.
Thanks,
Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Re: [PATCH RFC] clk: add support for automatic parent handling
Quoted 12 lines · Saravana Kannan
Quoted 7 lines · Thomas Gleixner
So what's wrong with that code:
1) struct clk is just a collection of function pointers and two locks
It lacks:
- a flag field for properties
Agree. I would very much like it.
Quoted 1 line
- a field for the parent
Quoted 8 lines
Agree.
Quoted 1 line
- a field for the current clock rate
Meh! Not a big deal. Some clocks don't have the concept of setting their rate since they share a parent with another unrelated clock (Ah, looks like you talk about with the tree diagram). So, it might be easier to have the rate inside each implementation if they need it. I shouldn't add too much code.
No. Each clock has a rate, even if it's fixed and there is no point in calling down the tree to figure that out.
Quoted 9 lines
Quoted 1 line
- a field for the base register
Definitely no. It's completely useless for clocks whose registers don't all line up with fixed offsets from the base register. Now I will have to put one register here and the rest of the registers in the internal data?
Quoted 2 lines
- a struct for the offsets of the most common registers relative to base
Quoted 6 lines
Ok, you thought about rest of the registers. But, how can this fit in the common code? Each clock h/w implementation has totally different set of registers. Sometimes different even within the same SoC. This would be quite wasteful and doesn't even make sense to store at the top level. Also, storing offsets is a pain in the neck when the register space is not clean (happens more often than we would like :-().
Depends, there is a lot of sane hardware out there (not necessarily in the ARM SoC world). We can do with a pointer if the need arises.
Quoted 5 lines
Quoted 2 lines
optionally a set of common register accessor functions like I did for the generic irq chip.
Again, I don't see the point in having this in the common code. May be I'm missing something?
See my RFC patch of a generic irq chip implementation and how much duplicated five line inline functions they removed.
Quoted 4 lines
IMO, a better option instead of the base register and the offsets would be an option to have a
priv_datapointer. I forgot the exact use case, but we thought that would have been helpful when we tried to port the msm clock driver in our tree on top of Jeremy's patches.
It works either way, but we should try to comeup with a sensible common base struct for sane hardware.
Quoted 11 lines
Quoted 7 lines
2) The "framework" API is just a set of low level primitive helper functions
It lacks:
- proper refcounting.
clk_get()/clk_put()should do that at the framework level.This has nothing to do with the patches Jeremy made. clk_get()/_put() is in clkdev. Also, I'm not sure if clk_get()/put() needs refcounting. That's like asking kalloc/kfree to have refcounting.
Ok. I missed the clkdev part.
Quoted 6 lines
Quoted 2 lines
- the ability to propagate enable/disable/prepare/unprepare down through the parent tree
Agree. That would be nice. I think the main reason people were not pushing for it was to do things in manageable steps. It took a long time for people to agree on even the current framework Jeremy added.
Sad enough. But I'm not happy about that in any way. I know where it ends if you try to please everyone and agree on everything.
Quoted 27 lines
Quoted 14 lines
- proper mechanisms to sanity check
clk_set_parent(),clk_set_rate()et. al.This is not a implementation detail inside a specific clock. It's a problem which is common at least on the tree level:
rootclk
/ \
clk1 clk2
/ \
clk3 clk4
/
clk5Quoted 7 lines
So now you want to change the rate of clk1. Can you do that?
No, but where is the sanity check which prevents that ?
In the
clk1->set_rate()callback ?Great, that's the wrong place.
Ah! Nice to see that this bothers you too. This has been a point of contention with in our internal team too. I keep pushing back on requests to make child clock's set rate propagate up to the patent when the parent has two unrelated child clocks going to different devices.
Quoted 5 lines
IMO, the set rate should only work on the parent clock and if there really in a need to change the child clock rates, then the users of those child clocks will have to co-ordinate it amongst themselves. Although, our use case is a bit simpler in that most of the time the child clocks are direct branches (no dividers) of the parent.
Still most of this should be handled in the common code. It's not a unique problem to a single hardware implementation. It's just a given problem due to the tree nature. And the current code completely lacks a representation of that and therefor all needs to be done at the implementation detail level.
Quoted 2 lines
I'm not sure how realistic/common your example of switching parents for clk3 is. May be it is -- I would interested in what people have to say.
I just used it to illustrate what common code should handle.
Quoted 5 lines
So, between
clk_set_divider(),clk_set_parent()andclk_set_rate(), I think we should be able to cover most clock trees as long as we don't propagateclk_set_rate()to parents with more than one children. In those case, the children should just implementclk_set_divider()(or not even that if there is no divider) and not allowclk_set_rate().
The problem starts exactly at the point where you have all that propagation decision stuff in the chip implementation.
clk_set_rate(clk, rate)
{
u64 parent_rate = 0;
if (clk->users > 1)
return -EBUSY;
if (!clk->set_rate)
return rate == clk->rate ? 0 : -EINVAL;
ret = clk->set_rate(rate, &div, &parent_rate);
if (!ret)
return 0;
if (ret != NEED_PARENT_CHANGE)
return ret;
if (WARN_ON(!clk->parent))
return -EINVAL;
ret = clk_set_rate(clk->parent, parent_rate);
return ret ? ret : clk->set_rate(rate, NULL);
}Something along that will cover the tree traversal and remove the propagation from the chip implementations.
Quoted 6 lines
Quoted 3 lines
So unless you fix this stuff you should not even think about converting anything to this "framework". That's just waste of time and effort. Aside of declaring it stable and useful ....
I think you haven't seen all the repetition of refcounting and each mach's implementation of some variant of clock ops. The current patch set from Jeremy
Yes, I have looked through the maze as I went through all irq stuff recently. Jeremys stuff is a start, but I think we should start with something a bit more complete than that minimal set. I know the pain when you start with a minimal set and try to force people into cleaning up their stuff over and over. :(
And we can identify stuff already, so it should be added now.
Quoted 3 lines
will certainly help cut down some of that. If we get the "enable parent before you enable child, etc" in now, I don't think there will be much churn when we try to add code to enforce the tree restrictions you mention above.
Yes, that's needs to be done before we start churning the tree.
Quoted 6 lines
Quoted 2 lines
The least thing which we need now are half baken "abstractions" which just shuffle code around for no value.
While a lot of your points are correct, I don't think the current patches from Jeremy are useless. May be I'm completely mistaken in assuming that you are referring to Jeremy's patches?
I'm not saying they are useless, but they need to be more complete before we start converting code to it.
Quoted 4 lines
Btw, on a slight tangent, there is also the problem of
clk_round_rate()not being sufficient when a driver is trying to work across different mach's. I think we need aclk_set_rate_range(min, ideal, max)but I can start a separate thread on that if you want. I talked about it a bit in another thread.
Yes, but that's one step after the minimal set :)
Thanks,
tglx
Re: [PATCH RFC] clk: add support for automatic parent handling
Quoted 7 lines · Thomas Gleixner
Quoted 6 lines · Saravana Kannan
Quoted 5 lines · Thomas Gleixner
2) The "framework" API is just a set of low level primitive helper functions
It lacks:
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
- proper refcounting.
clk_get()/clk_put()should do that at the framework level.This has nothing to do with the patches Jeremy made. clk_get()/_put() is in clkdev. Also, I'm not sure if clk_get()/put() needs refcounting. That's like asking kalloc/kfree to have refcounting.
Ok. I missed the clkdev part.
well... just look at this:
-> git grep __clk_get
arch/arm/mach-bcmring/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-davinci/include/mach/clkdev.h:static inline int __clk_get(struct clk *clk) arch/arm/mach-ep93xx/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-integrator/include/mach/clkdev.h:static inline int __clk_get(struct clk *clk) arch/arm/mach-lpc32xx/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-mmp/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-msm/include/mach/clkdev.h:static inline int __clk_get(struct clk *clk) { return 1; } arch/arm/mach-mxs/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-nomadik/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-nuc93x/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-pnx4008/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-pxa/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-realview/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-shmobile/clock.c:int __clk_get(struct clk *clk) arch/arm/mach-shmobile/clock.c:EXPORT_SYMBOL(__clk_get); arch/arm/mach-shmobile/include/mach/clkdev.h:int __clk_get(struct clk *clk); arch/arm/mach-tegra/include/mach/clkdev.h:static inline int __clk_get(struct clk *clk) arch/arm/mach-u300/clock.c:int __clk_get(struct clk *clk) arch/arm/mach-u300/clock.c:EXPORT_SYMBOL(__clk_get); arch/arm/mach-u300/include/mach/clkdev.h:int __clk_get(struct clk *clk); arch/arm/mach-ux500/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-versatile/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-vexpress/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/mach-w90x900/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/plat-mxc/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/plat-omap/include/plat/clkdev.h:static inline int __clk_get(struct clk *clk) arch/arm/plat-spear/include/plat/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/plat-stmp3xxx/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/arm/plat-tcc/include/mach/clkdev.h:#define __clk_get(clk) ({ 1; }) arch/sh/include/asm/clkdev.h:#define __clk_get(clk) ({ 1; })drivers/clk/clkdev.c: if (clk && !__clk_get(clk))
Signature · 1 line
torben Hohn
Re: [PATCH RFC] clk: add support for automatic parent handling
In reply to Thomas GleixnerQuoted 13 lines · Thomas Gleixner
Depends, there is a lot of sane hardware out there (not necessarily in the ARM SoC world). We can do with a pointer if the need arises.
Quoted 5 lines
Quoted 2 lines
optionally a set of common register accessor functions like I did for the generic irq chip.
Again, I don't see the point in having this in the common code. May be I'm missing something?
See my RFC patch of a generic irq chip implementation and how much duplicated five line inline functions they removed.
Quoted 7 lines
Quoted 4 lines
IMO, a better option instead of the base register and the offsets would be an option to have a
priv_datapointer. I forgot the exact use case, but we thought that would have been helpful when we tried to port the msm clock driver in our tree on top of Jeremy's patches.It works either way, but we should try to comeup with a sensible common base struct for sane hardware.
Doesn't have to be in the base struct tho. I think a better approach is to keep the base struct reasonably API-only, and have an "implementation" subclass called something like simple_clk for example, that carries those few fields common to most MMIO based implementation and which can be created with existing "helper" code for the most common ones.
Ben.
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Thomas GleixnerHello Thomas,
Quoted 12 lines · Thomas Gleixner
Quoted 11 lines · Uwe Kleine-K?nig
Quoted 9 lines · Thomas Gleixner
And this whole mess should be written:
ret = clk_prepare(clk->parent); if (ret) return ret;Which returns 0 when there is no parent and it also returns 0 when there is no prepare callback for the parent. Why the hell do we need all this ERRPTR checking mess and all this conditional crap ?
Quoted 7 lines
Quoted 1 line
struct clk has no parent member, there is only
clk_get_parent(). IfWhich is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Because someone claimed, that you need a callback to make it safe from changing? Or what's the reason for this?
If there were a pointer tracking the parent you still needed to program out the get_parent function anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. in set_parent.
Quoted 20 lines
Quoted 4 lines
there is no parent it returns
ERR_PTR(-ENOSYS)and if you pass that toclk_prepareit tries to dereference it. So either it must not be called with an error pointer orclk_prepareet al. need adaption to handleThe whole clk struct is an utter failure.
It's simply the least common denominator of all clk madness in the tree. Which results in a half documented data structure and a handful helper functions of which most of them are exported, though the functionality in them is less than the overhead of the
EXPORT_SYMBOL.That's not an abstraction and neither it's a framework. It's a half arsed conglomorate of primitives w/o the minimal documentation how those primitives should be used and why they are there in the first place.
This is new code and it should be aimed to cleanup things not to shuffle things around in a frenzy.
Quoted 7 lines
So what's wrong with that code:
1) struct clk is just a collection of function pointers and two locks
It lacks:
- a flag field for properties
Up to now there are no properties to distinguish. When the first comes up such a field is easily added, no?
Quoted 1 line
- a field for the parent
I can agree here, see above.
Quoted 1 line
- a field for the current clock rate
Then you need a mechanism to notify the children if the rate or parent of a clock changes. I assume you won't allow that for a clock that has more than one (enabled) consumer. Knowing only very few platforms I don't know if that is something you can forbid.
Quoted 1 line
- a field for the base register
This is not needed for all clocks (at least not a say void __iomem *). I think it's fine here to leave that to the platforms as it is now.
Quoted 2 lines
- a struct for the offsets of the most common registers relative to base
I'm not sure I understand you right here. If this is about not duplicating data/code for similar clocks, this works (IMHO) fine with the current approach (ie. sharing the ops pointer).
Quoted 2 lines
optionally a set of common register accessor functions like I did for the generic irq chip.
Agreed, this can (and should) come when the base API is fixed.
Quoted 7 lines
2) The "framework" API is just a set of low level primitive helper functions
It lacks:
- proper refcounting.
clk_get()/clk_put()should do that at the framework level.
For most clocks it's not important if they are referenced somewhere. What should be done with that reference count at the framework level? The only thing I currently can come up with now is to module_get an optional owner. I'm not convinced this is worth to include in the framework. Still it should be possible to do, and it is.
Quoted 2 lines
- the ability to propagate enable/disable/prepare/unprepare down through the parent tree
Ack, I'm working on that.
Quoted 14 lines
- proper mechanisms to sanity check
clk_set_parent(),clk_set_rate()et. al.This is not a implementation detail inside a specific clock. It's a problem which is common at least on the tree level:
rootclk
/ \
clk1 clk2
/ \
clk3 clk4
/
clk5
Quoted 3 lines
So now you want to change the rate of clk1. Can you do that?
No, but where is the sanity check which prevents that ?
I assume your ascii art should imply that clk3 and clk4 are enabled? What is the policy you suggest?
This was discussed at some point[1] with the result that the user of set_rate should be aware of the clk tree and the changes it introduces for now and that some policy could still be added later. Ditto for set_parent.
It's easy enough to implement such a policy on top of Jeremy's patches. I'm not able to see already now all the requirements of all users of the clk-API. So I agree with you that it probably isn't (yet) the perfect framework, but I think it's a good base to see these requirements.
Quoted 17 lines
In the
clk1->set_rate()callback ?Great, that's the wrong place.
So now you want to switch the parent of clk3 from clk1 to clk2. Can you do that?
No, but where is the sanity check which prevents that ?
In the
clk3->set_parent()callback ?Again, the wrong place.
And these are not problems of a particular clk implementation, these are general problems and those want to be addressed in a real framework.
Quoted 8 lines
It's debatable, whether you want to be able to change clocks which have active childs or not. If not the decision function is pretty simple. If yes, you need a list of child clks which you want to consult first before committing the change.
So unless you fix this stuff you should not even think about converting anything to this "framework". That's just waste of time and effort. Aside of declaring it stable and useful ....
With stable I didn't intend to say something about the quality (though I still think it's a good thing), but that I won't rewrite the commits such that others can base their work on top of them.
Before your mail nobody spoke up against these patches and some people see a value in them and want to convert their platform to it. So providing a branch seems sensible to me.
I don't say that this common struct clk is perfect already now and I expect it to change here and there. It allows to consolidate some code and so is a good thing. I think nobody disagrees that when having converted most or all platforms to it we're not done. It's just the first step. Maybe one of the next is to add a "class" of clocks that looks similar to this:
struct clk_generic {
struct clk clk;
unsigned long rate;
struct clk *parent;
void __iomem *iobase;
sometype enable_regoffset;
size_t enable_shift;
struct clk **possible_parents;
size_t num_possible_parents;
sometype parent_regoffset;
size_t parent_shift;
};and that could be used for a big part of the needed clocks.
Best regards
Uwe
[1] see for example
http://thread.gmane.org/gmane.linux.ports.sh.devel/9755/focus=1100223
and the replies to it.
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 9 lines · Uwe Kleine-K?nig
Quoted 5 lines
Which is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Because someone claimed, that you need a callback to make it safe from changing? Or what's the reason for this?
If there were a pointer tracking the parent you still needed to program out the
get_parentfunction anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. inset_parent.
That's nonsense. Why do you want a get_parent() function at all? parent is set up when the clock is established in the clock tree. And that's not done by some random driver. That's a property of the clock.
Quoted 5 lines
Quoted 3 lines
It lacks:
- a flag field for properties
Up to now there are no properties to distinguish. When the first comes up such a field is easily added, no?
Crap. FIXED_CLOCK_RATE is the first thing which comes to my mind
Quoted 7 lines
Quoted 1 line
- a field for the parent
I can agree here, see above.
Quoted 1 line
- a field for the current clock rate
Then you need a mechanism to notify the children if the rate or parent of a clock changes. I assume you won't allow that for a clock that has more than one (enabled) consumer.
Here we go. That's why I say that this code is not a framework at all. It's a random conglomorate of random functions with no functionality at all.
Quoted 2 lines
Knowing only very few platforms I
don't know if that is something you can forbid.
Did you ever take the time to look over the various clk implementations and try to see the patterens there? Obviously not, so what are you arguing about?
Quoted 3 lines
Quoted 1 line
- a field for the base register
This is not needed for all clocks (at least not a say void
__iomem*). I think it's fine here to leave that to the platforms as it is now.
Crap. All clocks which are configurable in some way or can be enabled/disabled need access register(s) so you need a base address.
Quoted 5 lines
Quoted 2 lines
- a struct for the offsets of the most common registers relative to base
I'm not sure I understand you right here. If this is about not duplicating data/code for similar clocks, this works (IMHO) fine with the current approach (ie. sharing the ops pointer).
Right and have tons of duplicated
struct myclock {
struct clk;
void *base;
unsigned long enable_reg;
unsigned long enable_reg_cache;
};all over the place. Brilliant.
Quoted 3 lines
Quoted 2 lines
optionally a set of common register accessor functions like I did for the generic irq chip.
Agreed, this can (and should) come when the base API is fixed.
Base API ?
Quoted 5 lines
Quoted 5 lines
2) The "framework" API is just a set of low level primitive helper functions
It lacks:
Quoted 7 lines
Quoted 2 lines
- proper refcounting.
clk_get()/clk_put()should do that at the framework level.For most clocks it's not important if they are referenced somewhere. What should be done with that reference count at the framework level? The only thing I currently can come up with now is to
module_getan optional owner. I'm not convinced this is worth to include in the framework. Still it should be possible to do, and it is.
For most clocks it's not important to be protected by a spinlock either, for many clocks even the prepare mutex is not needed.
The whole point of frameworks is to figure out common patterns and implement them in a common place. That includes code which is not needed for many of the users of the code. See all the other infrastructure stuff: clocksources, clockevents, genirq. Strictly most of arch/* could do with half of the functionality, but that's not an argument to implement only half of it and keep the rest somewhere in the arch/ driver/ implementation.
Quoted 16 lines
Quoted 16 lines
- proper mechanisms to sanity check
clk_set_parent(),clk_set_rate() et. al. This is not a implementation detail inside a specific clock. It's a problem which is common at least on the tree level: rootclk / \ clk1 clk2 / \ clk3 clk4 / clk5 So now you want to change the rate of clk1. Can you do that?
Quoted 7 lines
Quoted 1 line
No, but where is the sanity check which prevents that ?
I assume your ascii art should imply that clk3 and clk4 are enabled? What is the policy you suggest?
This was discussed at some point[1] with the result that the user ofset_rateshould be aware of the clk tree and the changes it introduces for now and that some policy could still be added later. Ditto forset_parent.
Crap. We add a new framework now and we better think twice before starting to grow any user at all.
Quoted 4 lines
It's easy enough to implement such a policy on top of Jeremy's patches. I'm not able to see already now all the requirements of all users of the clk-API. So I agree with you that it probably isn't (yet) the perfect framework, but I think it's a good base to see these requirements.
Stop calling this a framework and stop telling me that it's easy to implement stuff on top of it.
Quoted 6 lines
Quoted 3 lines
So unless you fix this stuff you should not even think about converting anything to this "framework". That's just waste of time and effort. Aside of declaring it stable and useful ....
With stable I didn't intend to say something about the quality (though I still think it's a good thing), but that I won't rewrite the commits such that others can base their work on top of them.
Stop that bullshit already. We don't add stuff which has questionable quality and questionable functionality.
Quoted 2 lines
Before your mail nobody spoke up against these patches and some people see a value in them and want to convert their platform to it. So
Yes, because most involved people have the same narrow mindset as you and all you could agree on was the least common denominator of non functionality. People who have taste and see the big picture gave up on that. But that does not mean that it's good and something which should go near the tree or be provided for anyone to convert his platform to it.
Quoted 1 line
providing a branch seems sensible to me.
Provide as much branches as you see fit. They wont go near anything.
Quoted 6 lines
I don't say that this common struct clk is perfect already now and I expect it to change here and there. It allows to consolidate some code and so is a good thing. I think nobody disagrees that when having converted most or all platforms to it we're not done. It's just the first step. Maybe one of the next is to add a "class" of clocks that looks similar to this:
Wrong. We make a sensible functionality first and then convert bulk instead of doing it over and over again.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 10 lines · Thomas Gleixner
Quoted 4 lines · Uwe Kleine-K?nig
If there were a pointer tracking the parent you still needed to program out the
get_parentfunction anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. inset_parent.That's nonsense. Why do you want a
get_parent()function at all? parent is set up when the clock is established in the clock tree. And that's not done by some random driver. That's a property of the clock.
That's not universal - right now the drivers can and do know about this on some platforms. In some cases there will be requirements beyond the clock rate which mean that the driver will need to be able to tell the framework that, for example, it needs one clock to be in the same clock domain as another.
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
- a field for the base register
This is not needed for all clocks (at least not a say void
__iomem*). I think it's fine here to leave that to the platforms as it is now.Crap. All clocks which are configurable in some way or can be enabled/disabled need access register(s) so you need a base address.
That's not reliably the case, some systems have some of the clock tree (esepcialy the core parts of the tree) controlled by a system management unit which isn't memory mapped and it's common for I2C or SPI connected chips to be involved to some extent too. One advantage we should be able to get from this framework is that it will be much easier to have standard drivers for off-SoC chips that could be shared.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 12 lines · Mark Brown
Quoted 10 lines · Thomas Gleixner
Quoted 4 lines · Uwe Kleine-K?nig
If there were a pointer tracking the parent you still needed to program out the
get_parentfunction anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. inset_parent.That's nonsense. Why do you want a
get_parent()function at all? parent is set up when the clock is established in the clock tree. And that's not done by some random driver. That's a property of the clock.
Quoted 5 lines
That's not universal - right now the drivers can and do know about this on some platforms. In some cases there will be requirements beyond the clock rate which mean that the driver will need to be able to tell the framework that, for example, it needs one clock to be in the same clock domain as another.
Also there can be multiple parent clocks. An example are the timers on omaps where the parent clock can be either the 32KiHz clock or external source clock. ?his may need to be reprogrammed dynamically in some cases for advanced idle modes as one of the parent clocks may be shut down.
Tony
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 19 lines · Tony Lindgren
Quoted 12 lines · Mark Brown
Quoted 10 lines · Thomas Gleixner
Quoted 4 lines · Uwe Kleine-K?nig
If there were a pointer tracking the parent you still needed to program out the
get_parentfunction anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. inset_parent.That's nonsense. Why do you want a
get_parent()function at all? parent is set up when the clock is established in the clock tree. And that's not done by some random driver. That's a property of the clock.Quoted 5 lines
That's not universal - right now the drivers can and do know about this on some platforms. In some cases there will be requirements beyond the clock rate which mean that the driver will need to be able to tell the framework that, for example, it needs one clock to be in the same clock domain as another.
Quoted 4 lines
Also there can be multiple parent clocks. An example are the timers on omaps where the parent clock can be either the 32KiHz clock or external source clock. ?his may need to be reprogrammed dynamically in some cases for advanced idle modes as one of the parent clocks may be shut down.
If you need to propagate from bottom up, then you need a list of childs in struct clk. Right ?
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 21 lines · Thomas Gleixner
Quoted 19 lines · Tony Lindgren
Quoted 17 lines · Mark Brown
Quoted 10 lines · Thomas Gleixner
Quoted 4 lines · Uwe Kleine-K?nig
If there were a pointer tracking the parent you still needed to program out the
get_parentfunction anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. inset_parent.That's nonsense. Why do you want a
get_parent()function at all? parent is set up when the clock is established in the clock tree. And that's not done by some random driver. That's a property of the clock.That's not universal - right now the drivers can and do know about this on some platforms. In some cases there will be requirements beyond the clock rate which mean that the driver will need to be able to tell the framework that, for example, it needs one clock to be in the same clock domain as another.
Quoted 7 lines
Quoted 4 lines
Also there can be multiple parent clocks. An example are the timers on omaps where the parent clock can be either the 32KiHz clock or external source clock. ?his may need to be reprogrammed dynamically in some cases for advanced idle modes as one of the parent clocks may be shut down.
If you need to propagate from bottom up, then you need a list of childs in struct clk. Right ?
Yes we need to be able to reprogram all children if the parent clock needs to be reprogrammed for cpufreq/DVFS.
Also a child may need to change the parent clock like I wrote above. However, it might be possible to deal with this by registering the same child for both parents and handle that directly in the driver for the special cases if that simplifies things.
In some clk_set_rate cases for a child the parent clock may need to be reprogrammed to provide the desired rate. I don't know how common this is, and this may be doable by requesting both parent and child in the driver if that simplifies things.
Would be good to hear Paul's comments on this, as he probably knows best what's really needed so I've added him to Cc.
Regards,
Tony
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 7 lines · Tony Lindgren
Quoted 6 lines · Thomas Gleixner
Quoted 4 lines · Tony Lindgren
Also there can be multiple parent clocks. An example are the timers on omaps where the parent clock can be either the 32KiHz clock or external source clock. ?his may need to be reprogrammed dynamically in some cases for advanced idle modes as one of the parent clocks may be shut down.
Quoted 5 lines
Quoted 2 lines
If you need to propagate from bottom up, then you need a list of childs in struct clk. Right ?
Yes we need to be able to reprogram all children if the parent clock needs to be reprogrammed for cpufreq/DVFS.
Bottom up propagation is not rocket science. :)
Quoted 9 lines
Also a child may need to change the parent clock like I wrote above. However, it might be possible to deal with this by registering the same child for both parents and handle that directly in the driver for the special cases if that simplifies things.
In some
clk_set_ratecases for a child the parent clock may need to be reprogrammed to provide the desired rate. I don't know how common this is, and this may be doable by requesting both parent and child in the driver if that simplifies things.
I don't think so. That should be done in a library function which traverses the tree an validates whether this can be done or not. Though that's an orthogonal problem and not necessary for the primary set of functionality as long as we have the proper bottom up propagation and validation mechanisms in place.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Mark BrownQuoted 6 lines · Mark Brown
That's not reliably the case, some systems have some of the clock tree (esepcialy the core parts of the tree) controlled by a system management unit which isn't memory mapped and it's common for I2C or SPI connected chips to be involved to some extent too. One advantage we should be able to get from this framework is that it will be much easier to have standard drivers for off-SoC chips that could be shared.
Fair enough.
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Thomas GleixnerQuoted 6 lines · Thomas Gleixner
Quoted 5 lines · Uwe Kleine-K?nig
Quoted 5 lines
Which is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Because someone claimed, that you need a callback to make it safe from changing? Or what's the reason for this?
Quoted 8 lines
Quoted 4 lines
If there were a pointer tracking the parent you still needed to program out the
get_parentfunction anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. inset_parent.That's nonsense. Why do you want a
get_parent()function at all? parent is set up when the clock is established in the clock tree. And that's not done by some random driver. That's a property of the clock.
It's *not* a fixed property of the clock. It's a runtime property.
If you change the rate of a clock, you may need to change its parent. If you change the operating point of the device, (eg, sleep mode where the main system PLL gets turned off) you may need to change its parent to a slower clock to ensure wakeup timers continue to run but at a lower resolution.
Sure the API doesn't handle the runtime cases at all well, but that's not a reason to enforce a fixed tree structure on something which isn't a fixed tree structure.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 12 lines · Russell King - ARM Linux
Quoted 11 lines · Thomas Gleixner
Quoted 9 lines · Uwe Kleine-K?nig
Quoted 5 lines
Which is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Because someone claimed, that you need a callback to make it safe from changing? Or what's the reason for this?
If there were a pointer tracking the parent you still needed to program out the
get_parentfunction anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. inset_parent.
Quoted 5 lines
Quoted 3 lines
That's nonsense. Why do you want a
get_parent()function at all? parent is set up when the clock is established in the clock tree. And that's not done by some random driver. That's a property of the clock.It's *not* a fixed property of the clock. It's a runtime property.
I know that stuff can change and needs to be changed runtime. But this has to be done at the framework level and not at some random place in some random clk->ops->fn() implementation.
Quoted 1 line
If you change the rate of a clock, you may need to change its parent.
If you have a proper description of properties like possible parents, then you can figure out at the framework level that you need to change the parent in order to get the requested rate. It's not a SoC specific problem, it's a problem which can be described pretty well for the most common cases.
Quoted 4 lines
If you change the operating point of the device, (eg, sleep mode where the main system PLL gets turned off) you may need to change its parent to a slower clock to ensure wakeup timers continue to run but at a lower resolution.
Again. That's a problem to be solved at the framework level. If the sleep code decides to shut down the main pll then the framework can walk the tree and figure out which clocks need to be moved to a different parent, as long as the affected clocks are marked "keep me always alive" or whatever property is chosen to make such decisions.
Quoted 3 lines
Sure the API doesn't handle the runtime cases at all well, but that's not a reason to enforce a fixed tree structure on something which isn't a fixed tree structure.
I don't want to enforce a fixed tree structure. I want proper tree handling - which includes runtime changes to the tree - at the framework level and not encoded in 10 different bogus ways in every other SoC implementation.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 18 lines · Thomas Gleixner
Quoted 16 lines · Russell King - ARM Linux
Quoted 14 lines · Thomas Gleixner
Quoted 9 lines · Uwe Kleine-K?nig
Quoted 5 lines
Which is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Because someone claimed, that you need a callback to make it safe from changing? Or what's the reason for this?
If there were a pointer tracking the parent you still needed to program out the
get_parentfunction anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. inset_parent.That's nonsense. Why do you want a
get_parent()function at all? parent is set up when the clock is established in the clock tree. And that's not done by some random driver. That's a property of the clock.
Quoted 5 lines
Quoted 1 line
It's *not* a fixed property of the clock. It's a runtime property.
I know that stuff can change and needs to be changed runtime. But this has to be done at the framework level and not at some random place in some random
clk->ops->fn()implementation.
Look, how do you _not_ do it at the clk->ops->fn() level when you have clocks which are pure muxes, and so are selected by a bitfield in a register vs other clocks which are muxes _and_ dividers combined which can't be separated. Do you _really_ want to teach the core clock framework about every type of platform quirk like that?
That's the direction you're heading for by demanding that the core clk code does all this kind of crap. Crap in the core clock code, rather than a set of compartmentalized clock implementations for fixed rate clocks, muxes, dividers, dividers with muxes, plls, etc.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 25 lines · Russell King - ARM Linux
Quoted 18 lines · Thomas Gleixner
Quoted 16 lines · Russell King - ARM Linux
Quoted 14 lines · Thomas Gleixner
Quoted 9 lines · Uwe Kleine-K?nig
Quoted 5 lines
Which is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Because someone claimed, that you need a callback to make it safe from changing? Or what's the reason for this?
If there were a pointer tracking the parent you still needed to program out the
get_parentfunction anyhow to set the pointer initially. But I agree that in other situations having a pointer is more comfortable and saves ugly error handling e.g. inset_parent.That's nonsense. Why do you want a
get_parent()function at all? parent is set up when the clock is established in the clock tree. And that's not done by some random driver. That's a property of the clock.Quoted 5 lines
Quoted 1 line
It's *not* a fixed property of the clock. It's a runtime property.
I know that stuff can change and needs to be changed runtime. But this has to be done at the framework level and not at some random place in some random
clk->ops->fn()implementation.
Quoted 5 lines
Look, how do you _not_ do it at the
clk->ops->fn()level when you have clocks which are pure muxes, and so are selected by a bitfield in a register vs other clocks which are muxes _and_ dividers combined which can't be separated. Do you _really_ want to teach the core clock framework about every type of platform quirk like that?
Not at all. The core code should merily handle the tree structure correctly and some common other functions, nothing else.
Quoted 4 lines
That's the direction you're heading for by demanding that the core clk code does all this kind of crap. Crap in the core clock code, rather than a set of compartmentalized clock implementations for fixed rate clocks, muxes, dividers, dividers with muxes, plls, etc.
You need that anyway. The core code does not want to know about those ugly details and there is no need to know it.
So lets look at an example:
[Root clock A]-
|
- [Selector] -- [Divisor] -- [ Gate ]
|[Root clock B]-
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 3 lines · Thomas Gleixner
This are all well defined semantical problems and should be solved in common code rather than having different buggy implementations in each SoC clock "framework".
Why are you associating functional elements in drivers/clk with the SoC clock framework?
I think that's the root cause of this misunderstanding, and until you start realising that these building blocks are not part of the SoC implementation, we're going to continue arguing about this.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 11 lines · Russell King - ARM Linux
Quoted 3 lines · Thomas Gleixner
This are all well defined semantical problems and should be solved in common code rather than having different buggy implementations in each SoC clock "framework".
Why are you associating functional elements in
drivers/clkwith the SoC clock framework?I think that's the root cause of this misunderstanding, and until you start realising that these building blocks are not part of the SoC implementation, we're going to continue arguing about this.
I'm realizing that those building blocks are separate abstractions for the various incarnations of clk functionalities, which are just configured per SoC.
I'm not confusing anything. I'm just looking at the status quo in the first place. And the status quo is that every SoC has it's own "framework".
So now you propose two things to consolidate that:
1) A common struct clk and a handful wrapper functions
2) A set of abstraction blocks which represent the various clk incarnations (divisors, muxes, plls etc)
And my point is that this is not going to work out really well.
There is no consolidated handling of the tree itself. The per clk locking does what? Serialize the prepare/enable functions for a single clock. Now, tree traversal to make sure that the parent clocks are enabled/prepared etc as well need to take the locks nested. That works nicely in descending down the parent chain.
Though when you need to propagate changes up the chain (e.g. rate changes) then you need to take the locks in reverse order with trylock and back down to the place where you started when a trylock fails. Otherwise you run into deadlocks. With the split locks you do that for the mutex chain first and then for the spinlock one. It's doable, but is it worth the trouble?
If it is worth the trouble, then where are you going to implement this?
The proposed "API" pushes the walk logic into the clkops->fn() callbacks. Into every single one.
This is simply wrong. That's like having each filesystem providing it's own directory traversal mechanism.
You don't want to have that logic in each callback. That's tree management which needs to be done one level above. And it does not matter which locking scheme you are using - global or per clk.
Lets look at a simple example (locking omitted)
clk_enable(clk) {
if (clk->enable_count == 0) {
res = clk->ops->enable(clk);
if (res)
return res;
}
enable_count++;
return 0;
}; So in each enable op you have:
*_enable(clk)
{
res = clk_enable(clk_get_parent(clk));
if (res)
return res;
res = hw_magic_enable(clk);
if (res)
clk_disable(clk_get_parent(clk));
return res;
}Instead of having at the core level:
clk_enable(clk)
{
if (clk->enable_count == 0) {
res = clk_enable(clk_get_parent(clk));
if (res)
return res;
res = clk->ops->enable(clk);
if (res) {
clk_disable(clk_get_parent(clk));
return res;
}
}
clk->enable_count++;
return 0;
}And in each *_enable op:
*_enable(clk)
{
return hw_magic_enable(clk);
}Now add the locking mess (whatever variant) to that whole thing and then tell me which solution is the proper one.
It gets worse when you look at the proposed clk_set_parent() wrapper:
clk_set_parent(clk)
{
if (!clk->ops->set_parent)
return -ENOSYS;
return clk->ops->set_parent(clk);
}So this does no locking at all for a simple reason. Because if you change the parent then you need to lock the clocks in the upwards direction with full trylock dance. And you have to do that because otherwise a clk_enable/disable/prepare/unprepare call on a leaf clk might follow down a chain which is changing under it.
So you want to do that in every possible set_parent() callback? Same for set_rate() implementations which need to disable and/or adjust the clocks tree upwards before they can change the rate at the bottom.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 29 lines · Thomas Gleixner
Lets look at a simple example (locking omitted)
clk_enable(clk) { if (clk->enable_count == 0) { res = clk->ops->enable(clk); if (res) return res; } enable_count++; return 0; };So in each enable op you have:
*_enable(clk){ res = clk_enable(clk_get_parent(clk)); if (res) return res; res = hw_magic_enable(clk); if (res) clk_disable(clk_get_parent(clk)); return res; }Instead of having at the core level:
clk_enable(clk)
Quoted 15 lines
{
if (clk->enable_count == 0) {
res = clk_enable(clk_get_parent(clk));
if (res)
return res;
res = clk->ops->enable(clk);
if (res) {
clk_disable(clk_get_parent(clk));
return res;
}
}
clk->enable_count++;
return 0;
}I'm going to give up discussing this with you - you have no desire to even understand what I'm saying. I don't see any point continuing this discussion any further.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 6 lines · Russell King - ARM Linux
Quoted 1 line · Thomas Gleixner
}
I'm going to give up discussing this with you - you have no desire to even understand what I'm saying. I don't see any point continuing this discussion any further.
Right, I have no interest in understanding what you want to do.
At the same time I have yet to see any reasonable answer to basic questions how the locking and the very basic tree traversal rules are going to be.
All I got so far is that I'm living in the wrong universe and that I'm neither able nor willing to understand the reasoning behind your grand master plan. Pretty constructive.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 9 lines · Thomas Gleixner
Quoted 6 lines · Russell King - ARM Linux
Quoted 1 line · Thomas Gleixner
}
I'm going to give up discussing this with you - you have no desire to even understand what I'm saying. I don't see any point continuing this discussion any further.
Right, I have no interest in understanding what you want to do.
And that's your basic problem. You don't even want to try and understand these arguments. So its pointless continuing the discussion.
Thanks for confirming that I've been wasting my time over the last couple of days.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 5 lines · Russell King - ARM Linux
Quoted 4 lines · Thomas Gleixner
Quoted 3 lines · Russell King - ARM Linux
Quoted 1 line · Thomas Gleixner
}
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
I'm going to give up discussing this with you - you have no desire to even understand what I'm saying. I don't see any point continuing this discussion any further.
Right, I have no interest in understanding what you want to do.
And that's your basic problem. You don't even want to try and understand these arguments. So its pointless continuing the discussion.
I see. We are at the point where selective quoting is the solution to the problem. And yes, it's my fault that I forgot to put the <SARCASM> tags around that sentence.
Quoted 2 lines
Thanks for confirming that I've been wasting my time over the last couple of days.
If you insist on moving a technical discussion to a personal mudslinging level, then we really can stop right here.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Russell King - ARM LinuxQuoted 7 lines · Russell King - ARM Linux
Quoted 3 lines · Thomas Gleixner
This are all well defined semantical problems and should be solved in common code rather than having different buggy implementations in each SoC clock "framework".
Why are you associating functional elements in
drivers/clkwith the SoC clock framework?
i think i pretty much understand what thomas is after. but i have problems understanding, what you want here.
until this point, it looks like you only want the driver/clk to model the clock endpoints inside the devices. A device itself shouldnt be caring for clock parents or anything. its only concern is that a clock pin is fed with the right frequency, or off...
Quoted 4 lines
I think that's the root cause of this misunderstanding, and until you start realising that these building blocks are not part of the SoC implementation, we're going to continue arguing about this.
what you say now, pretty much sounds like what thomas wants. these building blocks would be objects derived from the clock baseclass, which thomas is trying to define. he doesnt seem to be concerned about the second more special layer yet.
i am quite puzzled, what exactly your fighting over :S
Quoted 5 lines
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Signature · 1 line
torben Hohn
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 22 lines · torbenh
Quoted 7 lines · Russell King - ARM Linux
Quoted 3 lines · Thomas Gleixner
This are all well defined semantical problems and should be solved in common code rather than having different buggy implementations in each SoC clock "framework".
Why are you associating functional elements in
drivers/clkwith the SoC clock framework?i think i pretty much understand what thomas is after. but i have problems understanding, what you want here.
until this point, it looks like you only want the driver/clk to model the clock endpoints inside the devices. A device itself shouldnt be caring for clock parents or anything. its only concern is that a clock pin is fed with the right frequency, or off...
Quoted 4 lines
I think that's the root cause of this misunderstanding, and until you start realising that these building blocks are not part of the SoC implementation, we're going to continue arguing about this.
Quoted 6 lines
what you say now, pretty much sounds like what thomas wants. these building blocks would be objects derived from the clock baseclass, which thomas is trying to define. he doesnt seem to be concerned about the second more special layer yet.
i am quite puzzled, what exactly your fighting over :S
Thomas wants a core framework that handles the clock tree, with each clock being the implementation of just the clock. Russell thinks this is impossible, and wants to stop at implementing building blocks for the standard clock types, and let each SoC put them into a tree.
I don't think anybody can argue that a shared clock tree framework, if it was possible to do well, would be a benefit. But there are a few problems that make abstracting the differences between SoCs very hard at that level.
After implementing the Tegra clock tree at least 10 times to solve different problems, there are two very hard problems to solve.
First is locking. Per-clock locking is hard because it requires choosing up front which way locking will go, usually locking the child, then locking the parent, then enabling the parent, and enabling the child. Any operation flow that requires traversing the tree from the parent to the child, for example changing the rate of the parent, causes lock inversion. Global locking is easy, but can be wasteful on platforms that have some very slow clocks (think external i2c clocks), and some very fast clocks (internal register writes). This is mitigated by the separation of clk_prepare and clk_enable locking - clk_enable can never sleep, so it can't be blocked for long. Locking at the root node of the tree would be nice, but most SoCs don't have a root node - they have a fast root clock and a slow root clock, and can switch the all or most of clock tree over to the slow clock in some modes.
The second problem is rate changing. Different platforms require wildly different strategies for changing clock rates. On Tegra, clk_set_rate will never change the parent, because we can generally set up the parent clocks to the correct frequencies for all the devices, and then device drivers can change their dividers to get the rate they need. The few cases where the parent needs to change (cpufreq and display pclk), the driver manually calls clk_set_parent. On other platforms, it is common to need to change the parent to get the necessary rate.
Automatically selecting parents in a generic way is impossible. If one DEV1 calls clk_set_rate and clk_enable, and the core framework responds by setting pll A to frequency X, and setting the parent of DEV1 to A, what happens when DEV2 calls clk_set_rate to a frequency that can only be satisfied by setting pll A to frequency Y? DEV1 can't be switched to another pll, because it is already enabled, and some platforms can't support glitchlessly changing a mux, even if the frequency doesn't change.
I still think a common implementation of the clock tree framework would be useful, even if not all platforms can use it. Allow the platforms that can to use it, providing only clock data, and maybe a few clock implementations if the building blocks are not sufficient, and allow those that can't to implement their own versions of the clk_* functions on top of the clock building blocks. Tegra already has a fairly generic implementation of a clock tree in arch/arm/mach-tegra/clock.c, moving it to the common clk struct and sharing it with other platforms wouldn't be any extra code, even if no other platforms could use it. And I bet at least OMAP could use it, from what I've seen.
Per-tree locking is a solvable problem, as long as a tree was considered as an ordered graph - two root nodes that feed into the same clocks would be considered part of the same tree. The core framework could look at all possible parents of a clock to determine what clock trees were truly independent, which would result in a single global lock on most platforms, but multiple locks on platforms that really had independent clock trees. Dynamically added clocks would cause problems with this solution.
I think automatic clock parent and rate setting would need to be delegated to a platform-specific layer, and I'm not sure how. Maybe allow platforms to override the set_rate ops in the clock tree building blocks, or a new op that can determine the new tree structure, and call the old set_rate op to set the registers.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 28 lines · Colin Cross
Quoted 27 lines · torbenh
Quoted 7 lines · Russell King - ARM Linux
Quoted 3 lines · Thomas Gleixner
This are all well defined semantical problems and should be solved in common code rather than having different buggy implementations in each SoC clock "framework".
Why are you associating functional elements in
drivers/clkwith the SoC clock framework?i think i pretty much understand what thomas is after. but i have problems understanding, what you want here.
until this point, it looks like you only want the driver/clk to model the clock endpoints inside the devices. A device itself shouldnt be caring for clock parents or anything. its only concern is that a clock pin is fed with the right frequency, or off...
Quoted 4 lines
I think that's the root cause of this misunderstanding, and until you start realising that these building blocks are not part of the SoC implementation, we're going to continue arguing about this.
what you say now, pretty much sounds like what thomas wants. these building blocks would be objects derived from the clock baseclass, which thomas is trying to define. he doesnt seem to be concerned about the second more special layer yet.
Quoted 6 lines
Quoted 1 line
i am quite puzzled, what exactly your fighting over :S
Thomas wants a core framework that handles the clock tree, with each clock being the implementation of just the clock. Russell thinks this is impossible, and wants to stop at implementing building blocks for the standard clock types, and let each SoC put them into a tree.
Thomas wants the clocks to reference a clock_chip. (much like genirq... you have irq_desc and and irq_chip) so there is still one component which has the "big picture" and can implement crazy platform rules, if necessary.
Quoted 9 lines
I don't think anybody can argue that a shared clock tree framework, if it was possible to do well, would be a benefit. But there are a few problems that make abstracting the differences between SoCs very hard at that level.
After implementing the Tegra clock tree at least 10 times to solve different problems, there are two very hard problems to solve.
Quoted 14 lines
First is locking. Per-clock locking is hard because it requires choosing up front which way locking will go, usually locking the child, then locking the parent, then enabling the parent, and enabling the child. Any operation flow that requires traversing the tree from the parent to the child, for example changing the rate of the parent, causes lock inversion. Global locking is easy, but can be wasteful on platforms that have some very slow clocks (think external i2c clocks), and some very fast clocks (internal register writes). This is mitigated by the separation of
clk_prepareandclk_enablelocking -clk_enablecan never sleep, so it can't be blocked for long. Locking at the root node of the tree would be nice, but most SoCs don't have a root node - they have a fast root clock and a slow root clock, and can switch the all or most of clock tree over to the slow clock in some modes.
yeah. one of the big reasons, why the generic code should do the locking.
Quoted 11 lines
The second problem is rate changing. Different platforms require wildly different strategies for changing clock rates. On Tegra,
clk_set_ratewill never change the parent, because we can generally set up the parent clocks to the correct frequencies for all the devices, and then device drivers can change their dividers to get the rate they need. The few cases where the parent needs to change (cpufreq and display pclk), the driver manually callsclk_set_parent. On other platforms, it is common to need to change the parent to get the necessary rate.
Quoted 8 lines
Automatically selecting parents in a generic way is impossible. If one DEV1 calls
clk_set_rateandclk_enable, and the core framework responds by setting pll A to frequency X, and setting the parent of DEV1 to A, what happens when DEV2 callsclk_set_rateto a frequency that can only be satisfied by setting pll A to frequency Y? DEV1 can't be switched to another pll, because it is already enabled, and some platforms can't support glitchlessly changing a mux, even if the frequency doesn't change.
in the case where we cant change a parent clock, the generic code could just fail to set_rate. then delegate the problem to the clk_chip which can resolve the problem.
the locking would be tricky, but it is solvable.
but its still somthing we only want implemented once.
so how does changing a mux, which glitches, work now ?
do the child clocked devices need to be turned off/notified when this happens ?
Quoted 22 lines
I still think a common implementation of the clock tree framework would be useful, even if not all platforms can use it. Allow the platforms that can to use it, providing only clock data, and maybe a few clock implementations if the building blocks are not sufficient, and allow those that can't to implement their own versions of the clk_* functions on top of the clock building blocks. Tegra already has a fairly generic implementation of a clock tree in
arch/arm/mach-tegra/clock.c, moving it to the common clk struct and sharing it with other platforms wouldn't be any extra code, even if no other platforms could use it. And I bet at least OMAP could use it, from what I've seen.Per-tree locking is a solvable problem, as long as a tree was considered as an ordered graph - two root nodes that feed into the same clocks would be considered part of the same tree. The core framework could look at all possible parents of a clock to determine what clock trees were truly independent, which would result in a single global lock on most platforms, but multiple locks on platforms that really had independent clock trees. Dynamically added clocks would cause problems with this solution.
Quoted 5 lines
I think automatic clock parent and rate setting would need to be delegated to a platform-specific layer, and I'm not sure how. Maybe allow platforms to override the
set_rateops in the clock tree building blocks, or a new op that can determine the new tree structure, and call the oldset_rateop to set the registers.
yeah, getting these constraints solved automatically is pretty expensive. some heuristics are probably indicated here.
Signature · 1 line
torben Hohn
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Russell King - ARM LinuxQuoted 11 lines · Russell King - ARM Linux
Quoted 3 lines · Thomas Gleixner
This are all well defined semantical problems and should be solved in common code rather than having different buggy implementations in each SoC clock "framework".
Why are you associating functional elements in
drivers/clkwith the SoC clock framework?I think that's the root cause of this misunderstanding, and until you start realising that these building blocks are not part of the SoC implementation, we're going to continue arguing about this.
Ok, the discussion went down hill real quick after this point. So, I will start from here.
I will try and propose what I think might be a reasonable compromise based on what I have seen so far.
I think Thomas mostly cares about having the tree handling done at the core code level. Russell's main point seems to be that the parent can change for reasons other than "clk_set_parent()" and hence we can have the core code manage all of the parent handling.
The parent of a clock can really change for only two reasons (based on my experience with clocks -- in no way extensive, but not insignificant either):
* clk_set_rate() -- where the set rate code takes care of selecting the right parent for a given rate.
* clk_set_parent() -- where the "clk" is just a mux of a random bunch of inputs and we just allow the caller to pick the mux input. The clock framework might not even know what the rate/characteristic (jitter, duty cycle, etc) of the input are since some of them could come from an external source that's board specific.
A simple compromise might be to have the generic/base clk structure have a "parent" field. Then the generic clk_set_parent() and clk_set_rate() would grab the clock's mutex (currently named prepare_lock) before calling the clk->ops->set_rate/set_parent. I already suggested grabbing this mutex when Jeremy's patches were being review, but it was put off for later/Soc specific code (forgot what the decision was). That's why we see a might_sleep() in his clk_set_rate().
With the above suggestion, the Soc specific code can change the parent all it wants and the core code can still do the tree handling in clk_prepare/clk_unprepare (they already grab the mutex).
Although this might not be what each side wants, I think this is a reasonable compromise.
Thomas/Russell, Does it sound acceptable to both of you?
We can go to the per-clock vs. per-tree locking after we can agree on this. My current opinion (can change easily) is that while per-tree locking might be nice, it might be hard/ugly to capture it in the data structures. Per-clock locking will allow the soc-specific code which has a better idea of the tree to do per-tree locking internally while allowing the core code to handle propagating enable/disable up the tree.
Thanks,
Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 4 lines · Saravana Kannan
I think Thomas mostly cares about having the tree handling done at the core code level. Russell's main point seems to be that the parent can change for reasons other than "
clk_set_parent()" and hence we can have the core code manage all of the parent handling.
Typo. Meant to say:
and hence we can't have the core code manage all of the parent handling.
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Uwe Kleine-KönigQuoted 8 lines · Uwe Kleine-K?nig
Quoted 1 line · Thomas Gleixner
- a field for the current clock rate
Then you need a mechanism to notify the children if the rate or parent of a clock changes. I assume you won't allow that for a clock that has more than one (enabled) consumer. Knowing only very few platforms I don't know if that is something you can forbid.
I suspect you need it - cpufreq style scaling of the core clocks (which many SoCs can do) involves pretty much the entire clock tree, though obviously the idea is that the effects get hidden at the edges.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 5 lines · Mark Brown
Quoted 3 lines · Uwe Kleine-K?nig
Quoted 1 line · Thomas Gleixner
- a field for the current clock rate
Quoted 8 lines
Quoted 4 lines
Then you need a mechanism to notify the children if the rate or parent of a clock changes. I assume you won't allow that for a clock that has more than one (enabled) consumer. Knowing only very few platforms I don't know if that is something you can forbid.
I suspect you need it - cpufreq style scaling of the core clocks (which many SoCs can do) involves pretty much the entire clock tree, though obviously the idea is that the effects get hidden at the edges.
That's correct, scaling of the whole clock tree is needed for cpufreq and DVFS. An example is scaling of the L3 bus on omaps.
Tony
Sascha Hauer
maintainerRFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Thomas GleixnerQuoted 50 lines · Thomas Gleixner
Quoted 5 lines · Uwe Kleine-K?nig
Quoted 3 lines · Thomas Gleixner
On Wed, 20 Apr 2011, Uwe Kleine-K?nig wrote:
Very useful changelog.
IMHO OK for a RFC patch.
Not at all.
Quoted 7 lines
Quoted 7 lines
And this whole mess should be written:
ret = clk_prepare(clk->parent); if (ret) return ret;Quoted 5 lines
Quoted 3 lines
Which returns 0 when there is no parent and it also returns 0 when there is no prepare callback for the parent. Why the hell do we need all this ERRPTR checking mess and all this conditional crap ?
struct clk has no parent member, there is only
clk_get_parent(). IfWhich is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Because someone claimed, that you need a callback to make it safe from changing? Or what's the reason for this?
Quoted 4 lines
there is no parent it returns
ERR_PTR(-ENOSYS)and if you pass that toclk_prepareit tries to dereference it. So either it must not be called with an error pointer orclk_prepareet al. need adaption to handleThe whole clk struct is an utter failure.
It's simply the least common denominator of all clk madness in the tree. Which results in a half documented data structure and a handful helper functions of which most of them are exported, though the functionality in them is less than the overhead of the
EXPORT_SYMBOL.That's not an abstraction and neither it's a framework. It's a half arsed conglomorate of primitives w/o the minimal documentation how those primitives should be used and why they are there in the first place.
This is new code and it should be aimed to cleanup things not to shuffle things around in a frenzy.
So what's wrong with that code:
Quoted 8 lines
1) struct clk is just a collection of function pointers and two locks
It lacks:
- a flag field for properties
- a field for the parent
- a field for the current clock rate
Currently there is no possibility to bring the clock tree in sync with the hardware. clocks are not registered at all, they are just there. So there is no instance who could iterate over the tree in order to bring it in sync. Unless we create that (which I would like) there is no point in adding rate and parent fields.
Hm, thinking about this maybe we could add a CLK_IN_SYNC field which is initially cleared and gets set once the get_parent()/get_rate() callback has been called for a clock.
Quoted 3 lines
- a field for the base register
- a struct for the offsets of the most common registers relative to base
What's wrong with embedding struct clk into a more specific clock and access it with container_of()? It must be done anyway once a field is missing in struct clk, or we end up with a lot of fields in struct clk which are used in only few types of clocks.
Quoted 3 lines
The least thing which we need now are half baken "abstractions" which just shuffle code around for no value.
While I agree with several things you say even the half baken abstractions help to bring the problems into the light. What we have now is that all these problems are hidden in SoC specific abstractions which all have their own problems and bugs.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 9 lines · Sascha Hauer
Quoted 2 lines · Thomas Gleixner
- a field for the parent
- a field for the current clock rateCurrently there is no possibility to bring the clock tree in sync with the hardware. clocks are not registered at all, they are just there. So there is no instance who could iterate over the tree in order to bring it in sync. Unless we create that (which I would like) there is no point in adding rate and parent fields.
And that's where the problem starts. What's the point of that current conglomorate of function pointers and half baken helper wrappers if we don't have answers for how to populate the clk tree, how to simplify stuff w/o the need of tons of callbacks which have to be implemented all over the place ?
Quoted 4 lines
Hm, thinking about this maybe we could add a
CLK_IN_SYNCfield which is initially cleared and gets set once the get_parent()/get_rate() callback has been called for a clock.
Quoted 8 lines
Quoted 3 lines
- a field for the base register
- a struct for the offsets of the most common registers relative to baseWhat's wrong with embedding struct clk into a more specific clock and access it with
container_of()? It must be done anyway once a field is missing in struct clk, or we end up with a lot of fields in struct clk which are used in only few types of clocks.
As I explained already, that's the whole purpose of frameworks. See clockevents, clocksource, genirq. Lots of stuff is only used by a very small subset, but it's better to have that in common code than growing warts at all ends.
Quoted 8 lines
Quoted 3 lines
The least thing which we need now are half baken "abstractions" which just shuffle code around for no value.
While I agree with several things you say even the half baken abstractions help to bring the problems into the light. What we have now is that all these problems are hidden in SoC specific abstractions which all have their own problems and bugs.
And sadly enough the proposed solution keeps 90% of that crap where it is. So it's not a real improvement, just shuffling code around.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 12 lines · Thomas Gleixner
Quoted 10 lines · Sascha Hauer
Quoted 3 lines · Thomas Gleixner
- a field for the base register
- a struct for the offsets of the most common registers relative to baseWhat's wrong with embedding struct clk into a more specific clock and access it with
container_of()? It must be done anyway once a field is missing in struct clk, or we end up with a lot of fields in struct clk which are used in only few types of clocks.
Quoted 4 lines
As I explained already, that's the whole purpose of frameworks. See clockevents, clocksource, genirq. Lots of stuff is only used by a very small subset, but it's better to have that in common code than growing warts at all ends.
There's nothing intrinsic about the concept of a clock which means that it needs to be memory mapped or have a particular set of registers for us to work with. This sounds like something that ought to be factored out but it's not obvious to me that it should be part of the core struct.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 18 lines · Mark Brown
Quoted 12 lines · Thomas Gleixner
Quoted 10 lines · Sascha Hauer
Quoted 3 lines · Thomas Gleixner
- a field for the base register
- a struct for the offsets of the most common registers relative to baseWhat's wrong with embedding struct clk into a more specific clock and access it with
container_of()? It must be done anyway once a field is missing in struct clk, or we end up with a lot of fields in struct clk which are used in only few types of clocks.Quoted 4 lines
As I explained already, that's the whole purpose of frameworks. See clockevents, clocksource, genirq. Lots of stuff is only used by a very small subset, but it's better to have that in common code than growing warts at all ends.
Quoted 4 lines
There's nothing intrinsic about the concept of a clock which means that it needs to be memory mapped or have a particular set of registers for us to work with. This sounds like something that ought to be factored out but it's not obvious to me that it should be part of the core struct.
Care to look over the various implementations and find out that a lot of them look like:
static int _clk_enable(struct clk *clk)
{
unsigned int reg;
reg = __raw_readl(clk->enable_reg);
reg |= 1 << clk->enable_shift;
__raw_writel(reg, clk->enable_reg);
return 0;
}Just in about 100 variations of the theme. Which is basically the same as we have in irq chip implementations. And I showed how much of these things can be factored out when done right. And even if a particular clock does not implement enable/disable calls, then having regs.enable_reg around is not a problem.
That's not a requirement for the first step, but I want to see people thinking about it instead of mindlessly converting their clocks to the generic clock structure and the generic handling functions. And I'd rather see people coming and say: We see that the following thing would be cute:
clk_regs {
struct spin_lock *reg_lock;
void *base;
union {
void *enable_reg;
unsigned long enable_offset;
};
....
u32 enable_cache;
};Because that's what we implement via container_of now. And we can add such stuff which is obvious right away.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 9 lines · Thomas Gleixner
Quoted 4 lines · Mark Brown
There's nothing intrinsic about the concept of a clock which means that it needs to be memory mapped or have a particular set of registers for us to work with. This sounds like something that ought to be factored out but it's not obvious to me that it should be part of the core struct.
Care to look over the various implementations and find out that a lot of them look like:
Please bear in mind that due to the fact that we've currently got one clock implementation per subarchitecture anything off-SoC has some serious barriers to implementation in kernel. For the system management units you'd be looking at very new systems, this is a new development.
Quoted 5 lines
Just in about 100 variations of the theme. Which is basically the same as we have in irq chip implementations. And I showed how much of these things can be factored out when done right. And even if a particular clock does not implement enable/disable calls, then having regs.enable_reg around is not a problem.
This is why I said "This sounds like something that ought to be factored out but it's not obvious to me that it should be part of the core struct" above - I agree strongly that we should have a generic memory mapped implementation which factors out all the redundant code you'd get for these clocks.
Quoted 2 lines
Because that's what we implement via
container_ofnow. And we can add such stuff which is obvious right away.
That's exactly the sort of thing I'm suggesting. You were asking for this to be part of struct clk itself, embedding the struct clk in a struct mm_clk (or whatever) and having standard ops for the mm_clk a much better abstraction.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 8 lines · Mark Brown
Quoted 6 lines · Thomas Gleixner
Quoted 4 lines · Mark Brown
There's nothing intrinsic about the concept of a clock which means that it needs to be memory mapped or have a particular set of registers for us to work with. This sounds like something that ought to be factored out but it's not obvious to me that it should be part of the core struct.
Quoted 7 lines
Quoted 2 lines
Care to look over the various implementations and find out that a lot of them look like:
Please bear in mind that due to the fact that we've currently got one clock implementation per subarchitecture anything off-SoC has some serious barriers to implementation in kernel. For the system management units you'd be looking at very new systems, this is a new development.
How many arch have off-soc clocks? Where's the source?
At least for arm, nearly all is memory mapped clock registers. clk is free to override, we just need abstract the most common things.
Thanks
Richard
Quoted 26 lines
Quoted 6 lines
Just in about 100 variations of the theme. Which is basically the same as we have in irq chip implementations. And I showed how much of these things can be factored out when done right. And even if a particular clock does not implement enable/disable calls, then having regs.enable_reg around is not a problem.
This is why I said "This sounds like something that ought to be factored out but it's not obvious to me that it should be part of the core struct" above - I agree strongly that we should have a generic memory mapped implementation which factors out all the redundant code you'd get for these clocks.
Quoted 2 lines
Because that's what we implement via
container_ofnow. And we can add such stuff which is obvious right away.That's exactly the sort of thing I'm suggesting. You were asking for this to be part of struct clk itself, embedding the struct clk in a struct
mm_clk(or whatever) and having standard ops for themm_clka much better abstraction._______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 10 lines · Richard Zhao
Quoted 4 lines · Mark Brown
Please bear in mind that due to the fact that we've currently got one clock implementation per subarchitecture anything off-SoC has some serious barriers to implementation in kernel. For the system management units you'd be looking at very new systems, this is a new development.
How many arch have off-soc clocks? Where's the source?
At least for arm, nearly all is memory mapped clock registers. clk is free to override, we just need abstract the most common things.
Even for many ARMs it's common for the clock tree to be rooted in the PMIC (since it will always be on), and of course the full system clock tree will not just include the CPU but also any other digital components in the system.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 8 lines · Mark Brown
Quoted 6 lines · Richard Zhao
Quoted 4 lines · Mark Brown
Please bear in mind that due to the fact that we've currently got one clock implementation per subarchitecture anything off-SoC has some serious barriers to implementation in kernel. For the system management units you'd be looking at very new systems, this is a new development.
Quoted 8 lines
Quoted 3 lines
How many arch have off-soc clocks? Where's the source?
At least for arm, nearly all is memory mapped clock registers. clk is free to override, we just need abstract the most common things.Even for many ARMs it's common for the clock tree to be rooted in the PMIC (since it will always be on), and of course the full system clock tree will not just include the CPU but also any other digital components in the system.
Yes, I see pmic or other on-board osc may be clock source. I just didn't realize anyone will put them to clk.
Thanks
Richard
Quoted 5 lines
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 9 lines · Richard Zhao
Quoted 4 lines · Mark Brown
Even for many ARMs it's common for the clock tree to be rooted in the PMIC (since it will always be on), and of course the full system clock tree will not just include the CPU but also any other digital components in the system.
Yes, I see pmic or other on-board osc may be clock source. I just didn't realize anyone will put them to clk.
My point here is that right now nobody does anything like that unless they really have to in part because this then makes the driver for the off-SoC chip get tied in to the chip clock structure.
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Thomas GleixnerQuoted 14 lines · Thomas Gleixner
Care to look over the various implementations and find out that a lot of them look like:
static int
_clk_enable(struct clk *clk){ unsigned int reg; reg = __raw_readl(clk->enable_reg); reg |= 1 << clk->enable_shift; __raw_writel(reg, clk->enable_reg); return 0; }
Quoted 5 lines
Just in about 100 variations of the theme. Which is basically the same as we have in irq chip implementations. And I showed how much of these things can be factored out when done right. And even if a particular clock does not implement enable/disable calls, then having regs.enable_reg around is not a problem.
And you haven't noticed that with how things stand with what Jeremy's proposed, we _can_ abstract this kind of stuff.
Having read a number of your messages, I think you don't like it because you haven't been involved in creating it - I don't think there's anything much more specific than that to your protestations about it.
We _can_ (and I hope we do) factor out the 100 "clock gate" implementations into one instance - and I believe we can do that with Jeremy's proposal.
For those clocks which have an clock gate and a clock mux, we can create two clk structures, one being the clock gate container and one being the clock mux container, even if they're accessing the same register.
Shoving the enable crap into the core framework enforces that every clock has an gate attached to it, which is soo far departed from reality I've got to ask what universe you're living in.
Finally, go look at the OMAP clock structure where they stuff everything into one struct clk:
struct clk {
struct list_head node;
const struct clkops *ops;
const char *name;
struct clk *parent;
struct list_head children;
struct list_head sibling; /* node for children */
unsigned long rate;
void __iomem *enable_reg;
unsigned long (*recalc)(struct clk *);
int (*set_rate)(struct clk *, unsigned long);
long (*round_rate)(struct clk *, unsigned long);
void (*init)(struct clk *);
u8 enable_bit;
s8 usecount;
u8 fixed_div;
u8 flags;
#ifdef CONFIG_ARCH_OMAP2PLUS
void __iomem *clksel_reg;
u32 clksel_mask;
const struct clksel *clksel;
struct dpll_data *dpll_data;
const char *clkdm_name;
struct clockdomain *clkdm;
#else
u8 rate_offset;
u8 src_offset;#endif
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
struct dentry *dent; /* For visible tree hierarchy */
#endif
};
If you start saying "a clock struct should contain enable bit, register address" then you're well on the path to creating a horrid mess like the above. And this is something we _must_ avoid.
So, Jeremy's done the right thing and created a base struct clk which is very much like a kobject, along with a set of methods to operate on it. Around that can be built things like fixed rate clocks, MUXes, gates, PLLs, and everything else which is required with minimal expense
- and all provided by core clk code. And we avoid crappy bloated structures like the thing above.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 17 lines · Russell King - ARM Linux
Quoted 5 lines · Thomas Gleixner
Just in about 100 variations of the theme. Which is basically the same as we have in irq chip implementations. And I showed how much of these things can be factored out when done right. And even if a particular clock does not implement enable/disable calls, then having regs.enable_reg around is not a problem.
And you haven't noticed that with how things stand with what Jeremy's proposed, we _can_ abstract this kind of stuff.
Having read a number of your messages, I think you don't like it because you haven't been involved in creating it - I don't think there's anything much more specific than that to your protestations about it.
We _can_ (and I hope we do) factor out the 100 "clock gate" implementations into one instance - and I believe we can do that with Jeremy's proposal.
Quoted 7 lines
For those clocks which have an clock gate and a clock mux, we can create two clk structures, one being the clock gate container and one being the clock mux container, even if they're accessing the same register.
Shoving the enable crap into the core framework enforces that every clock has an gate attached to it, which is soo far departed from reality I've got to ask what universe you're living in.
Not at all. If a clk has clk->ops->enable() == NULL then you still need to do proper refcounting and descending down the parent tree to make sure, that the parent clocks are enabled.
Quoted 5 lines
};
If you start saying "a clock struct should contain enable bit, register address" then you're well on the path to creating a horrid mess like the above. And this is something we _must_ avoid.
I already have dumped that idea in course of the discussion and yes, we can implement something as a container like I did for the generic irq chip.
Quoted 6 lines
So, Jeremy's done the right thing and created a base struct clk which is very much like a kobject, along with a set of methods to operate on it. Around that can be built things like fixed rate clocks, MUXes, gates, PLLs, and everything else which is required with minimal expense
- and all provided by core clk code. And we avoid crappy bloated structures like the thing above.
I tend to disagree. Yes, he created the minimal common level for a struct clk and the ops around it. But does that change anything about the status quo of duplicated functions walking the tree, duplicated functions to validate and round clock rates? The whole approach will keep the whole code mess in the SoCs the same as it is now and just enforce a common data structure and a dozen wrapper "API" functions around it.
So omap will simply have their bloat in a struct omap_clk() and every other SoC will do the same. The duplicated code, the locking mess etc. will all remain in totally incompatible ways. So what's the win?
I looked at a few new SoC trees and guess what comes along ? Another few copies of existing clock implementations hacked into submission so the thing works on that new hardware.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 11 lines · Thomas Gleixner
I tend to disagree. Yes, he created the minimal common level for a struct clk and the ops around it. But does that change anything about the status quo of duplicated functions walking the tree, duplicated functions to validate and round clock rates? The whole approach will keep the whole code mess in the SoCs the same as it is now and just enforce a common data structure and a dozen wrapper "API" functions around it.
So omap will simply have their bloat in a struct
omap_clk()and every other SoC will do the same. The duplicated code, the locking mess etc. will all remain in totally incompatible ways. So what's the win?
I disagree. With a 'divider+mux' clk, OMAP can move those clocks over. With a 'pll' clk, OMAP can move the PLL stuff over. With a simple enable/disable clk, OMAP can move those over. That's a significant portion of the OMAP clk mess converted over to smaller, much more well defined, self contained clk structures.
I don't see any reason with this why OMAP - or anyone else - should have their own platform_clk structure if we have the necessary building blocks, and provided there is sufficient review to ensure that those building blocks which are found to be lacking get fixed along the way.
As for the locking mess, that's what happens when you try to generalize stuff and end up with a finer locking scheme. The more locks you have, the more complex the locking rules become, and the more problems you encounter with potential deadlocks. And it seems that lockdep also starts to struggle too (as it operates on classes of locks not actual locks.)
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 19 lines · Russell King - ARM Linux
Quoted 11 lines · Thomas Gleixner
I tend to disagree. Yes, he created the minimal common level for a struct clk and the ops around it. But does that change anything about the status quo of duplicated functions walking the tree, duplicated functions to validate and round clock rates? The whole approach will keep the whole code mess in the SoCs the same as it is now and just enforce a common data structure and a dozen wrapper "API" functions around it.
So omap will simply have their bloat in a struct
omap_clk()and every other SoC will do the same. The duplicated code, the locking mess etc. will all remain in totally incompatible ways. So what's the win?I disagree. With a 'divider+mux' clk, OMAP can move those clocks over. With a 'pll' clk, OMAP can move the PLL stuff over. With a simple enable/disable clk, OMAP can move those over. That's a significant portion of the OMAP clk mess converted over to smaller, much more well defined, self contained clk structures.
Quoted 4 lines
I don't see any reason with this why OMAP - or anyone else - should have their own
platform_clkstructure if we have the necessary building blocks, and provided there is sufficient review to ensure that those building blocks which are found to be lacking get fixed along the way.
Agreed. But that's an orthogonal problem to the proper handling of the tree walks, propagation of rates, enable, prepare etc. and common validation functions.
Quoted 6 lines
As for the locking mess, that's what happens when you try to generalize stuff and end up with a finer locking scheme. The more locks you have, the more complex the locking rules become, and the more problems you encounter with potential deadlocks. And it seems that lockdep also starts to struggle too (as it operates on classes of locks not actual locks.)
The per clk locking is not going to work ever except you want to have the trylock dance if you need to propagate changes up the tree and down the tree. So yes, we need per tree locking and I can see the need for the mutex and the spinlock to protect the tree, but you really want to have the logic dealing with those locks and how they both protect the tree in common code and not in some random place.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 6 lines · Thomas Gleixner
The per clk locking is not going to work ever except you want to have the trylock dance if you need to propagate changes up the tree and down the tree. So yes, we need per tree locking and I can see the need for the mutex and the spinlock to protect the tree, but you really want to have the logic dealing with those locks and how they both protect the tree in common code and not in some random place.
rotfl. "per tree locking". That's farsical when you have muxes which select between different distinct trees. That _surely_ is the path to locking mayhem, because the child clocks can have their lock changed beneath them as the mux changes its parent.
I still think you're in a different universe.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 8 lines · Russell King - ARM Linux
Quoted 6 lines · Thomas Gleixner
The per clk locking is not going to work ever except you want to have the trylock dance if you need to propagate changes up the tree and down the tree. So yes, we need per tree locking and I can see the need for the mutex and the spinlock to protect the tree, but you really want to have the logic dealing with those locks and how they both protect the tree in common code and not in some random place.
Quoted 6 lines
rotfl. "per tree locking". That's farsical when you have muxes which select between different distinct trees. That _surely_ is the path to locking mayhem, because the child clocks can have their lock changed beneath them as the mux changes its parent.
I still think you're in a different universe.
No, we just seem to talk past each other a lot.
So what you are referring to is the situation where you have different root clocks and consider them as a separate tree. There are two possible solutions to that:
1) Global locking
2) Per root clock tree locking:
That can be done, when the handling is at the clk_FN() API level.
clk_set_parent(clk, parent)
{
lock_trees(clk, parent);
handle_parent_switch();
unlock_trees(clk, parent); }
That's not a mayhem, as (un)lock_trees() can easily take care of the lock ordering issues.
It's going to be a mayhem if you have lock pointers and lock functions outside of the core code and let random clk implementations fiddle with it.
That's why I'm arguing for moving the tree handling and tree traversal functions one level above the building block abstractions.
Thanks,
tglx
Sascha Hauer
maintainerRFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Thomas GleixnerQuoted 39 lines · Thomas Gleixner
Quoted 9 lines · Sascha Hauer
Quoted 2 lines · Thomas Gleixner
- a field for the parent
- a field for the current clock rateCurrently there is no possibility to bring the clock tree in sync with the hardware. clocks are not registered at all, they are just there. So there is no instance who could iterate over the tree in order to bring it in sync. Unless we create that (which I would like) there is no point in adding rate and parent fields.
And that's where the problem starts. What's the point of that current conglomorate of function pointers and half baken helper wrappers if we don't have answers for how to populate the clk tree, how to simplify stuff w/o the need of tons of callbacks which have to be implemented all over the place ?
Quoted 4 lines
Hm, thinking about this maybe we could add a
CLK_IN_SYNCfield which is initially cleared and gets set once the get_parent()/get_rate() callback has been called for a clock.Quoted 8 lines
Quoted 3 lines
- a field for the base register
- a struct for the offsets of the most common registers relative to baseWhat's wrong with embedding struct clk into a more specific clock and access it with
container_of()? It must be done anyway once a field is missing in struct clk, or we end up with a lot of fields in struct clk which are used in only few types of clocks.As I explained already, that's the whole purpose of frameworks. See clockevents, clocksource, genirq. Lots of stuff is only used by a very small subset, but it's better to have that in common code than growing warts at all ends.
Quoted 4 lines
Quoted 3 lines
The least thing which we need now are half baken "abstractions" which just shuffle code around for no value.
Quoted 7 lines
Quoted 4 lines
While I agree with several things you say even the half baken abstractions help to bring the problems into the light. What we have now is that all these problems are hidden in SoC specific abstractions which all have their own problems and bugs.
And sadly enough the proposed solution keeps 90% of that crap where it is. So it's not a real improvement, just shuffling code around.
That's why I tried to sort out some common patterns (divider, gates, muxes) and put them into drivers/clk for other people to use it. It's enough to build a whole clock tree out of it (except plls and special stuff). All things you mentioned which are missing in the common clock stuff can be added without touching the i.MX specific parts. You want the framework (once it actually is one) to handle the parents? just move the parent handling out of drivers/clk/clk-[divider|mux|gate].c to drivers/clk/clk.c. Refcounting shall be fixed? do so in drivers/clk/clkdev.c.
I didn't say that the patches I posted shall be moved upstream as-is. I only wanted to show how a clock tree can look like when we sort out common patterns.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 10 lines · Sascha Hauer
On Thu, Apr 21, 2011 at 11:21:53AM +0200, Thomas Gleixner wrote:
That's why I tried to sort out some common patterns (divider, gates, muxes) and put them intodrivers/clkfor other people to use it. It's enough to build a whole clock tree out of it (except plls and special stuff). All things you mentioned which are missing in the common clock stuff can be added without touching the i.MX specific parts. You want the framework (once it actually is one) to handle the parents? just move the parent handling out of drivers/clk/clk-[divider|mux|gate].c todrivers/clk/clk.c. Refcounting shall be fixed? do so indrivers/clk/clkdev.c.
The point is that we want to do stuff like that now - BEFORE anyone starts using struct clk and the helper functions.
Quoted 3 lines
I didn't say that the patches I posted shall be moved upstream as-is. I only wanted to show how a clock tree can look like when we sort out common patterns.
We really want to get some sensible functionality for starting.
So what I can see now from the discussion is that we should at least add the following fields to struct clk:
unsigned long flags;
unsigned long rate;
struct clk *parent;
unsigned int users;Add the parent propagation to the clk_enable disable prepare unprepare functions.
And we should add right away:
struct hlist_head childs;
struct hlist_node node;Plus infrastructure to register clocks with the parent. Advanced things like bottom up propagation of clock rate changes is something we can do later, but we really want to make proper registration a required change for users of the new stuff.
That brings in another question and this really needs to be answered
now: Locking
I'm pushing hard on this because I know that retrofitting proper locking schemes is going to be a nightmare.
You already have a lock nesting problem when you do parent propagation. With your code you do the parent propagation in the child callback under the prepare_mutex or the enable_lock.
This is going to end up in lockdep being quite unhappy unless you want tons of different lock classes for this stuff. i.e.
clk_prepare(clk2) mutex_lock(clk2->mutex); clk->prepare(clk); clk_prepare(clk1) mutex_lock(clk1->mutex);
And you _CANNOT_ call clk1->prepare() from your clk2 prepare function as it would forgo the serialization and the prepare refcounting. And this kind of scheme is going to be even more problematic if you do bottom up propagation because you will run into lock inversion.
I seriously doubt that the fine grained per clock locking is going to work out at all.
How do you protect changes to the tree hierarchy against a traversal of a concurrent clk->prepare... propagation? Not at all, because you CANNOT. And you cannot use RCU for this either.
So what's the point of the per clk locks? I can't see one at all.
All those callbacks are not high frequency called functions, so if you want to make this a true framework which deals with tons of interesting stuff like propagation, reparenting and rate changes from bottom up then there is only one way to do that: global serialization.
There is no way around that. Everything else is going to be the locking hell and racy all over the place.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 33 lines · Thomas Gleixner
That brings in another question and this really needs to be answered
now: LockingI'm pushing hard on this because I know that retrofitting proper locking schemes is going to be a nightmare.
You already have a lock nesting problem when you do parent propagation. With your code you do the parent propagation in the child callback under the
prepare_mutexor theenable_lock.This is going to end up in lockdep being quite unhappy unless you want tons of different lock classes for this stuff. i.e.
? ?
clk_prepare(clk2)
? ? ? ?mutex_lock(clk2->mutex);
? ? ? ? ?clk->prepare(clk);
? ? ? ? ? ? ? ?clk_prepare(clk1)
? ? ? ? ? ? ? ? ? ?mutex_lock(clk1->mutex);And you _CANNOT_ call
clk1->prepare()from your clk2 prepare function as it would forgo the serialization and the prepare refcounting. And this kind of scheme is going to be even more problematic if you do bottom up propagation because you will run into lock inversion.I seriously doubt that the fine grained per clock locking is going to work out at all.
How do you protect changes to the tree hierarchy against a traversal of a concurrent
clk->prepare... propagation? Not at all, because you CANNOT. And you cannot use RCU for this either.So what's the point of the per clk locks? I can't see one at all.
Quoted 7 lines
All those callbacks are not high frequency called functions, so if you want to make this a true framework which deals with tons of interesting stuff like propagation, reparenting and rate changes from bottom up then there is only one way to do that: global serialization.
There is no way around that. Everything else is going to be the locking hell and racy all over the place.
Per clock locks are useful if you have some very slow clocks and some very fast clocks. PLLs may take 20 ms to lock, and preventing any other call to clk_prepare for that long could be problematic. The problem was worse before the clk_enable/clk_prepare split, maybe it's not necessary at all any more.
For Tegra, I solved my clock locking problems by (almost) always locking from child to parent, the normal case for clk_enable/clk_prepare. In general, you only need to lock parent and then child if you store the rate of the child in the child's clk struct and need to update it when the parent changes, or when traversing the tree for debugging output. I solved the first problem by storing the relation between the child and the parent in the child struct and locking from child to parent on clk_get_rate calls to calculate the rate, and the second by using a trylock loop over the list of clocks (see arch/arm/mach-tegra/clock.c).
Now that clk_prepare and clk_enable are split, the long-held locks (for plls, maybe dvfs?) are separated from the short-held locks for clk_enable/clk_disable, and the cost of global serialization is much more acceptable.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 10 lines · Colin Cross
Quoted 2 lines · Thomas Gleixner
There is no way around that. Everything else is going to be the locking hell and racy all over the place.
Per clock locks are useful if you have some very slow clocks and some very fast clocks. PLLs may take 20 ms to lock, and preventing any other call to
clk_preparefor that long could be problematic. The problem was worse before the clk_enable/clk_prepare split, maybe it's not necessary at all any more.
Quoted 10 lines
For Tegra, I solved my clock locking problems by (almost) always locking from child to parent, the normal case for clk_enable/clk_prepare. In general, you only need to lock parent and then child if you store the rate of the child in the child's clk struct and need to update it when the parent changes, or when traversing the tree for debugging output. I solved the first problem by storing the relation between the child and the parent in the child struct and locking from child to parent on
clk_get_ratecalls to calculate the rate, and the second by using a trylock loop over the list of clocks (seearch/arm/mach-tegra/clock.c).
Yes, and that's exaclty what we don't want to have. You still need a global lock for doing the full tree acquisition and the only advantage which is left is that you can do parallel prepare/unprepare and everything else (parent settings, rate propagations) will need to do the locking dance.
And the bad thing about your approach is that it requires a full tree lock acquisition all the time, while the real operation might be just affecting 3 clocks out of 50. To avoid that you'd need to do the trylock dance over the child list.
I doubt it's worth the trouble, really.
Quoted 4 lines
Now that
clk_prepareandclk_enableare split, the long-held locks (for plls, maybe dvfs?) are separated from the short-held locks for clk_enable/clk_disable, and the cost of global serialization is much more acceptable.
Right. And that's how we start. Simple. If it turns out to be a real issue, then we can revisit the fine grained locking approach, but I really want to avoid it as far as possible.
Another thing I'm pondering is to provide the ability to maintain separate clk trees. So you can have individual domains which have their per clk tree locking. Would that make sense ?
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 7 lines · Thomas Gleixner
On Thu, 21 Apr 2011, Colin Cross wrote:
Yes, and that's exaclty what we don't want to have. You still need a global lock for doing the full tree acquisition and the only advantage which is left is that you can do parallel prepare/unprepare and everything else (parent settings, rate propagations) will need to do the locking dance.
And worse with the prepare/unprepare separation you need to do the lock dance twice in some cases. Once for the mutex and once for the spinlock. Not really a intriguing idea.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Thomas GleixnerQuoted 3 lines · Thomas Gleixner
Another thing I'm pondering is to provide the ability to maintain separate clk trees. So you can have individual domains which have their per clk tree locking. Would that make sense ?
Clock trees are likely to be linked somewhere - an external clock chip that drives the main clock input on the SoC, or an SoC clock output that drives a chip with an internal clock tree. Domains would have to be dynamically managed to ensure two clocks from different clock chips that become linked are moved under the same clock lock. Probably easier to keep a global lock.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 11 lines · Colin Cross
Quoted 3 lines · Thomas Gleixner
Another thing I'm pondering is to provide the ability to maintain separate clk trees. So you can have individual domains which have their per clk tree locking. Would that make sense ?
Clock trees are likely to be linked somewhere - an external clock chip that drives the main clock input on the SoC, or an SoC clock output that drives a chip with an internal clock tree. Domains would have to be dynamically managed to ensure two clocks from different clock chips that become linked are moved under the same clock lock. Probably easier to keep a global lock.
Ok. It's easy enough to split later if the need arises.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 7 lines · Thomas Gleixner
Quoted 5 lines · Colin Cross
Quoted 3 lines · Thomas Gleixner
Another thing I'm pondering is to provide the ability to maintain separate clk trees. So you can have individual domains which have their per clk tree locking. Would that make sense ?
Quoted 8 lines
Quoted 6 lines
Clock trees are likely to be linked somewhere - an external clock chip that drives the main clock input on the SoC, or an SoC clock output that drives a chip with an internal clock tree. Domains would have to be dynamically managed to ensure two clocks from different clock chips that become linked are moved under the same clock lock. Probably easier to keep a global lock.
Ok. It's easy enough to split later if the need arises.
MSM certainly has the need for having independent clock trees. I would like support for this to be in from the start otherwise it's going to really screw clocks in one of the trees.
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 16 lines · Saravana Kannan
Quoted 15 lines · Thomas Gleixner
Quoted 12 lines · Colin Cross
Quoted 3 lines · Thomas Gleixner
Another thing I'm pondering is to provide the ability to maintain separate clk trees. So you can have individual domains which have their per clk tree locking. Would that make sense ?
Clock trees are likely to be linked somewhere - an external clock chip that drives the main clock input on the SoC, or an SoC clock output that drives a chip with an internal clock tree. Domains would have to be dynamically managed to ensure two clocks from different clock chips that become linked are moved under the same clock lock. Probably easier to keep a global lock.
Quoted 5 lines
Quoted 1 line
Ok. It's easy enough to split later if the need arises.
MSM certainly has the need for having independent clock trees. I would like support for this to be in from the start otherwise it's going to really screw clocks in one of the trees.
Are they completely independent or do you need a global synchronization mechanism between those clock trees as well ?
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 24 lines · Thomas Gleixner
Quoted 16 lines · Saravana Kannan
Quoted 15 lines · Thomas Gleixner
Quoted 12 lines · Colin Cross
Quoted 3 lines · Thomas Gleixner
Another thing I'm pondering is to provide the ability to maintain separate clk trees. So you can have individual domains which have their per clk tree locking. Would that make sense ?
Clock trees are likely to be linked somewhere - an external clock chip that drives the main clock input on the SoC, or an SoC clock output that drives a chip with an internal clock tree. Domains would have to be dynamically managed to ensure two clocks from different clock chips that become linked are moved under the same clock lock. Probably easier to keep a global lock.
Quoted 5 lines
Quoted 1 line
Ok. It's easy enough to split later if the need arises.
MSM certainly has the need for having independent clock trees. I would like support for this to be in from the start otherwise it's going to really screw clocks in one of the trees.
Quoted 6 lines
Are they completely independent or do you need a global synchronization mechanism between those clock trees as well ?
Thanks,
tglx
They are completely independent. No synchronization is needed between these clock trees. It's basically a bunch of clocks controlled by another processor that has it's own set of PLLs, etc.
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 4 lines · Saravana Kannan
They are completely independent. No synchronization is needed between these clock trees. It's basically a bunch of clocks controlled by another processor that has it's own set of PLLs, etc.
In fact the common struct clk work that Jeremy picked up from initial patches I did for powerpc was intended for just that ... ie by moving the implementation out to have the clock "provider" being the one creating the clock objects.
There's many other similar cases, ie, you can have a multifunction device (wifi + bt + mmc reader for example) which has its own internal clock network and might want to use struct clk to handle clocks between those parts.
None of that should sit in the arch or platform code.
In fact, with the device-tree, you could completely represent the binding between those objects without involving any platform code, that was the original intend and I hope that ARM eventually gets there.
Cheers,
Ben.
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Thomas GleixnerQuoted 75 lines · Thomas Gleixner
Quoted 10 lines · Sascha Hauer
On Thu, Apr 21, 2011 at 11:21:53AM +0200, Thomas Gleixner wrote:
That's why I tried to sort out some common patterns (divider, gates, muxes) and put them intodrivers/clkfor other people to use it. It's enough to build a whole clock tree out of it (except plls and special stuff). All things you mentioned which are missing in the common clock stuff can be added without touching the i.MX specific parts. You want the framework (once it actually is one) to handle the parents? just move the parent handling out of drivers/clk/clk-[divider|mux|gate].c todrivers/clk/clk.c. Refcounting shall be fixed? do so indrivers/clk/clkdev.c.The point is that we want to do stuff like that now - BEFORE anyone starts using struct clk and the helper functions.
Quoted 3 lines
I didn't say that the patches I posted shall be moved upstream as-is. I only wanted to show how a clock tree can look like when we sort out common patterns.
We really want to get some sensible functionality for starting.
So what I can see now from the discussion is that we should at least add the following fields to struct clk:
unsigned long flags; unsigned long rate; struct clk *parent; unsigned int users;Add the parent propagation to the
clk_enabledisable prepare unprepare functions.And we should add right away:
struct hlist_head childs; struct hlist_node node;Plus infrastructure to register clocks with the parent. Advanced things like bottom up propagation of clock rate changes is something we can do later, but we really want to make proper registration a required change for users of the new stuff.
That brings in another question and this really needs to be answered
now: LockingI'm pushing hard on this because I know that retrofitting proper locking schemes is going to be a nightmare.
You already have a lock nesting problem when you do parent propagation. With your code you do the parent propagation in the child callback under the
prepare_mutexor theenable_lock.This is going to end up in lockdep being quite unhappy unless you want tons of different lock classes for this stuff. i.e.
clk_prepare(clk2) mutex_lock(clk2->mutex); clk->prepare(clk); clk_prepare(clk1) mutex_lock(clk1->mutex);And you _CANNOT_ call
clk1->prepare()from your clk2 prepare function as it would forgo the serialization and the prepare refcounting. And this kind of scheme is going to be even more problematic if you do bottom up propagation because you will run into lock inversion.I seriously doubt that the fine grained per clock locking is going to work out at all.
How do you protect changes to the tree hierarchy against a traversal of a concurrent
clk->prepare... propagation? Not at all, because you CANNOT. And you cannot use RCU for this either.So what's the point of the per clk locks? I can't see one at all.
Quoted 7 lines
All those callbacks are not high frequency called functions, so if you want to make this a true framework which deals with tons of interesting stuff like propagation, reparenting and rate changes from bottom up then there is only one way to do that: global serialization.
There is no way around that. Everything else is going to be the locking hell and racy all over the place.
We (MSM guys) had to go thru this thought process when we did some internal reorg of the clock code. Per clock locks prevent us from slowing down clock manipulation of some fast clocks when there is another call going on to manipulate slow clocks. There are some clocks that are not controlled by writing to registers directly and they are extremely slow compared to the usual set of clocks.
One thing we did to handle the locking issue was to have a lock per "class" of clocks. For example, we had one lock for clocks controlled by writing to registers, one lock for voting clocks that just do aggregation and one lock for these extremely slow clocks. Since each class of clocks are generally implemented in their own file, having one lock per class was just a matter of declaring a static-global lock inside the file and grabbing it before you do any transaction.
For example, there are some clocks that need to disable all the children before changing their rate. So, what happens if someone calls clk_enable() on the child when the parent is going thru a set rate process. Since both these will grab the same "fast clocks lock", we don't have any problems.
(Just read Colin's email)
As Colin said in his email, a global lock is less of an issue with the clk_prepare/unprepare() APIs now in place. But even among prepare/unprepare or enable/disable, some clocks might take much longer than others. For example, prepare for a clock might just need enabling a PLL, but for another clock it might need enabling a PLL and increasing some voltage. If the voltage control is going to go thru I2C, then it's going to be pretty bad for the other clock doing the prepare.
I think if we have the parent/child relationship captured in the generic framework, we might be able to get away with per clock locking if we always make sure we grab the locks in a top-down or bottom-up fashion. We could even throw in some flags if we know that a clock will have a stable parent (one that doesn't change rates or need to lock children) to reduce how deep we have to traverse the tree.
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 11 lines · Saravana Kannan
Quoted 2 lines · Thomas Gleixner
I seriously doubt that the fine grained per clock locking is going to work out at all.
One thing we did to handle the locking issue was to have a lock per "class" of clocks. For example, we had one lock for clocks controlled by writing to registers, one lock for voting clocks that just do aggregation and one lock for these extremely slow clocks. Since each class of clocks are generally implemented in their own file, having one lock per class was just a matter of declaring a static-global lock inside the file and grabbing it before you do any transaction.
So you are talking about clock trees which are completely independent of each other where you can never have any relationship between them?
Quoted 7 lines
As Colin said in his email, a global lock is less of an issue with the clk_prepare/unprepare() APIs now in place. But even among prepare/unprepare or enable/disable, some clocks might take much longer than others. For example, prepare for a clock might just need enabling a PLL, but for another clock it might need enabling a PLL and increasing some voltage. If the voltage control is going to go thru I2C, then it's going to be pretty bad for the other clock doing the prepare.
Right, but that's pretty unavoidable if you need to do proper propagation. And really we need to be able to traverse the tree in both directions.
Quoted 3 lines
I think if we have the parent/child relationship captured in the generic framework, we might be able to get away with per clock locking if we always make sure we grab the locks in a top-down or bottom-up fashion. We could even
You _CANNOT_ make sure that you traverse only in one direction and with clocks which can be associated to different parents its going to be even worse as you can create arbitrary lock orders that way.
Quoted 3 lines
throw in some flags if we know that a clock will have a stable parent (one that doesn't change rates or need to lock children) to reduce how deep we have to traverse the tree.
Yes, we can be clever about how deep we traverse, but that's an optimization and not a design decision. But we won't go to a point, where we make locking conditional on a flag. That's broken by definition.
We can add support for completely independent clock trees and make the "global" locking per tree, but that's as far as it will go. Everything else will result in a total nightmare. See the locking horror in kernel/rtmutex.c:rt_mutex_adjust_prio_chain(). We'd end up with a way worse mess for protecting eg. parent changes or complex rate propagations.
We still have a mutex and a spinlock and either of them guarentees that the parent child relation ship is not changing during a traversal. So the fast path operations enable/disable require only the spinlock and everything else (parent changes and rate settings) need to be protected by the mutex simply because we can't do that with spinlocks held and interrupts disabled.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Thomas GleixnerQuoted 5 lines · Thomas Gleixner
Quoted 1 line · Uwe Kleine-K?nig
struct clk has no parent member, there is only
clk_get_parent(). IfWhich is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Thomas, you're wrong. You're looking at things far too simply, because all you can see is a tree of clocks.
When you have MUXes, a clock can have one of many parents. So a single clk->parent doesn't hack it. That's one reason why clk_get_parent() exists, so that MUXes can return the appropriate parent for the current MUX setting.
You may wish to store the current setting in clk->parent, but I'd argue that's a recipe for things going wrong when the MUX settings differ from the cached clk->parent value. Instead, having clk_get_parent()s implementation return the _current_ parent and let MUXes do the right thing depending on hardware is much easier and more reliably correct.
So I don't agree with you on some of these points.
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 9 lines · Russell King - ARM Linux
Quoted 5 lines · Thomas Gleixner
Quoted 1 line · Uwe Kleine-K?nig
struct clk has no parent member, there is only
clk_get_parent(). IfWhich is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Thomas, you're wrong. You're looking at things far too simply, because all you can see is a tree of clocks.
And that's what it is. Even if the clock can have sevaral possible parents, then there is only one active parent at a time. It's still a tree.
Quoted 4 lines
When you have MUXes, a clock can have one of many parents. So a single
clk->parentdoesn't hack it. That's one reason whyclk_get_parent()exists, so that MUXes can return the appropriate parent for the current MUX setting.
That's only ever needed when you register a clk with the framework to decode the current setting from the hardware.
Quoted 5 lines
You may wish to store the current setting in
clk->parent, but I'd argue that's a recipe for things going wrong when the MUX settings differ from the cachedclk->parentvalue. Instead, having clk_get_parent()s implementation return the _current_ parent and let MUXes do the right thing depending on hardware is much easier and more reliably correct.
If something changes the clk parent in the hardware without going through common framework functions, which take care of updating clk->parent in the proper way, then the implementer got it wrong badly. That's the same thing as if you change the clock rate of your timekeeping clock behind the timekeeping core and then complain about timekeeping going awry.
Thanks,
tglx
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 30 lines · Thomas Gleixner
Quoted 9 lines · Russell King - ARM Linux
Quoted 5 lines · Thomas Gleixner
Quoted 1 line · Uwe Kleine-K?nig
struct clk has no parent member, there is only
clk_get_parent(). IfWhich is a complete failure to begin with. Why the heck do you need a callback to figure that out?
Thomas, you're wrong. You're looking at things far too simply, because all you can see is a tree of clocks.
And that's what it is. Even if the clock can have sevaral possible parents, then there is only one active parent at a time. It's still a tree.
Quoted 4 lines
When you have MUXes, a clock can have one of many parents. So a single
clk->parentdoesn't hack it. That's one reason whyclk_get_parent()exists, so that MUXes can return the appropriate parent for the current MUX setting.That's only ever needed when you register a clk with the framework to decode the current setting from the hardware.
Quoted 5 lines
You may wish to store the current setting in
clk->parent, but I'd argue that's a recipe for things going wrong when the MUX settings differ from the cachedclk->parentvalue. Instead, having clk_get_parent()s implementation return the _current_ parent and let MUXes do the right thing depending on hardware is much easier and more reliably correct.
Quoted 6 lines
If something changes the clk parent in the hardware without going through common framework functions, which take care of updating
clk->parentin the proper way, then the implementer got it wrong badly. That's the same thing as if you change the clock rate of your timekeeping clock behind the timekeeping core and then complain about timekeeping going awry.
No, the question is whether you cache the parent clock in a pointer, or use an abstraction to obtain the parent clock. It's merely an implementation detail and is not as big a problem as you've been trying to make it out to be.
RFC PATCH 1/1 clk: add support for automatic parent handling
In reply to Uwe Kleine-KönigHi Uwe,
Quoted 27 lines · Uwe Kleine-K?nig
Signed-off-by Uwe Kleine-K?nig <[email protected]>---
Hello,only compile tested so far.
Best regards
Uwedrivers/clk/clk.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 8 ++++++++ 2 files changed, 51 insertions(+), 0 deletions(-)drivers/clk/clk.c +2
-0@@ -14,10 +14,23 @@int clk_prepare (struct clk *clk) {int ret =0 ; +struct clk *parent =ERR_PTR (-ENOSYS );if (!clk)return 0 ; +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) {
drivers/clk/clk.c line 32
Quoted 10 lines
drivers/clk/clk.c +10
-0+ parent =clk_get_parent (clk); + +if (!IS_ERR (parent)) { + ret =clk_prepare (parent); +if (ret) +return ret; + }else if (PTR_ERR (parent) != -ENOSYS ) +/* -ENOSYS means no parent and is OK */ +return PTR_ERR (parent); + }
Is this supposed to be in prepare_lock? If prepare_count > 1, we need do nothing. Other parent operations need to be in lock protect too.
Thanks
Richard
Quoted 114 lines
drivers/clk/clk.c +31
-0+mutex_lock (&clk->prepare_lock);if (clk->prepare_count ==0 && clk->ops->prepare) ret = clk->ops->prepare (clk);@@ -26,6 +39,9 @@ int clk_prepare(struct clk *clk) clk->prepare_count++;mutex_unlock (&clk->prepare_lock); +if (ret && !IS_ERR (parent)) +clk_unprepare (parent); +return ret; }EXPORT_SYMBOL_GPL (clk_prepare);@@ -45,6 +61,12 @@ void clk_unprepare(struct clk *clk) }mutex_unlock (&clk->prepare_lock); + +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) { +struct clk *parent =clk_get_parent (clk); +if (!IS_ERR (parent)) +clk_unprepare (parent); + } }EXPORT_SYMBOL_GPL (clk_unprepare);@@ -52,10 +74,22 @@ int clk_enable(struct clk *clk) {unsigned long flags;int ret =0 ; +struct clk *parent =ERR_PTR (-ENOSYS );if (!clk)return 0 ; +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) { + parent =clk_get_parent (clk); +if (!IS_ERR (parent)) { + ret =clk_enable (parent); +if (ret) +return ret; + }else if (PTR_ERR (parent) != -ENOSYS ) +/* -ENOSYS means no parent and is OK */ +return PTR_ERR (parent); + } +WARN_ON (clk->prepare_count ==0 );spin_lock_irqsave (&clk->enable_lock, flags);@@ -66,6 +100,9 @@ int clk_enable(struct clk *clk) clk->enable_count++;spin_unlock_irqrestore (&clk->enable_lock, flags); +if (ret && !IS_ERR (parent)) +clk_disable (parent); +return ret; }EXPORT_SYMBOL_GPL (clk_enable);@@ -85,6 +122,12 @@ void clk_disable(struct clk *clk) clk->ops->disable (clk);spin_unlock_irqrestore (&clk->enable_lock, flags); + +if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) { +struct clk *parent =clk_get_parent (clk); +if (!IS_ERR (parent)) +clk_disable (parent); + } }EXPORT_SYMBOL_GPL (clk_disable);include/linux/clk.h +8
-0@@ -62,6 +62,11 @@ struct clk { .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \ } +/* bit definitions for struct clk_ops.flags */ +#define CLK_OPS_GENERIC_PARENT 1/* automatically handle parent in +enable, disable, prepare and +unprepare functions */ +/** * struct clk_ops - Callback operations for clocks; these are to be provided * by the clock implementation, and will be called by drivers through the clk_* @@ -91,6 +96,8 @@ struct clk {* @put: Called by the core clock code when a devices driver releases a * clock via clk_put(). Optional. * +* @flags: see above for possible values. +* * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * implementations to split any work between atomic (enable) and sleepable * (prepare) contexts. If a clock requires sleeping code to be turned on, this @@ -119,6 +126,7 @@ struct clk_ops {int (*set_rate)(struct clk *,unsigned long );int (*set_parent)(struct clk *,struct clk *);struct clk * (*get_parent)(struct clk *); +unsigned int flags; };/** Signature · 7 lines
1.7.4.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel at lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
RFC PATCH 1/1 clk: add support for automatic parent handling
Quoted 28 lines · Richard Zhao
Hi Uwe,
Quoted 26 lines · Uwe Kleine-K?nig
Signed-off-by Uwe Kleine-K?nig <[email protected]>---
Hello,only compile tested so far.
Best regards
Uwedrivers/clk/clk.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 8 ++++++++ 2 files changed, 51 insertions(+), 0 deletions(-)drivers/clk/clk.c +1
-0@@ -14,10 +14,23 @@int clk_prepare (struct clk *clk) {int ret =0 ; +struct clk *parent =ERR_PTR (-ENOSYS );if (!clk)return 0 ;
Quoted 13 lines
drivers/clk/clk.c line 32
Quoted 11 lines
drivers/clk/clk.c +11
-0+if (clk->ops->flags &CLK_OPS_GENERIC_PARENT ) { + parent =clk_get_parent (clk); + +if (!IS_ERR (parent)) { + ret =clk_prepare (parent); +if (ret) +return ret; + }else if (PTR_ERR (parent) != -ENOSYS ) +/* -ENOSYS means no parent and is OK */ +return PTR_ERR (parent); + }Is this supposed to be in
prepare_lock? Ifprepare_count> 1, we need do nothing. Other parent operations need to be in lock protect too.
Yeah, I noticed that myself, too. Also it would be nice to handle the set_parent callback.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
PATCH 4/10 clk: implement parent pass through functions
In reply to Sascha HauerQuoted 2 lines · Sascha Hauer
That's the current behaviour (except that
ERR_PTR(-ENOSYS)is returned instead of NULL).
I think you're getting confused about clk being NULL. Let's take a step backwards shall we?
A NULL clk has no pointers to anything useful. It gets treated by the clk_* functions as a no-op. So, if clk_get_parent() returns NULL, then internally within the clk code, we know that it's going to be reated as a no-op clock. If it's a no-op clock then there is no parent.
The next point is - should clk_get_parent() return NULL? It can do as that's a valid return from clk_get() which is not an error case. Any driver asking for the parent clock should treat it no different from a non-NULL value:
/**
* clk_get_parent - get the parent clock source for this clock
* @clk: clock source
*
* Returns struct clk corresponding to parent clock source, or
* valid IS_ERR() condition containing errno.
*/
struct clk *clk_get_parent(struct clk *clk);
However, internally within the clk API we can make the assumption that a NULL return value means "no clk" because the clk internals is on the clock implementation side of the API dividing line and can deal with this knowledge.
Sascha Hauer
maintainerPATCH 5/10 clk: Add support for simple dividers
In reply to Sascha HauerThis patch adds support for the most common type of divider, which expects a register, width and shift values to desacribe the location of the divider. The divider can be zero based or one based (div = reg_val + 1 vs. div = reg_val).
--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk-divider.c | 132 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 31 +++++++++++ 4 files changed, 167 insertions(+), 0 deletions(-) create mode 100644 drivers/clk/clk-divider.c
drivers/clk/Kconfig +3 -0
@@ -5,3 +5,6 @@ config CLKDEV_LOOKUP config USE_COMMON_STRUCT_CLK bool + +config USE_COMMON_CLK_DIVIDER + bool
drivers/clk/Makefile +1 -0
@@ -1,3 +1,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o +obj-$(CONFIG_USE_COMMON_CLK_DIVIDER) += clk-divider.o
drivers/clk/clk-divider.c new file +132 -0
132 lines not on this page · raw message
include/linux/clk.h +31 -0
@@ -180,6 +180,37 @@ unsigned long clk_parent_get_rate(struct clk *clk);long clk_parent_round_rate (struct clk *clk,unsigned long rate);int clk_parent_set_rate (struct clk *clk,unsigned long rate); +/** +* clock divider +* +* @clk clock source +* @reg register containing the divider +* @shift shift to the divider +* @width width of the divider +* @lock register lock +* @parent parent clock +* +* This clock implements get_rate/set_rate/round_rate. prepare/unprepare and +* enable/disable are passed through to the parent. +* +* The divider is calculated as div = reg_val + 1 +* or if CLK_DIVIDER_FLAG_ONE_BASED is set as div = reg_val +* (with reg_val == 0 considered invalid) +*/ +struct clk_divider { +struct clk clk; +void __iomem *reg; +unsigned char shift; +unsigned char width; +unsigned int div; +struct clk *parent; +spinlock_t *lock; +#define CLK_DIVIDER_FLAG_ONE_BASED (1 << 0) +unsigned int flags; +}; + +extern struct clk_ops clk_divider_ops; +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */ /*
Signature · 1 line
1.7.4.1
PATCH 5/10 clk: Add support for simple dividers
Quoted 59 lines · Sascha Hauer
This patch adds support for the most common type of divider, which expects a register, width and shift values to desacribe the location of the divider. The divider can be zero based or one based (div =
reg_val+ 1 vs. div =reg_val).Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk-divider.c | 132 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 31 +++++++++++ 4 files changed, 167 insertions(+), 0 deletions(-) create mode 100644 drivers/clk/clk-divider.cdrivers/clk/Kconfig +3
-0@@ -5,3 +5,6 @@ config CLKDEV_LOOKUP config USE_COMMON_STRUCT_CLK bool + +config USE_COMMON_CLK_DIVIDER + booldrivers/clk/Makefile +1
-0@@ -1,3 +1,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o +obj-$(CONFIG_USE_COMMON_CLK_DIVIDER) += clk-divider.odrivers/clk/clk-divider.c new file +18
-0@@ -0,0 +1,132 @@ +/* +* Copyright (C) 2011 Sascha Hauer <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* Standard functionality for the common clock API. +*/ +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/io.h> + +#define to_clk_divider (clk) (container_of(clk, struct clk_divider, clk)) + +static unsigned long clk_divider_get_rate (struct clk *clk) +{ +struct clk_divider *divider =to_clk_divider (clk);
drivers/clk/clk-divider.c line 28
Quoted 10 lines
drivers/clk/clk-divider.c new file +10
-0+unsigned long rate =clk_get_rate (divider->parent); +unsigned int div; + + div =readl (divider->reg) >> divider->shift; + div &= (1 << divider->width) -1 ; + +if (!(divider->flags &CLK_DIVIDER_FLAG_ONE_BASED )) + div++; + +return rate / div;
DIV_ROUND_UP(rate, div)? (There is DIV_ROUND_CLOSEST, too, but I think you need to round up, see below.)
drivers/clk/clk-divider.c line 32
Quoted 4 lines
drivers/clk/clk-divider.c new file +4
-0+} + +static int clk_divider_bestdiv (struct clk *clk,unsigned long rate, +unsigned long *best_parent_rate)
conceptually this returns an unsigned value
drivers/clk/clk-divider.c line 38
Quoted 6 lines
drivers/clk/clk-divider.c new file +6
-0+{ +struct clk_divider *divider =to_clk_divider (clk); +int i, bestdiv =0 ; +unsigned long parent_rate, best =0 , now, maxdiv; + + maxdiv = (1 << divider->width);
Is divider->width == 32 a valid scenario? If so, this overflows.
drivers/clk/clk-divider.c line 51
Quoted 13 lines
drivers/clk/clk-divider.c new file +13
-0+ +if (divider->flags &CLK_DIVIDER_FLAG_ONE_BASED ) + maxdiv--; + +/* +* The maximum divider we can use without overflowing +* unsigned long in rate * i below +*/ + maxdiv =min (ULONG_MAX / rate, maxdiv); + +for (i =1 ; i <= maxdiv; i++) { + parent_rate =clk_round_rate (divider->parent, (rate +1 ) * i); + now = parent_rate / i;
This is buggy, take rate = 25, i = 4. You request the parent to set
104. If you get that, the resulting rate is 26. (And even if clk_round_rate only return 101 this might be too much.)
I think you need:
parent_rate = clk_round_rate(divider->parent, rate * i) now = DIV_ROUND_UP(parent_rate, i);
I think you really need DIV_ROUND_UP here, DIV_ROUND_CLOSEST won't work. Consider that a rate of 25 is requested, again with i=4. So the parent is asked for 100 and might return 97. With DIV_ROUND_CLOSEST you report to be able to set 24 now, but in fact it's more (24.25). If now further up in the recursion another divider considers 24 to be a great value to make 12Hz the value actually provided is too big.
Quoted 31 lines
drivers/clk/clk-divider.c new file +31
-0+ +if (now <= rate && now >= best) { + bestdiv = i; + best = now; + } + } + +if (!bestdiv) { + bestdiv = (1 << divider->width); + parent_rate =clk_round_rate (divider->parent,1 ); + }else { + parent_rate = best * bestdiv; + } + +if (best_parent_rate) + *best_parent_rate = parent_rate; + +return bestdiv; +} + +static long clk_divider_round_rate (struct clk *clk,unsigned long rate) +{ +unsigned long best_parent_rate; +int div =clk_divider_bestdiv (clk, rate, &best_parent_rate); + +return best_parent_rate / div; +} + +static int clk_divider_set_rate (struct clk *clk,unsigned long rate) +{ +unsigned long best_parent_rate;
drivers/clk/clk-divider.c line 92
Quoted 10 lines
drivers/clk/clk-divider.c new file +10
-0+struct clk_divider *divider =to_clk_divider (clk); +unsigned int div; +int ret; +unsigned long flags =0 ; +u32 val; + + div =clk_divider_bestdiv (clk, rate, &best_parent_rate); + +if (rate != best_parent_rate / div) +return -EINVAL ;
This is too harsh, isn't it. Or can you expect to only get values that are returned by round_rate? Again you need DIV_ROUND_UP.
Quoted 46 lines
drivers/clk/clk-divider.c new file +40
-0+ + ret =clk_set_rate (divider->parent, best_parent_rate); +if (ret) +return ret; + +if (divider->lock) +spin_lock_irqsave (divider->lock, flags); + +if (!(divider->flags &CLK_DIVIDER_FLAG_ONE_BASED )) + div--; + + val =readl (divider->reg); + val &= ~(((1 << divider->width) -1 ) << divider->shift); + val |= div << divider->shift; +writel (val, divider->reg); + +if (divider->lock) +spin_unlock_irqrestore (divider->lock, flags); + +return 0 ; +} + +static struct clk *clk_divider_get_parent (struct clk *clk) +{ +struct clk_divider *divider =to_clk_divider (clk); + +return divider->parent; +} + +struct clk_ops clk_divider_ops = { + .prepare = clk_parent_prepare, + .unprepare = clk_parent_unprepare, + .enable = clk_parent_enable, + .disable = clk_parent_disable, + .get_rate = clk_divider_get_rate, + .round_rate = clk_divider_round_rate, + .set_rate = clk_divider_set_rate, + .get_parent = clk_divider_get_parent, +}; +EXPORT_SYMBOL_GPL (clk_divider_ops);include/linux/clk.h +0
-0@@ -180,6 +180,37 @@ unsigned long clk_parent_get_rate(struct clk *clk);long clk_parent_round_rate (struct clk *clk,unsigned long rate);
include/linux/clk.h unsigned long clk_parent_get_rate(struct clk *clk); · line 190
Quoted 10 lines
include/linux/clk.h +8
-0int clk_parent_set_rate (struct clk *clk,unsigned long rate); +/** +* clock divider +* +* @clk clock source +* @reg register containing the divider +* @shift shift to the divider +* @width width of the divider +* @lock register lock
"optional register lock"?
include/linux/clk.h unsigned long clk_parent_get_rate(struct clk *clk); · line 191
Quoted 1 line
include/linux/clk.h +1
-0+* @parent parent clock
@flags is missing here. Maybe use the same ordering as in the struct?
Quoted 15 lines
include/linux/clk.h +15
-0+* +* This clock implements get_rate/set_rate/round_rate. prepare/unprepare and +* enable/disable are passed through to the parent. +* +* The divider is calculated as div = reg_val + 1 +* or if CLK_DIVIDER_FLAG_ONE_BASED is set as div = reg_val +* (with reg_val == 0 considered invalid) +*/ +struct clk_divider { +struct clk clk; +void __iomem *reg; +unsigned char shift; +unsigned char width; +unsigned int div; +struct clk *parent;
include/linux/clk.h unsigned long clk_parent_get_rate(struct clk *clk); · line 216
Quoted 10 lines
include/linux/clk.h +7
-0+spinlock_t *lock; +#define CLK_DIVIDER_FLAG_ONE_BASED (1 << 0) + unsigned int flags; +}; + +extern struct clk_ops clk_divider_ops; +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */ /*
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Sascha Hauer
maintainerPATCH 5/10 clk: Add support for simple dividers
Quoted 109 lines · Uwe Kleine-K?nig
Quoted 59 lines · Sascha Hauer
This patch adds support for the most common type of divider, which expects a register, width and shift values to desacribe the location of the divider. The divider can be zero based or one based (div =
reg_val+ 1 vs. div =reg_val).Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk-divider.c | 132 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 31 +++++++++++ 4 files changed, 167 insertions(+), 0 deletions(-) create mode 100644 drivers/clk/clk-divider.cdrivers/clk/Kconfig +3
-0@@ -5,3 +5,6 @@ config CLKDEV_LOOKUP config USE_COMMON_STRUCT_CLK bool + +config USE_COMMON_CLK_DIVIDER + booldrivers/clk/Makefile +1
-0@@ -1,3 +1,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o +obj-$(CONFIG_USE_COMMON_CLK_DIVIDER) += clk-divider.odrivers/clk/clk-divider.c new file +18
-0@@ -0,0 +1,132 @@ +/* +* Copyright (C) 2011 Sascha Hauer <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* Standard functionality for the common clock API. +*/ +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/io.h> + +#define to_clk_divider (clk) (container_of(clk, struct clk_divider, clk)) + +static unsigned long clk_divider_get_rate (struct clk *clk) +{ +struct clk_divider *divider =to_clk_divider (clk);drivers/clk/clk-divider.c line 28
Quoted 10 lines
drivers/clk/clk-divider.c new file +10
-0+unsigned long rate =clk_get_rate (divider->parent); +unsigned int div; + + div =readl (divider->reg) >> divider->shift; + div &= (1 << divider->width) -1 ; + +if (!(divider->flags &CLK_DIVIDER_FLAG_ONE_BASED )) + div++; + +return rate / div;
DIV_ROUND_UP(rate, div)? (There isDIV_ROUND_CLOSEST, too, but I think you need to round up, see below.)drivers/clk/clk-divider.c line 32
Quoted 4 lines
drivers/clk/clk-divider.c new file +4
-0+} + +static int clk_divider_bestdiv (struct clk *clk,unsigned long rate, +unsigned long *best_parent_rate)conceptually this returns an unsigned value
drivers/clk/clk-divider.c line 38
Quoted 6 lines
drivers/clk/clk-divider.c new file +6
-0+{ +struct clk_divider *divider =to_clk_divider (clk); +int i, bestdiv =0 ; +unsigned long parent_rate, best =0 , now, maxdiv; + + maxdiv = (1 << divider->width);Is
divider->width== 32 a valid scenario? If so, this overflows.drivers/clk/clk-divider.c line 51
Quoted 13 lines
drivers/clk/clk-divider.c new file +13
-0+ +if (divider->flags &CLK_DIVIDER_FLAG_ONE_BASED ) + maxdiv--; + +/* +* The maximum divider we can use without overflowing +* unsigned long in rate * i below +*/ + maxdiv =min (ULONG_MAX / rate, maxdiv); + +for (i =1 ; i <= maxdiv; i++) { + parent_rate =clk_round_rate (divider->parent, (rate +1 ) * i); + now = parent_rate / i;This is buggy, take rate = 25, i = 4. You request the parent to set
104. If you get that, the resulting rate is 26. (And even ifclk_round_rateonly return 101 this might be too much.)I think you need:
parent_rate = clk_round_rate(divider->parent, rate * i) now = DIV_ROUND_UP(parent_rate, i);
Quoted 6 lines
I think you really need
DIV_ROUND_UPhere,DIV_ROUND_CLOSESTwon't work. Consider that a rate of 25 is requested, again with i=4. So the parent is asked for 100 and might return 97. WithDIV_ROUND_CLOSESTyou report to be able to set 24 now, but in fact it's more (24.25). If now further up in the recursion another divider considers 24 to be a great value to make 12Hz the value actually provided is too big.
I will give it a try using the DIV_ROUND_ macros. I had problems with two cascaded dividers where due to rounding errors while dividing I got got the next smaller divider value when passing in a value which I could exactly get.
Quoted 7 lines
Quoted 7 lines
drivers/clk/clk-divider.c new file +7
-0+static int clk_divider_set_rate (struct clk *clk,unsigned long rate) +{ +unsigned long best_parent_rate; +struct clk_divider *divider =to_clk_divider (clk); +unsigned int div; +int ret; +unsigned long flags =0 ;
Quoted 8 lines
drivers/clk/clk-divider.c line 92
Quoted 6 lines
drivers/clk/clk-divider.c new file +6
-0+u32 val; + + div =clk_divider_bestdiv (clk, rate, &best_parent_rate); + +if (rate != best_parent_rate / div) +return -EINVAL ;This is too harsh, isn't it. Or can you expect to only get values that are returned by
round_rate? Again you needDIV_ROUND_UP.
AFAIK there are two different implementation types in the tree. Some implementations only allow to set to the exact rate round_rate returns while others round down in set_rate.
Has this been specified what behaviour is expected?
Quoted 10 lines
drivers/clk/clk-divider.c line 72
Quoted 9 lines
drivers/clk/clk-divider.c new file +8
-0+/** +* clock divider +* +* @clk clock source +* @reg register containing the divider +* @shift shift to the divider +* @width width of the divider +* @lock register lock "optional register lock"?
ok.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 5/10 clk: Add support for simple dividers
Quoted 33 lines · Sascha Hauer
Quoted 16 lines · Uwe Kleine-K?nig
Quoted 15 lines · Sascha Hauer
This patch adds support for the most common type of divider, which expects a register, width and shift values to desacribe the location of the divider. The divider can be zero based or one based (div =
reg_val+ 1 vs. div =reg_val).Signed-off-by Sascha Hauer<[email protected]>Cc Jeremy Kerr<[email protected]>--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk-divider.c | 132 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 31 +++++++++++ 4 files changed, 167 insertions(+), 0 deletions(-)create mode 100644
drivers/clk/clk-divider.cQuoted 15 lines
drivers/clk/clk-divider.c line 92
Quoted 13 lines
drivers/clk/clk-divider.c new file +13
-0+static int clk_divider_set_rate (struct clk *clk,unsigned long rate) +{ +unsigned long best_parent_rate; +struct clk_divider *divider =to_clk_divider (clk); +unsigned int div; +int ret; +unsigned long flags =0 ; +u32 val; + + div =clk_divider_bestdiv (clk, rate,&best_parent_rate); + +if (rate != best_parent_rate / div) +return -EINVAL ;This is too harsh, isn't it. Or can you expect to only get values that are returned by
round_rate? Again you needDIV_ROUND_UP.
Quoted 6 lines
AFAIK there are two different implementation types in the tree. Some implementations only allow to set to the exact rate
round_ratereturns while others round down inset_rate.Has this been specified what behaviour is expected?
This is something I have nagged Russell once or twice about and then sent out an email to the list for which there was very limited response. I think clk_round_rate() is too generic and not very useful.
We should really have something like:clk_set_rate_range(min, ideal, max)
That way, we don't have to guess what's best for the consumer. The consumers knows exactly what range it can work with and what is ideal. Also, this simplifies the life of the device driver writer when the device is used in many different SoCs with different clock plans and different meanings of round rate (up vs. down vs. closest). As of today, to deal with the latter case, the device drivers will have to get the clock rate passed through platform data.
I'm really hoping there is enough attention to finally get the clock API cleaned up for better clarity.
Thanks,
Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 5/10 clk: Add support for simple dividers
Hello,
Quoted 10 lines · Saravana Kannan
Quoted 8 lines · Sascha Hauer
Quoted 1 line · Uwe Kleine-K?nig
On Fri, Apr 15, 2011 at 09:08:10PM +0200, Sascha Hauer wrote:
AFAIK there are two different implementation types in the tree. Some implementations only allow to set to the exact rate
round_ratereturns while others round down inset_rate.Has this been specified what behaviour is expected?
Quoted 7 lines
This is something I have nagged Russell once or twice about and then sent out an email to the list for which there was very limited response. I think
clk_round_rate()is too generic and not very useful.We should really have something like:
clk_set_rate_range(min, ideal, max)
(Note this is orthogonal to the question if set_rate may barf on values other than the return values of round_rate.)
clk_set_rate_range can even be implemented with clk_round_rate that is just required to fulfill:
clk_round_rate(clk, X) > 0 => clk_set_rate(clk, clk_round_rate(clk, X)) == clk_round_rate(clk, X) and clk_round_rate(clk, clk_round_rate(clk, X)) == clk_round_rate(clk, X)
and
X >= Y => clk_round_rate(clk, X) >= clk_round_rate(clk, Y)
which every implementation should assert provided that X and Y are the domain of clk_round_rate(clk, .)
Something like:
long clk_round_rate_range(struct clk *clk, unsigned long minrate,
unsigned long optrate, unsigned long maxrate)
{
unsigned long bot = minrate, best, cur, top = maxrate;
unsigned long delta;
long tmp;
if (minrate > optrate || optrate > maxrate)
return -EINVAL;
if (maxrate > LONG_MAX)
/* can anything be done here? */
return -EINVAL;
best = cur = clk_round_rate(clk, optrate);
if (cur == optrate)
return optrate;
delta = optrate > best ? optrate - best : best - optrate;
while (1) {
if (cur > optrate) {
if (delta > cur - optrate)
best = cur;
top = cur;
cur = (bot + cur) / 2;
} else if (cur < optrate) {
if (delta > optrate - cur)
best = cur;
bot = cur;
cur = (cur + top + 1) / 2;
} else {
WARN(1, "Your clk_round_rate implementation is broken (clk = %pS, [%lu, %lu, %lu]\n.",
clk, minrate, optrate, maxrate);
return -EINVAL;
}
tmp = clk_round_rate(clk, cur);
if (tmp < 0)
return tmp;
cur = tmp;
if (bot == top)
break;
}
if (best < minrate || best > maxrate)
return -EINVAL;
return best;
}
int clk_set_rate_range(struct clk *clk, unsigned long minrate,
unsigned long optrate, unsigned long maxrate)
{
long rate = clk_round_rate_range(clk, minrate,
optrate, maxrate);
if (rate < 0)
return rate;
clk_set_rate(clk, rate);
}Completely untestet so probably broken.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
PATCH 5/10 clk: Add support for simple dividers
Quoted 18 lines · Uwe Kleine-K?nig
Hello,
Quoted 15 lines · Saravana Kannan
Quoted 8 lines · Sascha Hauer
Quoted 1 line · Uwe Kleine-K?nig
On Fri, Apr 15, 2011 at 09:08:10PM +0200, Sascha Hauer wrote:
AFAIK there are two different implementation types in the tree. Some implementations only allow to set to the exact rate
round_ratereturns while others round down inset_rate.Has this been specified what behaviour is expected?
This is something I have nagged Russell once or twice about and then sent out an email to the list for which there was very limited response. I think
clk_round_rate()is too generic and not very useful.
Quoted 7 lines
Quoted 2 lines
We should really have something like:
clk_set_rate_range(min, ideal, max)(Note this is orthogonal to the question if
set_ratemay barf on values other than the return values ofround_rate.)
clk_set_rate_rangecan even be implemented withclk_round_ratethat is just required to fulfill:
I think it's more important that we try to find a new API that's better than clk_round_rate(). We can worry about the specifics of the implementation later.
Thanks,
Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Sascha Hauer
maintainerPATCH 5/10 clk: Add support for simple dividers
Quoted 24 lines · Saravana Kannan
Quoted 23 lines · Uwe Kleine-K?nig
Hello,
Quoted 10 lines · Saravana Kannan
Quoted 8 lines · Sascha Hauer
Quoted 1 line · Uwe Kleine-K?nig
On Fri, Apr 15, 2011 at 09:08:10PM +0200, Sascha Hauer wrote:
AFAIK there are two different implementation types in the tree. Some implementations only allow to set to the exact rate
round_ratereturns while others round down inset_rate.Has this been specified what behaviour is expected?
Quoted 7 lines
This is something I have nagged Russell once or twice about and then sent out an email to the list for which there was very limited response. I think
clk_round_rate()is too generic and not very useful.We should really have something like:
clk_set_rate_range(min, ideal, max)(Note this is orthogonal to the question if
set_ratemay barf on values other than the return values ofround_rate.)
Quoted 6 lines
Quoted 2 lines
clk_set_rate_rangecan even be implemented withclk_round_ratethat is just required to fulfill:I think it's more important that we try to find a new API that's better than
clk_round_rate(). We can worry about the specifics of the implementation later.
You found it and Uwe found a way to implement this ontop of the old API, that's a comfortable situation, isn't it?
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 5/10 clk: Add support for simple dividers
Quoted 33 lines · Sascha Hauer
Quoted 8 lines · Saravana Kannan
Quoted 7 lines · Uwe Kleine-K?nig
Hello,
Quoted 4 lines · Saravana Kannan
Quoted 3 lines · Sascha Hauer
Quoted 1 line · Uwe Kleine-K?nig
On Fri, Apr 15, 2011 at 09:08:10PM +0200, Sascha Hauer wrote:
AFAIK there are two different implementation types in the tree.
Some
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
implementations only allow to set to the exact rate
round_ratereturns
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines
while others round down in
set_rate.Has this been specified what behaviour is expected?
This is something I have nagged Russell once or twice about and
then
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
sent out an email to the list for which there was very limited response. I think
clk_round_rate()is too generic and not very useful.We should really have something like:
clk_set_rate_range(min, ideal, max)(Note this is orthogonal to the question if
set_ratemay barf onvalues
Quoted 3 lines
Quoted 3 lines
other than the return values of
round_rate.)
clk_set_rate_rangecan even be implemented withclk_round_ratethatis
Quoted 2 lines
Quoted 1 line
just required to fulfill:
Quoted 8 lines
Quoted 1 line
I think it's more important that we try to find a new API that's
better
Quoted 2 lines
than
clk_round_rate(). We can worry about the specifics of the implementation later.You found it and Uwe found a way to implement this ontop of the old API,
that's a comfortable situation, isn't it?
Well, do we all agree to this new API? I have no problem with Uwe's helper fn or his suggestion, if we all agree on the final API. I just didn't want him wasting his time when the API is not finalized.
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Sascha Hauer
maintainerPATCH 5/10 clk: Add support for simple dividers
Quoted 18 lines · Saravana Kannan
Quoted 16 lines · Sascha Hauer
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
We should really have something like:
clk_set_rate_range(min, ideal, max)(Note this is orthogonal to the question if
set_ratemay barf onvalues
Quoted 3 lines
Quoted 3 lines
other than the return values of
round_rate.)
clk_set_rate_rangecan even be implemented withclk_round_ratethatis
Quoted 3 lines
Quoted 1 line
just required to fulfill:
I think it's more important that we try to find a new API that's
better
Quoted 2 lines
than
clk_round_rate(). We can worry about the specifics of the implementation later.
Quoted 7 lines
Quoted 3 lines
You found it and Uwe found a way to implement this ontop of the old API,
that's a comfortable situation, isn't it?Well, do we all agree to this new API? I have no problem with Uwe's helper fn or his suggestion, if we all agree on the final API. I just didn't want him wasting his time when the API is not finalized.
As Uwes suggestion does not change the internal clock API it's relatively simple to try out. With this we moved to the add-a-helper-function class of patches and are not in the change-internal-and-external-API-with-hundreds-of-users class anymore.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 5/10 clk: Add support for simple dividers
Quoted 27 lines · Sascha Hauer
Quoted 18 lines · Saravana Kannan
Quoted 16 lines · Sascha Hauer
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
We should really have something like:
clk_set_rate_range(min, ideal, max)(Note this is orthogonal to the question if
set_ratemay barf onvalues
Quoted 3 lines
Quoted 3 lines
other than the return values of
round_rate.)
clk_set_rate_rangecan even be implemented withclk_round_ratethatis
Quoted 3 lines
Quoted 1 line
just required to fulfill:
I think it's more important that we try to find a new API that's
better
Quoted 2 lines
than
clk_round_rate(). We can worry about the specifics of the implementation later.Quoted 7 lines
Quoted 3 lines
You found it and Uwe found a way to implement this ontop of the old API,
that's a comfortable situation, isn't it?Well, do we all agree to this new API? I have no problem with Uwe's helper fn or his suggestion, if we all agree on the final API. I just didn't want him wasting his time when the API is not finalized.
Quoted 5 lines
As Uwes suggestion does not change the internal clock API it's relatively simple to try out. With this we moved to the add-a-helper-function class of patches and are not in the change-internal-and-external-API-with-hundreds-of-users class anymore.
If clk_set_rate_range() is not made an external API, then it's pointless to even add it.
Also, you can make it an internal API (to be implemented by clock drivers) and still not need "hundreds of users to change". The generic code will use this helper function if the set_rate_range() API is not implemented by a specific clock/clock driver. If it's implemented by the specific clock, then that one will be used. That's not rocket science.
Let's stop discussion about whether Uwe's change is useful or not. I don't care. If you think it's great, then good for you both.
Or, may be I will start a separate thread if you don't like me using this thread to get an agreement on the API first. Just you and me agreeing is not enough.
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 5/10 clk: Add support for simple dividers
Quoted 28 lines · Saravana Kannan
Quoted 27 lines · Sascha Hauer
Quoted 25 lines · Saravana Kannan
Quoted 11 lines · Sascha Hauer
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
We should really have something like:
clk_set_rate_range(min, ideal, max)(Note this is orthogonal to the question if
set_ratemay barf onvalues
Quoted 3 lines
Quoted 3 lines
other than the return values of
round_rate.)
clk_set_rate_rangecan even be implemented withclk_round_ratethatis
Quoted 2 lines
Quoted 1 line
just required to fulfill:
Quoted 8 lines
Quoted 1 line
I think it's more important that we try to find a new API that's
better
Quoted 2 lines
than
clk_round_rate(). We can worry about the specifics of the implementation later.You found it and Uwe found a way to implement this ontop of the old API,
that's a comfortable situation, isn't it?Well, do we all agree to this new API? I have no problem with Uwe's helper fn or his suggestion, if we all agree on the final API. I just didn't want him wasting his time when the API is not finalized.
Quoted 8 lines
Quoted 5 lines
As Uwes suggestion does not change the internal clock API it's relatively simple to try out. With this we moved to the add-a-helper-function class of patches and are not in the change-internal-and-external-API-with-hundreds-of-users class anymore.
If
clk_set_rate_range()is not made an external API, then it's pointless to even add it.
Correct, if it's there every driver should be able to use it.
Quoted 6 lines
Also, you can make it an internal API (to be implemented by clock drivers) and still not need "hundreds of users to change". The generic code will use this helper function if the
set_rate_range()API is not implemented by a specific clock/clock driver. If it's implemented by the specific clock, then that one will be used. That's not rocket science.
It's discussable if it's worth to add it to the internal API or if my suggestion works for everybody. I think the best path to choose here is:
When this functionallity is needed add a global and generic function (like my suggestion). If this proves to behave bad for a certain clk a mechanism to override it per clk can still be added later.
Quoted 2 lines
Let's stop discussion about whether Uwe's change is useful or not. I don't care. If you think it's great, then good for you both.
Right, it only makes sense to think about adding such a function when the first user pops up.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
PATCH 5/10 clk: Add support for simple dividers
In reply to Saravana KannanQuoted 11 lines · Saravana Kannan
Quoted 6 lines · Sascha Hauer
AFAIK there are two different implementation types in the tree. Some implementations only allow to set to the exact rate
round_ratereturns while others round down inset_rate.Has this been specified what behaviour is expected?
This is something I have nagged Russell once or twice about and then sent out an email to the list for which there was very limited response. I think
clk_round_rate()is too generic and not very useful.
As I've always said, clk_round_rate() returns the rate which you will get if you ask clk_set_rate() to set the same rate. It's not ment to be "tell me the clock rate which I'd like to then pass to clk_set_rate(), oh that's not good enough, so lets tweak it a bit and try again".
For example, take a video driver. The user passes in the pixel clock as a picosecond argument. This gets converted to Hz. We can then use clk_round_rate() to find out what clock rate we _actually_ end up with when we set that rate using clk_set_rate(), and return that rate (again as ps) back to the user before we alter anything. The user can then make a decision whether they want to actually set it.
Having some sort of range stuff doesn't help you there because you're not supplied a range from userspace. You're just asked to set a 39752ps clock rate.
PATCH 5/10 clk: Add support for simple dividers
Quoted 9 lines · Russell King - ARM Linux
Quoted 8 lines · Saravana Kannan
Quoted 6 lines · Sascha Hauer
AFAIK there are two different implementation types in the tree. Some implementations only allow to set to the exact rate
round_ratereturns while others round down inset_rate.Has this been specified what behaviour is expected?
Quoted 8 lines
Quoted 3 lines
This is something I have nagged Russell once or twice about and then sent out an email to the list for which there was very limited response. I think
clk_round_rate()is too generic and not very useful.As I've always said,
clk_round_rate()returns the rate which you will get if you askclk_set_rate()to set the same rate. It's not ment to be "tell me the clock rate which I'd like to then pass toclk_set_rate(), oh that's not good enough, so lets tweak it a bit and try again".
Yes, I understood the purpose of clk_round_rate() from the previous discussion we had.
Quoted 6 lines
For example, take a video driver. The user passes in the pixel clock as a picosecond argument. This gets converted to Hz. We can then use
clk_round_rate()to find out what clock rate we _actually_ end up with when we set that rate usingclk_set_rate(), and return that rate (again as ps) back to the user before we alter anything. The user can then make a decision whether they want to actually set it.
Sure clk_round_rate() might be sufficient for this case.
Quoted 3 lines
Having some sort of range stuff doesn't help you there because you're not supplied a range from userspace. You're just asked to set a 39752ps clock rate.
But this not the problem I'm trying to solve though. There are several devices that have a freq operating range in their spec sheet and they can't operate outside of that range. As of today, when the device/drivers are used in multiple soc/arch, they are solving that issue either by using clk_round_rate() in a way that you didn't intend (to search for a freq that will work for them) or by passing in the clock freq through platform data.
I think a better way to solve this problem is to have a clk_set_rate_range() and hence suggesting it. This would also help reduce the no. of lines/data passed in board files which I think helps clean up ARM code.
Btw, one of the use cases this would help is actually related to display too. It's some clock that's fed to the display panel (I don't think it's the pixel clock) which has a 96 MHz - 103 MHz operating range.
-Saravana
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 5/10 clk: Add support for simple dividers
Hello,
Quoted 4 lines · Saravana Kannan
I think a better way to solve this problem is to have a
clk_set_rate_range()and hence suggesting it. This would also help reduce the no. of lines/data passed in board files which I think helps clean up ARM code.
Just an implementation detail: clk_round_rate_range would be enough.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
PATCH 5/10 clk: Add support for simple dividers
In reply to Uwe Kleine-KönigQuoted 7 lines · Uwe Kleine-K?nig
Quoted 7 lines
drivers/clk/clk-divider.c new file +7
-0+static int clk_divider_set_rate (struct clk *clk,unsigned long rate) +{ +unsigned long best_parent_rate; +struct clk_divider *divider =to_clk_divider (clk); +unsigned int div; +int ret; +unsigned long flags =0 ;
Quoted 8 lines
drivers/clk/clk-divider.c line 92
Quoted 6 lines
drivers/clk/clk-divider.c new file +6
-0+u32 val; + + div =clk_divider_bestdiv (clk, rate, &best_parent_rate); + +if (rate != best_parent_rate / div) +return -EINVAL ;This is too harsh, isn't it. Or can you expect to only get values that are returned by
round_rate? Again you needDIV_ROUND_UP.
It is too harsh, and I've wished many a time that people would implement clk_set_rate() and clk_round_rate() as:
long clk_round_rate(struct clk *clk, unsigned long rate)
{
err = calculate_clock_paramters(clk, params, rate);
if (err < 0)
return err;
return calculate_clock_rate(clk, params);
}int clk_set_rate(struct clk *clk, unsigned long rate)
{
err = calculate_clock_parameters(clk, params, rate);
if (err < 0)
return err;
set_clock_parameters(clk, params);
clk->rate = calculate_clock_rate(clk, params);
return 0;
}IOW, clk_round_rate() does what clk_set_rate() does but does _not_ set the hardware rate itself.
Sascha Hauer
maintainerPATCH 5/10 clk: Add support for simple dividers
Quoted 38 lines · Russell King - ARM Linux
Quoted 7 lines · Uwe Kleine-K?nig
Quoted 7 lines
drivers/clk/clk-divider.c new file +7
-0+static int clk_divider_set_rate (struct clk *clk,unsigned long rate) +{ +unsigned long best_parent_rate; +struct clk_divider *divider =to_clk_divider (clk); +unsigned int div; +int ret; +unsigned long flags =0 ;Quoted 8 lines
drivers/clk/clk-divider.c line 92
Quoted 6 lines
drivers/clk/clk-divider.c new file +6
-0+u32 val; + + div =clk_divider_bestdiv (clk, rate, &best_parent_rate); + +if (rate != best_parent_rate / div) +return -EINVAL ;This is too harsh, isn't it. Or can you expect to only get values that are returned by
round_rate? Again you needDIV_ROUND_UP.It is too harsh, and I've wished many a time that people would implement
clk_set_rate()andclk_round_rate()as:long
clk_round_rate(struct clk *clk, unsigned long rate){ err = calculate_clock_paramters(clk, params, rate); if (err < 0) return err; return calculate_clock_rate(clk, params); }int
clk_set_rate(struct clk *clk, unsigned long rate){ err = calculate_clock_parameters(clk, params, rate); if (err < 0) return err; set_clock_parameters(clk, params); clk->rate = calculate_clock_rate(clk, params); return 0; }
Quoted 2 lines
IOW,
clk_round_rate()does whatclk_set_rate()does but does _not_ set the hardware rate itself.
Ok. It's easier to implement anyway since rounding errors do not have such a bad impact.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 5/10 clk: Add support for simple dividers
In reply to Sascha HauerJust minor nitpicks.
Quoted 10 lines · Sascha Hauer
drivers/clk/clk-divider.c new file +4
-0@@ -0,0 +1,132 @@ +/* +* Copyright (C) 2011 Sascha Hauer <[email protected]> +* +* This program is free software; you can redistribute it and/or modify
drivers/clk/clk-divider.c line 14
Quoted 10 lines
drivers/clk/clk-divider.c new file +10
-0+* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* Standard functionality for the common clock API. +*/ +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/io.h> + +#define to_clk_divider (clk) (container_of(clk, struct clk_divider, clk))
Can you make this a static inline function with actual types? We get slightly more type safety that way. Ditto for similar constructs in this series.
Quoted 15 lines
include/linux/clk.h +7
-0@@ -180,6 +180,37 @@ unsigned long clk_parent_get_rate(struct clk *clk);long clk_parent_round_rate (struct clk *clk,unsigned long rate);int clk_parent_set_rate (struct clk *clk,unsigned long rate); +/** +* clock divider +* +* @clk clock source +* @reg register containing the divider +* @shift shift to the divider +* @width width of the divider
include/linux/clk.h unsigned long clk_parent_get_rate(struct clk *clk); · line 199
Quoted 10 lines
include/linux/clk.h +10
-0+* @lock register lock +* @parent parent clock +* +* This clock implements get_rate/set_rate/round_rate. prepare/unprepare and +* enable/disable are passed through to the parent. +* +* The divider is calculated as div = reg_val + 1 +* or if CLK_DIVIDER_FLAG_ONE_BASED is set as div = reg_val +* (with reg_val == 0 considered invalid) +*/
This isn't kernel-doc notation. See Documentation/kernel-doc-nano-HOWTO.txt
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 5/10 clk: Add support for simple dividers
Hi Stephen,
Quoted 4 lines
Quoted 1 line
+#define
to_clk_divider(clk)(container_of(clk, struct clk_divider, clk))Can you make this a static inline function with actual types? We get slightly more type safety that way.
Do we? The container_of macro requires that that it's first argument is the same type as type->member, and returns a (type), so I don't see how we're going to miss typing errors here.
However, with these macros, we need to use a parameter name that isn't the same as the member name. Sascha: can you fix this? I'll update the clk_fixed support.
Cheers,
Jeremy
PATCH 5/10 clk: Add support for simple dividers
Quoted 8 lines · Jeremy Kerr
Hi Stephen,
Quoted 3 lines
Quoted 1 line
+#define
to_clk_divider(clk)(container_of(clk, struct clk_divider, clk))Can you make this a static inline function with actual types? We get slightly more type safety that way.
Do we? The
container_ofmacro requires that that it's first argument is the same type astype->member, and returns a (type), so I don't see how we're going to miss typing errors here.
Ah yes you're right. Should have looked further. I still like static inline functions for these things but I don't see any reason why one is better over the other.
Thanks,
Stephen
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 5/10 clk: Add support for simple dividers
In reply to Sascha HauerQuoted 125 lines · Sascha Hauer
This patch adds support for the most common type of divider, which expects a register, width and shift values to desacribe the location of the divider. The divider can be zero based or one based (div =
reg_val+ 1 vs. div =reg_val).Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk-divider.c | 132 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 31 +++++++++++ 4 files changed, 167 insertions(+), 0 deletions(-) create mode 100644 drivers/clk/clk-divider.cdrivers/clk/Kconfig +3
-0@@ -5,3 +5,6 @@ config CLKDEV_LOOKUP config USE_COMMON_STRUCT_CLK bool + +config USE_COMMON_CLK_DIVIDER + booldrivers/clk/Makefile +1
-0@@ -1,3 +1,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o +obj-$(CONFIG_USE_COMMON_CLK_DIVIDER) += clk-divider.odrivers/clk/clk-divider.c new file +84
-0@@ -0,0 +1,132 @@ +/* +* Copyright (C) 2011 Sascha Hauer <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* Standard functionality for the common clock API. +*/ +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/io.h> + +#define to_clk_divider (clk) (container_of(clk, struct clk_divider, clk)) + +static unsigned long clk_divider_get_rate (struct clk *clk) +{ +struct clk_divider *divider =to_clk_divider (clk); +unsigned long rate =clk_get_rate (divider->parent); +unsigned int div; + + div =readl (divider->reg) >> divider->shift; + div &= (1 << divider->width) -1 ; + +if (!(divider->flags &CLK_DIVIDER_FLAG_ONE_BASED )) + div++; + +return rate / div; +} + +static int clk_divider_bestdiv (struct clk *clk,unsigned long rate, +unsigned long *best_parent_rate) +{ +struct clk_divider *divider =to_clk_divider (clk); +int i, bestdiv =0 ; +unsigned long parent_rate, best =0 , now, maxdiv; + + maxdiv = (1 << divider->width); + +if (divider->flags &CLK_DIVIDER_FLAG_ONE_BASED ) + maxdiv--; + +/* +* The maximum divider we can use without overflowing +* unsigned long in rate * i below +*/ + maxdiv =min (ULONG_MAX / rate, maxdiv); + +for (i =1 ; i <= maxdiv; i++) { + parent_rate =clk_round_rate (divider->parent, (rate +1 ) * i); + now = parent_rate / i; + +if (now <= rate && now >= best) { + bestdiv = i; + best = now; + } + } + +if (!bestdiv) { + bestdiv = (1 << divider->width); + parent_rate =clk_round_rate (divider->parent,1 ); + }else { + parent_rate = best * bestdiv; + } + +if (best_parent_rate) + *best_parent_rate = parent_rate; + +return bestdiv; +} + +static long clk_divider_round_rate (struct clk *clk,unsigned long rate) +{ +unsigned long best_parent_rate; +int div =clk_divider_bestdiv (clk, rate, &best_parent_rate); + +return best_parent_rate / div; +} + +static int clk_divider_set_rate (struct clk *clk,unsigned long rate) +{ +unsigned long best_parent_rate; +struct clk_divider *divider =to_clk_divider (clk); +unsigned int div;
drivers/clk/clk-divider.c line 94
Quoted 10 lines
drivers/clk/clk-divider.c new file +10
-0+int ret; +unsigned long flags =0 ; +u32 val; + + div =clk_divider_bestdiv (clk, rate, &best_parent_rate); + +if (rate != best_parent_rate / div) +return -EINVAL ; + + ret =clk_set_rate (divider->parent, best_parent_rate);
why do you set parent rate? It may impact hte parent's other children.
Thanks
Richard
Quoted 88 lines
drivers/clk/clk-divider.c new file +38
-0+if (ret) +return ret; + +if (divider->lock) +spin_lock_irqsave (divider->lock, flags); + +if (!(divider->flags &CLK_DIVIDER_FLAG_ONE_BASED )) + div--; + + val =readl (divider->reg); + val &= ~(((1 << divider->width) -1 ) << divider->shift); + val |= div << divider->shift; +writel (val, divider->reg); + +if (divider->lock) +spin_unlock_irqrestore (divider->lock, flags); + +return 0 ; +} + +static struct clk *clk_divider_get_parent (struct clk *clk) +{ +struct clk_divider *divider =to_clk_divider (clk); + +return divider->parent; +} + +struct clk_ops clk_divider_ops = { + .prepare = clk_parent_prepare, + .unprepare = clk_parent_unprepare, + .enable = clk_parent_enable, + .disable = clk_parent_disable, + .get_rate = clk_divider_get_rate, + .round_rate = clk_divider_round_rate, + .set_rate = clk_divider_set_rate, + .get_parent = clk_divider_get_parent, +}; +EXPORT_SYMBOL_GPL (clk_divider_ops);include/linux/clk.h +31
-0@@ -180,6 +180,37 @@ unsigned long clk_parent_get_rate(struct clk *clk);long clk_parent_round_rate (struct clk *clk,unsigned long rate);int clk_parent_set_rate (struct clk *clk,unsigned long rate); +/** +* clock divider +* +* @clk clock source +* @reg register containing the divider +* @shift shift to the divider +* @width width of the divider +* @lock register lock +* @parent parent clock +* +* This clock implements get_rate/set_rate/round_rate. prepare/unprepare and +* enable/disable are passed through to the parent. +* +* The divider is calculated as div = reg_val + 1 +* or if CLK_DIVIDER_FLAG_ONE_BASED is set as div = reg_val +* (with reg_val == 0 considered invalid) +*/ +struct clk_divider { +struct clk clk; +void __iomem *reg; +unsigned char shift; +unsigned char width; +unsigned int div; +struct clk *parent; +spinlock_t *lock; +#define CLK_DIVIDER_FLAG_ONE_BASED (1 << 0) +unsigned int flags; +}; + +extern struct clk_ops clk_divider_ops; +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */ /* Signature · 7 lines
1.7.4.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel at lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Sascha Hauer
maintainerPATCH 5/10 clk: Add support for simple dividers
Quoted 9 lines · Richard Zhao
drivers/clk/clk-divider.c line 94
Quoted 7 lines
drivers/clk/clk-divider.c new file +7
-0+ + div =clk_divider_bestdiv (clk, rate, &best_parent_rate); + +if (rate != best_parent_rate / div) +return -EINVAL ; + + ret =clk_set_rate (divider->parent, best_parent_rate);why do you set parent rate? It may impact hte parent's other children.
In a newer version I already created a barrier flag for not setting the parents rate. Setting the parents rate is needed for for example cascaded dividers. Otherwise this could be much simpler.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 5/10 clk: Add support for simple dividers
Quoted 11 lines · Sascha Hauer
Quoted 9 lines · Richard Zhao
drivers/clk/clk-divider.c line 94
Quoted 7 lines
drivers/clk/clk-divider.c new file +7
-0+ + div =clk_divider_bestdiv (clk, rate, &best_parent_rate); + +if (rate != best_parent_rate / div) +return -EINVAL ; + + ret =clk_set_rate (divider->parent, best_parent_rate);why do you set parent rate? It may impact hte parent's other children.
Quoted 3 lines
In a newer version I already created a barrier flag for not setting the parents rate. Setting the parents rate is needed for for example cascaded dividers. Otherwise this could be much simpler.
And do you find a way to let clock actual parents indepent on reset or uboot register settings. If we can register clk, maybe:
if (clk->ops.hw_get_parent)
clk->parent = clk->ops->hw_get_parent;
Thanks
Richard
Quoted 15 lines
Sascha
Signature · 9 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel at lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Sascha Hauer
maintainerPATCH 6/10 clk: Add support for a generic clock multiplexer
In reply to Sascha HauerThis patch adds support for a common type of clock multiplexer. The multiplexer is described with register, shift and width and an array of clocks which correspond to the bit value.
--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk-divider.c | 2 +- drivers/clk/clk-mux.c | 92 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 28 ++++++++++++++ 5 files changed, 125 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-mux.c
drivers/clk/Kconfig +3 -0
@@ -8,3 +8,6 @@ config USE_COMMON_STRUCT_CLK config USE_COMMON_CLK_DIVIDER bool + +config USE_COMMON_CLK_MUX + bool
drivers/clk/Makefile +1 -0
@@ -2,3 +2,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o obj-$(CONFIG_USE_COMMON_CLK_DIVIDER) += clk-divider.o +obj-$(CONFIG_USE_COMMON_CLK_MUX) += clk-mux.o
drivers/clk/clk-divider.c +1 -1
@@ -1,5 +1,5 @@/* -* Copyright (C) 2011 Sascha Hauer <[email protected]> +* Copyright (C) 2011 Sascha Hauer, Pengutronix <[email protected]> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as
drivers/clk/clk-mux.c new file +92 -0
92 lines not on this page · raw message
include/linux/clk.h +28 -0
@@ -211,6 +211,34 @@ struct clk_divider {extern struct clk_ops clk_divider_ops; +/** +* clock multiplexer +* +* @clk clock source +* @reg the register this multiplexer can be configured with +* @shift the shift to the start bit of this multiplexer +* @width the width in bits of this multiplexer +* @num_clks number of parent clocks +* @lock register lock +* @clks array of possible parents for this multiplexer. Can contain +* holes with NULL in it for invalid register settings +* +* This clock implements get_parent/set_parent. prepare/unprepare, +* enable/disable and get_rate operations are passed through to the parent, +* the rate is not adjustable. +*/ +struct clk_mux { +struct clk clk; +void __iomem *reg; +unsigned char shift; +unsigned char width; +unsigned char num_clks; +spinlock_t *lock; +struct clk **clks; +}; + +extern struct clk_ops clk_mux_ops; +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */ /*
Signature · 1 line
1.7.4.1
PATCH 6/10 clk: Add support for a generic clock multiplexer
Quoted 40 lines · Sascha Hauer
This patch adds support for a common type of clock multiplexer. The multiplexer is described with register, shift and width and an array of clocks which correspond to the bit value.
Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk-divider.c | 2 +- drivers/clk/clk-mux.c | 92 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 28 ++++++++++++++ 5 files changed, 125 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-mux.cdrivers/clk/Kconfig +3
-0@@ -8,3 +8,6 @@ config USE_COMMON_STRUCT_CLK config USE_COMMON_CLK_DIVIDER bool + +config USE_COMMON_CLK_MUX + booldrivers/clk/Makefile +1
-0@@ -2,3 +2,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o obj-$(CONFIG_USE_COMMON_CLK_DIVIDER) += clk-divider.o +obj-$(CONFIG_USE_COMMON_CLK_MUX) += clk-mux.odrivers/clk/clk-divider.c +0
-0
drivers/clk/clk-divider.c line 2
Quoted 3 lines
drivers/clk/clk-divider.c +1
-1@@ -1,5 +1,5 @@/* -* Copyright (C) 2011 Sascha Hauer <[email protected]> +* Copyright (C) 2011 Sascha Hauer, Pengutronix <[email protected]>
This should go into an earlier patch.
Quoted 34 lines
drivers/clk/clk-divider.c +0
-0* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as drivers/clk/clk-mux.c new file +25
-0@@ -0,0 +1,92 @@ +/* +* Copyright (C) 2011 Sascha Hauer, Pengutronix <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* Standard functionality for the common clock API. +*/ +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/io.h> + +#define to_clk_mux (clk) (container_of(clk, struct clk_mux, clk)) + +static struct clk *clk_mux_get_parent (struct clk *clk) +{ +struct clk_mux *mux =to_clk_mux (clk); +u32 val; + + val =readl (mux->reg) >> mux->shift; + val &= (1 << mux->width) -1 ; + +if (val >= mux->num_clks) +return ERR_PTR (-EINVAL );
drivers/clk/clk-mux.c line 35
Quoted 10 lines
drivers/clk/clk-mux.c new file +10
-0+ +return mux->clks[val]; +} + +static int clk_mux_set_parent (struct clk *clk,struct clk *parent) +{ +struct clk_mux *mux =to_clk_mux (clk); +u32 val; +int i; +unsigned long flags =0 ;
= 0 isn't needed. (Or does gcc wail without it?)
Quoted 34 lines
drivers/clk/clk-mux.c new file +34
-0+ +for (i =0 ; i < mux->num_clks; i++) +if (mux->clks[i] == parent) +break ; + +if (i == mux->num_clks) +return -EINVAL ; + +if (mux->lock) +spin_lock_irqsave (mux->lock, flags); + + val =readl (mux->reg); + val &= ~(((1 << mux->width) -1 ) << mux->shift); + val |= i << mux->shift; +writel (val, mux->reg); + +if (mux->lock) +spin_unlock_irqrestore (mux->lock, flags); + +return 0 ; +} + +static long clk_mux_round_rate (struct clk *clk,unsigned long rate) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return PTR_ERR (parent); + +return clk_get_rate (parent); +} + +static int clk_mux_set_rate (struct clk *clk,unsigned long desired) +{
drivers/clk/clk-mux.c line 79
Quoted 10 lines
drivers/clk/clk-mux.c new file +10
-0+struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return PTR_ERR (parent); + +if (desired !=clk_get_rate (parent)) +return -EINVAL ; + +return 0 ; +}
Isn't not implementing set_rate good enough? Ditto for .round_rate.
Quoted 21 lines
drivers/clk/clk-mux.c new file +12
-0+struct clk_ops clk_mux_ops = { + .prepare = clk_parent_prepare, + .unprepare = clk_parent_unprepare, + .enable = clk_parent_enable, + .disable = clk_parent_disable, + .get_rate = clk_parent_get_rate, + .round_rate = clk_mux_round_rate, + .set_rate = clk_mux_set_rate, + .get_parent = clk_mux_get_parent, + .set_parent = clk_mux_set_parent, +}; +EXPORT_SYMBOL_GPL (clk_mux_ops);include/linux/clk.h +1
-0@@ -211,6 +211,34 @@ struct clk_divider {extern struct clk_ops clk_divider_ops; +/**
include/linux/clk.h struct clk_divider { · line 224
Quoted 10 lines
include/linux/clk.h +10
-0+* clock multiplexer +* +* @clk clock source +* @reg the register this multiplexer can be configured with +* @shift the shift to the start bit of this multiplexer +* @width the width in bits of this multiplexer +* @num_clks number of parent clocks +* @lock register lock +* @clks array of possible parents for this multiplexer. Can contain +* holes with NULL in it for invalid register settings
NULL is a valid clk, isn't it?
Quoted 29 lines
include/linux/clk.h +17
-0+* +* This clock implements get_parent/set_parent. prepare/unprepare, +* enable/disable and get_rate operations are passed through to the parent, +* the rate is not adjustable. +*/ +struct clk_mux { +struct clk clk; +void __iomem *reg; +unsigned char shift; +unsigned char width; +unsigned char num_clks; +spinlock_t *lock; +struct clk **clks; +}; + +extern struct clk_ops clk_mux_ops; +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */ /* Signature · 7 lines
1.7.4.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel at lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Sascha Hauer
maintainerPATCH 6/10 clk: Add support for a generic clock multiplexer
Quoted 37 lines · Uwe Kleine-K?nig
Quoted 36 lines · Sascha Hauer
This patch adds support for a common type of clock multiplexer. The multiplexer is described with register, shift and width and an array of clocks which correspond to the bit value.
Signed-off-by Sascha Hauer <[email protected]>Cc Jeremy Kerr <[email protected]>--- drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk-divider.c | 2 +- drivers/clk/clk-mux.c | 92 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 28 ++++++++++++++ 5 files changed, 125 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-mux.cdrivers/clk/Kconfig +3
-0@@ -8,3 +8,6 @@ config USE_COMMON_STRUCT_CLK config USE_COMMON_CLK_DIVIDER bool + +config USE_COMMON_CLK_MUX + booldrivers/clk/Makefile +1
-0@@ -2,3 +2,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o obj-$(CONFIG_USE_COMMON_CLK_DIVIDER) += clk-divider.o +obj-$(CONFIG_USE_COMMON_CLK_MUX) += clk-mux.odrivers/clk/clk-divider.c +0
-0
Quoted 8 lines
drivers/clk/clk-divider.c line 2
Quoted 7 lines
index 2de94df..e3f5b7a 100644
drivers/clk/clk-divider.c +1
-1@@ -1,5 +1,5 @@/* -* Copyright (C) 2011 Sascha Hauer <[email protected]> +* Copyright (C) 2011 Sascha Hauer, Pengutronix <[email protected]> This should go into an earlier patch.
Indeed, already fixed.
Quoted 8 lines
drivers/clk/clk-divider.c
Quoted 7 lines
drivers/clk/clk-divider.c +7
-0+ +static int clk_mux_set_parent (struct clk *clk,struct clk *parent) +{ +struct clk_mux *mux =to_clk_mux (clk); +u32 val; +int i; +unsigned long flags =0 ;= 0 isn't needed. (Or does gcc wail without it?)
At least my gcc is not smart engough for this. flags may be used unitialized.
Quoted 38 lines
Quoted 38 lines
drivers/clk/clk-divider.c +37
-0+ +for (i =0 ; i < mux->num_clks; i++) +if (mux->clks[i] == parent) +break ; + +if (i == mux->num_clks) +return -EINVAL ; + +if (mux->lock) +spin_lock_irqsave (mux->lock, flags); + + val =readl (mux->reg); + val &= ~(((1 << mux->width) -1 ) << mux->shift); + val |= i << mux->shift; +writel (val, mux->reg); + +if (mux->lock) +spin_unlock_irqrestore (mux->lock, flags); + +return 0 ; +} + +static long clk_mux_round_rate (struct clk *clk,unsigned long rate) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent)) +return PTR_ERR (parent); + +return clk_get_rate (parent); +} + +static int clk_mux_set_rate (struct clk *clk,unsigned long desired) +{ +struct clk *parent =clk_get_parent (clk); + +if (IS_ERR (parent))
Quoted 8 lines
drivers/clk/clk-divider.c
Quoted 7 lines
drivers/clk/clk-divider.c +7
-0+return PTR_ERR (parent); + +if (desired !=clk_get_rate (parent)) +return -EINVAL ; + +return 0 ; +}Isn't not implementing
set_rategood enough? Ditto for .round_rate.
Yes, I removed these.
Quoted 12 lines
Quoted 12 lines
+/**
+ * clock multiplexer
+ *
+ * @clk clock source
+ * @reg the register this multiplexer can be configured with
+ * @shift the shift to the start bit of this multiplexer
+ * @width the width in bits of this multiplexer
+ * @num_clks number of parent clocks
+ * @lock register lock
+ * @clks array of possible parents for this multiplexer. Can contain
+ * holes with NULL in it for invalid register settings
Quoted 1 line
NULL is a valid clk, isn't it?
You're right. I think for invalid mux settings we should ERR_PTR(-EINVAL) or similar to the array.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH 6/10 clk: Add support for a generic clock multiplexer
Quoted 11 lines · Sascha Hauer
Quoted 9 lines · Uwe Kleine-K?nig
drivers/clk/clk-mux.c line 35
Quoted 7 lines · Sascha Hauer
drivers/clk/clk-mux.c new file +7
-0+ +static int clk_mux_set_parent (struct clk *clk,struct clk *parent) +{ +struct clk_mux *mux =to_clk_mux (clk); +u32 val; +int i; +unsigned long flags =0 ;= 0 isn't needed. (Or does gcc wail without it?)
Quoted 1 line
At least my gcc is not smart engough for this. flags may be used unitialized.
Then please use
unsigned long uninitialized_var(flags);
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
PATCH 6/10 clk: Add support for a generic clock multiplexer
In reply to Sascha HauerQuoted 12 lines · Sascha Hauer
Quoted 12 lines
Quoted 12 lines
+/**
+ * clock multiplexer
+ *
+ * @clk clock source
+ * @reg the register this multiplexer can be configured with
+ * @shift the shift to the start bit of this multiplexer
+ * @width the width in bits of this multiplexer
+ * @num_clks number of parent clocks
+ * @lock register lock
+ * @clks array of possible parents for this multiplexer. Can contain
+ * holes with NULL in it for invalid register settings
Quoted 3 lines
Quoted 1 line
NULL is a valid clk, isn't it?
You're right. I think for invalid mux settings we should
ERR_PTR(-EINVAL)or similar to the array.
Note that if you're using clkdev you can't actually return a NULL clock to the caller of clk_get() due to:
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
struct clk *clk;
mutex_lock(&clocks_mutex);
clk = clk_find(dev_id, con_id);
if (clk && !__clk_get(clk))
clk = NULL;
mutex_unlock(&clocks_mutex);
return clk ? clk : ERR_PTR(-ENOENT);
}So all this talk about NULL being a valid clock returned to drivers is kinda pointless unless the mach has a custom clk_get() implementation. Perhaps we should force clkdev on users of the generic struct clk framework?
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 6/10 clk: Add support for a generic clock multiplexer
Quoted 34 lines · Stephen Boyd
Quoted 12 lines · Sascha Hauer
Quoted 12 lines
Quoted 12 lines
+/**
+ * clock multiplexer
+ *
+ * @clk clock source
+ * @reg the register this multiplexer can be configured with
+ * @shift the shift to the start bit of this multiplexer
+ * @width the width in bits of this multiplexer
+ * @num_clks number of parent clocks
+ * @lock register lock
+ * @clks array of possible parents for this multiplexer. Can contain
+ * holes with NULL in it for invalid register settingsQuoted 3 lines
Quoted 1 line
NULL is a valid clk, isn't it?
You're right. I think for invalid mux settings we should
ERR_PTR(-EINVAL)or similar to the array.Note that if you're using clkdev you can't actually return a NULL clock to the caller of
clk_get()due to:struct clk *clk_get_sys(const char
*dev_id, const char*con_id){ struct clk *clk; mutex_lock(&clocks_mutex); clk = clk_find(dev_id, con_id); if (clk && !__clk_get(clk)) clk = NULL; mutex_unlock(&clocks_mutex); return clk ? clk : ERR_PTR(-ENOENT); }
Quoted 2 lines
So all this talk about NULL being a valid clock returned to drivers is kinda pointless unless the mach has a custom
clk_get()implementation.
Oops, clk_get_sys() and clk_find() really should be fixed for this. I'll sort a patch for it.
PATCH 6/10 clk: Add support for a generic clock multiplexer
Quoted 2 lines · Russell King - ARM Linux
Oops,
clk_get_sys()andclk_find()really should be fixed for this. I'll sort a patch for it.
And here it is:
8<----
Subject: [PATCH] Fix clkdev return value for NULL clk case
clkdev may incorrectly cause a clkdev entry with a NULL clk to return -ENOENT. This is not the intention of this code; -ENOENT should only be returned if the clock entry can not be found in the table. Fix this.
--- drivers/clk/clkdev.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
drivers/clk/clkdev.c +9 -10
@@ -32,10 +32,9 @@ static DEFINE_MUTEX(clocks_mutex);* Then we take the most specific entry - with the following * order of precedence: dev+con > dev only > con only. */ -static struct clk *clk_find (const char *dev_id,const char *con_id) +static struct clk_lookup *clk_find (const char *dev_id,const char *con_id) { -struct clk_lookup *p; -struct clk *clk =NULL ; +struct clk_lookup *p, *cl =NULL ;int match, best =0 ;list_for_each_entry (p, &clocks, node) {
@@ -52,27 +51,27 @@ static struct clk *clk_find(const char *dev_id, const char *con_id) }if (match > best) { - clk = p->clk; + cl = p;if (match !=3 ) best = match;else break ; } } -return clk; +return cl; }struct clk *clk_get_sys (const char *dev_id,const char *con_id) { -struct clk *clk; +struct clk_lookup *cl;mutex_lock (&clocks_mutex); - clk =clk_find (dev_id, con_id); -if (clk && !__clk_get (clk)) - clk =NULL ; + cl =clk_find (dev_id, con_id); +if (cl && !__clk_get (cl->clk)) + cl =NULL ;mutex_unlock (&clocks_mutex); -return clk ? clk :ERR_PTR (-ENOENT ); +return cl ? cl->clk :ERR_PTR (-ENOENT ); }EXPORT_SYMBOL (clk_get_sys);
PATCH 6/10 clk: Add support for a generic clock multiplexer
Quoted 5 lines · Russell King - ARM Linux
Quoted 2 lines · Russell King - ARM Linux
Oops,
clk_get_sys()andclk_find()really should be fixed for this. I'll sort a patch for it.And here it is:
Quoted 8 lines
8<----
Subject: [PATCH] Fix clkdev return value for NULL clk caseclkdev may incorrectly cause a clkdev entry with a NULL clk to return
-ENOENT. This is not the intention of this code;-ENOENTshould only be returned if the clock entry can not be found in the table. Fix this.Signed-off-by Russell King <[email protected]>
Thanks. Feel free to include a:
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Sascha Hauer
maintainerPATCH 7/10 ARM i.MX: Support for clock building blocks.
In reply to Sascha HauerThis patch adds generic code to handle different common patterns in i.MX clock code.
* gates clk_[en|dis]able
* groups Group together clocks which should be enabled at once.
--- arch/arm/plat-mxc/clock.c | 182 ++++++++++++++++++++++++++++++++ arch/arm/plat-mxc/include/mach/clock.h | 126 +++++++++++++++++++++- 2 files changed, 305 insertions(+), 3 deletions(-)
arch/arm/plat-mxc/clock.c +182 -0
@@ -44,6 +44,8 @@static LIST_HEAD (clocks);static DEFINE_MUTEX (clocks_mutex); +#ifndef CONFIG_USE_COMMON_STRUCT_CLK +/*------------------------------------------------------------------------- * Standard clock functions defined in include/linux/clk.h *-------------------------------------------------------------------------*/
@@ -199,6 +201,7 @@ struct clk *clk_get_parent(struct clk *clk) return clk->parent; }EXPORT_SYMBOL (clk_get_parent); +#endif /* * Get the resulting clock rate from a PLL register value and the input
@@ -244,3 +247,182 @@ unsigned long mxc_decode_pll(unsigned int reg_val, u32 freq)return ll; } + +#ifdef CONFIG_USE_COMMON_STRUCT_CLK + +DEFINE_SPINLOCK (imx_ccm_lock); + +/* clk gate support */ + +#define to_clk_gate (clk) (container_of(clk, struct clk_gate, clk)) + +static int clk_gate_enable (struct clk *clk) +{ +struct clk_gate *gate =to_clk_gate (clk); +u32 val; +int ret; +unsigned long flags; + +if (gate->parent) { + ret =clk_parent_enable (gate->parent); +if (ret) +return ret; + } + +spin_lock_irqsave (&imx_ccm_lock, flags); + + val =readl (gate->reg); + +if (gate->flags &CLK_GATE_TWO_BITS ) { +if (gate->flags &CLK_GATE_ENABLE_WAIT ) { + val &= ~(3 << (gate->shift *2 )); + val |=1 << (gate->shift *2 ); + }else { + val |=3 << (gate->shift *2 ); + } + }else { + val |=1 << (gate->shift); + } + +writel (val, gate->reg); + +spin_unlock_irqrestore (&imx_ccm_lock, flags); + +return 0 ; +} + +static void clk_gate_disable (struct clk *clk) +{ +struct clk_gate *gate =to_clk_gate (clk); +unsigned long flags; +u32 val; + +spin_lock_irqsave (&imx_ccm_lock, flags); + + val =readl (gate->reg); + +if (gate->flags &CLK_GATE_TWO_BITS ) { +if (gate->flags &CLK_GATE_DISABLE_WAIT ) { + val &= ~(3 << (gate->shift *2 )); + val |=1 << (gate->shift *2 ); + }else { + val &= ~(3 << (gate->shift *2 )); + } + }else { + val &= ~(1 << (gate->shift)); + } + +writel (val, gate->reg); + +spin_unlock_irqrestore (&imx_ccm_lock, flags); + +if (gate->parent) +clk_parent_disable (gate->parent); +} + +static struct clk *clk_gate_get_parent (struct clk *clk) +{ +struct clk_gate *gate =to_clk_gate (clk); + +return gate->parent; +} + +struct clk_ops clk_gate_ops = { + .prepare = clk_parent_prepare, + .unprepare = clk_parent_unprepare, + .enable = clk_gate_enable, + .disable = clk_gate_disable, + .get_rate = clk_parent_get_rate, + .round_rate = clk_parent_round_rate, + .set_rate = clk_parent_set_rate, + .get_parent = clk_gate_get_parent, +}; +EXPORT_SYMBOL_GPL (clk_gate_ops); + +#define to_clk_group (clk) (container_of(clk, struct clk_group, clk)) + +static int clk_group_prepare (struct clk *clk) +{ +struct clk_group *group =to_clk_group (clk); +int i, ret; + +for (i =0 ; i < group->num_clks; i++) { + ret =clk_prepare (group->clks[i]); +if (ret) + goto out; + } + +return 0 ; +out: +while (i-- >0 ) +clk_disable (group->clks[i]); +return ret; +} + +static void clk_group_unprepare (struct clk *clk) +{ +struct clk_group *group =to_clk_group (clk); +int i; + +for (i =0 ; i < group->num_clks; i++) +clk_disable (group->clks[i]); +} + +static int clk_group_enable (struct clk *clk) +{ +struct clk_group *group =to_clk_group (clk); +int i, ret; + +for (i =0 ; i < group->num_clks; i++) { + ret =clk_enable (group->clks[i]); +if (ret) + goto out; + } + +return 0 ; +out: +while (i-- >0 ) +clk_disable (group->clks[i]); +return ret; +} + +static void clk_group_disable (struct clk *clk) +{ +struct clk_group *group =to_clk_group (clk); +int i; + +for (i =0 ; i < group->num_clks; i++) +clk_disable (group->clks[i]); +} + +static unsigned long clk_group_get_rate (struct clk *clk) +{ +struct clk_group *group =to_clk_group (clk); + +return clk_get_rate (group->clks[0 ]); +} + +static long clk_group_round_rate (struct clk *clk,unsigned long rate) +{ +struct clk_group *group =to_clk_group (clk); + +return clk_round_rate (group->clks[0 ], rate); +} + +static int clk_group_set_rate (struct clk *clk,unsigned long rate) +{ +struct clk_group *group =to_clk_group (clk); + +return clk_set_rate (group->clks[0 ], rate); +} + +struct clk_ops clk_group_ops = { + .prepare = clk_group_prepare, + .unprepare = clk_group_unprepare, + .enable = clk_group_enable, + .disable = clk_group_disable, + .get_rate = clk_group_get_rate, + .round_rate = clk_group_round_rate, + .set_rate = clk_group_set_rate, +}; +#endif /* CONFIG_USE_COMMON_STRUCT_CLK */
arch/arm/plat-mxc/include/mach/clock.h +123 -3
133 lines not on this page · raw message
Signature · 1 line
1.7.4.1
Sascha Hauer
maintainerPATCH 8/10 ARM i.MX: Add generic support for pllv2
In reply to Sascha HauerThe pllv2 is found on i.MX5 SoCs.
--- arch/arm/plat-mxc/Makefile | 1 + arch/arm/plat-mxc/include/mach/clock.h | 24 ++++ arch/arm/plat-mxc/pllv2.c | 228 ++++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+), 0 deletions(-) create mode 100644 arch/arm/plat-mxc/pllv2.c
arch/arm/plat-mxc/Makefile +1 -0
@@ -5,6 +5,7 @@ # Common support obj-y := clock.o gpio.o time.o devices.o cpu.o system.o irq-common.o +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += pllv2.o # MX51 uses the TZIC interrupt controller, older platforms use AVIC obj-$(CONFIG_MXC_TZIC) += tzic.o obj-$(CONFIG_MXC_AVIC) += avic.o
arch/arm/plat-mxc/include/mach/clock.h +24 -0
@@ -182,5 +182,29 @@ extern struct clk_ops clk_group_ops; .num_clks = ARRAY_SIZE(_clks), \ } +/** +* pll v2 +* +* @clk clock source +* @parent the parent clock +* @base base address of pll registers +* +* PLL clock version two, found on i.MX50/51/53 +*/ +struct clk_pllv2 { +struct clk clk; +struct clk *parent; +void __iomem *base; +}; + +extern struct clk_ops clk_pllv2_ops; + +#define DEFINE_CLK_PLLV2 (name, _parent, _base) \ + struct clk_pllv2 name = { \ + .clk = INIT_CLK(name.clk, clk_pllv2_ops), \ + .parent = (_parent), \ + .base = (_base), \ + } +#endif /* __ASSEMBLY__ */ #endif /* __ASM_ARCH_MXC_CLOCK_H__ */
arch/arm/plat-mxc/pllv2.c new file +228 -0
228 lines not on this page · raw message
Signature · 1 line
1.7.4.1
Sascha Hauer
maintainerPATCH 9/10 ARM i.MX51/53: reimplement clock support
In reply to Sascha HauerReimplement i.MX51/53 clock support. This is tested with a babbage board and a loco board up to the point that UARTs, FEC and USB work. There are surely bugs left in the code, but I found several in the old code while reimplementing it, so who cares...
The implementation is mostly based on the datasheet and not the old code.
The old code is left in the tree and removed in the next patch.
--- arch/arm/mach-mx5/Kconfig | 6 + arch/arm/mach-mx5/Makefile | 2 +- arch/arm/mach-mx5/clock-imx51-imx53.c | 420 +++++++++++++++++++++++++++++++ arch/arm/plat-mxc/include/mach/clkdev.h | 2 + arch/arm/plat-mxc/include/mach/clock.h | 3 + 5 files changed, 432 insertions(+), 1 deletions(-) create mode 100644 arch/arm/mach-mx5/clock-imx51-imx53.c
arch/arm/mach-mx5/Kconfig +6 -0
@@ -26,12 +26,18 @@ config SOC_IMX51 select ARCH_MXC_AUDMUX_V2 select ARCH_HAS_CPUFREQ select ARCH_MX51 + select USE_COMMON_STRUCT_CLK + select USE_COMMON_CLK_DIVIDER + select USE_COMMON_CLK_MUX config SOC_IMX53 bool select MXC_TZIC select ARCH_MXC_IOMUX_V3 select ARCH_MX53 + select USE_COMMON_STRUCT_CLK + select USE_COMMON_CLK_DIVIDER + select USE_COMMON_CLK_MUX comment "MX5 platforms:"
arch/arm/mach-mx5/Makefile +1 -1
@@ -3,7 +3,7 @@ # # Object file lists. -obj-y := cpu.o mm.o clock-mx51-mx53.o devices.o ehci.o system.o +obj-y := cpu.o mm.o clock-imx51-imx53.o devices.o ehci.o system.o obj-$(CONFIG_SOC_IMX50) += mm-mx50.o obj-$(CONFIG_CPU_FREQ_IMX) += cpu_op-mx51.o
arch/arm/mach-mx5/clock-imx51-imx53.c new file +420 -0
420 lines not on this page · raw message
arch/arm/plat-mxc/include/mach/clkdev.h +2 -0
@@ -1,7 +1,9 @@#ifndef __ASM_MACH_CLKDEV_H#define __ASM_MACH_CLKDEV_H +#ifndef CONFIG_USE_COMMON_STRUCT_CLK #define __clk_get (clk) ({ 1; })#define __clk_put (clk) do { } while (0) +#endif #endif
arch/arm/plat-mxc/include/mach/clock.h +3 -0
@@ -25,6 +25,8 @@struct module ; +#ifdef CONFIG_USE_COMMON_STRUCT_CLK +#else struct clk { int id; /* Source clock this clk depends on */
@@ -56,6 +58,7 @@ struct clk {/* Function ptr to set the parent clock of the clock. */ int (*set_parent) (struct clk *, struct clk *); }; +#endif unsigned long mxc_decode_pll (unsigned int pll,u32 f_ref);
Signature · 1 line
1.7.4.1
Sascha Hauer
maintainerPATCH 10/10 ARM i.MX51/53: remove old clock support
In reply to Sascha Hauerreimplemented and not used anymore.
--- arch/arm/mach-mx5/clock-mx51-mx53.c | 1579 ----------------------------------- arch/arm/mach-mx5/crm_regs.h | 249 +------ 2 files changed, 1 insertions(+), 1827 deletions(-) delete mode 100644 arch/arm/mach-mx5/clock-mx51-mx53.c
arch/arm/mach-mx5/clock-mx51-mx53.c deleted +0 -1579
@@ -1,1579 +0,0 @@ -/* -* Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. -* Copyright (C) 2009-2010 Amit Kucheria <[email protected]> -* -* The code contained herein is licensed under the GNU General Public -* License. You may obtain a copy of the GNU General Public License -* Version 2 or later at the following locations: -* -* http://www.opensource.org/licenses/gpl-license.html -* http://www.gnu.org/copyleft/gpl.html -*/ - -#include <linux/mm.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/clkdev.h> - -#include <asm/div64.h> - -#include <mach/hardware.h> -#include <mach/common.h> -#include <mach/clock.h> - -#include "crm_regs.h" - -/* External clock values passed-in by the board code */ -static unsigned long external_high_reference, external_low_reference; -static unsigned long oscillator_reference, ckih2_reference; - -static struct clk osc_clk; -static struct clk pll1_main_clk; -static struct clk pll1_sw_clk; -static struct clk pll2_sw_clk; -static struct clk pll3_sw_clk; -static struct clk mx53_pll4_sw_clk; -static struct clk lp_apm_clk; -static struct clk periph_apm_clk; -static struct clk ahb_clk; -static struct clk ipg_clk; -static struct clk usboh3_clk; -static struct clk emi_fast_clk; -static struct clk ipu_clk; -static struct clk mipi_hsc1_clk; -static struct clk esdhc1_clk; -static struct clk esdhc2_clk; -static struct clk esdhc3_mx53_clk; - -#define MAX_DPLL_WAIT_TRIES 1000/* 1000 * udelay(1) = 1ms */ - -/* calculate best pre and post dividers to get the required divider */ -static void __calc_pre_post_dividers (u32 div,u32 *pre,u32 *post, -u32 max_pre,u32 max_post) -{ -if (div >= max_pre * max_post) { - *pre = max_pre; - *post = max_post; - }else if (div >= max_pre) { -u32 min_pre, temp_pre, old_err, err; - min_pre =DIV_ROUND_UP (div, max_post); - old_err = max_pre; -for (temp_pre = max_pre; temp_pre >= min_pre; temp_pre--) { - err = div % temp_pre; -if (err ==0 ) { - *pre = temp_pre; -break ; - } - err = temp_pre - err; -if (err < old_err) { - old_err = err; - *pre = temp_pre; - } - } - *post =DIV_ROUND_UP (div, *pre); - }else { - *pre = div; - *post =1 ; - } -} - -static void _clk_ccgr_setclk (struct clk *clk,unsigned mode) -{ -u32 reg =__raw_readl (clk->enable_reg); - - reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); - reg |= mode << clk->enable_shift; - -__raw_writel (reg, clk->enable_reg); -} - -static int _clk_ccgr_enable (struct clk *clk) -{ -_clk_ccgr_setclk (clk, MXC_CCM_CCGRx_MOD_ON); -return 0 ; -} - -static void _clk_ccgr_disable (struct clk *clk) -{ -_clk_ccgr_setclk (clk, MXC_CCM_CCGRx_MOD_OFF); -} - -static int _clk_ccgr_enable_inrun (struct clk *clk) -{ -_clk_ccgr_setclk (clk, MXC_CCM_CCGRx_MOD_IDLE); -return 0 ; -} - -static void _clk_ccgr_disable_inwait (struct clk *clk) -{ -_clk_ccgr_setclk (clk, MXC_CCM_CCGRx_MOD_IDLE); -} - -/* -* For the 4-to-1 muxed input clock -*/ -static inline u32 _get_mux (struct clk *parent,struct clk *m0, -struct clk *m1,struct clk *m2,struct clk *m3) -{ -if (parent == m0) -return 0 ; -else if (parent == m1) -return 1 ; -else if (parent == m2) -return 2 ; -else if (parent == m3) -return 3 ; -else -BUG (); - -return -EINVAL ; -} - -static inline void __iomem *_mx51_get_pll_base (struct clk *pll) -{ -if (pll == &pll1_main_clk) -return MX51_DPLL1_BASE ; -else if (pll == &pll2_sw_clk) -return MX51_DPLL2_BASE ; -else if (pll == &pll3_sw_clk) -return MX51_DPLL3_BASE ; -else -BUG (); - -return NULL ; -} - -static inline void __iomem *_mx53_get_pll_base (struct clk *pll) -{ -if (pll == &pll1_main_clk) -return MX53_DPLL1_BASE ; -else if (pll == &pll2_sw_clk) -return MX53_DPLL2_BASE ; -else if (pll == &pll3_sw_clk) -return MX53_DPLL3_BASE ; -else if (pll == &mx53_pll4_sw_clk) -return MX53_DPLL4_BASE ; -else -BUG (); - -return NULL ; -} - -static inline void __iomem *_get_pll_base (struct clk *pll) -{ -if (cpu_is_mx51 ()) -return _mx51_get_pll_base (pll); -else -return _mx53_get_pll_base (pll); -} - -static unsigned long clk_pll_get_rate (struct clk *clk) -{ -long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; -unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl; -void __iomem *pllbase; -s64 temp; -unsigned long parent_rate; - - parent_rate =clk_get_rate (clk->parent); - - pllbase =_get_pll_base (clk); - - dp_ctl =__raw_readl (pllbase +MXC_PLL_DP_CTL ); - pll_hfsm = dp_ctl &MXC_PLL_DP_CTL_HFSM ; - dbl = dp_ctl &MXC_PLL_DP_CTL_DPDCK0_2_EN ; - -if (pll_hfsm ==0 ) { - dp_op =__raw_readl (pllbase +MXC_PLL_DP_OP ); - dp_mfd =__raw_readl (pllbase +MXC_PLL_DP_MFD ); - dp_mfn =__raw_readl (pllbase +MXC_PLL_DP_MFN ); - }else { - dp_op =__raw_readl (pllbase +MXC_PLL_DP_HFS_OP ); - dp_mfd =__raw_readl (pllbase +MXC_PLL_DP_HFS_MFD ); - dp_mfn =__raw_readl (pllbase +MXC_PLL_DP_HFS_MFN ); - } - pdf = dp_op &MXC_PLL_DP_OP_PDF_MASK ; - mfi = (dp_op &MXC_PLL_DP_OP_MFI_MASK ) >>MXC_PLL_DP_OP_MFI_OFFSET ; - mfi = (mfi <=5 ) ?5 : mfi; - mfd = dp_mfd &MXC_PLL_DP_MFD_MASK ; - mfn = mfn_abs = dp_mfn &MXC_PLL_DP_MFN_MASK ; -/* Sign extend to 32-bits */ -if (mfn >=0x04000000 ) { - mfn |=0xFC000000 ; - mfn_abs = -mfn; - } - - ref_clk =2 * parent_rate; -if (dbl !=0 ) - ref_clk *=2 ; - - ref_clk /= (pdf +1 ); - temp = (u64 ) ref_clk * mfn_abs; -do_div (temp, mfd +1 ); -if (mfn <0 ) - temp = -temp; - temp = (ref_clk * mfi) + temp; - -return temp; -} - -static int _clk_pll_set_rate (struct clk *clk,unsigned long rate) -{ -u32 reg; -void __iomem *pllbase; - -long mfi, pdf, mfn, mfd =999999 ; -s64 temp64; -unsigned long quad_parent_rate; -unsigned long pll_hfsm, dp_ctl; -unsigned long parent_rate; - - parent_rate =clk_get_rate (clk->parent); - - pllbase =_get_pll_base (clk); - - quad_parent_rate =4 * parent_rate; - pdf = mfi =-1 ; -while (++pdf <16 && mfi <5 ) - mfi = rate * (pdf+1 ) / quad_parent_rate; -if (mfi >15 ) -return -EINVAL ; - pdf--; - - temp64 = rate * (pdf+1 ) - quad_parent_rate * mfi; -do_div (temp64, quad_parent_rate/1000000 ); - mfn = (long )temp64; - - dp_ctl =__raw_readl (pllbase +MXC_PLL_DP_CTL ); -/* use dpdck0_2 */ -__raw_writel (dp_ctl |0x1000L , pllbase +MXC_PLL_DP_CTL ); - pll_hfsm = dp_ctl &MXC_PLL_DP_CTL_HFSM ; -if (pll_hfsm ==0 ) { - reg = mfi <<4 | pdf; -__raw_writel (reg, pllbase +MXC_PLL_DP_OP ); -__raw_writel (mfd, pllbase +MXC_PLL_DP_MFD ); -__raw_writel (mfn, pllbase +MXC_PLL_DP_MFN ); - }else { - reg = mfi <<4 | pdf; -__raw_writel (reg, pllbase +MXC_PLL_DP_HFS_OP ); -__raw_writel (mfd, pllbase +MXC_PLL_DP_HFS_MFD ); -__raw_writel (mfn, pllbase +MXC_PLL_DP_HFS_MFN ); - } - -return 0 ; -} - -static int _clk_pll_enable (struct clk *clk) -{ -u32 reg; -void __iomem *pllbase; -int i =0 ; - - pllbase =_get_pll_base (clk); - reg =__raw_readl (pllbase +MXC_PLL_DP_CTL ) |MXC_PLL_DP_CTL_UPEN ; -__raw_writel (reg, pllbase +MXC_PLL_DP_CTL ); - -/* Wait for lock */ -do { - reg =__raw_readl (pllbase +MXC_PLL_DP_CTL ); -if (reg &MXC_PLL_DP_CTL_LRF ) -break ; - -udelay (1 ); - }while (++i <MAX_DPLL_WAIT_TRIES ); - -if (i ==MAX_DPLL_WAIT_TRIES ) { -pr_err ("MX5: pll locking failed\n" ); -return -EINVAL ; - } - -return 0 ; -} - -static void _clk_pll_disable (struct clk *clk) -{ -u32 reg; -void __iomem *pllbase; - - pllbase =_get_pll_base (clk); - reg =__raw_readl (pllbase +MXC_PLL_DP_CTL ) & ~MXC_PLL_DP_CTL_UPEN ; -__raw_writel (reg, pllbase +MXC_PLL_DP_CTL ); -} - -static int _clk_pll1_sw_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg, step; - - reg =__raw_readl (MXC_CCM_CCSR ); - -/* When switching from pll_main_clk to a bypass clock, first select a -* multiplexed clock in 'step_sel', then shift the glitchless mux -* 'pll1_sw_clk_sel'. -* -* When switching back, do it in reverse order -*/ -if (parent == &pll1_main_clk) { -/* Switch to pll1_main_clk */ - reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL ; -__raw_writel (reg,MXC_CCM_CCSR ); -/* step_clk mux switched to lp_apm, to save power. */ - reg =__raw_readl (MXC_CCM_CCSR ); - reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK ; - reg |= (MXC_CCM_CCSR_STEP_SEL_LP_APM << -MXC_CCM_CCSR_STEP_SEL_OFFSET ); - }else { -if (parent == &lp_apm_clk) { - step =MXC_CCM_CCSR_STEP_SEL_LP_APM ; - }else if (parent == &pll2_sw_clk) { - step =MXC_CCM_CCSR_STEP_SEL_PLL2_DIVIDED ; - }else if (parent == &pll3_sw_clk) { - step =MXC_CCM_CCSR_STEP_SEL_PLL3_DIVIDED ; - }else -return -EINVAL ; - - reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK ; - reg |= (step <<MXC_CCM_CCSR_STEP_SEL_OFFSET ); - -__raw_writel (reg,MXC_CCM_CCSR ); -/* Switch to step_clk */ - reg =__raw_readl (MXC_CCM_CCSR ); - reg |=MXC_CCM_CCSR_PLL1_SW_CLK_SEL ; - } -__raw_writel (reg,MXC_CCM_CCSR ); -return 0 ; -} - -static unsigned long clk_pll1_sw_get_rate (struct clk *clk) -{ -u32 reg, div; -unsigned long parent_rate; - - parent_rate =clk_get_rate (clk->parent); - - reg =__raw_readl (MXC_CCM_CCSR ); - -if (clk->parent == &pll2_sw_clk) { - div = ((reg &MXC_CCM_CCSR_PLL2_PODF_MASK ) >> -MXC_CCM_CCSR_PLL2_PODF_OFFSET ) +1 ; - }else if (clk->parent == &pll3_sw_clk) { - div = ((reg &MXC_CCM_CCSR_PLL3_PODF_MASK ) >> -MXC_CCM_CCSR_PLL3_PODF_OFFSET ) +1 ; - }else - div =1 ; -return parent_rate / div; -} - -static int _clk_pll2_sw_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg; - - reg =__raw_readl (MXC_CCM_CCSR ); - -if (parent == &pll2_sw_clk) - reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL ; -else - reg |=MXC_CCM_CCSR_PLL2_SW_CLK_SEL ; - -__raw_writel (reg,MXC_CCM_CCSR ); -return 0 ; -} - -static int _clk_lp_apm_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg; - -if (parent == &osc_clk) - reg =__raw_readl (MXC_CCM_CCSR ) & ~MXC_CCM_CCSR_LP_APM_SEL ; -else -return -EINVAL ; - -__raw_writel (reg,MXC_CCM_CCSR ); - -return 0 ; -} - -static unsigned long clk_cpu_get_rate (struct clk *clk) -{ -u32 cacrr, div; -unsigned long parent_rate; - - parent_rate =clk_get_rate (clk->parent); - cacrr =__raw_readl (MXC_CCM_CACRR ); - div = (cacrr &MXC_CCM_CACRR_ARM_PODF_MASK ) +1 ; - -return parent_rate / div; -} - -static int clk_cpu_set_rate (struct clk *clk,unsigned long rate) -{ -u32 reg, cpu_podf; -unsigned long parent_rate; - - parent_rate =clk_get_rate (clk->parent); - cpu_podf = parent_rate / rate -1 ; -/* use post divider to change freq */ - reg =__raw_readl (MXC_CCM_CACRR ); - reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK ; - reg |= cpu_podf <<MXC_CCM_CACRR_ARM_PODF_OFFSET ; -__raw_writel (reg,MXC_CCM_CACRR ); - -return 0 ; -} - -static int _clk_periph_apm_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg, mux; -int i =0 ; - - mux =_get_mux (parent, &pll1_sw_clk, &pll3_sw_clk, &lp_apm_clk,NULL ); - - reg =__raw_readl (MXC_CCM_CBCMR ) & ~MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK ; - reg |= mux <<MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET ; -__raw_writel (reg,MXC_CCM_CBCMR ); - -/* Wait for lock */ -do { - reg =__raw_readl (MXC_CCM_CDHIPR ); -if (!(reg &MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY )) -break ; - -udelay (1 ); - }while (++i <MAX_DPLL_WAIT_TRIES ); - -if (i ==MAX_DPLL_WAIT_TRIES ) { -pr_err ("MX5: Set parent for periph_apm clock failed\n" ); -return -EINVAL ; - } - -return 0 ; -} - -static int _clk_main_bus_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg; - - reg =__raw_readl (MXC_CCM_CBCDR ); - -if (parent == &pll2_sw_clk) - reg &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL ; -else if (parent == &periph_apm_clk) - reg |=MXC_CCM_CBCDR_PERIPH_CLK_SEL ; -else -return -EINVAL ; - -__raw_writel (reg,MXC_CCM_CBCDR ); - -return 0 ; -} - -static struct clk main_bus_clk = { - .parent = &pll2_sw_clk, - .set_parent = _clk_main_bus_set_parent, -}; - -static unsigned long clk_ahb_get_rate (struct clk *clk) -{ -u32 reg, div; -unsigned long parent_rate; - - parent_rate =clk_get_rate (clk->parent); - - reg =__raw_readl (MXC_CCM_CBCDR ); - div = ((reg &MXC_CCM_CBCDR_AHB_PODF_MASK ) >> -MXC_CCM_CBCDR_AHB_PODF_OFFSET ) +1 ; -return parent_rate / div; -} - - -static int _clk_ahb_set_rate (struct clk *clk,unsigned long rate) -{ -u32 reg, div; -unsigned long parent_rate; -int i =0 ; - - parent_rate =clk_get_rate (clk->parent); - - div = parent_rate / rate; -if (div >8 || div <1 || ((parent_rate / div) != rate)) -return -EINVAL ; - - reg =__raw_readl (MXC_CCM_CBCDR ); - reg &= ~MXC_CCM_CBCDR_AHB_PODF_MASK ; - reg |= (div -1 ) <<MXC_CCM_CBCDR_AHB_PODF_OFFSET ; -__raw_writel (reg,MXC_CCM_CBCDR ); - -/* Wait for lock */ -do { - reg =__raw_readl (MXC_CCM_CDHIPR ); -if (!(reg &MXC_CCM_CDHIPR_AHB_PODF_BUSY )) -break ; - -udelay (1 ); - }while (++i <MAX_DPLL_WAIT_TRIES ); - -if (i ==MAX_DPLL_WAIT_TRIES ) { -pr_err ("MX5: clk_ahb_set_rate failed\n" ); -return -EINVAL ; - } - -return 0 ; -} - -static unsigned long _clk_ahb_round_rate (struct clk *clk, -unsigned long rate) -{ -u32 div; -unsigned long parent_rate; - - parent_rate =clk_get_rate (clk->parent); - - div = parent_rate / rate; -if (div >8 ) - div =8 ; -else if (div ==0 ) - div++; -return parent_rate / div; -} - - -static int _clk_max_enable (struct clk *clk) -{ -u32 reg; - -_clk_ccgr_enable (clk); - -/* Handshake with MAX when LPM is entered. */ - reg =__raw_readl (MXC_CCM_CLPCR ); -if (cpu_is_mx51 ()) - reg &= ~MX51_CCM_CLPCR_BYPASS_MAX_LPM_HS ; -else if (cpu_is_mx53 ()) - reg &= ~MX53_CCM_CLPCR_BYPASS_MAX_LPM_HS ; -__raw_writel (reg,MXC_CCM_CLPCR ); - -return 0 ; -} - -static void _clk_max_disable (struct clk *clk) -{ -u32 reg; - -_clk_ccgr_disable_inwait (clk); - -/* No Handshake with MAX when LPM is entered as its disabled. */ - reg =__raw_readl (MXC_CCM_CLPCR ); -if (cpu_is_mx51 ()) - reg |=MX51_CCM_CLPCR_BYPASS_MAX_LPM_HS ; -else if (cpu_is_mx53 ()) - reg &= ~MX53_CCM_CLPCR_BYPASS_MAX_LPM_HS ; -__raw_writel (reg,MXC_CCM_CLPCR ); -} - -static unsigned long clk_ipg_get_rate (struct clk *clk) -{ -u32 reg, div; -unsigned long parent_rate; - - parent_rate =clk_get_rate (clk->parent); - - reg =__raw_readl (MXC_CCM_CBCDR ); - div = ((reg &MXC_CCM_CBCDR_IPG_PODF_MASK ) >> -MXC_CCM_CBCDR_IPG_PODF_OFFSET ) +1 ; - -return parent_rate / div; -} - -static unsigned long clk_ipg_per_get_rate (struct clk *clk) -{ -u32 reg, prediv1, prediv2, podf; -unsigned long parent_rate; - - parent_rate =clk_get_rate (clk->parent); - -if (clk->parent == &main_bus_clk || clk->parent == &lp_apm_clk) { -/* the main_bus_clk is the one before the DVFS engine */ - reg =__raw_readl (MXC_CCM_CBCDR ); - prediv1 = ((reg &MXC_CCM_CBCDR_PERCLK_PRED1_MASK ) >> -MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET ) +1 ; - prediv2 = ((reg &MXC_CCM_CBCDR_PERCLK_PRED2_MASK ) >> -MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET ) +1 ; - podf = ((reg &MXC_CCM_CBCDR_PERCLK_PODF_MASK ) >> -MXC_CCM_CBCDR_PERCLK_PODF_OFFSET ) +1 ; -return parent_rate / (prediv1 * prediv2 * podf); - }else if (clk->parent == &ipg_clk) -return parent_rate; -else -BUG (); -} - -static int _clk_ipg_per_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg; - - reg =__raw_readl (MXC_CCM_CBCMR ); - - reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL ; - reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL ; - -if (parent == &ipg_clk) - reg |=MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL ; -else if (parent == &lp_apm_clk) - reg |=MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL ; -else if (parent != &main_bus_clk) -return -EINVAL ; - -__raw_writel (reg,MXC_CCM_CBCMR ); - -return 0 ; -} - -#define clk_nfc_set_parent NULL - -static unsigned long clk_nfc_get_rate (struct clk *clk) -{ -unsigned long rate; -u32 reg, div; - - reg =__raw_readl (MXC_CCM_CBCDR ); - div = ((reg &MXC_CCM_CBCDR_NFC_PODF_MASK ) >> -MXC_CCM_CBCDR_NFC_PODF_OFFSET ) +1 ; - rate =clk_get_rate (clk->parent) / div; -WARN_ON (rate ==0 ); -return rate; -} - -static unsigned long clk_nfc_round_rate (struct clk *clk, -unsigned long rate) -{ -u32 div; -unsigned long parent_rate =clk_get_rate (clk->parent); - -if (!rate) -return -EINVAL ; - - div = parent_rate / rate; - -if (parent_rate % rate) - div++; - -if (div >8 ) -return -EINVAL ; - -return parent_rate / div; - -} - -static int clk_nfc_set_rate (struct clk *clk,unsigned long rate) -{ -u32 reg, div; - - div =clk_get_rate (clk->parent) / rate; -if (div ==0 ) - div++; -if (((clk_get_rate (clk->parent) / div) != rate) || (div >8 )) -return -EINVAL ; - - reg =__raw_readl (MXC_CCM_CBCDR ); - reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK ; - reg |= (div -1 ) <<MXC_CCM_CBCDR_NFC_PODF_OFFSET ; -__raw_writel (reg,MXC_CCM_CBCDR ); - -while (__raw_readl (MXC_CCM_CDHIPR ) & -MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY ){ - } - -return 0 ; -} - -static unsigned long get_high_reference_clock_rate (struct clk *clk) -{ -return external_high_reference; -} - -static unsigned long get_low_reference_clock_rate (struct clk *clk) -{ -return external_low_reference; -} - -static unsigned long get_oscillator_reference_clock_rate (struct clk *clk) -{ -return oscillator_reference; -} - -static unsigned long get_ckih2_reference_clock_rate (struct clk *clk) -{ -return ckih2_reference; -} - -static unsigned long clk_emi_slow_get_rate (struct clk *clk) -{ -u32 reg, div; - - reg =__raw_readl (MXC_CCM_CBCDR ); - div = ((reg &MXC_CCM_CBCDR_EMI_PODF_MASK ) >> -MXC_CCM_CBCDR_EMI_PODF_OFFSET ) +1 ; - -return clk_get_rate (clk->parent) / div; -} - -static unsigned long _clk_ddr_hf_get_rate (struct clk *clk) -{ -unsigned long rate; -u32 reg, div; - - reg =__raw_readl (MXC_CCM_CBCDR ); - div = ((reg &MXC_CCM_CBCDR_DDR_PODF_MASK ) >> -MXC_CCM_CBCDR_DDR_PODF_OFFSET ) +1 ; - rate =clk_get_rate (clk->parent) / div; - -return rate; -} - -/* External high frequency clock */ -static struct clk ckih_clk = { - .get_rate = get_high_reference_clock_rate, -}; - -static struct clk ckih2_clk = { - .get_rate = get_ckih2_reference_clock_rate, -}; - -static struct clk osc_clk = { - .get_rate = get_oscillator_reference_clock_rate, -}; - -/* External low frequency (32kHz) clock */ -static struct clk ckil_clk = { - .get_rate = get_low_reference_clock_rate, -}; - -static struct clk pll1_main_clk = { - .parent = &osc_clk, - .get_rate = clk_pll_get_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* Clock tree block diagram (WIP): -* CCM: Clock Controller Module -* -* PLL output -> | -* | CCM Switcher -> CCM_CLK_ROOT_GEN -> -* PLL bypass -> | -* -*/ - -/* PLL1 SW supplies to ARM core */ -static struct clk pll1_sw_clk = { - .parent = &pll1_main_clk, - .set_parent = _clk_pll1_sw_set_parent, - .get_rate = clk_pll1_sw_get_rate, -}; - -/* PLL2 SW supplies to AXI/AHB/IP buses */ -static struct clk pll2_sw_clk = { - .parent = &osc_clk, - .get_rate = clk_pll_get_rate, - .set_rate = _clk_pll_set_rate, - .set_parent = _clk_pll2_sw_set_parent, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* PLL3 SW supplies to serial clocks like USB, SSI, etc. */ -static struct clk pll3_sw_clk = { - .parent = &osc_clk, - .set_rate = _clk_pll_set_rate, - .get_rate = clk_pll_get_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* PLL4 SW supplies to LVDS Display Bridge(LDB) */ -static struct clk mx53_pll4_sw_clk = { - .parent = &osc_clk, - .set_rate = _clk_pll_set_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* Low-power Audio Playback Mode clock */ -static struct clk lp_apm_clk = { - .parent = &osc_clk, - .set_parent = _clk_lp_apm_set_parent, -}; - -static struct clk periph_apm_clk = { - .parent = &pll1_sw_clk, - .set_parent = _clk_periph_apm_set_parent, -}; - -static struct clk cpu_clk = { - .parent = &pll1_sw_clk, - .get_rate = clk_cpu_get_rate, - .set_rate = clk_cpu_set_rate, -}; - -static struct clk ahb_clk = { - .parent = &main_bus_clk, - .get_rate = clk_ahb_get_rate, - .set_rate = _clk_ahb_set_rate, - .round_rate = _clk_ahb_round_rate, -}; - -static struct clk iim_clk = { - .parent = &ipg_clk, - .enable_reg =MXC_CCM_CCGR0 , - .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, -}; - -/* Main IP interface clock for access to registers */ -static struct clk ipg_clk = { - .parent = &ahb_clk, - .get_rate = clk_ipg_get_rate, -}; - -static struct clk ipg_perclk = { - .parent = &lp_apm_clk, - .get_rate = clk_ipg_per_get_rate, - .set_parent = _clk_ipg_per_set_parent, -}; - -static struct clk ahb_max_clk = { - .parent = &ahb_clk, - .enable_reg =MXC_CCM_CCGR0 , - .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, -}; - -static struct clk aips_tz1_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg =MXC_CCM_CCGR0 , - .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk aips_tz2_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg =MXC_CCM_CCGR0 , - .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk gpc_dvfs_clk = { - .enable_reg =MXC_CCM_CCGR5 , - .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable, -}; - -static struct clk gpt_32k_clk = { - .id =0 , - .parent = &ckil_clk, -}; - -static struct clk dummy_clk = { - .id =0 , -}; - -static struct clk emi_slow_clk = { - .parent = &pll2_sw_clk, - .enable_reg =MXC_CCM_CCGR5 , - .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, - .get_rate = clk_emi_slow_get_rate, -}; - -static int clk_ipu_enable (struct clk *clk) -{ -u32 reg; - -_clk_ccgr_enable (clk); - -/* Enable handshake with IPU when certain clock rates are changed */ - reg =__raw_readl (MXC_CCM_CCDR ); - reg &= ~MXC_CCM_CCDR_IPU_HS_MASK ; -__raw_writel (reg,MXC_CCM_CCDR ); - -/* Enable handshake with IPU when LPM is entered */ - reg =__raw_readl (MXC_CCM_CLPCR ); - reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS ; -__raw_writel (reg,MXC_CCM_CLPCR ); - -return 0 ; -} - -static void clk_ipu_disable (struct clk *clk) -{ -u32 reg; - -_clk_ccgr_disable (clk); - -/* Disable handshake with IPU whe dividers are changed */ - reg =__raw_readl (MXC_CCM_CCDR ); - reg |=MXC_CCM_CCDR_IPU_HS_MASK ; -__raw_writel (reg,MXC_CCM_CCDR ); - -/* Disable handshake with IPU when LPM is entered */ - reg =__raw_readl (MXC_CCM_CLPCR ); - reg |=MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS ; -__raw_writel (reg,MXC_CCM_CLPCR ); -} - -static struct clk ahbmux1_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg =MXC_CCM_CCGR0 , - .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk ipu_sec_clk = { - .parent = &emi_fast_clk, - .secondary = &ahbmux1_clk, -}; - -static struct clk ddr_hf_clk = { - .parent = &pll1_sw_clk, - .get_rate = _clk_ddr_hf_get_rate, -}; - -static struct clk ddr_clk = { - .parent = &ddr_hf_clk, -}; - -/* clock definitions for MIPI HSC unit which has been removed -* from documentation, but not from hardware -*/ -static int _clk_hsc_enable (struct clk *clk) -{ -u32 reg; - -_clk_ccgr_enable (clk); -/* Handshake with IPU when certain clock rates are changed. */ - reg =__raw_readl (MXC_CCM_CCDR ); - reg &= ~MXC_CCM_CCDR_HSC_HS_MASK ; -__raw_writel (reg,MXC_CCM_CCDR ); - - reg =__raw_readl (MXC_CCM_CLPCR ); - reg &= ~MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS ; -__raw_writel (reg,MXC_CCM_CLPCR ); - -return 0 ; -} - -static void _clk_hsc_disable (struct clk *clk) -{ -u32 reg; - -_clk_ccgr_disable (clk); -/* No handshake with HSC as its not enabled. */ - reg =__raw_readl (MXC_CCM_CCDR ); - reg |=MXC_CCM_CCDR_HSC_HS_MASK ; -__raw_writel (reg,MXC_CCM_CCDR ); - - reg =__raw_readl (MXC_CCM_CLPCR ); - reg |=MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS ; -__raw_writel (reg,MXC_CCM_CLPCR ); -} - -static struct clk mipi_hsp_clk = { - .parent = &ipu_clk, - .enable_reg =MXC_CCM_CCGR4 , - .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, - .enable = _clk_hsc_enable, - .disable = _clk_hsc_disable, - .secondary = &mipi_hsc1_clk, -}; - -#define DEFINE_CLOCK_CCGR (name, i, er, es, pfx, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = pfx##_get_rate, \ - .set_rate = pfx##_set_rate, \ - .round_rate = pfx##_round_rate, \ - .set_parent = pfx##_set_parent, \ - .enable = _clk_ccgr_enable, \ - .disable = _clk_ccgr_disable, \ - .parent = p, \ - .secondary = s, \ - } - -#define DEFINE_CLOCK_MAX (name, i, er, es, pfx, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = pfx##_get_rate, \ - .set_rate = pfx##_set_rate, \ - .set_parent = pfx##_set_parent, \ - .enable = _clk_max_enable, \ - .disable = _clk_max_disable, \ - .parent = p, \ - .secondary = s, \ - } - -#define CLK_GET_RATE (name, nr, bitsname) \ -static unsigned long clk_##name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, pred, podf; \ - \ - reg = __raw_readl(MXC_CCM_CSCDR##nr); \ - pred = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK) \ - >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ - podf = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK) \ - >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ - \ - return DIV_ROUND_CLOSEST(clk_get_rate(clk->parent), \ - (pred + 1) * (podf + 1)); \ -} - -#define CLK_SET_PARENT (name, nr, bitsname) \ -static int clk_##name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - u32 reg, mux; \ - \ - mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, \ - &pll3_sw_clk, &lp_apm_clk); \ - reg = __raw_readl(MXC_CCM_CSCMR##nr) & \ - ~MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_MASK; \ - reg |= mux << MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_OFFSET; \ - __raw_writel(reg, MXC_CCM_CSCMR##nr); \ - \ - return 0; \ -} - -#define CLK_SET_RATE (name, nr, bitsname) \ -static int clk_##name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u32 reg, div, parent_rate; \ - u32 pre = 0, post = 0; \ - \ - parent_rate = clk_get_rate(clk->parent); \ - div = parent_rate / rate; \ - \ - if ((parent_rate / div) != rate) \ - return -EINVAL; \ - \ - __calc_pre_post_dividers(div, &pre, &post, \ - (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK >> \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET) + 1, \ - (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK >> \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET) + 1);\ - \ -/* Set sdhc1 clock divider */ \ - reg = __raw_readl(MXC_CCM_CSCDR##nr) & \ - ~(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK \ - | MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK); \ - reg |= (post - 1) << \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ - reg |= (pre - 1) << \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ - __raw_writel(reg, MXC_CCM_CSCDR##nr); \ - \ - return 0; \ -} - -/* UART */ -CLK_GET_RATE(uart, 1, UART) -CLK_SET_PARENT(uart, 1, UART) - -static struct clk uart_root_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_uart_get_rate, - .set_parent = clk_uart_set_parent, -}; - -/* USBOH3 */ -CLK_GET_RATE(usboh3, 1, USBOH3) -CLK_SET_PARENT(usboh3, 1, USBOH3) - -static struct clk usboh3_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_usboh3_get_rate, - .set_parent = clk_usboh3_set_parent, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable, - .enable_reg =MXC_CCM_CCGR2 , - .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, -}; - -static struct clk usb_ahb_clk = { - .parent = &ipg_clk, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable, - .enable_reg =MXC_CCM_CCGR2 , - .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, -}; - -static int clk_usb_phy1_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg; - - reg =__raw_readl (MXC_CCM_CSCMR1 ) & ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL ; - -if (parent == &pll3_sw_clk) - reg |=1 <<MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET ; - -__raw_writel (reg,MXC_CCM_CSCMR1 ); - -return 0 ; -} - -static struct clk usb_phy1_clk = { - .parent = &pll3_sw_clk, - .set_parent = clk_usb_phy1_set_parent, - .enable = _clk_ccgr_enable, - .enable_reg =MXC_CCM_CCGR2 , - .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, - .disable = _clk_ccgr_disable, -}; - -/* eCSPI */ -CLK_GET_RATE(ecspi, 2, CSPI) -CLK_SET_PARENT(ecspi, 1, CSPI) - -static struct clk ecspi_main_clk = { - .parent = &pll3_sw_clk, - .get_rate = clk_ecspi_get_rate, - .set_parent = clk_ecspi_set_parent, -}; - -/* eSDHC */ -CLK_GET_RATE(esdhc1, 1, ESDHC1_MSHC1) -CLK_SET_PARENT(esdhc1, 1, ESDHC1_MSHC1) -CLK_SET_RATE (esdhc1,1 ,ESDHC1_MSHC1 ) - -/* mx51 specific */ -CLK_GET_RATE(esdhc2, 1, ESDHC2_MSHC2) -CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2) -CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2) - -static int clk_esdhc3_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg; - - reg =__raw_readl (MXC_CCM_CSCMR1 ); -if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC3_CLK_SEL ; -else if (parent == &esdhc2_clk) - reg |=MXC_CCM_CSCMR1_ESDHC3_CLK_SEL ; -else -return -EINVAL ; -__raw_writel (reg,MXC_CCM_CSCMR1 ); - -return 0 ; -} - -static int clk_esdhc4_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg; - - reg =__raw_readl (MXC_CCM_CSCMR1 ); -if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL ; -else if (parent == &esdhc2_clk) - reg |=MXC_CCM_CSCMR1_ESDHC4_CLK_SEL ; -else -return -EINVAL ; -__raw_writel (reg,MXC_CCM_CSCMR1 ); - -return 0 ; -} - -/* mx53 specific */ -static int clk_esdhc2_mx53_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg; - - reg =__raw_readl (MXC_CCM_CSCMR1 ); -if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL ; -else if (parent == &esdhc3_mx53_clk) - reg |=MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL ; -else -return -EINVAL ; -__raw_writel (reg,MXC_CCM_CSCMR1 ); - -return 0 ; -} - -CLK_GET_RATE(esdhc3_mx53, 1, ESDHC3_MX53) -CLK_SET_PARENT(esdhc3_mx53, 1, ESDHC3_MX53) -CLK_SET_RATE(esdhc3_mx53, 1, ESDHC3_MX53) - -static int clk_esdhc4_mx53_set_parent (struct clk *clk,struct clk *parent) -{ -u32 reg; - - reg =__raw_readl (MXC_CCM_CSCMR1 ); -if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL ; -else if (parent == &esdhc3_mx53_clk) - reg |=MXC_CCM_CSCMR1_ESDHC4_CLK_SEL ; -else -return -EINVAL ; -__raw_writel (reg,MXC_CCM_CSCMR1 ); - -return 0 ; -} - -#define DEFINE_CLOCK_FULL (name, i, er, es, gr, sr, e, d, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .set_rate = sr, \ - .enable = e, \ - .disable = d, \ - .parent = p, \ - .secondary = s, \ - } - -#define DEFINE_CLOCK (name, i, er, es, gr, sr, p, s) \ - DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, _clk_ccgr_enable, _clk_ccgr_disable, p, s) - -/* Shared peripheral bus arbiter */ -DEFINE_CLOCK (spba_clk,0 ,MXC_CCM_CCGR5 , MXC_CCM_CCGRx_CG0_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); - -/* UART */ -DEFINE_CLOCK (uart1_ipg_clk,0 ,MXC_CCM_CCGR1 , MXC_CCM_CCGRx_CG3_OFFSET, -NULL ,NULL , &ipg_clk, &aips_tz1_clk); -DEFINE_CLOCK (uart2_ipg_clk,1 ,MXC_CCM_CCGR1 , MXC_CCM_CCGRx_CG5_OFFSET, -NULL ,NULL , &ipg_clk, &aips_tz1_clk); -DEFINE_CLOCK (uart3_ipg_clk,2 ,MXC_CCM_CCGR1 , MXC_CCM_CCGRx_CG7_OFFSET, -NULL ,NULL , &ipg_clk, &spba_clk); -DEFINE_CLOCK (uart1_clk,0 ,MXC_CCM_CCGR1 , MXC_CCM_CCGRx_CG4_OFFSET, -NULL ,NULL , &uart_root_clk, &uart1_ipg_clk); -DEFINE_CLOCK (uart2_clk,1 ,MXC_CCM_CCGR1 , MXC_CCM_CCGRx_CG6_OFFSET, -NULL ,NULL , &uart_root_clk, &uart2_ipg_clk); -DEFINE_CLOCK (uart3_clk,2 ,MXC_CCM_CCGR1 , MXC_CCM_CCGRx_CG8_OFFSET, -NULL ,NULL , &uart_root_clk, &uart3_ipg_clk); - -/* GPT */ -DEFINE_CLOCK (gpt_ipg_clk,0 ,MXC_CCM_CCGR2 , MXC_CCM_CCGRx_CG10_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); -DEFINE_CLOCK (gpt_clk,0 ,MXC_CCM_CCGR2 , MXC_CCM_CCGRx_CG9_OFFSET, -NULL ,NULL , &ipg_clk, &gpt_ipg_clk); - -DEFINE_CLOCK (pwm1_clk,0 ,MXC_CCM_CCGR2 , MXC_CCM_CCGRx_CG6_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); -DEFINE_CLOCK (pwm2_clk,0 ,MXC_CCM_CCGR2 , MXC_CCM_CCGRx_CG8_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); - -/* I2C */ -DEFINE_CLOCK (i2c1_clk,0 ,MXC_CCM_CCGR1 , MXC_CCM_CCGRx_CG9_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); -DEFINE_CLOCK (i2c2_clk,1 ,MXC_CCM_CCGR1 , MXC_CCM_CCGRx_CG10_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); -DEFINE_CLOCK (hsi2c_clk,0 ,MXC_CCM_CCGR1 , MXC_CCM_CCGRx_CG11_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); - -/* FEC */ -DEFINE_CLOCK (fec_clk,0 ,MXC_CCM_CCGR2 , MXC_CCM_CCGRx_CG12_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); - -/* NFC */ -DEFINE_CLOCK_CCGR (nfc_clk,0 ,MXC_CCM_CCGR5 , MXC_CCM_CCGRx_CG10_OFFSET, - clk_nfc, &emi_slow_clk,NULL ); - -/* SSI */ -DEFINE_CLOCK (ssi1_ipg_clk,0 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG8_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); -DEFINE_CLOCK (ssi1_clk,0 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG9_OFFSET, -NULL ,NULL , &pll3_sw_clk, &ssi1_ipg_clk); -DEFINE_CLOCK (ssi2_ipg_clk,1 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG10_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); -DEFINE_CLOCK (ssi2_clk,1 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG11_OFFSET, -NULL ,NULL , &pll3_sw_clk, &ssi2_ipg_clk); -DEFINE_CLOCK (ssi3_ipg_clk,2 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG12_OFFSET, -NULL ,NULL , &ipg_clk,NULL ); -DEFINE_CLOCK (ssi3_clk,2 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG13_OFFSET, -NULL ,NULL , &pll3_sw_clk, &ssi3_ipg_clk); - -/* eCSPI */ -DEFINE_CLOCK_FULL (ecspi1_ipg_clk,0 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG9_OFFSET, -NULL ,NULL , _clk_ccgr_enable_inrun, _clk_ccgr_disable, - &ipg_clk, &spba_clk); -DEFINE_CLOCK (ecspi1_clk,0 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG10_OFFSET, -NULL ,NULL , &ecspi_main_clk, &ecspi1_ipg_clk); -DEFINE_CLOCK_FULL (ecspi2_ipg_clk,0 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG11_OFFSET, -NULL ,NULL , _clk_ccgr_enable_inrun, _clk_ccgr_disable, - &ipg_clk, &aips_tz2_clk); -DEFINE_CLOCK (ecspi2_clk,0 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG12_OFFSET, -NULL ,NULL , &ecspi_main_clk, &ecspi2_ipg_clk); - -/* CSPI */ -DEFINE_CLOCK (cspi_ipg_clk,0 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG9_OFFSET, -NULL ,NULL , &ipg_clk, &aips_tz2_clk); -DEFINE_CLOCK (cspi_clk,0 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG13_OFFSET, -NULL ,NULL , &ipg_clk, &cspi_ipg_clk); - -/* SDMA */ -DEFINE_CLOCK (sdma_clk,1 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG15_OFFSET, -NULL ,NULL , &ahb_clk,NULL ); - -/* eSDHC */ -DEFINE_CLOCK_FULL (esdhc1_ipg_clk,0 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG0_OFFSET, -NULL ,NULL , _clk_max_enable, _clk_max_disable, &ipg_clk,NULL ); -DEFINE_CLOCK_MAX (esdhc1_clk,0 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG1_OFFSET, - clk_esdhc1, &pll2_sw_clk, &esdhc1_ipg_clk); -DEFINE_CLOCK_FULL (esdhc2_ipg_clk,1 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG2_OFFSET, -NULL ,NULL , _clk_max_enable, _clk_max_disable, &ipg_clk,NULL ); -DEFINE_CLOCK_FULL (esdhc3_ipg_clk,2 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG4_OFFSET, -NULL ,NULL , _clk_max_enable, _clk_max_disable, &ipg_clk,NULL ); -DEFINE_CLOCK_FULL (esdhc4_ipg_clk,3 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG6_OFFSET, -NULL ,NULL , _clk_max_enable, _clk_max_disable, &ipg_clk,NULL ); - -/* mx51 specific */ -DEFINE_CLOCK_MAX (esdhc2_clk,1 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG3_OFFSET, - clk_esdhc2, &pll2_sw_clk, &esdhc2_ipg_clk); - -static struct clk esdhc3_clk = { - .id =2 , - .parent = &esdhc1_clk, - .set_parent = clk_esdhc3_set_parent, - .enable_reg =MXC_CCM_CCGR3 , - .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc3_ipg_clk, -}; -static struct clk esdhc4_clk = { - .id =3 , - .parent = &esdhc1_clk, - .set_parent = clk_esdhc4_set_parent, - .enable_reg =MXC_CCM_CCGR3 , - .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc4_ipg_clk, -}; - -/* mx53 specific */ -static struct clk esdhc2_mx53_clk = { - .id =2 , - .parent = &esdhc1_clk, - .set_parent = clk_esdhc2_mx53_set_parent, - .enable_reg =MXC_CCM_CCGR3 , - .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc3_ipg_clk, -}; - -DEFINE_CLOCK_MAX (esdhc3_mx53_clk,2 ,MXC_CCM_CCGR3 , MXC_CCM_CCGRx_CG5_OFFSET, - clk_esdhc3_mx53, &pll2_sw_clk, &esdhc2_ipg_clk); - -static struct clk esdhc4_mx53_clk = { - .id =3 , - .parent = &esdhc1_clk, - .set_parent = clk_esdhc4_mx53_set_parent, - .enable_reg =MXC_CCM_CCGR3 , - .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc4_ipg_clk, -}; - -DEFINE_CLOCK (mipi_esc_clk,0 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG5_OFFSET,NULL ,NULL ,NULL , &pll2_sw_clk); -DEFINE_CLOCK (mipi_hsc2_clk,0 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG4_OFFSET,NULL ,NULL , &mipi_esc_clk, &pll2_sw_clk); -DEFINE_CLOCK (mipi_hsc1_clk,0 ,MXC_CCM_CCGR4 , MXC_CCM_CCGRx_CG3_OFFSET,NULL ,NULL , &mipi_hsc2_clk, &pll2_sw_clk); - -/* IPU */ -DEFINE_CLOCK_FULL (ipu_clk,0 ,MXC_CCM_CCGR5 , MXC_CCM_CCGRx_CG5_OFFSET, -NULL ,NULL , clk_ipu_enable, clk_ipu_disable, &ahb_clk, &ipu_sec_clk); - -DEFINE_CLOCK_FULL (emi_fast_clk,0 ,MXC_CCM_CCGR5 , MXC_CCM_CCGRx_CG7_OFFSET, -NULL ,NULL , _clk_ccgr_enable, _clk_ccgr_disable_inwait, - &ddr_clk,NULL ); - -DEFINE_CLOCK (ipu_di0_clk,0 ,MXC_CCM_CCGR6 , MXC_CCM_CCGRx_CG5_OFFSET, -NULL ,NULL , &pll3_sw_clk,NULL ); -DEFINE_CLOCK (ipu_di1_clk,0 ,MXC_CCM_CCGR6 , MXC_CCM_CCGRx_CG6_OFFSET, -NULL ,NULL , &pll3_sw_clk,NULL ); - -#define _REGISTER_CLOCK (d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup mx51_lookups[] = { - _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - _REGISTER_CLOCK("fec.0", NULL, fec_clk) - _REGISTER_CLOCK("mxc_pwm.0", "pwm", pwm1_clk) - _REGISTER_CLOCK("mxc_pwm.1", "pwm", pwm2_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_ahb_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_phy1", usb_phy1_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_ahb_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_ahb_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) - _REGISTER_CLOCK("imx-keypad", NULL, dummy_clk) - _REGISTER_CLOCK("mxc_nand", NULL, nfc_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk) - _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk) - _REGISTER_CLOCK(NULL, "ckih", ckih_clk) - _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk) - _REGISTER_CLOCK(NULL, "gpt_32k", gpt_32k_clk) - _REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk) - _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk) - _REGISTER_CLOCK("imx51-cspi.0", NULL, cspi_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_clk) - _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk) - _REGISTER_CLOCK(NULL, "iim_clk", iim_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk) - _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk) - _REGISTER_CLOCK(NULL, "mipi_hsp", mipi_hsp_clk) - _REGISTER_CLOCK("imx-ipuv3", NULL, ipu_clk) - _REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk) - _REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk) -_REGISTER_CLOCK (NULL ,"gpc_dvfs" , gpc_dvfs_clk) -}; - -static struct clk_lookup mx53_lookups[] = { - _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - _REGISTER_CLOCK("fec.0", NULL, fec_clk) - _REGISTER_CLOCK(NULL, "iim_clk", iim_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_mx53_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_mx53_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_mx53_clk) - _REGISTER_CLOCK("imx53-ecspi.0", NULL, ecspi1_clk) - _REGISTER_CLOCK("imx53-ecspi.1", NULL, ecspi2_clk) - _REGISTER_CLOCK("imx53-cspi.0", NULL, cspi_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk) -_REGISTER_CLOCK ("imx2-wdt.1" ,NULL , dummy_clk) -}; - -static void clk_tree_init (void ) -{ -u32 reg; - - ipg_perclk.set_parent (&ipg_perclk, &lp_apm_clk); - -/* -* Initialise the IPG PER CLK dividers to 3. IPG_PER_CLK should be at -* 8MHz, its derived from lp_apm. -* -* FIXME: Verify if true for all boards -*/ - reg =__raw_readl (MXC_CCM_CBCDR ); - reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK ; - reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK ; - reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK ; - reg |= (2 <<MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET ); -__raw_writel (reg,MXC_CCM_CBCDR ); -} - -int __init mx51_clocks_init (unsigned long ckil,unsigned long osc, -unsigned long ckih1,unsigned long ckih2) -{ -int i; - - external_low_reference = ckil; - external_high_reference = ckih1; - ckih2_reference = ckih2; - oscillator_reference = osc; - -for (i =0 ; i <ARRAY_SIZE (mx51_lookups); i++) -clkdev_add (&mx51_lookups[i]); - -clk_tree_init (); - -clk_enable (&cpu_clk); -clk_enable (&main_bus_clk); - -clk_enable (&iim_clk); -mx51_revision (); -clk_disable (&iim_clk); -mx51_display_revision (); - -/* move usb_phy_clk to 24MHz */ -clk_set_parent (&usb_phy1_clk, &osc_clk); - -/* set the usboh3_clk parent to pll2_sw_clk */ -clk_set_parent (&usboh3_clk, &pll2_sw_clk); - -/* Set SDHC parents to be PLL2 */ -clk_set_parent (&esdhc1_clk, &pll2_sw_clk); -clk_set_parent (&esdhc2_clk, &pll2_sw_clk); - -/* set SDHC root clock as 166.25MHZ*/ -clk_set_rate (&esdhc1_clk,166250000 ); -clk_set_rate (&esdhc2_clk,166250000 ); - -/* System timer */ -mxc_timer_init (&gpt_clk,MX51_IO_ADDRESS (MX51_GPT1_BASE_ADDR ), -MX51_MXC_INT_GPT ); -return 0 ; -} - -int __init mx53_clocks_init (unsigned long ckil,unsigned long osc, -unsigned long ckih1,unsigned long ckih2) -{ -int i; - - external_low_reference = ckil; - external_high_reference = ckih1; - ckih2_reference = ckih2; - oscillator_reference = osc; - -for (i =0 ; i <ARRAY_SIZE (mx53_lookups); i++) -clkdev_add (&mx53_lookups[i]); - -clk_tree_init (); - -clk_set_parent (&uart_root_clk, &pll3_sw_clk); -clk_enable (&cpu_clk); -clk_enable (&main_bus_clk); - -clk_enable (&iim_clk); -mx53_revision (); -clk_disable (&iim_clk); - -/* Set SDHC parents to be PLL2 */ -clk_set_parent (&esdhc1_clk, &pll2_sw_clk); -clk_set_parent (&esdhc3_mx53_clk, &pll2_sw_clk); - -/* set SDHC root clock as 200MHZ*/ -clk_set_rate (&esdhc1_clk,200000000 ); -clk_set_rate (&esdhc3_mx53_clk,200000000 ); - -/* System timer */ -mxc_timer_init (&gpt_clk,MX53_IO_ADDRESS (MX53_GPT1_BASE_ADDR ), -MX53_INT_GPT ); -return 0 ; -}
arch/arm/mach-mx5/crm_regs.h +1 -248
267 lines not on this page · raw message
Signature · 1 line
1.7.4.1
Quoted 2 lines · Sascha Hauer
The following tries to solve the chicken-egg problem we have with the common struct clk support and its users.
Thanks for doing this. This really shows exactly what I wanted to know.
Quoted 7 lines
drivers/clk/Kconfig | 6 + drivers/clk/Makefile | 2 + drivers/clk/clk-divider.c | 132 +++ drivers/clk/clk-mux.c | 92 ++ drivers/clk/clk.c | 104 ++ include/linux/clk.h | 68 ++ 16 files changed, 1395 insertions(+), 1831 deletions(-)
If we can have more people using the generic mux and divider stuff, that should cut many more hundreds of LOC from arch/arm.
This is exactly the kind of stuff we need to be seeing.
1. How does this fit in with the other MX stuff?
2. Is it based upon Jeremy's git tree, and is Jeremy's git tree a stable base for this?
3. Is this sufficiently separated that it can be pulled as-is?
Sascha Hauer
maintainerQuoted 14 lines · Russell King - ARM Linux
Quoted 2 lines · Sascha Hauer
The following tries to solve the chicken-egg problem we have with the common struct clk support and its users.
Thanks for doing this. This really shows exactly what I wanted to know.
Quoted 7 lines
drivers/clk/Kconfig | 6 + drivers/clk/Makefile | 2 + drivers/clk/clk-divider.c | 132 +++ drivers/clk/clk-mux.c | 92 ++ drivers/clk/clk.c | 104 ++ include/linux/clk.h | 68 ++ 16 files changed, 1395 insertions(+), 1831 deletions(-)
Quoted 6 lines
If we can have more people using the generic mux and divider stuff, that should cut many more hundreds of LOC from
arch/arm.This is exactly the kind of stuff we need to be seeing.
1. How does this fit in with the other MX stuff?
The other regular i.MXs should fit into this fine, they have the same patterns. mxs is different though, instead of enable bits they have disable bits and dividers are one based instead of zero. We can probably extend the patterns to handle some additional flags, but I haven't looked deeply into it.
Quoted 2 lines
2. Is it based upon Jeremy's git tree, and is Jeremy's git tree a stable base for this?
It's a very late series from Jeremy, I don't know if it's exactly the latest. I'll rebase it. Jeremys git tree is here:
git://kernel.ubuntu.com/jk/dt/linux-2.6.git
Quoted 1 line
3. Is this sufficiently separated that it can be pulled as-is?
Should be, but it's the result of a long day, so I hesitate to say yes.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Quoted 5 lines · Sascha Hauer
The other regular i.MXs should fit into this fine, they have the same patterns. mxs is different though, instead of enable bits they have disable bits and dividers are one based instead of zero. We can probably extend the patterns to handle some additional flags, but I haven't looked deeply into it.
A suggestion from work tglx is currently doing - name the two functions which manipulate the mask bits 'set' and 'clear' rather than 'enable' and 'disable'.
Then, the clk ops can do this:
.clk_enable = clk_gate_mask_set,
.clk_disable = clk_gate_mask_clear,
for ones with positive logic, and:
.clk_enable = clk_gate_mask_clear,
.clk_disable = clk_gate_mask_set,
for negative logic. No additional code required, just a variance in data structure.
Quoted 16 lines · Russell King - ARM Linux
Quoted 5 lines · Sascha Hauer
The other regular i.MXs should fit into this fine, they have the same patterns. mxs is different though, instead of enable bits they have disable bits and dividers are one based instead of zero. We can probably extend the patterns to handle some additional flags, but I haven't looked deeply into it.
A suggestion from work tglx is currently doing - name the two functions which manipulate the mask bits 'set' and 'clear' rather than 'enable' and 'disable'.
Then, the clk ops can do this:
.clk_enable =
clk_gate_mask_set,
.clk_disable =clk_gate_mask_clear,
Quoted 7 lines
for ones with positive logic, and:
.clk_enable =
clk_gate_mask_clear,
.clk_disable =clk_gate_mask_set,for negative logic. No additional code required, just a variance in data structure.
Bah. Except they may need to reference the parent... which kills that idea.
Quoted 19 lines · Russell King - ARM Linux
Quoted 18 lines · Russell King - ARM Linux
Quoted 5 lines · Sascha Hauer
The other regular i.MXs should fit into this fine, they have the same patterns. mxs is different though, instead of enable bits they have disable bits and dividers are one based instead of zero. We can probably extend the patterns to handle some additional flags, but I haven't looked deeply into it.
A suggestion from work tglx is currently doing - name the two functions which manipulate the mask bits 'set' and 'clear' rather than 'enable' and 'disable'.
Then, the clk ops can do this:
.clk_enable =
clk_gate_mask_set,
.clk_disable =clk_gate_mask_clear,for ones with positive logic, and:
Quoted 8 lines
Quoted 5 lines
.clk_enable =
clk_gate_mask_clear,
.clk_disable =clk_gate_mask_set,for negative logic. No additional code required, just a variance in data structure.
Bah. Except they may need to reference the parent... which kills that idea.
Then the actuall en/disabling needs to be a seperate callback.
clk_gate_enable(clk) then does
clk_enable(clk->parent) clk->sensiblename_enable(clk)
with sensiblename_enable pointing to clk_gate_mask_set or clk_gate_mask_clear.
Just my 2 cents before going to bed,
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Hi Sascha,
Quoted 20 lines · Sascha Hauer
Quoted 19 lines · Russell King - ARM Linux
Quoted 2 lines · Sascha Hauer
The following tries to solve the chicken-egg problem we have with the common struct clk support and its users.
Thanks for doing this. This really shows exactly what I wanted to know.
Quoted 7 lines
drivers/clk/Kconfig | 6 + drivers/clk/Makefile | 2 + drivers/clk/clk-divider.c | 132 +++ drivers/clk/clk-mux.c | 92 ++ drivers/clk/clk.c | 104 ++ include/linux/clk.h | 68 ++ 16 files changed, 1395 insertions(+), 1831 deletions(-)If we can have more people using the generic mux and divider stuff, that should cut many more hundreds of LOC from
arch/arm.This is exactly the kind of stuff we need to be seeing.
Quoted 8 lines
Quoted 1 line
1. How does this fit in with the other MX stuff?
The other regular i.MXs should fit into this fine, they have the same patterns. mxs is different though, instead of enable bits they have disable bits and dividers are one based instead of zero. We can probably extend the patterns to handle some additional flags, but I haven't looked deeply into it.
I will try to migrate mxs clock to it and let you know where we need to extend.
Signature · 2 lines
Regards, Shawn
Quoted 11 lines · Sascha Hauer
The following tries to solve the chicken-egg problem we have with the common struct clk support and its users. It switches i.MX51 clock support to the new API. Included are some generic clock helpers for dividers and multiplexer. I first made them i.MX specific but after looking round in the other architectures I found them useful enough for other architectures aswell. If you could use the helpers but missing some bits please speak up.
There is one thing missing in Jeremys series and this series does not fix it. Once I add the new (un)prepare calls to drivers they won't compile without common struct clk support anymore. Maybe a
Quoted 6 lines
#ifndef
CONFIG_USE_COMMON_STRUCT_CLK
#defineclk_prepare()
#defineclk_unprepare()
#endifwill do.
This already exists in the latest version and works since v14[1].
Best regards
Uwe
[1]
http://thread.gmane.org/gmane.linux.ports.sh.devel/9755/focus=10241
has:
+static inline int clk_prepare(struct clk *clk) { return 0; } +static inline void clk_unprepare(struct clk *clk) { }
in a !CONFIG_USE_COMMON_STRUCT_CLK cpp branch.
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Sascha Hauer
maintainerQuoted 6 lines · Sascha Hauer
The following tries to solve the chicken-egg problem we have with the common struct clk support and its users. It switches i.MX51 clock support to the new API. Included are some generic clock helpers for dividers and multiplexer. I first made them i.MX specific but after looking round in the other architectures I found them useful enough for other architectures aswell. If you could use the helpers but missing some bits please speak up.
Note that this series also changes the way clocks are organized. We have many clocks on i.MX which implemenent set_parent and set_rate at once. Now with the split into building blocks only the multiplexers implement set_parent. It's no longer possible in general to call set_parent on clocks given to drivers as these are mostly dividers and gates which do not allow to change its parent.
The upside of this change is that it's really simple and straight forward to implement a clock tree which can be easily reviewed with the datasheet.
There will be updates to this series as I found some leftovers from earlier versions of this series.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |