Linux启动内核必要节点分析及时钟系统简述
文章目录
前言
本文主要对设备树和时钟系统进行说明。
-
设备树:主要由 cpus node 和 soc node 两部分组成。
cpus node 对所使用的 cpu信息进行描述,架构、支持频率、时钟等。
soc node 对板载的信息进行描述,晶振、内存、外设等等。
-
时钟系统
参考“IMX6ULL参考手册” 以IMX6ULL为例从时钟生成、时钟控制、时钟树到时钟选择/配置几方面进行描述。
1. 设备树
本次整理的设备树是基于精简后的IMX6ULL的设备树文件,只包含内核启动的必要元素。(设备树的组成、基本语法、匹配内核及搭建,查看 “ 设备树的组成及搭建.pdf ” )
1.1. cpus node
因为 imx6ull 是单核的,所以只有一个 cpu0 子节点,cpu0节点信息描述如下所示:
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "arm,cortex-a7"; /* 架构信息 */
device_type = "cpu";
reg = <0>;
clock-latency = <61036>; /* 时钟延时:two CLK32 periods */
/* 时钟延时(lantency)时钟从时钟源(例如晶振、PLL 或分频器输出端)出发到达触发器端口的延迟时
间,称为时钟延时。时钟延时包括时钟源延迟(source latency)和时钟网络延迟(network latency) */
operating-points = < /* 支持频率 */
/* kHz uV */
996000 1275000
792000 1225000
528000 1175000
396000 1025000
198000 950000
>;
fsl,soc-operating-points = <
/* KHz uV */
996000 1175000
792000 1175000
528000 1175000
396000 1175000
198000 1175000
>;
fsl,low-power-run;
clocks = <&clks IMX6UL_CLK_ARM>, /* 时钟 */
<&clks IMX6UL_CLK_PLL2_BUS>,
<&clks IMX6UL_CLK_PLL2_PFD2>,
<&clks IMX6UL_CA7_SECONDARY_SEL>,
<&clks IMX6UL_CLK_STEP>,
<&clks IMX6UL_CLK_PLL1_SW>,
<&clks IMX6UL_CLK_PLL1_SYS>,
<&clks IMX6UL_PLL1_BYPASS>,
<&clks IMX6UL_CLK_PLL1>,
<&clks IMX6UL_PLL1_BYPASS_SRC>,
<&clks IMX6UL_CLK_OSC>;
clock-names = "arm", "pll2_bus", "pll2_pfd2_396m", "secondary_sel", "step",
"pll1_sw", "pll1_sys", "pll1_bypass", "pll1", "pll1_bypass_src", "osc";
};
};
1.2. soc node
1.2.1 时钟源 - clocks
时钟源是固定参数,其他时钟都是经过时钟源进行分频/倍频得到的。设备树中时钟源的描述,如下:
clocks {
#address-cells = <1>;
#size-cells = <0>;
ckil: clock@0 { /* 32.768KHZ晶振,RTC时钟源 */
compatible = "fixed-clock";
reg = <0>;
#clock-cells = <0>;
clock-frequency = <32768>;
clock-output-names = "ckil";
};
osc: clock@1 { /* 24MHZ的晶振 */
compatible = "fixed-clock";
reg = <1>;
#clock-cells = <0>;
clock-frequency = <24000000>;
clock-output-names = "osc";
};
};
1.2.2. 串口 - uart
用于串口信息打印,因为在 chosen 中指定 uart1 为标准输出串口,所以只保留了 uart1。
chosen {
stdout-path = &uart1;
};
uart1 设备树节点信息
uart1: serial@02020000 {
compatible = "fsl,imx6ul-uart", "fsl,imx6q-uart", "fsl,imx21-uart";
reg = <0x02020000 0x4000>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_UART1_IPG>,
<&clks IMX6UL_CLK_UART1_SERIAL>;
clock-names = "ipg", "per";
status = "disabled";
};
1.2.3. anatop调节器
Anatop调节器驱动器提供低电平控制电源调节器,并选择电压电平。该设备驱动程序利用调节器核心驱动程序访问Anatop硬件控制寄存器,仅在i.MX 6和i.MX 7上支持。
下面是imx6ull设备树中的内容:
anatop: anatop@020c8000 {
compatible = "fsl,imx6ul-anatop", "fsl,imx6q-anatop",
"syscon", "simple-bus";
reg = <0x020c8000 0x1000>;
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
reg_arm: regulator-vddcore@140 { /* cpu 电压调节器 */
compatible = "fsl,anatop-regulator";
regulator-name = "cpu";
regulator-min-microvolt = <725000>; /* 最小电压(微伏) */
regulator-max-microvolt = <1450000>;
regulator-always-on;
anatop-reg-offset = <0x140>; /* Anatop MFD寄存器偏移量 */
anatop-vol-bit-shift = <0>; /* 寄存器的位移位 */
anatop-vol-bit-width = <5>; /* 寄存器中使用的位数 */
anatop-delay-reg-offset = <0x170>; /* Anatop MF单步时间寄存器偏移量 */
anatop-delay-bit-shift = <24>; /* 单步时间寄存器位偏移 */
anatop-delay-bit-width = <2>; /* 单步时间寄存器使用位数 */
anatop-min-bit-val = <1>; /* 此寄存器最小值 */
anatop-min-voltage = <725000>; /* 最小电压 */
anatop-max-voltage = <1450000>; /* 最大电压 */
};
reg_soc: regulator-vddsoc@140 { /* soc 电压调节器 */
compatible = "fsl,anatop-regulator";
regulator-name = "vddsoc";
regulator-min-microvolt = <725000>;
regulator-max-microvolt = <1450000>;
regulator-always-on;
anatop-reg-offset = <0x140>;
anatop-vol-bit-shift = <18>;
anatop-vol-bit-width = <5>;
anatop-delay-reg-offset = <0x170>;
anatop-delay-bit-shift = <28>;
anatop-delay-bit-width = <2>;
anatop-min-bit-val = <1>;
anatop-min-voltage = <725000>;
anatop-max-voltage = <1450000>;
};
};
1.2.3.1 anatop 调节器说明
linux-imx6/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
Anatop Voltage regulators
Required properties:
- compatible: Must be "fsl,anatop-regulator"
- anatop-reg-offset: Anatop MFD register offset
- anatop-vol-bit-shift: Bit shift for the register
- anatop-vol-bit-width: Number of bits used in the register
- anatop-min-bit-val: Minimum value of this register
- anatop-min-voltage: Minimum voltage of this regulator
- anatop-max-voltage: Maximum voltage of this regulator
Optional properties:
- anatop-delay-reg-offset: Anatop MFD step time register offset
- anatop-delay-bit-shift: Bit shift for the step time register
- anatop-delay-bit-width: Number of bits used in the step time register
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
Example:
regulator-vddpu {
compatible = "fsl,anatop-regulator";
regulator-name = "vddpu";
regulator-min-microvolt = <725000>;
regulator-max-microvolt = <1300000>;
regulator-always-on;
anatop-reg-offset = <0x140>;
anatop-vol-bit-shift = <9>;
anatop-vol-bit-width = <5>;
anatop-delay-reg-offset = <0x170>;
anatop-delay-bit-shift = <24>;
anatop-delay-bit-width = <2>;
anatop-min-bit-val = <1>;
anatop-min-voltage = <725000>;
anatop-max-voltage = <1300000>;
};
###1.2.4. USDHC—Ultra-Secure Digital Host Controller
超安全数字主机控制器,MMC/SD/eSD/SDXC/eMMC 可以连接到任何USDHC块,并且可以通过将 4KB 的数据从MMC/SDESD/eMMC设备复制到内部RAM来启动。
下面是关于usdhc1节点,.dtsi 中 usdhc1: usdhc@02190000 节点内容如下:
usdhc1: usdhc@02190000 {
compatible = "fsl,imx6ull-usdhc", "fsl,imx6sx-usdhc"; /* 匹配驱动 */
reg = <0x02190000 0x4000>; /* 寄存器地址 */
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>; /* 中断 */
clocks = <&clks IMX6UL_CLK_USDHC1>, /* 表示具有三个时钟输入设备;分别为ipg、ahb、per*/
<&clks IMX6UL_CLK_USDHC1>,
<&clks IMX6UL_CLK_USDHC1>;
clock-names = "ipg", "ahb", "per";
/* 提供两路时钟 */
assigned-clocks = <&clks IMX6UL_CLK_USDHC1_SEL>, <&clks IMX6UL_CLK_USDHC1>;
assigned-clock-parents = <&clks IMX6UL_CLK_PLL2_PFD2>; /* 父时钟 */
assigned-clock-rates = <0>, <132000000>; /* 两路时钟频率分别为 0MHz 和 132MHz */
bus-width = <4>; /* 总线位宽 */
fsl,tuning-step= <2>; /* 调优过程中增加的延迟单元 */
status = "disabled";
};
.dts 中 &usdhc1 节点内容如下:
&usdhc1 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc1>; // pinctrl子系统管脚配置
pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; //gpio1_19,低电平有效 检测是否在
keep-power-in-suspend; //表示待机是不掉电
enable-sdio-wakeup; // 支持1-bit/4-bit SD和SDIO模式,1-bti/4-bit SD/8-bit MMC模式
vmmc-supply = <®_sd1_vmmc>; //指向regulator设备树节点
status = "okay";
};
regulator 节点用来供电,内容如下:
reg_sd1_vmmc: regulator@1 {
compatible = "regulator-fixed";
regulator-name = "VSD_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
1.2.5. 时钟控制模块节点 - CCM
该节点匹配到时钟配置文件(clk_imx6ul.c),关于CCM 时钟控制模块在时钟系统中说明。
clks: ccm@020c4000 {
compatible = "fsl,imx6ul-ccm"; /* 匹配驱动(clk_imx6ul.c) */
reg = <0x020c4000 0x4000>; /* CCM Memory Map/Register 地址范围0x020c4000-0x020c8000 */
interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
#clock-cells = <1>;
clocks = <&ckil>, <&osc>;
clock-names = "ckil", "osc";
};
1.3. pinctrl 子系统和 gpio 子系统
###1.3.1. pinctrl 子系统
pinctrl 子系统用于管理芯片的引脚。芯片上拥有众多的片上外设,大多数外设需要通过芯片的引脚与外部器件相连实现相对应的控制,例如 I2C、SPI、LCD、USDHC 等等。而芯片的引脚数量是有限的,为了提高硬件设计的灵活性,一个芯片引脚往往可以作为多个片上外设的功能引脚。
pinctrl 子系统时由芯片厂商实现,用于帮助管理芯片引脚并自动完成引脚的初始化
如下是 imx6ull.dtsi 上的 iomuxc 节点:
iomuxc: iomuxc@020e0000 {
compatible = "fsl,imx6ul-iomuxc"; /* 匹配驱动 */
reg = <0x020e0000 0x4000>; /* 引脚配置寄存器的基地址 */
};
.dtsi 中的 iomuxc 节点主要是当前芯片的通用配置,pinctrl 使用者具体的配置信息在 .dts 文件中描述,如下所示:
&iomuxc {
pinctrl-names = "default";
/* 默认状态下,将使用pinctrl_hog_1这个设备点来设置GPIO状态 */
pinctrl-0 = <&pinctrl_hog_1>;
imx6ul-evk {
pinctrl_hog_1: hoggrp-1 {
fsl,pins = <
/* 复用GPIO1_IO9,通过读取其高低电平判断SD卡有没有插入 */
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
/* SD1 VSELECT 用来选择使用3.3v还是1.8v */
MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059
MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */
>;
};
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
>;
};
pinctrl_usdhc1: usdhc1grp {
fsl,pins = <
MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059
MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10071
MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059
MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059
MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059
MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059
>;
};
pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
fsl,pins = <
MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9
MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9
MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
>;
};
pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
fsl,pins = <
MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9
MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9
MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
>;
};
};
};
###1.3.2. gpio 子系统
在没有使用GPIO子系统之前,如过想点亮一个LED,首先要得到led相关的配置寄存器,再手动地读、改、写这些配置寄存器实现控制LED地目的。有了GPIO子系统后这部分工作由GPIO子系统完成。只需要调用GPIO子系统提供地API函数即可完成GPIO地控制动作。
gpio1节点描述如下所示:
gpio1: gpio@0209c000 {
compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio"; /* 匹配驱动 */
reg = <0x0209c000 0x4000>; /* GPIO寄存器基地址 */
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>, /* 中断 */
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller; /* 表示gpio1是个GPIO控制器 */
#gpio-cells = <2>;
interrupt-controller; /* 表示gpio1是个中断控制器 */
#interrupt-cells = <2>;
};
SD卡使用到GPIO1_IO9
reg_sd1_vmmc: regulator@1 {
compatible = "regulator-fixed";
regulator-name = "VSD_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; /* GPIO1_IO9 高电平有效 */
enable-active-high;
};
##1.4. 中断子系统
// 顶层GIC控制器
intc: interrupt-controller@00a01000 {
compatible = "arm,cortex-a7-gic";
/* #interrupt-cells = <3>; 说明子中断调用需要3个cell说明该中断
* 第一个cell代表中断类型,SGI 软件中断、PPI 私有外设中断、SPI 共享外设中断
* 第二个cell表示中断号
* 第三个cell表示触发类型*/
#interrupt-cells = <3>;
interrupt-controller; /* 中断控制器 */
reg = <0x00a01000 0x1000>,
<0x00a02000 0x100>;
};
从imx6ull中摘录 gpio1 的关联中断,如下:
// gpio中断控制器
gpio1: gpio@0209c000 {
compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
reg = <0x0209c000 0x4000>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller; /* gpio 中断控制器 */
/* #gpio-cells = <2>; 说明子中断调用需要2个cell说明该中断
* 第一个cell代表中断号
* 第二个cell的 bit[3:0] 用来表示触发类型,
* 1:上升沿触发,2:下降沿触发,4:高电平触发,8:低电平触发 */
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
gpio1节点中没有标注其父节点,这是需要看gpio1父节点的中断父节点(继承关系),gpio1父节点为soc节点:
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
interrupt-parent = <&gpc>;
ranges;
}
所以 gpio1 节点的中断父节点为 gpc 中断控制器。
注:只需要1个 cell 说明中断时,cell 表示中断号。
1.5. 通用定时器 - GPT
cortex-A7 拥有2个EPIT定时器和2个GPT定时器。
imx6ull使用的是 GPT 定时器(具体说明见 “ **IMX6ULL参考手册 **” 的 “ Chapter 30 General Purpose Timer (GPT) ”章节)
- GPT 定时器简介:
- GPT定时器时32位向上寄存器。
- GPT定时器有两路输入捕获和三路输出比较。
- GPT定时器有一个12位分频器。
- GPT时钟源可以选择。
- GPT定时器有两种工作模式:Restart和Free-Run模式(通过控制寄存器GPT_CR的bit9 FRR设置)。\
- Restart模式:此模式下,当计数值和比较寄存器中的值相等的时候,计数值清零,重新开始向上计数(只有比较通道1才有此模式,比较通道2,3没有)。
- Free-Run模式:此模式下,当比较事件发生后并不会复位寄存器,而是继续计数,直到计到0xFFFFFFFF,然后重新回到0x00000000。
设备树中 gpt1: gpt@02098000 节点内容如下所示:
/* GPT(General Purpose Timer)通用定时器 */
gpt1: gpt@02098000 {
compatible = "fsl,imx6ul-gpt", "fsl,imx31-gpt";
reg = <0x02098000 0x4000>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; /* 中断 */
clocks = <&clks IMX6UL_CLK_GPT1_BUS>, /* 输入时钟 */
<&clks IMX6UL_CLK_GPT_3M>;
clock-names = "ipg", "osc_per";
};
-------------- 设备树中 OCOTP 没查到较官方的说明 -------------------
1.6. OCOTP
OCOTP_CTRL 详细信息见 “IMX6ULL参考手册” 的 “Chapter 37 On-Chip OTP Controller (OCOTP_CTRL) ”章节
OCOTP_CTRL(片上 OTP 控制器;OCOTP 包含 eFUse)
OTP 分为 eFuse OTP NVM 和 Anti-Fuse OTP NVM。
eFuse(electric-fuse,电子保险丝)是一次性可编程存储器,在芯片出厂之前会被写入信息,在一个芯片中,eFuse的容量通常很小。
Fuse是i.Mxxx芯片中一块特殊存储区域,用于存放全部芯片配置信息,其中一部分配置信息和Boot相关。
1.6.1 启动关联
内核的启动从片上的boot rom开始执行,SBMR - 启动模式寄存器。
boot rom根据 BOOT_MODE[1:0] 的值及 fuse 或 GPIO 对应状态确定启动设备。
SRC_SBMR2 寄存器的 BT_FUSE_SEL 位与 BOOT_MODE[1:0] 共同决定了启动设置是否由GPIO引脚控制。
00 ------- Boot From Fuses(根据 efuse 的值确定启动流程)
01 ------- Serial Downloader(uart/USB)
10 ------- Internal Boot模式(Serial NOR/NAND、SD/EMMC………)
11 ------- 预留
BOOT_MODE[1:0] = 10,BT_FUSE_SEL = 0时,SRC_SBMR寄存器的值将被GPIO覆盖;如果BT_FUSE_SEL = 1
时,SRC_SBMR寄存器的特殊位将由eFUSE设置。
BOOT_MODE[1:0] = 00,BT_FUSE_SEL = 0时,启动配置熔丝没有被编程,自动跳转到serial downloader;BT_FUSE_SEL = 1时,启动配置eFUSE已经编程,执行常规启动流程。
以下是设备树中对 ocotp 节点的描述:
ocotp: ocotp-ctrl@021bc000 {
compatible = "fsl,imx6ull-ocotp", "syscon";
reg = <0x021bc000 0x4000>;
clocks = <&clks IMX6UL_CLK_OCOTP>;
};
2. 时钟系统
2.1. 时钟控制模块 - CCM
i.MX6U 的时钟系统由时钟控制模块(CCM)进行控制,其主要功能如下:
- 使用PLL锁相环电路将参考时钟倍频,得到频率更高的时钟。
为芯片内核和外设提供可选的时钟源。i.MX6U 共有 7 个 PLL 锁相环电路,分别为:
ARM PLL(PLL 1)、System PLL(PLL 2)、USB1 PLL(PLL 3)、Audio PLL(PLL 4)、Video PLL(PLL5)、ENET PLL(PLL 6)、USB2 PLL(PLL 7)。 - 提供PLL控制寄存器、时钟选择寄存器、时钟分频寄存器。
- 控制低功耗模块。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s3tPmBzX-1685697696372)(photo/CCM.png)]
- **CCM_CLK_IGNITION **
管理从外部晶振时钟到稳定的根时钟输出的整个过程。GPC 是 General Power Controller 的缩写,即总电源管理模块,它不属于CCM。但是系统最高时钟频率受系统电压影响,CCM又可以控制总电源管理模块(GPC)进入待机或低功耗状态。
- CCM_ANALOG - PLL时钟产生
CCM_ANALOG 为 CCM 的模拟部分,作用是将频率较低的参考时钟(例如24MHz的XTALOSC时钟)使用PLL锁相环电路倍频到更高的时钟。 CCM_CLK_SWITCHER模块接收来自CCM_ANALOG模块的锁相环时钟输输出,以及锁相环的旁路时钟, 并为CCM_CLK_ROOT_GEN子模块生成切换时钟输出(pll1_sw_clk)。i.MX 6U共有7个PLL锁相环电路,可以独立配置。 其中PLL2与PLL3结合PFD能够输出多个频率可调的时钟。
- CCM_CLK_ROOT_GEN - 根时钟生成
CCM_CLK_ROOT_GEN接收来自CCM_CLK_SWITCHER模块的PLL或PFD时钟,经过时钟的选择、分频等操作之后产生并输出根时钟。根时钟将会作内核或外设的时钟源。
- CCM_HND_SK - 时钟同步
当更改某些时钟的时钟源时需要进行时钟的同步 CCM_HND_SK 模块用于管理时钟握手,即时钟的同步。
- CCM_LPM - 低功耗管理与时钟启用模块
CCM_LPM用于管理低功耗模式,管理时钟的开启与关闭。CCM_CLK_LOGIC,根据来自CCM_LPM模块和CCM_IP的信号产生时钟启用或关闭信号。
- LPCG - 低功耗时钟门控模块
低功耗时钟门控模块(LPCG)根据CCM_CLK_LOGIC模块输出信号控制时钟输出。时钟越多、频率越高功耗也就越高。关闭没有使用的时钟或降低时钟频率能够有效的降低功耗。
2.2. 时钟生成
2.2.1. 时钟源(晶振)
- 高频振荡器(典型频率为24 MHz)
- 低频实时时钟振荡器(典型频率为32.768 KHz)组成。
2.2.2. PLL
时钟源分为了 7 组 PLL,且 PLL2 和 PLL3 各分了4组 PFD。
-
**PLL1(ARM PLL) **供 ARM 内核使用的, ARM 内核时钟就是由此 PLL生成的,最高可倍频1.3GHz。
-
**PLL2(System_PLL or 528_PLL)**固定的 22 倍频。此外还有 4 路 PFD,分别为 PLL2_PFD0~PLL2_PFD3,这 4 路 PFD 和 528_PLL共同作为其它很多外设的根时钟源。
-
**PLL3(USB1_PLL)**固定的 22 倍频。此外还有 4 路 PFD,分别为:PLL3_PFD0~PLL3_PFD3,这 4 路 PFD 和 480_PLL共同作为其它很多外设的根时钟源。
-
PLL4(Audio PLL)用于音频相关的外设,此路 PLL的倍频可以调整,范围650MHz~1300MHz,最终输出的时候也可以进行分频,可选 1/2/4 分频。
-
**PLL5(Video PLL)**用于显示相关的外设,比如LCD,此路 PLL 的倍频可以调整,范围650MHz~1300MHz,最终输出的时候还可以进行分频, 可选 1/2/4/8/16 分频。
-
PLL6(ENET_PLL)用于网络所需时钟,固定为 20+5/6 倍频,在此 PLL 的基础上生成 25/50/100/125MHz的网络时钟。
-
**PLL7(USB2_PLL)**USB2PHY使用,固定20倍频,480MHz。
2.3. CCM时钟树 - Clock Tree
时钟树主要分4个部分:
-
Clock Switcher
-
Clock Root Generator
-
Low Power Clock Gating module(LPCG)
-
System Clocks
2.3.1. 时钟选择 - Clock Switcher
Clock Switcher 是多次通过选择器来选择时钟源 (CCM_CCSR 寄存器)来选择最终的时钟。
时钟选择如下图示:
结合上图和 CCM_CCSR 寄存器
以 pll1_sw_clk 的时钟选择为例,pll1_sw_clk 可选时钟源有 PLL1(996M)、osc_clk(24M)、PFD2(400M)和 PLL2(528M)。CCM_CCSR 寄存器结构如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I3AC7TFa-1685697696376)(photo/CCM_CCSR.png)]
2.3.2. 根时钟生成 - Clock Root Generator
如下图所示,根时钟生成使用3个寄存器(CCM_CBCDR、CCM_CBCMR 和 CCM_CSCMR1)进行一系列操作最终得到对应的根时钟(AXI_CLK_ROOT、AHB_CLK_ROOT 、 IPG_CLK_ROOT等···)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SEekB9yf-1685697696378)(photo/Clock root Generator.png)]
2.3.2.1. AHB_CLK_ROOT、PERCLK_CLK_ROOT 配置为 132MHz 和 66MHz
Clock Root | Default Frequency (MHz) | Maximum Frequency (MHz) |
---|---|---|
ARM_CLK_ROOT | 12 | 528 |
MMDC_CLK_ROOT FABRIC_CLK_ROOT | 24 | 396 |
AXI_CLK_ROOT | 12 | 264 |
AHB_CLK_ROOT | 6 | 132 |
PERCLK_CLK_ROOT | 3 | 66 |
… | … | … |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5FWTiITR-1685697696379)(photo/132MHz.png)]
-
AHB_CLK_ROOT – 132MHz
AHB_CLK_ROOT根时钟经过了两个(1、2)选择器和一个分频器(3)最终输出132Mhz,过程如下:
-
选择pre_periph_clk的时钟源,可以选择PLL2、PLL2_PFD2、PLL2_PFD0和PLL2_PFD2/2。
寄存器CCM_CBCMR 的 PRE_PERIPH_CLK_SEL 位选择 PLL2_PFD2(01),PLL2_PFD2=396MHz。PRE_PERIPH2_CLK_SEL位:pre_periph2 时钟源选择,00 选择 PLL2,01 选择 PLL2_PFD2,10 选择 PLL2_PFD0,11 选择 PLL4。
-
选择periph_clk的时钟源,由寄存器CCM_CBCDR的ERIPH_CLK_SEL位与PLL_bypass_en2组成的或门来选择。寄存器 CCM_CBCDR 的 PERIPH_CLK_SEL选择 PLL2,则 periph_clk = pr_periph_clk = 396MHz。
PERIPH_CLK_SEL位:peripheral 主时钟选择,如果为 0 的话选择 PLL2,如果为 1 的话选择 periph_clk2_clock。修改此位会引起一次与 MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信号由寄存器 CCM_CDHIPR 中指定位表示。
-
CBCDR的AHB_PODF位来设置AHB_CLK_ROOT的分频值,1~8分频8种,AHB_CLK_ROOT = 132MHz的话就应该设置为3分频:396/3 = 132MHz。
AHB_PODF:ahb 时钟分频,可设置 0~7,分别对应 1~8 分频。修改此位会引起一次与MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信号由寄存器 CCM_CDHIPR 中指定位表示。
-
-
PERCLK_CLK_ROOT – 66MHz
-
因为 PERCLK_CLK_ROOT 的时钟源使用的是 peripheral,所以直接通过CBCDR的 IPG_PODF 位来设置PERCLK_CLK_ROOT 的分频值为 2 分频:132/2=66MHz。
IPG_PODF:ipg 时钟分频,可设置 0~3,分别对应 1~4 分频。
-
2.3.2.2. MMDC 握手
-
引起MMDC握手信号
修改以下分频器和选择器时候会引起握手信号,寄存器CCM_CDHIPR中保存着握手信号是否完成,如果相应的位为1的话就表示握手没有完成,如果为0的话就表示握手完成。:
mmdc_podf、periph_clk_sel、periph2_clk_se、arm_podf、ahb_podf
-
其他不需要握手的更新PODF需要:
- 在更新PODF值之前关闭输出时钟;
- 更新PODF值稳定后接通;
在不关闭输出时钟的情况下更新 PODF 会发生意外,例如无时钟输出;
2.3.2.2. CCM_CBCDR、CCM_CBCMR 、CCM_CSCMR1 和CCM_CCDR寄存器
- CCM_CBCDR 寄存器结构
寄存器 CCM_CBCDR 每位的含义如下:
PERIPH_CLK2_PODF:periph2 时钟分频,可设置 0~7,分别对应 1~8 分频。
PERIPH2_CLK_SEL:选择 peripheral2 的主时钟,如果为 0 的话选择 PLL2,如果为 1 的话选择periph2_clk2_clk。修改此位会引起一次与 MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信号由寄存器 CCM_CDHIPR 中指定位表示。
PERIPH_CLK_SEL:peripheral 主时钟选择,如果为 0 的话选择 PLL2,如果为 1 的话选择 periph_clk2_clock。修改此位会引起一次与 MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信号由寄存器 CCM_CDHIPR 中指定位表示。
AXI_PODF:axi 时钟分频,可设置 0~7,分别对应 1~8 分频。
AHB_PODF:ahb 时钟分频,可设置 0~7,分别对应 1~8 分频。修改此位会引起一次与MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信号由寄存器 CCM_CDHIPR 中指定位表示。
IPG_PODF:ipg 时钟分频,可设置 0~3,分别对应 1~4 分频。
AXI_ALT_CLK_SEL:axi_alt 时钟选择,为 0 的话选择 PLL2_PFD2,如果为 1 的话选择PLL3_PFD1。
AXI_CLK_SEL:axi 时钟源选择,为 0 的话选择 periph_clk,为 1 的话选择 axi_alt 时钟。
FABRIC_MMDC_PODF:fabric/mmdc 时钟分频设置,可设置 0~7,分别对应 1~8 分频。
PERIPH2_CLK2_PODF:periph2_clk2 的时钟分频,可设置 0~7,分别对应 1~8 分频。
- CCM_CBCMR 寄存器结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cdwB3kdi-1685697696380)(photo/CCM_CBCMR.png)]
LCDIF1_PODF:lcdif1 的时钟分频,可设置 0~7,分别对应 1~8 分频。
PRE_PERIPH2_CLK_SEL:pre_periph2 时钟源选择,00 选择 PLL2,01 选择 PLL2_PFD2,10 选择 PLL2_PFD0,11 选择 PLL4。
PERIPH2_CLK2_SEL:periph2_clk2 时钟源选择为 0 的时候选择 pll3_sw_clk,为 1 的时候选择 OSC。
PRE_PERIPH_CLK_SEL:pre_periph 时钟源选择,00 选择 PLL2,01 选择 PLL2_PFD2,10 选择 PLL2_PFD0,11 选择 PLL2_PFD2/2。
PERIPH_CLK2_SEL:peripheral_clk2 时钟源选择,00 选择 pll3_sw_clk,01 选择 osc_clk,10 选择 pll2_bypass_clk。
- CCM_CSCMR1 寄存器结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X899ofLs-1685697696381)(photo/CCM_CSCMR1.png)]
CCM_CSCMR1 寄存器主要用于外设时钟源的选择,重点关注以下两位:
PERCLK_CK_SEL:perclk 时钟源选择,为 0 的话选择 ipg clk,为 1 的话选择 osc clk。
PERCLK_PODF:perclk 的时钟分频,可设置 0~7,分别对应 1~8 分频。
- CCM_CCDR 寄存器结构
2.4. CCM 内存映射/寄存器
2.4.1. CCM Memory Map/Register
如下表为CCM内存映射地址及寄存器名称,寄存器描述见 ’IMX6ULL参考手册‘ ‘18.6 CCM Memory Map/Register Definition’
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MOGZilTN-1685697696383)(photo/CCM memory map.png)]
2.4.2. CCM_ANALOG memory map
本节介绍模拟锁相环的寄存器。具有相同描述的寄存器被分组在{}中。各种锁相环的寄存器偏移量如下:
- ARM PLL: {0h000, 0h004, 0h008, 0h00C}.
- USB1 PLL: {0h010, 0h014, 0h018, 0h01C}, {0h0F0, 0h0F4, 0h0F8, 0h0FC}.
- System PLL: {0h030, 0h034, 0h038, 0h03C}, 0h040, 0h050, 0h060, {0h100, 0h104,0h108, 0h10C}.
- Audio / Video PLL: {0h070, 0h074, 0h078, 0h07C}, 0h080, 0h090, {0h0A0, 0h0A4,0h0A8, 0h0AC}, 0h0B0, 0h0C0
寄存器描述见’IMX6ull参考手册 ‘18.7.1 Analog ARM PLL control Register (CCM_ANALOG_PLL_ARMn) ’