了解、熟悉 驱动设备树中时钟属性
基本目标:不需要掌握设备树中怎么编写,只需要如何配置 照着更改,因为时钟相关属性不多,学会修改属性值即可。
文章目录
参考资料
Linux 内核设备树时钟绑定
Linux kernel中的CPU时钟管理
linux设备树-时钟
Common Clock Framework系统结构
一、 clock 相关属性
时钟(Clock)用于描述硬件设备和系统中的时钟源以及时钟相关的配置和连接关系。时钟在计算机系统中起着至关重要的作用,用于同步和定时各种硬件设备的操作。时钟可以分为两个主要角色:时钟生产者(clock provider)和时钟消费者(clock consumer)。
时钟生产者(clock provider)
clock-cells
- 作用:定义时钟控制器(Clock Provider)的输出时钟需要几个参数(通常用于区分多个时钟输出)
- 常见值:
#clock-cells = <0>:时钟控制器只有一个输出,引用时不需要参数(如 <&clk_fixed>)。
#clock-cells = <1>:时钟控制器有多个输出,引用时需要传递一个参数(通常是索引,如 <&clkctrl 0>)。
- 示例如下;
示例 1:单个时钟
osc24m: osc24m {
compatible = "clock";
clock-frequency = <24000000>;
clock-output-names = "osc24m";
#clock-cells = <O>;
};
示例 2:多个时钟
clock: clock {
#clock-cells = <1>;
clock-output-names = "clock1", "clock2";
};
如上 #clock-cells 配置0 和 1 表示,一个或2个时钟 。
clock-frequency
表示时钟频率:
clock-frequency 属性是设备树中用于指定时钟频率的属性。它用于描述时钟节点所提供的时钟信号的频率,使用 Hertz (Hz) 作为单位。对于时钟生产者节点,clock-frequency 属性表示该节点生成的时钟信号的频率。它用于描述时钟控制器、晶振、PLL 等产生时钟信号的硬
件或软件模块的输出频率,例如指定时钟频率为 24000000 的具体示例如下所示
-
作用:指定固定频率时钟的硬件默认频率(单位:Hz)。
-
适用场景:通常用于晶振、固定频率时钟源
osc24m: osc24m {
compatible = "clock";
clock-frequency = <24000000>; // 24MHz
clock-output-names = "osc24m";
#clock-cells = <O>;
};
assigned-clocks 和 assigned-clock-rates
-
assigned-clocks 属性用于标识时钟消费者节点所使用的时钟源。它是一个整数数组,每个元素对应一个时钟编号。时钟编号是指时钟生产者节点(如时钟控制器)所提供的时钟源的编号。通过在时钟消费者节点中使用 assigned-clocks 属性,可以指定该节点所需的时钟源。
-
assigned-clock-rates 属性用于指定每个时钟源的时钟频率。它是一个整数数组,每个元素对应一个时钟源的频率。时钟频率以 Hz (赫兹) 为单位表示。assigned-clock-rates 属性的元素数量和顺序应与 assigned-clocks 属性中的时钟编号相对应。
关于 assigned-clocks 和 assigned-clock-rates 属性的一个具体示例如下所示
简单说:
- 作用:动态配置时钟的父源或频率(由时钟框架在启动时处理)。
assigned-clocks:列出需要配置的时钟(引用时钟控制器输出)。
assigned-clock-rates:为每个时钟指定目标频率(单位:Hz)
cru: clock-controller@fdd20000 {
#clock-cells = <1>;
assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru ACLK_RKVDEC_PRE>;
assigned-clock-rates = <32768>, <300000000>;
};
分析:
上面的assigned-clocks 后面的值可以这么理解:
- #clock-cells值为 <1> 本身表示了2个时钟源
- <&pmucru CLK_RTC_32K> 第一个表示模块,第二个表示时钟类型名称。
assigned-clock-rates 不就是频率嘛
clock-indices
clock-indices 属性用于指定时钟消费者节点所使用的时钟源的索引值。它是一个整数数组,每个元素对应一个时钟源的索引。时钟索引是指时钟生产者节点(如时钟控制器)所提供的时钟源的编号。通过在时钟消费者节点中使用 clock-indices 属性,可以明确指定该节点所需的时钟源,并按照特定的顺序进行匹配。一个 clock-indices 示例如下所示:
作用: 显式定义时钟控制器输出的时钟索引号(可选属性)。
适用场景:
- 时钟控制器的输出索引不连续时。
- 需要明确文档化时钟索引时
scpi_dvfs: clocks-0 {
#clock-cells = <1>;
clock-indices = <0>, <1>, <2>;
clock-output-names = "atlclk", "aplclk", "gpuclk";
};
scpi_clk: clocks-1 {
#clock-cells = <1>;
clock-indices = <3>;
clock-output-names = "pxlclk";
};
在第一个节点中"atlclk", “aplclk”, "gpuclk"三个时钟源的索引就分别被设置为了 0、1、2,在第二个节点中"pxlclk"时钟源的索引值被设置为了 3.
assigned-clock-parents
assigned-clock-parents 属性用于指定时钟消费者节点所使用的时钟源的父时钟源。它是一个时钟源引用的数组,每个元素对应一个父时钟源的引用。在时钟的层次结构中,某些时钟源可能是其他时钟源的父时钟源,即它们提供时钟信号给其他时钟源作为输入。通过在时钟消费者节点中使用 assigned-clock-parents 属性,可以明确指定该节点所需的父时钟源,并按照特定的顺序进行匹配。一个实际的 assigned-clock-parents 属性例子如下所示
- 作用:动态配置时钟的父时钟源(选择多路复用器的输入)。
- 与 assigned-clocks 配合使用
uart0 {
assigned-clocks = <&clkctrl CLK_UART0>; // 引用UART时钟
assigned-clock-parents = <&clkctrl CLK_PLL>; // 设置父时钟为PLL
};
clock: clock {
assigned-clocks = <&clkcon 0>, <&pll 2>;
assigned-clock-parents = <&pll 2>;
assigned-clock-rates = <115200>, <9600>;
};
上述设备树表示了一个名为 clock 的时钟消费者节点,具有以下属性:
- assigned-clocks 属性指定了该节点使用的时钟源,引用了两个时钟源节点:clkcon 0 和 pll 2。
- assigned-clock-parents 属性指定了这些时钟源的父时钟源,引用了 pll 2 时钟源节点。
- assigned-clock-rates 属性指定了每个时钟源的时钟频率,分别是 115200 和 9600。
时钟消费者(clock consumer)
clocks
该属性用于指定时钟消费者节点所需的时钟源。它是一个整数数组,每个元
素是一个时钟编号,表示时钟消费者需要的一个时钟源。
clock-names
可选属性,用于指定时钟消费者节点所需时钟源的名称。它是一个字符串数组,与 clocks 数组一一对应,用于提供时钟源的描述性名称
一个消费时钟 示例如下:
clock: clock {
clocks = <&cru CLK_VOP>;
clock-names = "clk_vop";
};
- clocks 属性指定了该节点使用的时钟源,引用了 cru 节点中的 CLK_VOP 时钟源。
- clock-names 属性指定了时钟源的名称,这里是 “clk_vop”。
属性分类总结
属性 | 用途 | 常见位置 |
---|---|---|
#clock-cells | 定义时钟控制器的输出参数数量 | 时钟控制器节点 |
clock-frequency | 固定时钟源的频率 | 固定时钟节点(如晶振) |
assigned-clocks | 需动态配置的时钟列表 | 时钟消费者节点 |
assigned-clock-rates | 动态配置的目标频率 | 时钟消费者节点 |
clock-indices | 显式声明时钟控制器的输出索引 | 时钟控制器节点 |
assigned-clock-parents | 动态配置时钟的父源 | 时钟消费者节点 |
clocks | 外设引用的时钟列表 | 时钟消费者节点 |
clock-names | 为外设引用的时钟命名 | 时钟消费者节点 |
典型示例
时钟控制器定义:
clkctrl: clock-controller@40000000 {
compatible = "vendor,clk-controller";
reg = <0x40000000 0x1000>;
#clock-cells = <1>; // 输出时钟需要1个参数
clock-indices = <0>, <1>, <2>; // 支持的时钟索引
clock-output-names = "clk_core", "clk_bus", "clk_uart";
};
外设引用时钟:
uart0: serial@40010000 {
compatible = "vendor,uart";
reg = <0x40010000 0x1000>;
clocks = <&clkctrl 2>; // 引用第三个时钟(索引2)
clock-names = "uart_clk";
assigned-clocks = <&clkctrl 2>; // 动态配置该时钟
assigned-clock-parents = <&osc24m>; // 父时钟设为24MHz晶振
assigned-clock-rates = <115200>; // 配置波特率对应频率
};
常见问题
-
何时需要 assigned-* 属性?
当时钟需在启动时由框架自动配置(如切换PLL源、设置频率时)。 -
clock-names 是否必须?
非必须,但建议为时钟命名,提高驱动代码可读性。 -
clock-indices 的作用?
主要用于文档化和非连续索引的场景,多数情况下可省略。
总结
- 了解、熟悉 设备树中时钟模块的配置
- 对于实际中设备树配置中的时钟模块需要看到能够读懂并根据实际需求进行配置。
- 理解这些属性后,可以更灵活地描述硬件时钟关系!