基于RK3399分析Linux系统下的CPU时钟管理 - 第3篇

article/2025/8/29 9:56:37

1. 时钟系统结构

rockchip的时钟系统代码位于drivers/clk/rockchip,目录整体结构如下:

├── rockchip
│   ├── clk.c---------------时钟系统注册
│   ├── clk-cpu.c-----------CPU调频
│   ├── clk-ddr.c-----------DDR调频
│   ├── clk-half-divider.c--二分频
│   ├── clk-inverter.c------极性翻转
│   ├── clk-mmc-phase.c-----mmc相位
│   ├── clk-muxgrf.c--------时钟复用
│   ├── clk-pll.c-----------PLL配置
│   ├── clk-pvtm.c----------电压温度检测调频
│   ├── clk-rk3399.c--------RK3399时钟核心初始化、PLL初始化、使能控制、分频等
│   ├── clk-rockchip.c------RK系列芯片时钟
└──────────────────────────────────────────────────────

从上面的文件结构中我们可以看到,rockchip的时钟系统基本包含了CCF框架提到的时钟使能、复用、分频、倍频等功能。RK3399的时钟系统主体是clk-rk3399.c这个文件。

2. 初始化方式

kernel中的时钟初始化代码位于驱动初始化这个层面,相较于CPU初始化而言,它是比较靠后的。在此之前,CPU及基本外设的工作时钟,由bootrom或者U-Boot及其他bootloader配置,有的CPU在时钟系统完全工作之前是工作于低频模式,而有的CPU则上电解复位之后便工作于高频模式,不可一概而论。
说到kernel中的时钟系统初始化,就不得不提CLK_OF_DECLARE这个宏定义,在时钟驱动中通过它来声明初始化函数,其实现原理如下图所示:

CLK_OF_DECLARE

3. RK3399时钟系统实现

rockchip为全系列芯片提供了统一的时钟初始化API,这一点非常值得我们借鉴同时也是很好的一种代码架构模式。RK3399的时钟初始化涉及两部分内容,分别是crupmu,二者原理相通,本文以cru初始化为例。具体包括:

RK3399时钟初始化涉及到的文件

上图中涉及到的CCF文件在前文已经描述过:

Linux时钟系统CCF原理

3.1 核心初始化

RK3399基于数据结构rockchip_clk_provider描述整体的时钟结构,以此代表clock provider

struct rockchip_clk_provider {void __iomem *reg_base;struct clk_onecell_data clk_data;struct device_node *cru_node;struct regmap *grf;struct regmap *pmugrf;spinlock_t lock;
};

在设备树rk3399.dtsi文件中以grf: syscon@ff770000pmugrf: syscon@ff320000定义了grfpmugrf,包含了时钟控制相关的寄存器。
通过rockchip_clk_init()例化数据结构struct rockchip_clk_provider

	ctx->reg_base = base;ctx->clk_data.clks = clk_table;  ctx->clk_data.clk_num = nr_clks;      //---CLK数量,共497路ctx->cru_node = np;                   //---设备树中的cru结点ctx->grf = ERR_PTR(-EPROBE_DEFER);    //---设备树中的grf结点ctx->pmugrf = ERR_PTR(-EPROBE_DEFER); //---设备树中的pmugrf结点spin_lock_init(&ctx->lock);ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node,"rockchip,grf");ctx->pmugrf = syscon_regmap_lookup_by_phandle(ctx->cru_node,"rockchip,pmugrf");

3.2 PLL初始化

RK3399芯片内部包含了8个PLL,分别是LPLL, BPLL, CPLL, GPLL, NPLL, VPLL, VPLL, PPLL,如下图所示:

Fractional PLL

在代码中使用数据结构struct rockchip_pll_clock描述RK3399的PLL:

struct rockchip_pll_clock {unsigned int		id;const char		*name;const char		*const *parent_names;u8			num_parents;unsigned long		flags;int			con_offset;int			mode_offset;int			mode_shift;int			lock_shift;enum rockchip_pll_type	type;u8			pll_flags;struct rockchip_pll_rate_table *rate_table;
};

PLL的配置在程序中进行固化,如下:

