很多硬件的正常运行需要有总线时钟的支持,比如LCD、I2C等设备。
本文分析一下s3c2440的总线时钟,以及在linux中对s3c2440总线时钟频率的相关操作。
首先分析硬件s3c2440的总线时钟。
s3c2440的FCLK HCLK PCLK
时钟源首先来自外部晶振12MHz。
对于必须运行在200MHz以上的ARM920t内核来说,这个频率实在太低了,不能直接使用,所以首先要通过s3c2440片上
的pll硬件电路将12MHz的晶振时钟信号升频,而具体升到多少MHz是通过MPLL控制寄存器来控制的。
比如MPLLCON赋值为 0x5c<<12 | 2<<4 | 1就可以将 PLL电路的输出时钟设置为400MHz,也就是
将12MHz的外部时钟升频为400MHz供s3c2440使用。另外系统的USB时钟可以配置UPLL来获取USB所需的合适时钟信号,此处不介绍。
当PLL可以稳定输出时,其输出信号直接给FCLK使用,FCLK连接的是s3c2440的ARM内核。相当于ARM内核运行在400MHz了。
那i2c控制器LCD控制器等外设的时钟怎么获取呢?
s3c2440的外设时钟有两条,分别是PCLK、HCLK。
使用PCLK的外设有:WDT, IIS, I2C, PWM timer, MMC interface,ADC, UART, GPIO, RTC and SPI(IO型)
使用HCLK的外设有:memory controller,interrupt controller,LCD controller, DMA and USB host block(总线型)
对上述外设来经过PLL升频后的400MHz的频率太高了,需要降频使用,所以通过分频器将FCLK的频率降下来给PCLK、HCLK使用。
那么降低多少怎么控制呢?
可以通过分频控制寄存器CLKDIVN来控制。
例如将CLKDIVN赋值0x5时 也就是FCLK:HCLK:PCLK = 1:4:8 = 400MHz:100MHz:50MHz。
U-boot、linux中对s3c2440时钟的设置
s3c2440的总线时钟是在bootload中就设置好的。linux中只是读取了MPLL以及CLKDIVN寄存器中的值,通过这些数值
来算出s3c2440当前运行的频率,而并不会对其修改!
uboot对时钟的设置再board_init()函数中完成。
linux对时钟方面的设置是在smdk2440_map_io->s3c24xx_init_clocks()->(cpu->init_clocks)(xtal);
此处的cup数值为arch/arm/plat-s3c24xx/cpu.c中的cpu_ids数组。
s3c2440的代码为0x32440001,时钟初始话函数为s3c244x_init_clocks。
在此函数中
调用s3c244x_setup_clocks来计算当前设备运行的频率等。
调用s3c2410_baseclk_add函数将i2c uart spi rtc等需要使用时钟的外设通过链表链接起来。