前言
要想使一个硬件模块工作的话,最基本的几点:
- 根据原理图设置GPIO,比如i2c, 需要确定core上的哪个GPIO复用为 SDA,SCL等
- 设置好时钟 (为了工作,通过时钟,使得通信的步调一致)
- 接入电源(PMIC)
一般情况下,开发驱动的时候我们很少关注 时钟的设置,因为都是原厂给配好的,但是原厂配置难免也有不符合需求的情况,比如i2c controller配置的时钟频率不够等,比如说默认配置是 200M,但是外设需要400M的通信速度,所以就需要修改默认时钟频率,查看代码就发现很多函数类似于:clk_get, clk_set_rate等,那它们是怎么得来的呢? ,不急,慢慢来。
时钟的概念
这里说的时钟,并不是指时间,而是指硬件之间通信的 “步调”,就像我们说话一样,要想彼此间明白,汉字就是规则,语速就是"步调"。
同理硬件也是一样的,两边传输数据,一定要有规则,比如I2c,spi等,每一种规则中,都要有一个稳定的"步调"来指挥数据的传输,还是拿i2c来做比喻,两条线,SCL,SDA,其中SCL是时钟线.
- 步调:通信时,master就在 SCL上就发出稳定的时钟脉冲,
- 规则:SCL为高脉冲时放入一个数据(即SDA 线拉高(1)还是拉低(0)),slave端侧在 SCL由高变低的时候,接收一个字符(取出SDA的值),这个放数据&收数据的动作 ,都是靠SCL这个时钟,并且我们也可以看出,SCL越快,传入数据的速率也就越快。
时钟树
我们知道每个板子内部有很多的硬件模块,我们可以理解为有很多的控制器(controller),这些控制器都有 “插槽”,用于外设的插入,比如: spi controller, usb controller, lcd controller 等等,这些controller 在linux的领域被叫做 platform device。当外设插到这个"插槽"中,设定好规则(通信协议)跟步调(时钟),就可以工作,但是由于外设的工作频率不尽相同,所以各个controller发出的频率也要不一样,所以我们要解决的问题是,如何分配给controller时钟呢? 靠的就是倍频跟分频。
-
倍频:在cpu core的的组成中有很多用于把时钟提高的模块,我们叫做锁相环,软件用pll表示。
板子上电后,晶振震荡稳定后,之后流入各个pll中,通过pll后,频率被扩大数倍甚至数十倍,比如目前我用的全志的T7,晶振是 24Mhz,流入pll后,变为 800Mhz。 -
分频:低速设备不需要那么大的频率,可以 pll之后,通过div进行分频,从而降低频率,提供给低速设备的controller。
由于目前soc都异常强大,无数的分频与倍频,所以就形成了个树状。
我们这里举个实际的例子:
项目中需要 打出 1080@60fps的图像,我们要设置lcd_controller的时钟频率,时钟的名字叫做 tcon_lcd0.
如上图,就是一个时钟树,首先 -
板子上电后,晶振24Mhz
-
之后晶振产生的脉冲经过 一裤衩子 pll(上图中只是一部分)进行倍频,比如PLL_VIDEO0(1x)倍增为 297HMz,那297HMz 是从哪里来的呢?关于PLL_VIDEO0有对应的寄存器,寄存器中有倍增系数,设定的越高,值越大。
可以看到,PLL_VIDEO0(1x) 寄存器默认 N: 0x62+1, M: 0x7+1.
经过计算得出 PLL_VIDEO0(1x) = (24Mhz(晶振) X 99) / 8 = 297 (上图表示的值)
我们可以知道,晶振的时钟脉冲,流入了 PLL_VIDEO0,即 PLL_VIDEO0的父亲就是 hosc(晶振),
经发现基本上所有 pll的父亲都是 hosc,他们都是基于 父亲的时钟,调节倍频系数(M,N),从而达到倍频效果。
但也有例外,请往下看。 -
之后 经过 PLL_VIDEO0(1x) 脉冲,流入了 PLL_MIPI,提供时钟的 PLL_VIDEO0(1x) ,就是父亲,获取时钟的PLL_MIPI,就是孩子。
即: PLL_MIPI->parent = PLL_VIDEO0(1x) 。然后经过 PLL_MIPI继续扩大,变为了 594Mhz。
这里为了加深理解,我们在看一下寄存器的值:
我们可以看到 PLL_MIPI的父亲只有 PLL_VIDEO0(不是从 hsoc)并且默认频率是 297Mhz X 6X2 /6 = 595Mhz,即也是基于流过来的时钟频率(父亲),调节倍频系数,进行倍频。
完全符合上图信息。 -
接下来,PLL_MIPI的时钟,会经过选择TCON_LCD0,我们可以看到 TCON_LCD0有可以选择很多的 输入来源,即,可以选择很多的parent,我们看下寄存器
我们发现,tcon_lcd0 可以设置5个 clock Source,即parent,另外,注意它没有 分频系数
同上面的途中也可以看出,TCON_LCD这条线没有 /m /n,即不用除m,在除n,另外,可以看下TVE的这个分支
可以看出 tve 的父时钟也可以设置为 pll_mipi,并且有分频系数。
所以综上我们可以看到,一个pll底下,可以同时设定有多个 children,一个 children可以选择多种parent,但每次只能选一个。