static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = {[lpll] = PLL(pll_rk3399, PLL_APLLL, "lpll", mux_pll_p, 0, RK3399_PLL_CON(0),RK3399_PLL_CON(3), 8, 31, 0, rk3399_pll_rates),[bpll] = PLL(pll_rk3399, PLL_APLLB, "bpll", mux_pll_p, 0, RK3399_PLL_CON(8),RK3399_PLL_CON(11), 8, 31, 0, rk3399_pll_rates),[dpll] = PLL(pll_rk3399, PLL_DPLL, "dpll", mux_pll_p, 0, RK3399_PLL_CON(16),RK3399_PLL_CON(19), 8, 31, 0, NULL),
#ifdef RK3399_TWO_PLL_FOR_VOP[cpll] = PLL(pll_rk3399, PLL_CPLL, "cpll", mux_pll_p, 0, RK3399_PLL_CON(24),RK3399_PLL_CON(27), 8, 31, 0, rk3399_pll_rates),
#else[cpll] = PLL(pll_rk3399, PLL_CPLL, "cpll", mux_pll_p, 0, RK3399_PLL_CON(24),RK3399_PLL_CON(27), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
#endif[gpll] = PLL(pll_rk3399, PLL_GPLL, "gpll", mux_pll_p, 0, RK3399_PLL_CON(32),RK3399_PLL_CON(35), 8, 31, 0, rk3399_pll_rates),[npll] = PLL(pll_rk3399, PLL_NPLL, "npll",  mux_pll_p, 0, RK3399_PLL_CON(40),RK3399_PLL_CON(43), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),[vpll] = PLL(pll_rk3399, PLL_VPLL, "vpll",  mux_pll_p, 0, RK3399_PLL_CON(48),RK3399_PLL_CON(51), 8, 31, 0, rk3399_vpll_rates),
};

通过rockchip_clk_register_pll()函数初始化PLL,主要是例化数据结构struct rockchip_clk_pll并完成时钟的注册,重点包含如下几个方面:

pll->pll_mux_ops = &clk_mux_ops;      //--PLL复用
init.ops = &rockchip_rk3399_pll_clk_ops;//--PLL控制
pll->hw.init = &init;                 //--PLL数据
pll->type = pll_type;                 //--PLL类型
pll->ctx = ctx;                       //--关联时钟核心

上面的rockchip_rk3399_pll_clk_ops数据结构包含了PLL一系列的控制函数,如:

static const struct clk_ops rockchip_rk3399_pll_clk_ops = {.recalc_rate = rockchip_rk3399_pll_recalc_rate,.round_rate = rockchip_pll_round_rate,.set_rate = rockchip_rk3399_pll_set_rate,.enable = rockchip_rk3399_pll_enable,.disable = rockchip_rk3399_pll_disable,.is_enabled = rockchip_rk3399_pll_is_enabled,.init = rockchip_rk3399_pll_init,
};

3.2 复用/分频/GATE

这部分的初始化内容不限于标题所述,只是这3部分内容更为重要而已。

在代码中通过数据结构rockchip_clk_branch描述RK3399时钟系统的控制功能,如下:

struct rockchip_clk_branch {unsigned int			id;enum rockchip_clk_branch_type	branch_type;const char			*name;const char			*const *parent_names;u8				num_parents;unsigned long			flags;
...
};

其相关配置在程序中固化,基本涵盖了cru时钟单元的所有输出时钟控制信息。

static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {GATE(SCLK_USB2PHY0_REF, "clk_usb2phy0_ref", "xin24m", CLK_IGNORE_UNUSED,RK3399_CLKGATE_CON(6), 5, GFLAGS),GATE(SCLK_USB2PHY1_REF, "clk_usb2phy1_ref", "xin24m", CLK_IGNORE_UNUSED,RK3399_CLKGATE_CON(6), 6, GFLAGS),GATE(SCLK_USBPHY0_480M_SRC, "clk_usbphy0_480m_src", "clk_usbphy0_480m", 0,RK3399_CLKGATE_CON(13), 12, GFLAGS),GATE(SCLK_USBPHY1_480M_SRC, "clk_usbphy1_480m_src", "clk_usbphy1_480m", 0,RK3399_CLKGATE_CON(13), 12, GFLAGS),MUX(0, "clk_usbphy_480m", mux_usbphy_480m_p, 0,RK3399_CLKSEL_CON(14), 6, 1, MFLAGS),
...
}

通过函数rockchip_clk_register_branches()完成进行各功能的例化并完成时钟注册。

rockchip_clk_register_branches(ctx, rk3399_clk_branches,ARRAY_SIZE(rk3399_clk_branches));

3.3 其他时钟控制项

- Tips 1

以上所有的时钟完成注册后,会将时钟信息更新进RK3399的时钟信息表,如下:

void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx,struct clk *clk, unsigned int id)
{if (ctx->clk_data.clks && id)ctx->clk_data.clks[id] = clk;
}

- Tips 2
若希望上电之后某些时钟常开,可以配置数据结构rk3399_cru_critical_clocks,例如:

static const char *const rk3399_cru_critical_clocks[] __initconst = {"aclk_usb3_noc","aclk_gmac_noc","pclk_gmac_noc","pclk_center_main_noc","aclk_cci_noc0","aclk_cci_noc1","clk_dbg_noc",
...
}

