Skip to contentSkip to conversation

sanitizing crazy clock data files

RFC New Sascha Hauer 20 participants 157 messages Apr 15, 2011 – May 10, 2011

Subsystems (7)
lore
Share & tools
lore

Sascha Hauer

author maintainer
#0 lore raw

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

#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
author maintainer
#1 lore raw

PATCH 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
index 4168c88..6e3ae54 100644
@@ -2,3 +2,6 @@
 config CLKDEV_LOOKUP
 	bool
 	select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+	bool
drivers/clk/Makefile +1 -0
index 07613fa..a1a06d3 100644
@@ -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
index 0fc0a79..a7999d2 100644
@@ -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
#2 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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

#3 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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 to clk->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

#4 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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 to clk->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

#5 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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().

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

#6 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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 to clk->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_prepare only have to be called before clk_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

#7 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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 to clk->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_prepare only have to be called before clk_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

#8 lore raw

PATCH 1/10 Add a common struct clk

In reply to Thomas Gleixner

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 to clk->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_prepare only have to be called before clk_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

#9 lore raw

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 to clk->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_prepare only have to be called before clk_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 -ENODEV and 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

#10 lore raw

PATCH 1/10 Add a common struct clk

In reply to Thomas Gleixner
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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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 to clk->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.
#11 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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 to clk->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

#12 lore raw

PATCH 1/10 Add a common struct clk

In reply to Thomas Gleixner
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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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 to clk->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.

#13 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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 to clk->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:117
arch/arm/mach-omap2/clock2430_data.c:126
arch/arm/mach-omap2/clock3xxx_data.c:235
arch/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

#14 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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 to clk->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?

Quoted 7 lines

arch/arm/mach-omap2/clock2420_data.c:117
arch/arm/mach-omap2/clock2430_data.c:126
arch/arm/mach-omap2/clock3xxx_data.c:235
arch/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.

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

#15 lore raw

PATCH 1/10 Add a common struct clk

In reply to Thomas Gleixner
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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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().

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_ops struct, 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.

#16 lore raw

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 via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_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().

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_ops struct, 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
#17 lore raw

PATCH 1/10 Add a common struct clk

In reply to Sascha Hauer

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:

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

#18 lore raw

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.

#19 lore raw

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

#20 lore raw

PATCH 1/10 Add a common struct clk

In reply to Sascha Hauer

Jeremy,

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_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
index 4168c88..6e3ae54 100644
@@ -2,3 +2,6 @@
  config CLKDEV_LOOKUP
  	bool
  	select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+	bool
drivers/clk/Makefile +1 -0
index 07613fa..a1a06d3 100644
@@ -1,2 +1,3 @@
 
  obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
drivers/clk/clk.c new file +7 -0
new file mode 100644
index 0000000..0bc9c6f
@@ -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

#21 lore raw

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

#22 lore raw

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

#23 lore raw

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

#24 lore raw

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_get call. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, like clk_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

#25 lore raw

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_get call. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, like clk_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.

#26 lore raw

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 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_get call. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, like clk_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.

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 like clk_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.
author maintainer
#27 lore raw

PATCH 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 like clk_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.

#28 lore raw

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 like clk_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 for clk_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 think clk_set_rate for 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 using clk_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.
#29 lore raw

PATCH 1/10 Add a common struct clk

In reply to Russell King - ARM Linux

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 like clk_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

#30 lore raw

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 like clk_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.
#31 lore raw

PATCH 1/10 Add a common struct clk

In reply to Jeremy Kerr
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 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_get call. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, like clk_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.
#32 lore raw

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_get call. This 'noop clock' would be a good contender for inclusion into the kernel-wide infrastructure, like clk_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_get and 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.
author maintainer
#33 lore raw

PATCH 2/10 clk: Generic support for fixed-rate clocks

In reply to Sascha Hauer

From: 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
index 0bc9c6f..0da0bb9 100644
@@ -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
index 7b406bd..d2f0db0 100644
@@ -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
author maintainer
#34 lore raw

PATCH 3/10 clk: Make NULL a valid clock again

In reply to 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.

---
 drivers/clk/clk.c |   27 +++++++++++++++++++++++++++
 1 files changed, 27 insertions(+), 0 deletions(-)
drivers/clk/clk.c +27 -0
index 0da0bb9..264c809 100644
@@ -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
#35 lore raw

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

author maintainer
#36 lore raw

PATCH 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 |
#37 lore raw

PATCH 3/10 clk: Make NULL a valid clock again

In reply to Sascha Hauer
Quoted 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.

---
 drivers/clk/clk.c |   27 +++++++++++++++++++++++++++
 1 files changed, 27 insertions(+), 0 deletions(-)
