Edit online

模块架构

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 rate clock

  • fixed parent module clock

  • multiple parent module clock

  • display module clock

  • pll clock

fixed rate clock 包含 M、RC1M、OSC32K 三个时钟,这种时钟频率固定,不能调节频率,不能打开或关闭(即底层 ops 无 enable 和 disable 函数)。

fixed parent module clock 实现只有一个父时钟源的时钟驱动,主要是各个外设模块的时钟,该类型时钟可以改变时钟频率,打开或关闭时钟,获取父时钟源参数,但不能设置或改变父时钟源。

multiple parent module clock 实现有多个父时钟源的时钟驱动,主要是各种总线时钟,该类型的时钟最为复杂,可以打开或关闭时钟,调节频率,获取或改变父时钟源。

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

pll clock 实现了 CMU 的 pll 时钟驱动。

在上述的几种分类中,每中分类都自定义了一个该类型的结构体,基于该结构体实现各种时钟操作。在 module 的结构体中,定义了模块的 gate 和 gate,以及该类型时钟的分频系数,相当于综合了 CCF 框架中的 gate 和 divider。multiple parent module 的结构体中定义了 gate,mux 以及分频系数,相当于综合了 CCF 框架中的 gate,divider 和 mux。几种类型的时钟支持的 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

时钟树框图

根据 CMU 驱动中对时钟的五种分类,对时钟树中各个时钟的归类进行了划分,如上图所示。
1. fixed rate clock
类型 时钟
fixed rate clock OSC24M
OSC32K
RC1M
2. fixed parent clock
类型 时钟
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_TWI0-3
CLK_CAN0-1
CLK_PWM
CLK_ADCIM
CLK_GPADC
CLK_RTP
CLK_TSEN
CLK_CIR
CLK_RGB
CLK_LVDS
CLK_MIPIDSI
3. multiple parent clock
类型 时钟
multi parent clock CLK_CPU
CLK_AHB0
CLK_APB0
CLK_APB1
CLK_AXI0
CLK_OUT0
CLK_OUT1
CLK_OUT2
CLK_OUT3
4. pll clock
类型 时钟
pll clock CLK_PLL_INT0
CLK_PLL_INT1
CLK_PLL_FRA0
CLK_PLL_FRA1
CLK_PLL_FRA2
5. disp clock
类型 时钟
disp clock CLK_PIX
CLK_SCLK

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 三个函数指针的填充。