Tips 3
打印RK3399的时钟树(信息很多),可以查看当前环境下所有的时钟信息,例如:

[root@rk3399:/]# cat /sys/kernel/debug/clk/clk_summaryclock                         enable_cnt  prepare_cnt        rate   accuracy   phase
----------------------------------------------------------------------------------------rk808-clkout2                            0            0       32768          0 0xin32k                                   0            0       32768          0 0CLK_CAMERA_24MHZ                         0            0    24000000          0 0ap6256_lpo_clk                           2            2       32768          0 0clkin_gmac                               1            1   125000000          0 0clk_rmii_src                          4            4   125000000          0 0clk_rmii_tx                        2            2   125000000          0 0clk_rmii_rx                        1            1   125000000          0 0clk_mac_ref                        1            1   125000000          0 0clk_mac_refout                     1            1   125000000          0 0dummy_vpll                               0            0           0          0 0dummy_cpll                               0            0           0          0 0clk_test_pre                          0            0           0          0 0clk_test                           0            0           0          0 0clk_test_frac                      0            0           0          0 0clk_cifout_src                        0            0           0          0 0clk_testout2_pll_src                  0            0           0          0 0clk_testout1_pll_src                  0            0           0          0 0
......

http://chatgpt.dhexx.cn/article/lZVFuhWv.shtml

相关文章

基于RK3399+PID的手持稳定云台的设计与实现

手持稳定云台的主要作用是将外界环境因数引起的相机姿态变化进行隔离。如因操作者运动造成的机体震动、风阻力矩等,为了确保工作中相机的视轴始终保持期望的姿态不动。云台相机要拍摄出高质量的影像最重要的就是保证相机的视轴相对目标保持稳定。因此在相机拍摄的过…

RK3399学习

RK3399学习 韦东山rk3399:http://dev.t-firefly.com/forum-460-1.html firefly官网教程:http://wiki.t-firefly.com/zh_CN/Firefly-RK3399/started.html firefly官网3399资料:http://dev.t-firefly.com/forum-263-1.html 100ask 3399-pc教…

RK3399平台开发系列讲解(内核入门篇)1.53、platform平台设备

