S3C2440下clock的源码分析

来源:互联网 发布:传智播客java笔记 编辑:程序博客网 时间:2024/06/08 11:22

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,}};

到此我们已经知道在系统启动后我们的那些时钟已经启动了,那些没有启动。


原创粉丝点击