Linux CommonClock Framework子系统分析之一 系统概述

本文介绍Linux的CCF子系统,阐述时钟源概念,包括晶振、锁相环、divider、mux和与门电路。分析CCF框架,说明如何通过抽象的struct clk_ops接口操作时钟源,如使能、频率修改等。并概述CCF内部设计,包括clk_hw、clk_ops和clk数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  本专栏主要介绍linux的ccf子系统,主要用于系统clock的管理等操作。本专栏我们大概分为如下几章进行学习:

一、CCF子系统概述

 

二、CCF子系统数据结构分析及关联说明

 

三、CCF子系统的clk注册与注销接口实现分析

 

四、虚拟的clk设备驱动实现

 

   本章我们主要进行CCF子系统的概述。大致说明下CCF的框架。以便我们后续深入的分析下CCF的实现机制。

 

clk的种类说明

如上图所示,时钟源大概可分为如下几种:

  1. 提供基础时钟源的晶振(可分为有源晶振、无源晶振两种);
  2. 用于倍频的锁相环;
  3. 用于分频的divider;
  4. 用于多路时钟源选择的mux;
  5. 用于时钟使能的与门电路等。

    而在CCF子系统的抽象中,这五种均抽象为clk,但是针对这5种类型的时钟也提供了单独的时钟注册函数(也就是对clk_register函数的封装,并针对不同的时钟类型定义了不同的结构体)

 

    在CCF子系统中,针对硬件时钟的操作接口,也抽象了对应的结构体struct clk_ops,包含时钟的使能接口、时钟频率的修改接口等等。而针对上述所说的不同种类的时钟源,其并不需要实现所有struct clk_ops中定义的接口。如下图所示,针对“时钟使能的与门电路”而言,仅需要实现enabel、disable、is_enable接口即可;针对多路时钟源选择的mux而言,则需要实现父时钟源的设置及获取的接口set_parent、get_parent等;对于倍频、分频而言,则需要实现时钟频率相关的接口set_rate、recalc_rate等。

 

 

CCF子系统的框架说明

 

    如下图所示,是CCF子系统的软件框架,其对各设备驱动子系统提供统一时钟源操作的接口,实现为具体的硬件设备获取其对应的输入时钟源,并可通过统一的接口实现对时钟源的配置(如时钟的使能、时钟频率的配置等等);在CCF内部,针对每一个时钟源,抽象结构体struct clk_hw,该结构体中包含每一个硬件时钟源的操作接口(struct clk_ops),当时钟源驱动程序完成时钟操作接口的定义,并调用clk_register完成注册后,则CCF即可借助clk_hw的clk_ops完成对时钟源的参数配置等操作。

 

    clk子系统抽象了数据结构struct clk、struct clk_hw、struct clk_ops,其中clk_hw是对一个时钟源的抽象,而clk_ops是时钟源的操作接口的抽象,而struct clk可以理解为访问clk_hw的实例)。

 

 

        本章主要是简要说明一下时钟源的概念以及CCF子系统的框架,下一篇我们重点分析CCF子系统内部的实现,此专栏分析的目的主要是了解CCF子系统内部的实现流程以及CCF子系统的设计,因此重点会分析CCF子系统内部数据结构的划分、内部接口的实现及调用逻辑等内容,而不仅仅是说明CCF子系统下的时钟源驱动的注册以及时钟控制等,因为CCF子系统内部设计上做了很好的设计与抽象,因此时钟源设备驱动的开发以及时钟的使用等接口就相对来说简单了许多,在本专栏的最后一章我们将实现一个虚拟时钟源的驱动程序,从而说明时钟源驱动的开发流程(像这些设备驱动子系统而言,使用它们提供的接口实现驱动的注册一般都是比较简单的,因此我们最好能理解其子系统内部的设计逻辑,可能我们以后实现驱动或者应用程序开发时,也可以借鉴这种设计思路)。

