目录
[一,clk-fixed and clk-pll](#一,clk-fixed and clk-pll)
[二,clk时钟数 divider/factor/gate/mux/ratio/link介绍](#二,clk时钟数 divider/factor/gate/mux/ratio/link介绍)
[4,clk-ratio 分频比](#4,clk-ratio 分频比)
[三,clk配置,包含配置parent rate和使能](#三,clk配置,包含配置parent rate和使能)
一,clk-fixed and clk-pll
1,clk-fixed
fixed:{ "name": "xtal", "rate": 24000000 }
没啥内容,就是套在时钟树里面,作为后续的parent,实现get_rate可以作为后续clk节点的计算参考。
2,clk-pll
{"parent":"xtal","name":"apll","channel":0},
{"parent":"xtal","name":"dpll","channel":1},
{"parent":"xtal","name":"cpll","channel":2},
{"parent":"xtal","name":"gpll","channel":3},
{"parent":"xtal","name":"npll","channel":4},



val = (read32(CRU_MODE_CON) >> ((pdat->channel == 4) ? 14 : pdat->channel * 4)) & 0x3;
npll的bit位特殊,所以4单独处理,
if(val == 0x1)
{
val = read32(pdat->channel * 0x10);
no = ((val >> 0) & 0x0f) + 1;
nr = ((val >> 8) & 0x3f) + 1;
val = read32((pdat->channel * 0x10 + 0x4));
nf = ((val >> 0) & 0x1fff) + 1;
rate = (24 * nf / (nr * no)) * 1000000;
}
else if(val == 0x2)
{
rate = 32768;
}
else
{
rate = 24000000;
}
以npll为例,con0和con1存放这锁相环nr no nf值,当cru_mode_con寄存器npll值为0x01时
rate = (24 * nf / (nr * no)) * 1000000;

二,clk时钟数 divider/factor/gate/mux/ratio/link介绍
1,clk-divider分频器
执行分频功能的硬件电路
在Linux内核的通用时钟框架(CCF)中,CLK_DIVIDER_ONE_BASED 是一个用于时钟分频器(clk divider)的标志位,它定义了分频寄存器值与实际分频系数之间的映射关系。
当一个分频器时钟被设置为 CLK_DIVIDER_ONE_BASED 模式时,分频寄存器中的值直接等于实际的分频系数。例如,如果寄存器中存储的值是 5,那么输出时钟频率就是父时钟频率除以 5。
这与另一种常见的模式(非 ONE_BASED)形成对比:在非 ONE_BASED 模式下,寄存器值为 0 通常表示分频系数为 1(即不分频),寄存器值为 1 表示分频系数为 2,以此类推。而在 ONE_BASED 模式下,寄存器值 0 会被视为无效或特殊状态(通常避免使用),而 1 就代表分频系数为 1
clk_divider_set_rate
{
div = prate / rate;获取分频系数
if(pdat->onebased)
div--;
if(div > mask)
div = mask;
val = read32(pdat->virt);
val &= ~(mask << pdat->shift);
val |= div << pdat->shift;
val |= mask << (pdat->shift + 16);
write32(pdat->virt, val);
}
2,clk-gate开关控制
clk_gate_set_enable
{
val = read32(pdat->virt);
val &= ~(0x1 << pdat->shift);
if(enable)
val |= (pdat->invert ? 0x0 : 0x1) << pdat->shift;
else
val |= (pdat->invert ? 0x1 : 0x0) << pdat->shift;
val |= 0x1 << (pdat->shift + 16);
write32(pdat->virt, val);
}
3,clk-mux多路选择器
clk_mux_set_parent
{
for(i = 0; i < pdat->nparent; i++)
{
if(strcmp(pdat->parent[i].name, pname) == 0)
{
val = read32(pdat->virt);
val &= ~(((1 << pdat->width) - 1) << pdat->shift);
val |= pdat->parent[i].value << pdat->shift;
val |= ((1 << pdat->width) - 1) << (pdat->shift + 16);
write32(pdat->virt, val);
break;
}
}
}
4,clk-ratio 分频比
Clk Ratio(时钟分频比):这是一个数值参数或配置项,用于定义分频器的行为。它指明了输出时钟频率与输入时钟频率之间的比例关系。通常用一个整数 N 表示,表示输出频率是输入频率的 1/N。例如,当 clk_ratio 设置为10时,意味着分频器需要将输入时钟频率降低为原来的十分之一,此时分频器的分频系数 N 就是10。
peri_hclk_div_con
Control the divider ratio between aclk_periph
and hclk_periph
2'b00: aclk_periph:hclk_periph = 1:1
2'b01: aclk_periph:hclk_periph = 2:1
2'b10: aclk_periph:hclk_periph = 4:1

clk_ratio_set_rate
{
div = prate / rate;
if(div > mask)
div = mask;
val = read32(pdat->virt);
val &= ~(mask << pdat->shift);
/* fls - find last (most-significant) bit set,Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32*/
val |= fls(div) << pdat->shift;
val |= mask << (pdat->shift + 16);
write32(pdat->virt, val);
}
5,clk-link仅仅做父子绑定,通路使用
比如G0_3作为aclk_bus_pre的parent做一个link

6,divider和ratio的区别
两者的区别可以类比为:
Divider 是"做什么"------ 它是执行分频功能的硬件电路本身。
Clk Ratio 是"怎么做"------ 它是控制这个电路如何工作的配置参数。
简单理解,分频器(divider)是实现分频功能的模块,而分频比(clk ratio)是这个模块的一个关键设定值,决定了分频的倍数
7,clk-factor
clk-factor分数分频时钟(Fractional Divider Clock),这是一种能够产生非整数倍分频时钟信号的技术。与只能输出整数分频(如2分频、5分频)的简单计数器不同,分数分频器可以实现如3.5分频、13/3分频等精确的非整数分频比,这对于需要高精度时钟频率的系统(如通信、音频处理、高速串行接口)至关重要,比如图中S17

clk_gcd 求prate和rate的最大公因数
{
u64_t c;
while(b != 0)
{
c = a % b;
a = b;
b = c;
}
return a;
}
clk_factor_set_rate
{
cdiv = clk_gcd(prate, rate);求prate和rate的最大公因数
div = (prate / cdiv) & 0xffff;
mult = (rate / cdiv) & 0xffff;
write32(pdat->virt, (mult << 16) | (div << 0));
}
三,clk配置,包含配置parent rate和使能
在dts中分散在各个node中
比如
{ "name": "mux-dclk-vop0", "parent": "gpll", "enable": true },
{ "name": "div-dclk-vop0", "rate": 45000000, "enable": true },
关联这几个函数,就是配置和使能
clk_set_parent(name, parent);有些多路选择指定parent
clk_set_rate(name, rate);配置帧率
clk_enable(name)或clk_disable(name);使能