[LINUX] The Common Clk Framework

Originally, it is a part of the Linux Kernel source code, so it will be treated as GPLv2 (recognition that it should be).

https://www.kernel.org/doc/html/latest/index.html

Licensing documentation

The following describes the license of the Linux kernel source code (GPLv2), how to properly mark the license of individual files in the source tree, as well as links to the full license text.

https://www.kernel.org/doc/html/latest/process/license-rules.html#kernel-licensing

https://www.kernel.org/doc/html/latest/driver-api/clk.html

The Common Clk Framework

Author: Mike Turquette [email protected]

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.

This document details the general clk framework and how to make this framework unique across platforms. There is no detailed description of the clock api in ʻinclude / linux / clk.h`, but it will probably include some.

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 common clk framework is the interface that controls the clock nodes that are valid in various devices today. It provides clock gating, rate adjustment, muxing or other operations. This framwork is enabled by the CONFIG_COMMON_CLK option.

The interface itself is divided into two halves, each shielded from the details of its counterpart.

This interface itself can be roughly divided into two parts. Each protects from the details of the corresponding part.

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.

The first is a common definition of clk structures. The clk structure integrates the framework-level accounting and infrastructure that have traditionally been replicated on various platforms.

Second is a common implementation of the clk.h api, defined in drivers/clk/clk.c.

The second is a common implementation of clk.h api defined in drivers / clk / clk.c.

Finally there is struct clk_ops, whose operations are invoked by the clk api implementation.

Finally, there is a clk_ops structure, which is called 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.

The second half of the interface consists of hardware-specific callbacks registered in the clk_ops structure 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.

The rest of this document references some of the callbacks contained in the clk_ops structure. Means a hardware-specific implementation, for example .enable or .set_rate.

Likewise, references to struct clk_foo serve as a convenient shorthand for the implementation of the hardware-specific bits for the hypothetical "foo" hardware.

Similarly, the clk_foo structure serves as a convenient abbreviation for hardware-specific implementations of fictitious "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_core.

The clk_hw structure integrates the two halves of this interface. It is defined in the clk_foo structure and is pointered to in the clk_core structure.

This allows for easy navigation between the two discrete halves of the common clock interface.

This facilitates navigation between the two separate halves of the common clock interface.

Common data structures and api

Below is the common struct clk_core definition from drivers/clk/clk.c, modified for brevity::

Below is the common clk_core structure defined in drivers / clk / clk.c. It has been modified for brevity.

	struct clk_core {
		const char		*name;
		const struct clk_ops	*ops;
		struct clk_hw		*hw;
		struct module		*owner;
		struct clk_core		*parent;
		const char		**parent_names;
		struct clk_core		**parents;
		u8			num_parents;
		u8			new_parent_index;
		...
	};

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.

The above members make up the core of the clk tree topology. The clk api itself defines some functions of the driver interface for controlling the clk structure. This api is documented at ʻinclude / linux / clk.h`.

Platforms and devices utilizing the common struct clk_core use the struct clk_ops pointer in struct clk_core to perform the hardware-specific parts of the operations defined in clk-provider.h::

Platform and device drivers that utilize the common clk_core structure use pointers to the clk_ops structure in the clk_core structure to perform hardware-specific processing as defined in clk-providor.h.

	struct clk_ops {
		int		(*prepare)(struct clk_hw *hw);
		void		(*unprepare)(struct clk_hw *hw);
		int		(*is_prepared)(struct clk_hw *hw);
		void		(*unprepare_unused)(struct clk_hw *hw);
		int		(*enable)(struct clk_hw *hw);
		void		(*disable)(struct clk_hw *hw);
		int		(*is_enabled)(struct clk_hw *hw);
		void		(*disable_unused)(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);
		int		(*determine_rate)(struct clk_hw *hw,
						  struct clk_rate_request *req);
		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);
		int		(*get_phase)(struct clk_hw *hw);
		int		(*set_phase)(struct clk_hw *hw, int degrees);
		void		(*init)(struct clk_hw *hw);
		void		(*debug_init)(struct clk_hw *hw,
					      struct dentry *dentry);
	};

Hardware clk implementations

The strength of the common struct clk_core comes from its .ops and .hw pointers which abstract the details of struct clk from the hardware-specific bits, and vice versa.

The strength of the common clk_core structure is that it itself has an abstraction for hardware-specific bits with .ops and .hw pointers. The reverse is also true.

To illustrate consider the simple gateable clk implementation in drivers/clk/clk-gate.c::

Illustrates the simple clock gating possible implemented 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.

The clk_gate structure contains the clk_hw structure as hardware-specific knowledge about the registers and bits for controlling the gating of the clock.

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

There is no need for clock topology or accounting, such as enable_count or notifier_count. This is all handled by a common framework code and clk_core structure.

Let's walk through enabling this clk from driver code::

Let's check the procedure to enable this clk structure from the 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::

The clk_enable call graph is very concise.

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

And the definition of clk_get_set_bit is as follows.

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

Where to_clk_gate is defined as follows:

#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)

This pattern of abstraction is used for every clock hardware representation.

This pattern of abstraction is used in all clock hardware representations.

Supporting your own clk hardware

