系列文章目录
Exynos4412的Linux时钟驱动开发(一)——Exynos4412的时钟管理单元CMU
Exynos4412的Linux时钟驱动开发(二)——时钟驱动的初始化(CLK_OF_DECLARE的机制)
Exynos4412的Linux时钟驱动开发(三)——Common Clock Framework(CCF)简介
Exynos4412的Linux5.4.174时钟驱动开发(四)——clk API的调用方法
Exynos4412的Linux5.4.174时钟驱动开发(五)——时钟设备树的修改方法
Exynos4412的Linux时钟驱动开发(一)——Exynos4412的时钟管理单元CMU
一、Exynos4412的CMU
CMU:Clock Management Unit
1、时钟域
Exynos4412有很多时钟功能模块,异步地为不同的硬件提供不同频率,例如
- CPU时钟模块(CPU block)
- DMC模块
- 左总线和右总线
- CMU_TOP
2、时钟源
(1)顶层时钟包括:
- 外接晶振: XXTI(24MHz), and XUSBXTI(24MHz),XRTCXTI(32.768kHz),HDMIXTI(27MHz)
- CMU生成内部时钟:ARMCLK, ACLK, HCLK, and SCLK
- USB PHY
- HDMI_PHY
- GPIO外接输入时钟源
(2)CMU的时钟源
- 外部晶振
- 四种PLL:APLL、MPLL、EPLL、VPLL。官方建议APLL, MPLL, EPLL, and VPLL的输入时钟为24MHz
- USB PHY 和HDMI PHY
APLL和MPLL可以生成22MHz~1.4GHz的时钟。通过配置P、M、S三种数值产生不同频率。数据手册中建议的PMS值,部分如下:
3、时钟树
产生时钟是由时钟源
、多路选择器MUX
、分频器DIV
、门开关GATE
等clock_provider
共同完成。
数据手册中时钟树框图,部分如上图所示。可以看出,首先由XOM[0]
决定多路选择器
,选择XXTI
或者XUSBXTI
作为FINPLL,成为APLL
的输入时钟。
XOM[0]
是chipid register中的一位。linux-5.4.174/drivers/clk/samsung/clk-exynos4.c
中读取XOM[0]
并选择FINPLL
。代码如下:
/*
* The parent of the fin_pll clock is selected by the XOM[0] bit. This bit
* resides in chipid register space, outside of the clock controller memory
* mapped space. So to determine the parent of fin_pll clock, the chipid
* controller is first remapped and the value of XOM[0] bit is read to
* determine the parent clock.
*/
static unsigned long __init exynos4_get_xom(void)
{
unsigned long xom = 0;
void __iomem *chipid_base;
struct device_node *np;
np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-chipid");
if (np) {
chipid_base = of_iomap(np, 0);
if (chipid_base)
xom = readl(chipid_base + 8);
iounmap(chipid_base);
of_node_put(np);
}
return xom;
}
static void __init exynos4_clk_register_finpll(struct samsung_clk_provider *ctx)
{
struct samsung_fixed_rate_clock fclk;
struct clk *clk;
unsigned long finpll_f = 24000000;
char *parent_name;
unsigned int xom = exynos4_get_xom();
parent_name = xom & 1 ? "xusbxti" : "xxti";
clk = clk_get(NULL, parent_name);
if (IS_ERR(clk)) {
pr_err("%s: failed to lookup parent clock %s, assuming "
"fin_pll clock frequency is 24MHz\n", __func__,
parent_name);
} else {
finpll_f = clk_get_rate(clk);
}
fclk.id = CLK_FIN_PLL;
fclk.name = "fin_pll";
fclk.parent_name = NULL;
fclk.flags = 0;
fclk.fixed_rate = finpll_f;
samsung_clk_register_fixed_rate(ctx, &fclk, 1);
}
4、设置FSYS
系统推荐主频1.4GHz的各种寄存器配置数值,可以参考《【TINY4412】U-BOOT移植笔记:(5)时钟分析》。
这里以设置FSYS为例进行分析相关时钟寄存器。我的开发板上网卡控制器DM9000A是连接在SROC控制器上的,FSYS是给SROMC提供时钟的。
以设置FSYS时钟为例分析。由时钟树图可以看出,设置FSYS的时钟频率,需要设置3个多路选择器MUX和2个分频器DIV,涉及如下寄存器:
- MUXMPLL_CTRL_USER_T
CLK_SRC_TOP1
:
Base Address: 0x1003_0000,Address = Base Address + 0xC214,
Reset Value = 0x0000_0000
- MUXACLK_133、MUXONENAND、MUXONENAND_1
CLK_SRC_TOP0
:
Base Address: 0x1003_0000,Address = Base Address + 0xC210,
Reset Value = 0x0000_0000
- DIVACLK_133、DIVONENAND
CLK_DIV_TOP
:
Base Address: 0x1003_0000,Address = Base Address + 0xC510,
Reset Value = 0x0000_0000
二、Linux启动时默认的时钟频率
Exynos4412在刚上电时,会执行64KB的iROM中的代码,初始化系统的时钟。此时,APLL和MPLL的MPS值分别为100、3、1,产生400MHz时钟。
然后,由BootLoader进一步配置时钟,使Exynos4412工作在最佳时钟状态。也就是说,Linux在启动的时候,CMU的各个寄存器已经配置完毕了。
因此,对于Linux而言,就是如何编写关于时钟的驱动程序,配置和使用时钟。其实,对于驱动开发人员来说,只需要调用Common Clock Framework(CCF)的clk API,就能够操作各种类型的时钟,没必要重新配置CMU。