🚀返回专栏总目录 文章目录 一、设备配置-非设备树1.1、资源1.2、平台数据1.3、声明平台设备二、设备配置 - DTS沉淀、分享、成长,让自己和他人都能有所收获!😄 📢平台设备在内核中表示为struct platform_device的实例。 有两种方法可以把有关设备所需的资源(IRQ、DMA…

RK3399 Android7.1 编译

RK3399 Android7.1 编译 文章目录 RK3399 Android7.1 编译前言设置 Linux 编译环境安装 JDK可选- 更新默认的 Java 版本 安装所需的程序包(Ubuntu 14.04) 下载 Android SDK 前言 RK官网编译 Android搭建编译环境 设置 Linux 编译环境 使用的环境Linux 16.0.4 安装 JDK 如…

基于RK3399+5G的医用视频终端设计

当前在各种先进的信息通信技术的驱动下,医疗行业已呈现出信息化、移动化、智能化的发展趋势。特别是 5G 通信技术的落地应用推动了智慧医疗行业的 蓬勃发展,涌现出大量基于 5G 技术的医疗健康应用与服务,进一步融合了 5G 、 物联网与大数据…

RK3399平台开发系列讲解(PCI/PCI-E)PCIE相关配置说明

🚀返回专栏总目录 文章目录 一、DTS 配置二、menuconfig 配置三、cmdline 配置沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 本篇将介绍在使用 RK3399 平台 PCIE 时候的配置。 一、DTS 配置 ep-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; 此项是设置 PCIe…

RK3399快速上手 | 02-rockchip rk3399 linux sdk的使用(编译内核、编译uboot)

更新时间更新内容2022-09-15增加内核编译方法2022-10-21增加uboot编译方法和sdk开发版配置链路分析一、sdk区别 瑞芯微提供了两套sdk,一套是通过官方git仓库释放,适合于项目使用,另一套是通过github释放,适合于爱好者。 本文中使用从瑞芯微官方释放的正式linux sdk 2.7版…

RK3399平台开发系列讲解(中断篇)中断控制器驱动初始化

🚀返回专栏总目录 文章目录 一、设备树源文件1.1、gic控制器节点1.2、timer节点二、中断控制器匹配表三、中断控制器初始化3.1、函数of_irq_init3.2、函数gicv3_of_init3.3、函数gic_init_bases沉淀、分享、成长,让自己和他人都能有所收获!😄 一、设备树源文件 ARM64架构…

RK3399平台开发系列讲解(内存篇)15.34、 Linux 进程内存布局

🚀返回专栏总目录 文章目录 一、抽象内存布局二、32位机器 Linux 进程内存布局三、64位机器 Linux 进程内存布局沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 我们一起来看下进程内部的虚拟内存布局,或者说单一进程是如何安排自己的各种数据的。 一、抽象内存布…

RK3399平台开发系列讲解(内核调试篇)2.50、嵌入式产品启动速度优化

平台内核版本安卓版本RK3399Linux4.4Android7.1🚀返回专栏总目录 沉淀、分享、成长,让自己和他人都能有所收获!😄 📢启动速度是嵌入式产品一个重要的性能指标,更快的启动速度会让客户有更好的使用体验,在某些方面还会节省能耗,因为可以直接关机而不需要休眠。 启动速…

钉钉F1 RK3399 咸鱼80元板子使用记录

1.简单介绍 12V电源&#xff0c;建议2A&#xff0c; 默认插电不开机&#xff0c;有大佬找到金属罩下的焊盘&#xff0c;短接可上电开机。 在usb旁边的旁边有个端子接口&#xff0c;短接就可以开机&#xff0c;建议找个一样大的接口接个开关&#xff0c;到目前为止还未测试需要…

RK3399平台开发系列讲解(网络篇)7.38、网卡驱动程序数据结构

平台内核版本安卓版本RK3399Linux4.4Android7.1🚀返回专栏总目录 文章目录 一、套接字缓冲区结构:sk_buff二、网络接口结构:net_device沉淀、分享、成长,让自己和他人都能有所收获!😄 📢处理网卡设备时需要使用两种数据结构。 struct sk_buff结构在include/linux/skb…

RK3399平台开发系列讲解(中断篇)中断控制器(Generic Interrupt Controller)

🚀返回专栏总目录 文章目录 一、GIC硬件的实现形态二、主要的功能块三、中断类型四、中断状态沉淀、分享、成长,让自己和他人都能有所收获!😄 📢外围设备不是把中断请求直接发给处理器,而是发给中断控制器,由中断控制器转发给处理器。ARM公司提供了一种标准的中断控制…

RK3399平台开发系列讲解(DMA篇)深刻理解DMA

🚀返回专栏总目录 文章目录 一、什么是DMA二、DMA的产生:背景三、理解 DMA:协处理器沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将带领大家深刻理解DMA。 一、什么是DMA DMA (Direct Memory Access) is used to copy data directly between devices and R…

RK3399——裸机大全

CSDN仅用于增加百度收录权重&#xff0c;排版未优化&#xff0c;日常不维护。请访问&#xff1a;www.hceng.cn 查看、评论。 本博文对应地址: https://hceng.cn/2018/08/16/RK3399——裸机大全/#more 以64位的RK3399为例&#xff0c;实现裸机的启动、中断、串口(printf移植)、…

RK3399平台开发系列讲解(CPU篇)CPUFreq 中央处理器频率调节技术

🚀返回专栏总目录 文章目录 一、CPUFreq组成二、设备树配置三、原理沉淀、分享、成长,让自己和他人都能有所收获!😄 📢中央处理器频率调节(Central Processing Unit frequency,CPUFreq)技术可以降低ARM芯片的功耗,例如在系统对任务压力较小时,通过调整处理器工作频…

RK3399中文简介

1.概述 RK3399是一种低功耗、高性能的处理器&#xff0c;可用于计算、个人移动互联网设备和其他智能设备应用程序。基于大。小架构&#xff0c;它集成了双核心Cortex-A72和四核Cortex-A53与单独的NEON协处理器。 许多嵌入式功能强大的硬件引擎为高端应用程序提供了优化的性能。…

RK3399平台入门到精通系列讲解 - 总目录

总目录 欢迎大家来到内核笔记的《RK3399平台开发入门到精通系列讲解》&#xff0c;开始前博主先列出RK3399平台学习的大纲&#xff0c;同时这也可以作为大家学习RK3399内核与安卓框架的参考。下面蓝字都是传送门&#xff0c;点击进入即可&#xff1a; 更新说明 此系列已更新…

网络渗透测试实验四 CTF实践

实验目的&#xff1a;通过对目标靶机的渗透过程&#xff0c;了解CTF竞赛模式&#xff0c;理解CTF涵盖的知识范围&#xff0c;如MISC、PPC、WEB等&#xff0c;通过实践&#xff0c;加强团队协作能力&#xff0c;掌握初步CTF实战能力及信息收集能力。熟悉网络扫描、探测HTTP web服…

20159302《网络攻击与防范》第五周学习总结

教材内容学习总结 1.基础知识回顾 通过教材内容的学习了解&#xff0c;掌握了基本的网站运行模式&#xff0c;并了解其结构方式。如下图&#xff1a; 运行过程为&#xff1a;首先客户在浏览器端发送请求&#xff0c;将相关的表单、数据交付给服务器&#xff1b;然后服务器根据所…