Clock
| Chip Name | Kernel Version |
|---|---|
| RK303X | LINUX4.4 & 4.19 & 5.10 |
| RK312X | LINUX4.4 & 4.19 & 5.10 |
| RK322X | LINUX4.4 & 4.19 & 5.10 |
| RK3288X | LINUX4.4 & 4.19 & 5.10 |
| RK3328 | LINUX4.4 & 4.19 & 5.10 |
| RK3368 | LINUX4.4 & 4.19 & 5.10 |
| RK3399 | LINUX4.4 & 4.19 & 5.10 |
| RV1108 | LINUX4.4 & 4.19 & 5.10 |
| PX30 | LINUX4.4 & 4.19 & 5.10 |
| RV1126 | LINUX4.19 & 5.10 |
| RK356X | LINUX4.19 & 5.10 |
| RK3588 | LINUX5.10 |
| RK3576 | LINUX6.1 |
| RV1103B | LINUX5.10 |
| RK3506 | LINUX6.1 |
Preface
This document mainly introduces the RK platform clock subsystem framework and configuration.
Target Audience
This document (this guide) is mainly intended for the following engineers:
- Technical support engineers
- Software development engineers
1. Solution Overview
1.1 Overview
This chapter mainly describes important concepts related to the clock subsystem, clock schemes, overall process, and code structure.
1.2 Important Concepts
Clock Subsystem
The clock here refers to the tree framework that provides clocks to various SOC components, not the time used by the kernel. Like other modules, CLOCK also has a framework for adapting to different platforms. Above the adaptation layer is customer code and interfaces, that is, drivers for each module (such as peripherals that require clock signals, USB, etc.). Below the adaptation layer are the specific SOC-level clock operation details.
Clock Tree Structure
Mainstream processor platforms that can run LINUX all have very complex CLOCK TREEs. If you look at the CLOCK-related chapters in any processor's SPEC, there will definitely be a huge and complex tree diagram, which consists of CLOCK-related devices and the CLOCKs output by these devices.
Related Devices
CLOCK-related devices include: Oscillator (active oscillator, also called resonator) or Crystal (passive oscillator, also called crystal oscillator) for generating CLOCK; PLL (Phase Locked Loop) for frequency multiplication; Divider for frequency division; MUX for multi-way selection; AND gate for CLOCK ENABLE control; hardware modules using CLOCK (can be called CONSUMER); etc.
1.3 Clock Scheme
Each SOC has its own clock allocation scheme, mainly including PLL settings, parent attributes of each CLOCK, DIV, MUX, etc. The clock scheme varies with different chips.
Table 1‑1 Example of Clock Tree Diagram

| Item | Function | Path |
|---|---|---|
| clk | In rk3xxx.c, mainly register description of CLOCK, tree relationship between CLOCKs, etc. | drivers/clk/rockchip/clk-rk3xxx.c |
| rk3xxx.c | .h defines CLOCK IDs, matches CLOCK Name by ID | include/dt-bindings/clock/rk3xxx-cru.h |
| RK special handling | Handles RK's PLL clocks, some special clocks such as LCDC, I2S, etc. | drivers/clk/rockchip/clk-xxx.c |
| CLK API | Provides interfaces for Driver calls in Linux environment | drivers/clk/clk-xxx.x |
1.4 Overall Process
Table 1‑2 Clock Configuration Flowchart