drivers/clk/clk.c +12 -0
index 0da0bb9..264c809 100644
@@ -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/  |
author maintainer
#38 lore raw

PATCH 4/10 clk: implement parent pass through functions

In reply to 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

---
 drivers/clk/clk.c   |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/clk.h |    9 ++++++
 2 files changed, 86 insertions(+), 0 deletions(-)
drivers/clk/clk.c +77 -0
index 264c809..7e2c182 100644
@@ -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
index d2f0db0..d014341 100644
@@ -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
#39 lore raw

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

---
 drivers/clk/clk.c   |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/clk.h |    9 ++++++
 2 files changed, 86 insertions(+), 0 deletions(-)
drivers/clk/clk.c +19 -0
index 264c809..7e2c182 100644
@@ -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
index d2f0db0..d014341 100644
@@ -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/  |
author maintainer
#40 lore raw

PATCH 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

---
 drivers/clk/clk.c   |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/clk.h |    9 ++++++
 2 files changed, 86 insertions(+), 0 deletions(-)
drivers/clk/clk.c +23 -0
index 264c809..7e2c182 100644
@@ -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_enable but 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 |
#41 lore raw

PATCH 4/10 clk: implement parent pass through functions

In reply to Sascha Hauer
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

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.
author maintainer
#42 lore raw

PATCH 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

Quoted 6 lines

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.

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 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.

Quoted 4 lines

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?

+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 |
#43 lore raw

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

Quoted 6 lines

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.

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 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.

Quoted 8 lines
Quoted 4 lines

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?

+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/  |
author maintainer
#44 lore raw

PATCH 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 |
#45 lore raw

PATCH 4/10 clk: implement parent pass through functions

In reply to Uwe Kleine-König
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.

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

#46 lore raw

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/  |
#47 lore raw

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

#48 lore raw

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
index 264c809..7627815 100644
@@ -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
index d2f0db0..125e525 100644
@@ -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
#49 lore raw

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

---
Hello,

only compile tested so far.

You are not listening at all, right?

Quoted 5 lines
drivers/clk/clk.c +0 -0
index 264c809..7627815 100644

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

#50 lore raw

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

---
Hello,

only compile tested so far.

You are not listening at all, right?

Quoted 10 lines
drivers/clk/clk.c +1 -0
index 264c809..7627815 100644
@@ -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 -0
 	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

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/  |
#51 lore raw

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 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

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

#52 lore raw

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(). 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 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

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.

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/or
clk_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.
#53 lore raw

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_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.

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
/
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.

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() 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().

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 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.

Yes, but that's one step after the minimal set :)

Thanks,

tglx

#54 lore raw

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
#55 lore raw

Re: [PATCH RFC] clk: add support for automatic parent handling

In reply to Thomas Gleixner
Quoted 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_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.

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.

#56 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Thomas Gleixner

Hello 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(). 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?

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 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

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.

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/  |
#57 lore raw

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_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.

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_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.

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 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.

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

#58 lore raw

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_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.

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.

#59 lore raw

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_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.

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

#60 lore raw

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_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.

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

#61 lore raw

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_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.

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

#62 lore raw

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_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.

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

#63 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Mark Brown
Quoted 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.

#64 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Thomas Gleixner
Quoted 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_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.

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.

#65 lore raw

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_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 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

#66 lore raw

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_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.

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.

#67 lore raw

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_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.

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]-

#68 lore raw

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.

#69 lore raw

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/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.

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

#70 lore raw

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.

#71 lore raw

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

#72 lore raw

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.

#73 lore raw

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

#74 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Russell King - ARM Linux
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/clk with 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
#75 lore raw

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/clk with 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.

#76 lore raw

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/clk with 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_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.

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_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.

Quoted 8 lines

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.

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_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.

yeah, getting these constraints solved automatically is pretty expensive. some heuristics are probably indicated here.

Signature · 1 line
torben Hohn
#77 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Russell King - ARM Linux
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/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.

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.
#78 lore raw

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.
#79 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Uwe Kleine-König
Quoted 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.

#80 lore raw

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

author maintainer
#81 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Thomas Gleixner
Quoted 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(). 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 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

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:

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 |
#82 lore raw

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 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.

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_SYNC field 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 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.

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

#83 lore raw

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 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 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.

#84 lore raw

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 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 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

#85 lore raw

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_of now. 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.

#86 lore raw

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_of now. 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.

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

#87 lore raw

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.

#88 lore raw

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

#89 lore raw

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.

#90 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Thomas Gleixner
Quoted 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.

#91 lore raw

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

#92 lore raw

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.)

