mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-24 03:24:55 +08:00
234 lines
8.5 KiB
Plaintext
234 lines
8.5 KiB
Plaintext
|
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 easy for 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,
|
||
|
unsigned long *);
|
||
|
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);
|
||
|
void (*init)(struct clk_hw *hw);
|
||
|
};
|
||
|
|
||
|
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 capbilities 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 uneccesary. 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 | | | |
|
||
|
.set_rate | | y | | | |
|
||
|
| | | | | |
|
||
|
.set_parent | | | n | y | n |
|
||
|
.get_parent | | | n | y | n |
|
||
|
| | | | | |
|
||
|
.init | | | | | |
|
||
|
-----------------------------------------------------------
|
||
|
|
||
|
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.
|