Edit online

设计说明

Edit online

源码说明

内核的时钟驱动框架位于 linux-5.10/drivers/clk 目录下,CMU 的底层驱动位于/drivers/clk/artinchip/目录下。

ArtInChip 的目录结构如下图所示:

文件

说明

clk-aic.h

aic 公用头文件

clk-aic.c

CMU 各个时钟的初始化,注册文件

clk-disp.c

显示模块的时钟文件

clk-fixed-parent-mod.c

只有一个父时钟源的时钟文件

clk-multi-parent-mod.c

具有多个父时钟源的时钟文件

clk-pll.c

PLL 时钟文件

Edit online

时钟树


clock_tree

1. 时钟树
CMU 驱动将时钟树中的时钟分为五种类型,每种类型的时钟具有不同的特性和功能:
  • Fixed rate clock:具有固定的输出频率,通常用于驱动一些不需要动态调整频率的外设。时钟频率固定,不能调节频率,不能打开或关闭。固定频率时钟包括 OSC24M、RC1M 和 OSC32K。

  • Fixed parent module clock:从另一个时钟信号派生出来的时钟,其输出频率与父时钟信号的频率相同。该类型时钟可以实现只有一个父时钟源的时钟驱动,主要用于各个外设模块的时钟驱动。该类型时钟可以改变时钟频率,打开或关闭时钟,获取父时钟源参数,但不能设置或改变父时钟源。

  • Multiple parent module clock:可以从多个父时钟源中选择其中一个作为其输入,并根据需要调整输出频率。 该类型时钟可以实现有多个父时钟源的时钟驱动,主要用于各种总线时钟驱动,可以打开或关闭时钟,调节频率,获取或改变父时钟源。

  • Display module clock: 实现了几个与显示模块相关的时钟驱动,除了自身的模块时钟外,显示模块还有一个像素时钟,相应的底层寄存器的设计也不同,所以显示相关的几个时钟重新设计了底层驱动。

  • PLL clock:实现了 CMU 的 PLL 时钟驱动。PLL 是一种能够产生高频时钟信号的电路。PLL 可以将一个低频率的参考时钟信号乘以一个整数倍的频率因子,从而得到一个高频率的时钟信号。

下列表格列出了各种时钟分类对应的时钟树:
类型 时钟
Fixed rate clock OSC24M
OSC32K
RC1M
Fixed parent clock CLK_DMA
CLK_CE
CLK_USBD
CLK_USBH0-1
CLK_USB_PHY0-1
CLK_GMAC0-1
CLK_SPI0-1
CLK_SDMMC0-2
CLK_SYSCON
CLK_RTC
CLK_I2S0-1
CLK_ADDA
CLK_DE
CLK_GE
CLK_VE
CLK_WDOG
CLK_SID
CLK_GTC
CLK_GPIO
CLK_UART0-7
CLK_I2C0-3
CLK_CAN0-1
CLK_PWM
CLK_ADCIM
CLK_GPADC
CLK_RTP
CLK_TSEN
CLK_CIR
CLK_RGB
CLK_LVDS
CLK_MIPIDSI
Multi parent clock CLK_CPU
CLK_AHB0
CLK_APB0
CLK_APB1
CLK_AXI0
CLK_OUT0
CLK_OUT1
CLK_OUT2
CLK_OUT3
PLL clock CLK_PLL_INT0
CLK_PLL_INT1
CLK_PLL_FRA0
CLK_PLL_FRA1
CLK_PLL_FRA2
Disp clock CLK_PIX
CLK_SCLK
Edit online

关键流程设计

Clock 和 Reset 驱动初始化

  • Clock 驱动初始化

    通过 DECLARE 宏定义,CMU 的 clock 驱动会在__clock_of_table 段存放一个 id 类型的变量。在系统初始化内核时,调用 init 函数,在该函数中调用相应的时钟初始化函数。初始化流程如下:



  • Reset 驱动初始化

    通过 initcall 宏,将 reset 驱动存放到.initcall2.init 段中。在系统初始化内核时,调用 init 函数进行 reset controller 的初始化和注册。

Edit online

数据结构设计