#93 lore raw

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_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.

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

#94 lore raw

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.

#95 lore raw

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

author maintainer
#96 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Thomas Gleixner
Quoted 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 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.

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_SYNC field 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 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.

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 |
#97 lore raw

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 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.

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

#98 lore raw

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: 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.

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.

#99 lore raw

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_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.

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_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).

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_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.

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

#100 lore raw

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

#101 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Thomas Gleixner
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.

#102 lore raw

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

#103 lore raw

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.
#104 lore raw

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

#105 lore raw

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.
#106 lore raw

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.

#107 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Thomas Gleixner
Quoted 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 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.

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.

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.
#108 lore raw

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

#109 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Thomas Gleixner
Quoted 5 lines · Thomas Gleixner
Quoted 1 line · Uwe Kleine-K?nig

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?

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.

#110 lore raw

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(). If

Which 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->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.

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 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.

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

#111 lore raw

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(). If

Which 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->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.

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 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.

Quoted 6 lines

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.

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.

#112 lore raw

RFC PATCH 1/1 clk: add support for automatic parent handling

In reply to Uwe Kleine-König

Hi Uwe,

Quoted 27 lines · Uwe Kleine-K?nig

---
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 +2 -0
index 264c809..7627815 100644
@@ -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
index d2f0db0..125e525 100644
@@ -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
#113 lore raw

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

---
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 +1 -0
index 264c809..7627815 100644
@@ -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? If prepare_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/  |
#114 lore raw

PATCH 4/10 clk: implement parent pass through functions

In reply to Sascha Hauer
Quoted 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.

author maintainer
#115 lore raw

PATCH 5/10 clk: Add support for simple dividers

In reply to 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).

---
 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
index 6e3ae54..76bb4c9 100644
@@ -5,3 +5,6 @@ config CLKDEV_LOOKUP
 
 config USE_COMMON_STRUCT_CLK
 	bool
+
+config USE_COMMON_CLK_DIVIDER
+	bool
drivers/clk/Makefile +1 -0
index a1a06d3..723d884 100644
@@ -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
index d014341..6f9771b 100644
@@ -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
#116 lore raw

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).

---
 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
index 6e3ae54..76bb4c9 100644
@@ -5,3 +5,6 @@ config CLKDEV_LOOKUP
 
 config USE_COMMON_STRUCT_CLK
 	bool
+
+config USE_COMMON_CLK_DIVIDER
+	bool
drivers/clk/Makefile +1 -0
index a1a06d3..723d884 100644
@@ -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 +18 -0
new file mode 100644
index 0000000..2de94df
@@ -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
index d014341..6f9771b 100644
@@ -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 -0
 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

"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/  |
author maintainer
#117 lore raw

PATCH 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).

---
 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
index 6e3ae54..76bb4c9 100644
@@ -5,3 +5,6 @@ config CLKDEV_LOOKUP
 
 config USE_COMMON_STRUCT_CLK
 	bool
+
+config USE_COMMON_CLK_DIVIDER
+	bool
drivers/clk/Makefile +1 -0
index a1a06d3..723d884 100644
@@ -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 +18 -0
new file mode 100644
index 0000000..2de94df
@@ -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);
Quoted 6 lines

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.

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 need DIV_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 |
#118 lore raw

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).

---
  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

Quoted 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 need DIV_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_rate returns 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 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.
#119 lore raw

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_rate returns while others round down in set_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/  |
#120 lore raw

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_rate returns 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 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_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:

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.
author maintainer
#121 lore raw

PATCH 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_rate returns while others round down in set_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.)

Quoted 6 lines
Quoted 2 lines

clk_set_rate_range can even be implemented with clk_round_rate that 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 |
#122 lore raw

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_rate

returns

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_rate may barf on

values

Quoted 3 lines
Quoted 3 lines

other than the return values of round_rate.)

clk_set_rate_range can even be implemented with clk_round_rate that

is

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.
author maintainer
#123 lore raw

PATCH 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_rate may barf on

values

Quoted 3 lines
Quoted 3 lines

other than the return values of round_rate.)

clk_set_rate_range can even be implemented with clk_round_rate that

is

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 |
#124 lore raw

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_rate may barf on

values

Quoted 3 lines
Quoted 3 lines

other than the return values of round_rate.)

clk_set_rate_range can even be implemented with clk_round_rate that

is

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.
#125 lore raw

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_rate may barf on

values

Quoted 3 lines
Quoted 3 lines

other than the return values of round_rate.)

clk_set_rate_range can even be implemented with clk_round_rate that

is

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/  |
#126 lore raw

PATCH 5/10 clk: Add support for simple dividers