Main contents include (not all CLOCKs need to support):
- Enable/Disable CLOCK.
- Set the frequency of CLOCK.
- Select the Parent of CLOCK.
1.5 Code Structure
Table 1‑3 CLOCK Code Composition
| Item | Function | Path |
|---|---|---|
| clk-rk3xxx.c | .c mainly describes CLOCK registers, tree relationship between CLOCKs, etc. | drivers/clk/rockchip/clk-rk3xxx.c |
| rk3xxx-cru.h | .h defines CLOCK IDs, matches CLOCK Name by ID | include/dt-bindings/clock/rk3xxx-cru.h include/dt-bindings/clock/rockchip,rk3xxx-cru.h |
| RK special handling | Handles RK's PLL clocks, some special clocks such as LCDC, I2S, etc. | drivers/clk/rockchip/clk-xxx.c |
| CLK API | Provides interfaces for Driver calls in Linux environment | drivers/clk/clk-xxx.x |
The software framework of CLOCK consists of three parts: Device Tree of CLOCK (register description of CLOCK, tree relationship between CLOCKs, etc.), Device driver CLOCK configuration, and CLOCK API. The functions of these three parts and the code paths of CLOCK are shown in Table 1-1.
2. CLOCK Development Guide
2.1 Overview
This chapter describes how to modify clock configuration, use API interfaces, and debug CLOCK programs.
2.2 Clock Related Concepts
2.2.1 PLL
Phase Locked Loop, which is input by a 24M crystal oscillator, and then the internal PLL locks the corresponding frequency. This is the source of all CLOCKs in the SOC. All bus and device clocks of the SOC are divided down from the PLL. The main PLLs on the RK platform are:
Table 2‑1 PLL Description
| PLL | Sub-device | Purpose | Remarks |
|---|---|---|---|
| APLL | CLOCK_CORE | CPU clock | Generally only for CPU use, because CPU will change frequency, APLL will change according to CPU required frequency |
| DPLL | CLOCK_DDR | DDR clock | Generally only for DDR use, because DDR will change frequency, DPLL will change according to DDR requirements |
| GPLL | Provides backup for bus and peripheral clocks | Generally set at 594M or 1200M to ensure basic 100, 200, 300, 400M clocks are output | |
| CPLL | Backup for GMAC or other devices | Generally may be 400, 500, 800, 1000M. Or exclusively for Lcdc | |
| NPLL | Backup for other devices | Generally may be 1188M, or exclusively for Lcdc |
2.2.2 Bus
Our SOC buses include ACLK_PERI, HCLK_PERI, PCLK_PERI, ACLK_BUS, HCLK_BUS, PCLK_BUS. (ACLK is used for data transfer, PCLK and HCLK are generally used for register read/write)
The distinction between BUS and PERI is mainly to distinguish between high-speed and low-speed buses. ACLK range is 100-300M, PCLK range is 50M150M, HCLK range is 37M150M. Under BUS are mainly some low-speed devices, such as I2C, I2S, SPI, etc., while under PERI are generally EMMC, GMAC, USB, etc. Different chips may have some differences in design. For example: for some devices that require high bus speed, a separate ACLK may be designed for this device (such as ACLK_EMMC or ACLK_USB, etc.).
The bus clocks of each device will be attached to these clocks, as shown in the following structure:
Table 2‑2 Bus Clock Structure


Note:
On RK3399, high-speed and low-speed buses are completely separated, divided into high-speed: ACLK_PERIHP, HCLK_PERIHP, PCLK_PERIHP; low-speed: ACLK_PERILP0, HCLK_PERILP0, PCLK_PERILP0, HCLK_PERILP1, PCLK_PERILP1. This is for optimal power consumption, and different bus frequencies can be set according to different needs. (See the clock diagram for details of which device is under which bus)
You can refer to (EMMC, GMAC, USB, etc. have their own ACLK).
2.2.3 GATING
There are many GATINGs in the CLOCK framework, mainly used to reduce power consumption. When some devices are turned off and CLOCK is not needed, GATING can be turned off to save power.
The GATING of the RK CLOCK framework is structured as a tree with parent-child attributes. The GATING switch has a reference counting mechanism. When CLOCK is enabled, it will traverse and enable its parent CLOCK. When the child CLOCK is turned off, the parent CLOCK will traverse all child CLOCKs, and only when all children are turned off will the parent CLOCK be turned off.
(For example: When I2S2 is used, the three GATINGs in the figure (as shown in Figure 2-2) must be enabled, but in software, only the last level of GATING needs to be enabled, and the clock structure will automatically enable its parent GATING.)
Table 2‑3 GATING Example Diagram

