Edit online

设计说明

25 Nov 2024
Read time: 3 minute(s)

源码说明

内核的时钟驱动框架位于 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 时钟文件

Clock

按照 CCF 框架,时钟分为下列类别:
  • fixed rate clock

  • gate clock

  • divider clock

  • mux clock

  • fixed clock

  • composite clock

时钟树中的每一个 divider、gate、mux 都需要定义一个 hw 结构体。CMU 模块中有大量 gate 和 divider,因此为了代码的简洁性和易用性,CMU 的驱动并未严格按照 CCF 框架编写。CMU 驱动模块将时钟分为多种类型,且每种分类都有一个对应的自定义结构体,用来实现各种时钟操作:
注: 关于时钟分类和时钟树的描述,可查看下列时钟树章节时钟树
  • 在 fixed parent module 的结构体中,定义了模块的 bus_gate 和 module_gate,以及该类型时钟的分频系数,相当于综合了 CCF 框架中的 gate 和 divider。

  • 在 multiple parent module 的结构体中定义了 gate,mux 以及分频系数,相当于综合了 CCF 框架中的 gate,divider 和 mux。

1. 各时钟类型支持的 API 接口
类型 fixed rate clock fixed parent clock multi parent clock disp clock pll clock
clk_prepare
clk_prepare_enable
clk_unprepare
clk_disable_unprepare
clk_set_rate -
clk_get_rate
clk_round_rate -
clk_set_parent - - - -
clk_get_parent - - - -
recalc_rate

Reset

CMU 模块的 reset 驱动实现基于内核提供的 framework。其实现过程是创建并填充内核提供的 controller 设备结构体(struct reset_controller_dev),并调用相应的接口:
  • reset_controller_register

  • reset_controller_unregister

注册或注销。reset controller 的结构体如下:
struct reset_controller_dev {
        const struct reset_control_ops *ops;
        struct module *owner;
        struct list_head list;
        struct list_head reset_control_head;
        struct device *dev;
        struct device_node *of_node;
        int of_reset_n_cells;
        int (*of_xlate)(struct reset_controller_dev *rcdev,
                    const struct of_phandle_args *reset_spec);
        unsigned int nr_resets;
};

驱动实现过程主要是对 ops 结构体中的函数指针进行填充,基本上是 reset 驱动的所有工作量。在 CMU 模块的 reset 驱动中,实现了对 assert 和 deassert 及 status 三个函数指针的填充。

时钟树


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