In reply to Saravana Kannan
Quoted 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_rate returns 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 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.

#127 lore raw

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_rate returns while others round down in set_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 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".

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 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.

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.
#128 lore raw

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/  |
#129 lore raw

PATCH 5/10 clk: Add support for simple dividers

In reply to Uwe Kleine-König
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 need DIV_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.

author maintainer
#130 lore raw

PATCH 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 need DIV_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;
}
Quoted 2 lines

IOW, clk_round_rate() does what clk_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 |
#131 lore raw

PATCH 5/10 clk: Add support for simple dividers

In reply to Sascha Hauer

Just minor nitpicks.

Quoted 10 lines · Sascha Hauer
drivers/clk/clk-divider.c new file +4 -0
new file mode 100644
index 0000000..2de94df
@@ -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
index d014341..6f9771b 100644
@@ -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.
#132 lore raw

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

#133 lore raw

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_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.

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.
#134 lore raw

PATCH 5/10 clk: Add support for simple dividers

In reply to Sascha Hauer
Quoted 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).

---
 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
index 6e3ae54..76bb4c9 100644
@@ -5,3 +5,6 @@ config CLKDEV_LOOKUP
 
 config USE_COMMON_STRUCT_CLK
 	bool
+
+config USE_COMMON_CLK_DIVIDER
+	bool
drivers/clk/Makefile +1 -0
index a1a06d3..723d884 100644
@@ -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 +84 -0
new file mode 100644
index 0000000..2de94df
@@ -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
index d014341..6f9771b 100644
@@ -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
author maintainer
#135 lore raw

PATCH 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 |
#136 lore raw

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
author maintainer
#137 lore raw

PATCH 6/10 clk: Add support for a generic clock multiplexer

In reply to 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.

---
 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
index 76bb4c9..710d73d 100644
@@ -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
index 723d884..195a434 100644
@@ -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
index 2de94df..e3f5b7a 100644
@@ -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
index 6f9771b..fb2c2f5 100644
@@ -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
#138 lore raw

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.

---
 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
index 76bb4c9..710d73d 100644
@@ -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
index 723d884..195a434 100644
@@ -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 +0 -0
index 2de94df..e3f5b7a 100644

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
new file mode 100644
index 0000000..d33b15f
@@ -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
index 6f9771b..fb2c2f5 100644
@@ -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/  |
author maintainer
#139 lore raw

PATCH 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.

---
 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
index 76bb4c9..710d73d 100644
@@ -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
index 723d884..195a434 100644
@@ -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 +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_rate good 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 |
#140 lore raw

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/  |
#141 lore raw

PATCH 6/10 clk: Add support for a generic clock multiplexer

In reply to Sascha Hauer
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 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.
#142 lore raw

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 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);
}
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.

#143 lore raw

PATCH 6/10 clk: Add support for a generic clock multiplexer

Quoted 2 lines · Russell King - ARM Linux

Oops, clk_get_sys() and clk_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
index 0fc0a79..36a134f 100644
@@ -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);
 
#144 lore raw

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() and clk_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 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.

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.
author maintainer
#145 lore raw

PATCH 7/10 ARM i.MX: Support for clock building blocks.

In reply to Sascha Hauer

This 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
index 2ed3ab1..e881ab2 100644
@@ -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
author maintainer
#146 lore raw

PATCH 8/10 ARM i.MX: Add generic support for pllv2

In reply to Sascha Hauer

The 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
index a138787..c5ea019 100644
@@ -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
index 73a72af..4943ab0 100644
@@ -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
author maintainer
#147 lore raw

PATCH 9/10 ARM i.MX51/53: reimplement clock support

In reply to Sascha Hauer

Reimplement 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
index 159340d..c39cf42 100644
@@ -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
index 0b9338c..164d300 100644
@@ -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
index 04b37a8..ad1e227 100644
@@ -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
index 4943ab0..cc11577 100644
@@ -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
author maintainer
#148 lore raw

PATCH 10/10 ARM i.MX51/53: remove old clock support

In reply to Sascha Hauer

reimplemented 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
deleted file mode 100644
index fdbc05e..0000000
@@ -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
#149 lore raw
In reply to Sascha Hauer
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?

author maintainer
#150 lore raw
Quoted 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 |
#151 lore raw
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.

#152 lore raw
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.

#153 lore raw
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/  |
#154 lore raw
In reply to Sascha Hauer

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
#155 lore raw
In reply to Sascha Hauer
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
#define clk_prepare()
#define clk_unprepare()
#endif

will 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/  |
author maintainer
#156 lore raw
In reply to Sascha Hauer
Quoted 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 |