2.3 Clock Configuration
2.3.1 Clock Initialization Configuration
Unlike LINUX3.10, after kernel 4.4, clock initialization uses "of_clk_set_defaults" and then parses "assigned clocks" to get the CLOCK ID, then gets the CLOCK Name, parses "assigned-clock-parents" to get the parent to be set, and parses "assigned-clock-rates" to get the frequency to be set.
- Frequency
Frequency set during CLOCK TREE initialization:
arch/arm64/dts/rockchip/rk33xx.dtsi
cru: clock-controller@ff760000 {
compatible = "rockchip,rk3399-cru";
reg = <0x0 0xff760000 0x0 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
assigned-clocks =
<&cru ACLK_VOP0>, <&cru HCLK_VOP0>,
<&cru ACLK_VOP1>, <&cru HCLK_VOP1>,
<&cru ARMCLKL>, <&cru ARMCLKB>,
<&cru PLL_GPLL>, <&cru PLL_CPLL>,
<&cru PLL_NPLL>,
<&cru ACLK_PERIHP>, <&cru HCLK_PERIHP>,
<&cru PCLK_PERIHP>,
<&cru ACLK_PERILP0>, <&cru HCLK_PERILP0>,
<&cru PCLK_PERILP0>,
<&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>;
};
assigned-clock-rates =
<400000000>, <200000000>,
<400000000>, <200000000>,
<816000000>, <816000000>,
<594000000>, <800000000>,
<1000000000>,
<150000000>, <75000000>,
<37500000>,
<100000000>, <100000000>,
<50000000>,
<100000000>, <50000000>;
-
Parent
Parent set during CLOCK TREE initialization:
Note:
When configuring Parent and Rate for Assigned, they need to correspond one-to-one with Assigned-Clocks, because the setting is done by looking up and setting the CLK ID of Assigned Clocks. -
Gating
Whether CLOCK is enabled by default during CLOCK TREE initialization:
Note: For clocks that are not enabled by default and are not referenced by the device to enable, they will be turned off after CLOCK initialization is complete.
(1) Always-on CLOCK:
You need to add Critical configuration in clk-rk3xxx.c, mainly add the CLOCK Name that needs to be enabled by default in rk3399_cru_critical_clocks. Once added, the count of this CLOCK is increased by 1, and this CLOCK cannot be turned off later.
(2) When defining CLOCK, add the Flag attribute CLK_IGNORE_UNUSED. Even if this CLOCK is not used, it will not be turned off when unused CLOCKs are turned off at the end. However, the Enable Cnt seen in the CLOCK TREE is still 0, but the CLOCK is enabled.
(3) After kernel 6.1, always-on clk has changed, there are two ways
Enable all clk:
assigned-clock-parents =
<&cru VPLL>, <&cru VPLL>,
<&cru CPLL>, <&cru CPLL>,
<&cru APLLL>, <&cru APLLB>,
<&cru GPLL>, <&cru GPLL>,
<&cru GPLL>,
<&cru GPLL>, <&cru GPLL>;
static const char *const rk3399_cru_critical_clocks[] __initconst = {
"aclk_usb3_noc",
"aclk_gmac_noc",
"pclk_gmac_noc",
"pclk_center_main_noc",
"aclk_cci_noc0",
"aclk_cci_noc1",
"clk_dbg_noc",
"hclk_vcodec_noc",
"aclk_vcodec_noc",
"hclk_vdu_noc",
"aclk_vdu_noc",
};
GATE(PCLK_PMUGRF_PMU, "pclk_pmugrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED,
RK3399_PMU_CLKGATE_CON(1), 1, GFLAGS),
Specify a particular clock to be always-on, add the Flag attribute CLK_IS_CRITICAL when defining CLOCK:
2.3.2 Clock ID
In LINUX4.4 and above, all CLOCK operations refer to CLOCK ID. How to get the ID?
Find the CLOCK you need to control in clk-rk3xxx.c (you can search by Name):
Table 2‑4 CLOCKID Example Diagram

2.3.3 Main CLOCK Registration Type Functions
Common types include:
- GATE: Describes GATING, mainly including CLOCK ID, type, GATING register offset address, BIT position, etc.
- MUX: Describes SELECT, mainly including CLOCK ID, type, MUX register offset address, BIT position, etc.
- COMPOSITE: Describes CLK with MUX, DIV, GATING, mainly including CLOCK ID, type, MUX, DIV, GATING register offset address, BIT position, etc.
Table 2‑5 CLOCKTYPE Example Diagram

Table 2‑6 CLOCKPARENT Example Diagram

2.3.4 Driver Clock Configuration
- Get CLOCK pointer
- Add CLOCK reference information in DTS device node (recommended)
- DTS device node does not add CLOCK reference information

