Overview of Clock Framework
[ English | 简体中文 ]
I. Clock Configuration
Configuration Options
The following are the relevant options for clock configuration:
CONFIG_CLK=y
CONFIG_CLK_RPMSG=y // Support cross-core control
II. Clock Framework
1. Overall Architecture
The following are the main components of the clock framework and their functions:
Middle Layer:
- Provides a unified clock control interface, supporting multiple clock types and hardware adaptation.
2. Southbound Adaptation Layer
Southbound Interface Implementation
The southbound adaptation of the clock needs to implement the struct clk_ops_s interface to support the following features:
| Feature | Southbound Interface | Function |
|---|---|---|
| clk gate | enable |
Enable the clock. |
disable |
Disable the clock. | |
is_enabled |
Determine whether the clock is enabled. | |
| calc rate | recalc_rate |
Calculate the current clock frequency based on the parent clock frequency. |
round_rate |
Calculate the appropriate frequency and parent clock frequency based on the target frequency. | |
determine_rate |
Calculate the best frequency, the best parent clock, and its frequency based on the target frequency. | |
| multiplexer | set_parent |
Set the corresponding parent clock. |
get_parent |
Obtain the current parent clock. | |
| set rate | set_rate |
Configure the current clock frequency based on the parent clock frequency. |
set_rate_and_parent |
Configure the current clock frequency based on the parent clock frequency and select the corresponding parent clock. | |
| phase | get_phase |
Obtain the clock phase. |
set_phase |
Set the clock phase. |
-
struct clk_ops_sdefinitionThe following is the definition of
struct clk_ops_sand its interface parameters:
struct clk_ops_s
{
CODE int (*enable)(FAR struct clk_s *clk);
CODE void (*disable)(FAR struct clk_s *clk);
CODE int (*is_enabled)(FAR struct clk_s *clk);
CODE uint32_t (*recalc_rate)(FAR struct clk_s *clk, uint32_t parent_rate);
CODE uint32_t (*round_rate)(FAR struct clk_s *clk,
uint32_t rate, uint32_t *parent_rate);
CODE uint32_t (*determine_rate)(FAR struct clk_s *clk, uint32_t rate,
uint32_t *best_parent_rate,
struct clk_s **best_parent_clk);
CODE int (*set_parent)(FAR struct clk_s *clk, uint8_t index);
CODE uint8_t (*get_parent)(FAR struct clk_s *clk);
CODE int (*set_rate)(FAR struct clk_s *clk, uint32_t rate,
uint32_t parent_rate);
CODE int (*set_rate_and_parent)(FAR struct clk_s *clk, uint32_t rate,
uint32_t parent_rate,
uint8_t index);
CODE int (*get_phase)(FAR struct clk_s *clk);
CODE int (*set_phase)(FAR struct clk_s *clk, int degrees);
};
-
Clock node registration interface
The framework provides the
clk_registerinterface for registering clock control nodes. The definition is as follows:
FAR struct clk_s *clk_register(FAR const char *name,
FAR const char * const *parent_names,
uint8_t num_parents, uint8_t flags,
FAR const struct clk_ops_s *ops,
FAR void *private_data, size_t private_size);
Parameter Description
| Parameter | Description |
|---|---|
| name | Name of the clock unit |
| parent_names | Array of parent clock unit names |
| num_parents | Number of parent clock units |
| flags | Attributes of the clock unit |
| ops | Clock unit control interface |
| private_data | Private data |
| private_size | Length of private data |
Description of Registration Attributes
The following are the attribute flags during clock registration and their descriptions:
| flag | Attribute Description |
|---|---|
| CLK_SET_RATE_GATE | When calling clk_set_rate to set the frequency, it is necessary to gate the current clock. |
| CLK_SET_PARENT_GATE | When calling clk_set_parent to associate a non-current parent clock, it is necessary to gate the current clock. |
| CLK_SET_RATE_PARENT | When calling clk_set_rate to set the frequency, the parent clock and its frequency can be changed. |
| CLK_SET_RATE_NO_REPARENT | When setting the frequency, there is no need to rechange the parent clock. |
| CLK_GET_RATE_NOCACHE | When calling clk_get_rate, the frequency is recalculated based on the parent clock frequency; otherwise, it is directly obtained from the memory structure. |
| CLK_NAME_IS_STATIC | When calling clk_register, the clock name is static memory. |
| CLK_PARENT_NAME_IS_STATIC | When calling clk_register, the parent clock name is static memory. |
| CLK_IS_CRITICAL | The clock is not allowed to be turned off. |
| CLK_OPS_PARENT_ENABLE | When calling clk_set_parent, clk_set_rate, clk_enable, or clk_disable, the parent clock needs to be enabled. |
3. Registration Interfaces of Middle Framework Layer
3.1 Divider
The following is the registration interface of the divider middle framework:
FAR struct clk_s *clk_register_divider(FAR const char *name,
FAR const char *parent_name,
uint8_t flags, uint32_t reg,
uint8_t shift, uint8_t width,
uint16_t clk_divider_flags)
- Parameter Description
| Parameter | Description |
|---|---|
| name | Name of the clock unit |
| parent_name | Name of the parent clock unit |
| flags | Attribute flags of the clock unit |
| reg | Specify the address of the operation register |
| shift | Offset of the configuration register |
| width | Width of the configuration register |
| clk_divider_flags | Divider attribute flags, used to control the behavior of the divider |
-
Function: Divide the parent clock frequency according to the value of the bit corresponding to
reg. -
Attributes and Calculation Formulas
The following are the attribute flags of the divider, their calculation formulas, and functions:
| Attribute | Calculation Formula and Function |
|---|---|
| CLK_DIVIDER_ONE_BASED | fout = (fin + val − 1) / valThe division factor starts from 1. When this flag is not present, val needs to be incremented by 1 after being read from the register. |
| CLK_DIVIDER_HIWORD_MASK | High 16-bit mask. When modifying the value of the low 16 bits, mask operations are performed, and configuration can be completed without rereading the register. |
| CLK_DIVIDER_ROUND_CLOSEST | When round_rate is called, find the division value closest to the target frequency. |
| CLK_DIVIDER_READ_ONLY | When round_rate is called, modifying the register value is not allowed. |
| CLK_DIVIDER_MAX_HALF | The maximum division factor is calculated as half of the mask value. |
| CLK_DIVIDER_DIV_NEED_EVEN | The division factor needs to be even. |
| CLK_DIVIDER_POWER_OF_TWO | fout = (fin + 2^n − 1) / 2^nThe division factor is the nth power of 2. |
| CLK_DIVIDER_MINDIV_OFF | Offset of the minimum division number in flags. |
| CLK_DIVIDER_MINDIV_MSK | Bit mask of the minimum division number in flags. |
-
round_ratealgorithm flowThe following is the flow chart of the divider
round_ratealgorithm:
3.2 Fixed Factor Frequency Modulator
FAR struct clk_s *clk_register_fixed_factor(FAR const char *name,
FAR const char *parent_name,
uint8_t flags, uint8_t mult,
uint8_t div)
-
Frequency Modulation Formula
The output frequency (fout) of the fixed factor frequency modulator is calculated by the following formula:
fout = fin * mult / divfin: Parent clock frequency. mult: Multiplication factor. div: Division factor. round_rate algorithm -
The
round_ratealgorithm is used to calculate the output frequency closest to the target frequency, and the specific steps are as follows:-
Invert the parent clock frequency (
fp) based on the target output frequency (fout):fp = fout * div / mult
-
Round the parent clock frequency (
fp) to obtain the closest parent clock frequency (fpbest). -
Calculate the optimal output frequency (
foutbest) based on the optimal parent clock frequency (fpbest):foutbest = fpbest * mult / div
-
3.3 Fixed Frequency Regulator
FAR struct clk_s *clk_register_fixed_rate(FAR const char *name,
FAR const char *parent_name,
uint8_t flags, uint32_t fixed_rate)
- fixed_rate: Fixed output frequency value.
3.4 Strobe
FAR struct clk_s *clk_register_gate(FAR const char *name,
FAR const char *parent_name,
uint8_t flags, uint32_t reg,
uint8_t bit_idx,
uint8_t clk_gate_flags)
- bit_idx: Specifies the bit index in the register used for strobe operations.
3.5 Multiplier
FAR struct clk_s *clk_register_multiplier(FAR const char *name,
FAR const char *parent_name,
uint8_t flags, uint32_t reg,
uint8_t shift,
uint8_t width,
uint8_t clk_multiplier_flags)
- Parameter Description
| Parameter | Description |
|---|---|
| reg | Address of the multiplier register. |
| shift | Offset of the multiplier register. |
| width | Width of the multiplier register. |
-
Multiplier Attributes and Calculation Formulas
The following are the attribute flags of the multiplier, their calculation formulas, and functions:
| Attribute | Calculation Formula and Function |
|---|---|
| CLK_MULT_ONE_BASED | fout = fin * val The multiplication factor starts from 1. When this flag is not present, val needs to be incremented by 1 after being read from the register. |
| CLK_MULT_ALLOW_ZERO | Allow the multiplication factor to be 0. |
| CLK_MULT_HIWORD_MASK | High 16-bit mask. When modifying the value of the low 16 bits, mask operations are performed, and configuration can be completed without rereading the register. |
| CLK_MULT_MAX_HALF | The maximum multiplication factor is calculated as half of the mask value. |
| CLK_MULT_ROUND_CLOSEST | When round_rate is called, find the multiplication value closest to the target frequency. |
round_ratealgorithm flow
3.6 Multiplexer
FAR struct clk_s *clk_register_mux(FAR const char *name,
const char * const *parent_names,
uint8_t num_parents,
uint8_t flags, uint32_t reg,
uint8_t shift, uint8_t width,
uint8_t clk_mux_flags)
- Parameter Description
| Parameter | Description |
|---|---|
| reg | Address of the multiplexer register. |
| shift | Offset of the multiplexer register. |
| width | Width of the multiplexer register. |
Function: Select the parent clock frequency output according to the bit corresponding to reg.
- Description of Multiplexer Attributes
| Attribute | Description |
|---|---|
| CLK_MUX_HIWORD_MASK | High 16-bit mask. When modifying the value of the low 16 bits, mask operations are performed, and configuration can be completed without rereading the register. |
| CLK_MUX_READ_ONLY | Only supports obtaining the parent clock frequency, not modifying it. |
| CLK_MUX_ROUND_CLOSEST | When determine_rate is called, find the parent clock frequency closest to the target frequency. |
determine_ratesteps

