diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
commit | 57f0f512b273f60d52568b8c6b77e17f5636edc0 (patch) | |
tree | 5e910f0e82173f4ef4f51111366a3f1299037a7b /Documentation/clk.txt |
Initial import
Diffstat (limited to 'Documentation/clk.txt')
-rw-r--r-- | Documentation/clk.txt | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/Documentation/clk.txt b/Documentation/clk.txt new file mode 100644 index 000000000..0e4f90aa1 --- /dev/null +++ b/Documentation/clk.txt @@ -0,0 +1,299 @@ + The Common Clk Framework + Mike Turquette <mturquette@ti.com> + +This document endeavours to explain the common clk framework details, +and how to port a platform over to this framework. It is not yet a +detailed explanation of the clock api in include/linux/clk.h, but +perhaps someday it will include that information. + + Part 1 - introduction and interface split + +The common clk framework is an interface to control the clock nodes +available on various devices today. This may come in the form of clock +gating, rate adjustment, muxing or other operations. This framework is +enabled with the CONFIG_COMMON_CLK option. + +The interface itself is divided into two halves, each shielded from the +details of its counterpart. First is the common definition of struct +clk which unifies the framework-level accounting and infrastructure that +has traditionally been duplicated across a variety of platforms. Second +is a common implementation of the clk.h api, defined in +drivers/clk/clk.c. Finally there is struct clk_ops, whose operations +are invoked by the clk api implementation. + +The second half of the interface is comprised of the hardware-specific +callbacks registered with struct clk_ops and the corresponding +hardware-specific structures needed to model a particular clock. For +the remainder of this document any reference to a callback in struct +clk_ops, such as .enable or .set_rate, implies the hardware-specific +implementation of that code. Likewise, references to struct clk_foo +serve as a convenient shorthand for the implementation of the +hardware-specific bits for the hypothetical "foo" hardware. + +Tying the two halves of this interface together is struct clk_hw, which +is defined in struct clk_foo and pointed to within struct clk. This +allows for easy navigation between the two discrete halves of the common +clock interface. + + Part 2 - common data structures and api + +Below is the common struct clk definition from +include/linux/clk-private.h, modified for brevity: + + struct clk { + const char *name; + const struct clk_ops *ops; + struct clk_hw *hw; + char **parent_names; + struct clk **parents; + struct clk *parent; + struct hlist_head children; + struct hlist_node child_node; + ... + }; + +The members above make up the core of the clk tree topology. The clk +api itself defines several driver-facing functions which operate on +struct clk. That api is documented in include/linux/clk.h. + +Platforms and devices utilizing the common struct clk use the struct +clk_ops pointer in struct clk to perform the hardware-specific parts of +the operations defined in clk.h: + + struct clk_ops { + int (*prepare)(struct clk_hw *hw); + void (*unprepare)(struct clk_hw *hw); + int (*enable)(struct clk_hw *hw); + void (*disable)(struct clk_hw *hw); + int (*is_enabled)(struct clk_hw *hw); + unsigned long (*recalc_rate)(struct clk_hw *hw, + unsigned long parent_rate); + long (*round_rate)(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate); + long (*determine_rate)(struct clk_hw *hw, + unsigned long rate, + unsigned long min_rate, + unsigned long max_rate, + unsigned long *best_parent_rate, + struct clk_hw **best_parent_clk); + int (*set_parent)(struct clk_hw *hw, u8 index); + u8 (*get_parent)(struct clk_hw *hw); + int (*set_rate)(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate); + int (*set_rate_and_parent)(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index); + unsigned long (*recalc_accuracy)(struct clk_hw *hw, + unsigned long parent_accuracy); + void (*init)(struct clk_hw *hw); + int (*debug_init)(struct clk_hw *hw, + struct dentry *dentry); + }; + + Part 3 - hardware clk implementations + +The strength of the common struct clk comes from its .ops and .hw pointers +which abstract the details of struct clk from the hardware-specific bits, and +vice versa. To illustrate consider the simple gateable clk implementation in +drivers/clk/clk-gate.c: + +struct clk_gate { + struct clk_hw hw; + void __iomem *reg; + u8 bit_idx; + ... +}; + +struct clk_gate contains struct clk_hw hw as well as hardware-specific +knowledge about which register and bit controls this clk's gating. +Nothing about clock topology or accounting, such as enable_count or +notifier_count, is needed here. That is all handled by the common +framework code and struct clk. + +Let's walk through enabling this clk from driver code: + + struct clk *clk; + clk = clk_get(NULL, "my_gateable_clk"); + + clk_prepare(clk); + clk_enable(clk); + +The call graph for clk_enable is very simple: + +clk_enable(clk); + clk->ops->enable(clk->hw); + [resolves to...] + clk_gate_enable(hw); + [resolves struct clk gate with to_clk_gate(hw)] + clk_gate_set_bit(gate); + +And the definition of clk_gate_set_bit: + +static void clk_gate_set_bit(struct clk_gate *gate) +{ + u32 reg; + + reg = __raw_readl(gate->reg); + reg |= BIT(gate->bit_idx); + writel(reg, gate->reg); +} + +Note that to_clk_gate is defined as: + +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, clk) + +This pattern of abstraction is used for every clock hardware +representation. + + Part 4 - supporting your own clk hardware + +When implementing support for a new type of clock it only necessary to +include the following header: + +#include <linux/clk-provider.h> + +include/linux/clk.h is included within that header and clk-private.h +must never be included from the code which implements the operations for +a clock. More on that below in Part 5. + +To construct a clk hardware structure for your platform you must define +the following: + +struct clk_foo { + struct clk_hw hw; + ... hardware specific data goes here ... +}; + +To take advantage of your data you'll need to support valid operations +for your clk: + +struct clk_ops clk_foo_ops { + .enable = &clk_foo_enable; + .disable = &clk_foo_disable; +}; + +Implement the above functions using container_of: + +#define to_clk_foo(_hw) container_of(_hw, struct clk_foo, hw) + +int clk_foo_enable(struct clk_hw *hw) +{ + struct clk_foo *foo; + + foo = to_clk_foo(hw); + + ... perform magic on foo ... + + return 0; +}; + +Below is a matrix detailing which clk_ops are mandatory based upon the +hardware capabilities of that clock. A cell marked as "y" means +mandatory, a cell marked as "n" implies that either including that +callback is invalid or otherwise unnecessary. Empty cells are either +optional or must be evaluated on a case-by-case basis. + + clock hardware characteristics + ----------------------------------------------------------- + | gate | change rate | single parent | multiplexer | root | + |------|-------------|---------------|-------------|------| +.prepare | | | | | | +.unprepare | | | | | | + | | | | | | +.enable | y | | | | | +.disable | y | | | | | +.is_enabled | y | | | | | + | | | | | | +.recalc_rate | | y | | | | +.round_rate | | y [1] | | | | +.determine_rate | | y [1] | | | | +.set_rate | | y | | | | + | | | | | | +.set_parent | | | n | y | n | +.get_parent | | | n | y | n | + | | | | | | +.recalc_accuracy| | | | | | + | | | | | | +.init | | | | | | + ----------------------------------------------------------- +[1] either one of round_rate or determine_rate is required. + +Finally, register your clock at run-time with a hardware-specific +registration function. This function simply populates struct clk_foo's +data and then passes the common struct clk parameters to the framework +with a call to: + +clk_register(...) + +See the basic clock types in drivers/clk/clk-*.c for examples. + + Part 5 - static initialization of clock data + +For platforms with many clocks (often numbering into the hundreds) it +may be desirable to statically initialize some clock data. This +presents a problem since the definition of struct clk should be hidden +from everyone except for the clock core in drivers/clk/clk.c. + +To get around this problem struct clk's definition is exposed in +include/linux/clk-private.h along with some macros for more easily +initializing instances of the basic clock types. These clocks must +still be initialized with the common clock framework via a call to +__clk_init. + +clk-private.h must NEVER be included by code which implements struct +clk_ops callbacks, nor must it be included by any logic which pokes +around inside of struct clk at run-time. To do so is a layering +violation. + +To better enforce this policy, always follow this simple rule: any +statically initialized clock data MUST be defined in a separate file +from the logic that implements its ops. Basically separate the logic +from the data and all is well. + + Part 6 - Disabling clock gating of unused clocks + +Sometimes during development it can be useful to be able to bypass the +default disabling of unused clocks. For example, if drivers aren't enabling +clocks properly but rely on them being on from the bootloader, bypassing +the disabling means that the driver will remain functional while the issues +are sorted out. + +To bypass this disabling, include "clk_ignore_unused" in the bootargs to the +kernel. + + Part 7 - Locking + +The common clock framework uses two global locks, the prepare lock and the +enable lock. + +The enable lock is a spinlock and is held across calls to the .enable, +.disable and .is_enabled operations. Those operations are thus not allowed to +sleep, and calls to the clk_enable(), clk_disable() and clk_is_enabled() API +functions are allowed in atomic context. + +The prepare lock is a mutex and is held across calls to all other operations. +All those operations are allowed to sleep, and calls to the corresponding API +functions are not allowed in atomic context. + +This effectively divides operations in two groups from a locking perspective. + +Drivers don't need to manually protect resources shared between the operations +of one group, regardless of whether those resources are shared by multiple +clocks or not. However, access to resources that are shared between operations +of the two groups needs to be protected by the drivers. An example of such a +resource would be a register that controls both the clock rate and the clock +enable/disable state. + +The clock framework is reentrant, in that a driver is allowed to call clock +framework functions from within its implementation of clock operations. This +can for instance cause a .set_rate operation of one clock being called from +within the .set_rate operation of another clock. This case must be considered +in the driver implementations, but the code flow is usually controlled by the +driver in that case. + +Note that locking must also be considered when code outside of the common +clock framework needs to access resources used by the clock operations. This +is considered out of scope of this document. |