s3c2440时钟的体系结构
OM控制使用内部时钟和内部时钟,详细情况可以看数据手册
这里使用的源代码版本是2.6.35.14
初始化时钟代码arch\arm\s3c2440\s3c244x.c
void __init s3c244x_init_clocks(int xtal) { /* initialise the clocks here, to allow other things like the * console to use them, and to add new ones after the initialisation */ s3c24xx_register_baseclocks(xtal); s3c244x_setup_clocks(); s3c2410_baseclk_add(); }
首先我们看一下s3c24xx_register_baseclocks(xtal)函数在这里注册时钟arch\arm\plat-samsung\clock.c
/* initalise all the clocks */ int __init s3c24xx_register_baseclocks(unsigned long xtal) { printk(KERN_INFO "S3C24XX Clocks, Copyright 2004 Simtec Electronics\n"); clk_xtal.rate = xtal; /* register our clocks */ if (s3c24xx_register_clock(&clk_xtal) < 0) printk(KERN_ERR "failed to register master xtal\n"); if (s3c24xx_register_clock(&clk_mpll) < 0) printk(KERN_ERR "failed to register mpll clock\n"); if (s3c24xx_register_clock(&clk_upll) < 0) printk(KERN_ERR "failed to register upll clock\n"); if (s3c24xx_register_clock(&clk_f) < 0) printk(KERN_ERR "failed to register cpu fclk\n"); if (s3c24xx_register_clock(&clk_h) < 0) printk(KERN_ERR "failed to register cpu hclk\n"); if (s3c24xx_register_clock(&clk_p) < 0) printk(KERN_ERR "failed to register cpu pclk\n"); return 0; }
这里面用到了s3c24xx_register_clock()函数看他是如何实现的
arch\arm\plat-samsung\clock.c
/* initialise the clock system */ /** * s3c24xx_register_clock() - register a clock * @clk: The clock to register * * Add the specified clock to the list of clocks known by the system. */ int s3c24xx_register_clock(struct clk *clk) { if (clk->enable == NULL) clk->enable = clk_null_enable; /* add to the list of available clocks */ /* Quick check to see if this clock has already been registered. */ BUG_ON(clk->list.prev != clk->list.next); spin_lock(&clocks_lock); list_add(&clk->list, &clocks); //添加到时钟列表中 spin_unlock(&clocks_lock); return 0; }
接下来我们看一下s3c244x_steup_clocks(xtal)函数
所在目录arch\arm\mach-s3c2440\s3c244x.c
void __init_or_cpufreq s3c244x_setup_clocks(void) { struct clk *xtal_clk; unsigned long clkdiv; unsigned long camdiv; unsigned long xtal; unsigned long hclk, fclk, pclk; int hdiv = 1; xtal_clk = clk_get(NULL, "xtal"); xtal = clk_get_rate(xtal_clk); clk_put(xtal_clk); fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2; clkdiv = __raw_readl(S3C2410_CLKDIVN); camdiv = __raw_readl(S3C2440_CAMDIVN); /* work out clock scalings */ switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) { case S3C2440_CLKDIVN_HDIVN_1: hdiv = 1; break; case S3C2440_CLKDIVN_HDIVN_2: hdiv = 2; break; case S3C2440_CLKDIVN_HDIVN_4_8: hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4; break; case S3C2440_CLKDIVN_HDIVN_3_6: hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3; break; } hclk = fclk / hdiv; pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1); /* print brief summary of clocks, etc */ printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); s3c24xx_setup_clocks(fclk, hclk, pclk); }
再看看s3c24xx_setup_clocks函数arch\arm\plat-s3c24xx\clock.c
/* initalise all the clocks */ void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk, unsigned long hclk, unsigned long pclk) { clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON), clk_xtal.rate); clk_mpll.rate = fclk; clk_h.rate = hclk; clk_p.rate = pclk; clk_f.rate = fclk; }
文件目录arch\arm\plat-s3c24xx\s3c2410-clock.c
/* s3c2410_baseclk_add() * * Add all the clocks used by the s3c2410 or compatible CPUs * such as the S3C2440 and S3C2442. * * We cannot use a system device as we are needed before any * of the init-calls that initialise the devices are actually * done. */ int __init s3c2410_baseclk_add(void) { unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); //快慢时钟寄存器 unsigned long clkcon = __raw_readl(S3C2410_CLKCON); //时钟控制寄存器 struct clk *clkp; struct clk *xtal; int ret; int ptr; clk_upll.enable = s3c2410_upll_enable; //记录使能函数 if (s3c24xx_register_clock(&clk_usb_bus) < 0) //注册USB时钟 printk(KERN_ERR "failed to register usb bus clock\n"); /* register clocks from clock array */ clkp = init_clocks; //初始化要注册的clock列表 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { /* ensure that we note the clock state */ clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; //判断clock当前的状态 ret = s3c24xx_register_clock(clkp); //注册clock列表 if (ret < 0) { printk(KERN_ERR "Failed to register clock %s (%d)\n", clkp->name, ret); } } /* We must be careful disabling the clocks we are not intending to * be using at boot time, as subsystems such as the LCD which do * their own DMA requests to the bus can cause the system to lockup * if they where in the middle of requesting bus access. * * Disabling the LCD clock if the LCD is active is very dangerous, * and therefore the bootloader should be careful to not enable * the LCD clock if it is not needed. */ /* install (and disable) the clocks we do not need immediately */ s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); //注册启动不需要使用的clock列表 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); //禁止clock列表中的各项时钟 /* show the clock-slow value */ xtal = clk_get(NULL, "xtal"); //获得xtal的时钟 printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n", print_mhz(clk_get_rate(xtal) / ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))), (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast", (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); s3c_pwmclk_init(); //初始化PWM时钟
return 0;
}
看看init_clocks中都有哪些时钟目录arch\arm\plat-s3c24xx\s3c2410-clock.c
static struct clk init_clocks[] = { { .name = "lcd", .id = -1, .parent = &clk_h, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_LCDC, }, { .name = "gpio", .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_GPIO, }, { .name = "usb-host", .id = -1, .parent = &clk_h, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_USBH, }, { .name = "usb-device", .id = -1, .parent = &clk_h, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_USBD, }, { .name = "timers", .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_PWMT, }, { .name = "uart", .id = 0, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_UART0, }, { .name = "uart", .id = 1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_UART1, }, { .name = "uart", .id = 2, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_UART2, }, { .name = "rtc", .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_RTC, }, { .name = "watchdog", .id = -1, .parent = &clk_p, .ctrlbit = 0, }, { .name = "usb-bus-host", .id = -1, .parent = &clk_usb_bus, }, { .name = "usb-bus-gadget", .id = -1, .parent = &clk_usb_bus, }, };
再看看init_clocks_0ff中都有哪些时钟目录arch\arm\plat-s3c24xx\s3c2410-clock.c
* standard clock definitions */ static struct clk init_clocks_off[] = { { .name = "nand", .id = -1, .parent = &clk_h, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_NAND, }, { .name = "sdi", .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_SDI, }, { .name = "adc", .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_ADC, }, { .name = "i2c", .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_IIC, }, { .name = "iis", .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_IIS, }, { .name = "spi", .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_SPI, } };
到此我们已经知道在系统启动后我们的那些时钟已经启动了,那些没有启动。
S3C2440下clock的源码分析
最新推荐文章于 2018-12-21 16:46:42 发布