3.7 Phase Regulator
FAR struct clk_s *clk_register_phase(FAR const char *name,
FAR const char *parent_name,
uint8_t flags, uint32_t reg,
uint8_t shift, uint8_t width,
uint8_t clk_phase_flags)
- Parameter Description
| Parameter | Description |
|---|---|
| reg | Address of the phase regulator register. |
| shift | Offset of the phase regulator register. |
| width | Width of the phase regulator register. |
Function: Select the parent clock frequency according to the bit corresponding to reg and perform phase regulation.
- Description of Phase Regulator Attributes
| Attribute | Description |
|---|---|
| CLK_PHASE_HIWORD_MASK | High 16-bit mask. When modifying the value of the low 16 bits, mask operations are performed, and configuration can be completed without rereading the register. |
3.8 Fractional Divider
FAR struct clk_s *
clk_register_fractional_divider(FAR const char *name,
FAR const char *parent_name,
uint8_t flags, uint32_t reg,
uint8_t mshift, uint8_t mwidth,
uint8_t nshift, uint8_t nwidth,
uint8_t clk_divider_flags)
- Parameter Description
| Parameter | Description |
|---|---|
| reg | Address of the fractional divider register. |
| mshift | Offset of the fractional divider denominator register. |
| mwidth | Width of the fractional divider denominator register. |
| nshift | Offset of the fractional divider numerator register. |
| nwidth | Width of the fractional divider numerator register. |
Function: Select the parent clock frequency according to the bit corresponding to reg and calculate the output frequency through fractional division.
- Fractional Divider Attributes and Calculation Formulas
| Attribute | Description |
|---|---|
| CLK_FRAC_DIV_DOUBLE | Without this flag: fout = fin * m /n With this flag: fout = fin * m /2n |
| CLK_FRAC_MUL_NEED_EVEN | When round_rate is called, the m value needs to be even. |
4. API Interface Layer
| API | Function |
|---|---|
| clk_get | Match the clk_s with the specified name from g_clk_root_list and g_clk_orphan_list. |
| clk_get_parent | Obtain the clk_s of the current associated parent clock of clk_s. |
| clk_get_parent_by_index | Obtain the clk_s corresponding to the indexth parent clock of clk_s. |
| clk_set_parent | Associate the parent clock according to whether the parent clock name matches the parent clock name of clk, and refresh the frequency of clk based on the parent clock frequency. |
| clk_enable | Enable the parent clock, enable clk_s, and increment enable_count. |
| clk_disable | Decrement enable_count, disable clk_s, and disable the parent clock. |
| clk_is_enabled | Determine whether clk_s has been enabled. |
| clk_round_rate | Calculate the most appropriate frequency based on the target frequency. |
| clk_set_rate | Set the frequency of clk. |
| clk_set_rates | Batch configure the frequencies of multiple clk. |
| clk_get_rate | Obtain the current frequency of clk. |
| clk_set_phase | Configure the phase of clk. |
| clk_get_phase | Obtain the phase of clk. |
| clk_disable_unused | Turn off the unused clk. |
| clk_get_name | Obtain the name of clk. |
III. Debug PROCFS
Through the /proc/clk file node, you can view the structural relationship of the clock tree and the following information of each clock node:
- enable_cnt: Clock enable count.
- rate: Clock frequency.
- phase: Clock phase.
- Example Operations
The following is an example of viewing the /proc/clk file through the cat command:
ap> cat /proc/clk
clock enable_cnt rate phase
clk_1000 0 1000 0
clk_2000 0 2000 0
ap>
IV. Reference Documents
- For asynchronous cross-core support, please refer to the relevant documents of
rpmsg clk.