<think>好的,我现在要处理用户关于Linux内核4.19.35版本中IMX6ULL SOC的CCM模块的问题。用户需要了解CCM系统的相关内容,包括系统、驱动程序、设备树配置等,并希望获得一个教程式的回答。我需要先理解用户的具体需求,然后根据提供的引用内容整理相关信息。 首先,用户提到的IMX6ULL是NXP的一款处理器,CCM(Clock Control Module)是时钟控制模块,负责管理和分配各个外设的时钟。在内核中,CCM的配置通常涉及设备树、驱动程序和相关的系统。用户引用了三个参考资料,其中引用1提到了设备树文件的路径和作用,引用2提到了启动内核时卡住的问题,引用3详细描述了CCM的时钟设置,包括分频系数、PLL配置等。 接下来,我需要结合这些引用内容,梳理出CCM模块在设备树中的配置方法、驱动程序的实现以及系统的结构。根据引用3,CCM的时钟设置包括设置分频寄存器、选择PLL源等,这可能涉及到设备树中的时钟节点配置。引用1指出设备树文件的位置在`ebf-buster-linux/arch/arm/boot/dts/imx6ull-mmc-npi.dts`,用户可能需要查看这个文件中的相关节点,比如`clks`节点。 此外,用户提供的引用2中提到了启动时卡在Starting kernel的问题,这可能设备树配置错误有关,特别是时钟配置不正确导致内核无法正确初始化。因此,在教程中需要强调设备树配置的正确性,以及如何调试相关问题。 接下来,我需要整理CCM系统的结构。Linux内核中的时钟系统通常由Common Clock FrameworkCCF)来管理,CCM驱动应基于此框架实现。驱动程序部分可能涉及到注册时钟提供者(clock provider),定义各个时钟的初始化数据,并在设备树中指定时钟源和父时钟。 关于设备树配置,用户需要知道如何在设备树中定义时钟控制器节点,如何为各外设分配时钟,以及如何引用这些时钟。例如,在设备树中,CCM节点可能包含多个时钟定义,每个外设的节点会通过`clocks`属性引用相应的时钟。 另外,引用3中提到PLL2、PLL3和PLL7的固定频率,以及如何设置分频系数,这些信息需要体现在设备树或驱动程序的初始化代码中。可能需要在设备树中配置某些时钟的父节点和频率参数,或者在驱动程序中设置寄存器值。 最后,用户可能需要一个步骤指南,指导如何在内核中配置CCM,包括设备树的修改、驱动的加载以及调试方法。同时,需要提醒用户注意常见问题,比如时钟配置错误导致的启动失败,以及如何通过读取寄存器或调试信息来排查问题。 总结来说,回答应涵盖以下几个部分: 1. CCM系统在内核中的结构,特别是Common Clock Framework的关系。 2. 设备树中CCM相关节点的配置方法,包括时钟控制器节点和各外设的时钟引用。 3. 驱动程序如何设备树交互,初始化时钟设置。 4. 常见问题及解决方法,如启动失败时的调试技巧。 需要确保引用提供的资料,特别是设备树路径、时钟设置细节以及启动问题的分析。同时,生成的相关问题应围绕CCM配置、设备树调试、时钟问题排查等方面。</think>### Linux Kernel 4.19.35 IMX6ULL CCM模块配置教程 #### 1. CCM系统概述 CCM(Clock Control Module)是IMX6ULL的时钟控制模块,负责管理CPU、外设和总线时钟的分配分频。在Linux内核中,其驱动基于**Common Clock Framework (CCF)** 实现,通过设备树描述硬件资源[^1]。关键功能包括: - PLL配置(如PLL2固定为528MHz,PLL3/PLL7固定为480MHz)[^3] - 分频系数设置(如`DIV_SELECT`和`cacrr`寄存器操作) - 时钟源切换(如`ARM_PLL``ARM_ROOT`的关联) #### 2. 设备树配置 设备树文件路径为: `ebf-buster-linux/arch/arm/boot/dts/imx6ull-mmc-npi.dts`[^1] ##### 2.1 时钟控制器定义 ```dts clocks { #address-cells = <1>; #size-cells = <0>; osc24m: osc24m { compatible = "fixed-clock"; clock-frequency = <24000000>; #clock-cells = <0>; }; // 其他PLL和分频器定义... }; &ccm { assigned-clocks = <&clks IMX6UL_CLK_PLL3_PFD1>; assigned-clock-rates = <454736000>; // 分频设置示例 clocks = <&osc24m>, <&clks IMX6UL_CLK_OSC>; clock-names = "osc", "ipp_di0"; }; ``` 关键参数: - `assigned-clocks`指定需动态配置的时钟 - `assigned-clock-rates`设置目标频率 - 通过`clock-names`标识时钟源层级关系 #### 3. 驱动程序分析 驱动文件位于: `drivers/clk/imx/clk-imx6ul.c` ##### 3.1 时钟注册流程 ```c static void __init imx6ul_clocks_init(struct device_node *ccm_node) { // 初始化基础时钟源 clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); clks[IMX6UL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil"); // 配置PLL2分频 clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(...); clks[IMX6UL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2", ccm_base + CCM_CCDR, 16); // 注册到CCF框架 for (i = 0; i < ARRAY_SIZE(clks); i++) clk_register_clkdev(clks[i], NULL, __clk_get_name(clks[i])); } ``` #### 4. 调试常见问题 **问题现象**:启动卡在`Starting kernel...`[^2] **排查步骤**: 1. 检查设备树中CCM节点是否硬件匹配 2. 使用`clk_summary`查看时钟分配: ```bash cat /sys/kernel/debug/clk/clk_summary ``` 3. 验证PLL配置寄存器值是否符合预期(参考引用3的分频逻辑) #### 5. 关键寄存器操作 根据引用3的配置流程: 1. 设置`CCM_CACRR`寄存器分频系数 2. 通过`CCM_CCSR`切换ARM内核时钟源 3. 检查`CCM_CDHIPR`寄存器状态位(如bit31是否置1) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值