When implementing support for a new type of clock it is only necessary to include the following header::

When implementing to support the new clock type, just include the header below.

#include <linux/clk-provider.h>

To construct a clk hardware structure for your platform you must define the following::

The following definitions are required to configure the clk hardware structure for your platform.

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

To take advantage of the benefits of using data, clk needs support for the right controls.

	struct clk_ops clk_foo_ops = {
		.enable		= &clk_foo_enable,
		.disable	= &clk_foo_disable,
	};

Implement the above functions using container_of::

Implement the above function 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.

Below is a matrix detailing whether clk_ops are needed for that clock based on hardware capabilities.

A cell marked as "y" means mandatory, a cell marked as "n" implies that either including that callback is invalid or otherwise unnecessary.

The cell marked "y" is required, and "n" means whether the callback is invalid or not needed.

Empty cells are either optional or must be evaluated on a case-by-case basis.

Empty cells should be optional or evaluated on a case-by-case basis.

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

[1] Required by either round_rate or determine_rate

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

Finally, the clock is registered at run time using a hardware-specific registration function. This function simply populates the data for the clk_foo structure and tells framwork the general clk structure parameters in the next call.

clk_register(...)

See the basic clock types in drivers/clk/clk-*.c for examples.

Please refer to the basic clock type in drivers / clk / clk-*. C.

Disabling clock gating of unused clocks

Sometimes during development it can be useful to be able to bypass the default disabling of unused clocks.

During development, it is often useful to disable the clock by default.

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.

For example, if the driver does not enable the clock properly, but relies on the benefits of the bootloader, bypassing the disable will continue to work as long as the problem is resolved.

To bypass this disabling, include "clk_ignore_unused" in the bootargs to the kernel.

To bypass this invalidation, include "clk_ignore_unused" in the kernel bootargs.

Locking

The common clock framework uses two global locks, the prepare lock and the enable lock.

The common clock framework uses two global locks. prepare lock and enable lock.

The enable lock is a spinlock and is held across calls to the .enable, .disable operations.

The enable lock is a spinlock, which is held while performing .enable or .disable operations.

Those operations are thus not allowed to sleep, and calls to the clk_enable(), clk_disable() API functions are allowed in atomic context.

Therefore, these operations cannot sleep and the clk_enable () and cld_disable () APIs are allowed to be called within the atomic context.

.

For clk_is_enabled() API, it is also designed to be allowed to be used in atomic context.

Also, the clk_is_enable () API is designed to be used within the atomic context.

However, it doesn't really make any sense to hold the enable lock in core, unless you want to do something else with the information of the enable state with that lock held.

But unless you want to do something else with the lock hold enabled state information while the core is holding the enable lock.

Otherwise, seeing if a clk is enabled is a one-shot read of the enabled state, which could just as easily change after the function returns because the lock is released.

Otherwise, checking if the clock is enabled is a one-shot read of the enabled state, which releases the lock so you can easily change it after the function returns.

Thus the user of this API needs to handle synchronizing the read of the state with whatever they're using it for to make sure that the enable state doesn't change during that time.

Therefore, users of this API should synchronize their discharge reads with the ones they are using so that the enable state does not change in the meantime.

.

The prepare lock is a mutex and is held across calls to all other operations.

The prepare lock is a mutex and is held while invoking other operations.

All those operations are allowed to sleep, and calls to the corresponding API functions are not allowed in atomic context.

All of these operations can sleep and the corresponding API function calls are not allowed in the atomic context.

This effectively divides operations in two groups from a locking perspective.

This effectively splits the process into 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.

Drivers do not have to manually protect resources shared by a group of investigators, regardless of whether the resources are shared by multiple clocks.

However, access to resources that are shared between operations of the two groups needs to be protected by the drivers.

However, access to resources shared between the operations of the two groups must be protected by the driver.

An example of such a resource would be a register that controls both the clock rate and the clock enable/disable state.

An example of such a resource is a register that controls both the clock rate and the enabled / disabled state of the clock.

.

The clock framework is reentrant, in that a driver is allowed to call clock framework functions from within its implementation of clock operations.

The clock framework is reentrant in that the driver can call it from within the implementation of clock manipulation.

This can for instance cause a .set_rate operation of one clock being called from within the .set_rate operation of another clock.

This can cause, for example, a .set_rate operation on one clock to be called from within a .set_rate operation on another clock.

This case must be considered in the driver implementations, but the code flow is usually controlled by the driver in that case.

This case should be considered in the driver implementation. However, the code flow is usually controlled by the driver in such cases.

.

Note that locking must also be considered when code outside of the common clock framework needs to access resources used by the clock operations.

Keep in mind that if the external code of the common clock framework needs to access the resources used for clock operations, then locking should also be considered.

This is considered out of scope of this document.

It is outside the scope of this document.

Recommended Posts

The Common Clk Framework
Investigate the .NET Framework bzip2 library
Split the pyramid framework ini file
Introducing the BOT framework Minette for Python
Understand the benefits of the Django Rest Framework
Try using the web application framework Flask
Miscellaneous notes about the Django REST framework
What is the ETL processing framework clivoa?
I tried the Python Tornado Testing Framework