CMU 模块关键结构体定义如下:
  • fixed_parent_clk_cfg
    struct fixed_parent_clk_cfg {              //fixed parent clock 的配置结构体
        u32 id;                            //fixed parent clock 的索引值,参考 3.2 节 CLK_xxx
        u16 type;
        u8 fact_mult;
        u8 fact_div;
        const char *name;                  //fixed parent clock 的名字
        const char * const *parent_names;    //父时钟的名字
        int num_parents;                   //父时钟个数
        u32 offset_reg;                     //时钟在 CMU 中的偏移地址
        s8 bus_gate_bit;                    //总线使能位偏移
        s8 mod_gate_bit;                   //模块使能位偏移
        u8 div_bit;                         //分频系数偏移
        u8 div_width;                       //分频系数所占位宽
        struct clk_hw *(*func)(void __iomem *base, const struct fixed_parent_clk_cfg *cfg); //指向初始化和注册 parent 时钟的函数指针
  • multi_parent_clk_cfg
    struct multi_parent_clk_cfg {                 //multi parent clock 的配置结构体
        u32 id;                               //multi parent clock 的索引值,参考 3.3 节 CLK_xxx
        const char *name;
        const char * const *parent_names;
        int num_parents;
        u32 offset_reg;
        s32 gate_bit;
        u8 mux_bit;                          //父时钟源选择位的 bit 偏移
        u8 mux_width;                        //父时钟源选择位所占位宽
        u8 div0_bit;                           //分频系数偏移
        u8 div0_width;                         //分频系数所占位宽
        struct clk_hw *(*func)(void __iomem *base, const struct multi_parent_clk_cfg *cfg); //指向初始化和注册 parent 时钟的函数指针
    };
  • pll_clk_cfg
    struct pll_clk_cfg {                          //pll 时钟的配置结构体
        u32 id;                               //pll 时钟的索引值,参考 3.4 节 CLK_xxx
        enum aic_pll_type type;                 //pll 时钟的类型,是整数分频还是小数分频
        const char *name;
        const char * const *parent_names;
        int num_parents;
        u32 offset_int;                         //整数分频寄存器的偏移
        u32 offset_fra;                         //小数分频寄存器的偏移
        u32 offset_sdm;                       //展频寄存器的偏移
        struct clk_hw *(*func)(void __iomem *base, const struct pll_clk_cfg *cfg); //指向初始化和注册 pll 时钟的函数指针
    };
  • disp_clk_cfg
    struct disp_clk_cfg {                          //显示模块时钟配置的结构体
        u32 id;                                 //显示模块时钟的索引值,参考 3.5 节 CLK_xxx
        const char *name;
        const char * const *parent_names;
        int num_parents;
        u32 offset_reg;                          //显示模块时钟使能寄存器
        s8 bus_gate_bit;                         //显示模块总线使能位偏移
        s8 mod_gate_bit;                        //显示模块模块使能位偏移
        u32 offset_div_reg;                      //显示模块分频寄存器偏移
        u8 divn_bit;                            //分频系数 N 偏移
        u8 divn_width;                         //分频系数 N 所占位宽
        u8 divm_bit;                           //分频系数 M 偏移
        u8 divm_width;                         //分频系数 M 所占位宽
        u8 flag_bit;                             //分频系数 M 标志位
        struct clk_hw *(*func)(void __iomem *base, const struct disp_clk_cfg *cfg); //指向初始化和注册显示模块时钟的函数指针
    };
Edit online

接口设计

1. aic_clk_hw_fixed_parent_module

函数原型

struct clk_hw *aic_clk_hw_fixed_parent(void __iomem *base, const struct fixed_parent_clk_cfg *cfg)

功能说明

初始化 clock,并对时钟进行注册。

参数定义

  • base:CMU 寄存器的基地址。
  • cfg:指向配置参数的指针。

返回值

返回 struct clk_hw*类型的指针。

注意事项

-

2. aic_clk_hw_multi_parent_module

函数原型

struct clk_hw *aic_clk_hw_multi_parent(void __iomem *base, const struct multi_parent_clk_cfg *cfg)

功能说明

初始化 clock,并对时钟进行注册。

参数定义

  • base:CMU 寄存器的基地址。
  • cfg:指向配置参数的指针。

返回值

返回 struct clk_hw*类型的指针。

注意事项

-

3. aic_clk_hw_pll

函数原型

struct clk_hw *aic_clk_hw_pll(void __iomem *base, const struct pll_clk_cfg *cfg)

功能说明

初始化 clock,并对时钟进行注册。

参数定义

  • base:CMU 寄存器的基地址。
  • cfg:指向配置参数的指针。

返回值

返回 struct clk_hw*类型的指针。

注意事项

-

4. aic_clk_hw_disp

函数原型

struct clk_hw *aic_clk_hw_disp(void __iomem *base, const struct disp_clk_cfg *cfg)

功能说明

初始化 clock,并对时钟进行注册。

参数定义

  • base:CMU 寄存器的基地址。
  • cfg:指向配置参数的指针。

返回值

返回 struct clk_hw*类型的指针。

注意事项

-