您的位置:首页 > 编程语言

关于 如何实践kernel/driver/u-boot ,怎么样按照作者的思路实现自己的代码

2012-07-26 00:11 573 查看
 给你指一个方向或者说是方法, 可以提高自己编程kernel/driver/u-boot的能力,或者说写code的能力。
 
 
举个例子,
 
比如说 kernel 里面的clock时钟的初始化部分, kernel的代码也不复杂, 但是我们要达到的目标就是 根据datasheet 能自己写出来,而不仅仅能看明白, 好比说 ,
会看小说的人,不见得都会写小说, 金庸只有一个。 我们现在就要作金庸。只有试着写 ,才能作为作家。  
 
 
只是举个简单的例子:至少我是这样来练习的,
你可以对照你自己的u-boot或者omap5912 作类似的动作。 方法都是一样的。 总之, 就是截取现有的功能, 自己试着实现它, 久而久之, 能力就提高了。
 
看的时候, 对照着原来的driver 和datasheet ,了解到流程很简单,
 
1> 读取 MPLLCON 寄存器 , 比如读到 mpllcon_value 变量中,
2> 对 mpllcon_value 分别移位操作, 取得 MDIV ,PDIV ,SDIV
3> 利用公式:
Mpll = (m * Fin) / (p * 2^s)
m = (MDIV + 8), p = (PDIV + 2), s = SDIV
4> fclk = Mpll
 
5》 读取 CLKDIVN 寄存器 ,
 
6》 然后作相应的计算: 求出 FCLK , HCLK , PCLK (WATCHDOG 用到了,我们kernel就要初始化)
 
HDIVN
[1]
0: HCLK has the clock same as the FCLK.
0
 
 
1: HCLK has the clock same as the FCLK/2.
 
PDIVN
[0]
0: PCLK has the clock same as the HCLK.
0
 
 
1: PCLK has the clock same as the HCLK/2.
 
 
 
 
到现在流程已经知道了,  估计 2410自带的代码也忘记的差不多了,那就可以自己写了。   只有自己写, 才能发现自己的问题, 也才能领会 作者那样写的妙处,当然作者也不见得都对
 
 
我就自己重新实现了一个,
 
我自己写的时候, 就会考虑几个问题,
 
1> 我是要int 还是用 u32 ,会不会溢出呢?还有可移植性。
2> 小的临时变量 是用 u8 , 还是 u32
3> datasheet 有没有提到有些操作需要delay ,比如 delay(400) 什么的?
4> 最后 拿到板子上去验证。 看写的有没有问题?
 
 
 
自己实现的,  后面 有 2410 作者写的。 自己对比一下 。  
 
 
static inline u32 s3c2410_get_pll_bob_version(u32 Fin, u32 mpllcon_value)
{
       //u8 is enought for mdiv and pdiv and sdiv
       u8 mdiv = 0; //作者都用
       u8 pdiv = 0;
       u8 sdiv = 0;
 
       u32 mpll = 0;
 
//相比作者的代码, 这里面没有用 宏来标记一些bit 或者bitmask 。别人看起来可能一头污水, 不过标出来
//refer P240  CLOCK DIVIDER CONTROL (CLKDIVN) REGISTER     这样别人就一下子知道了。
 
       mdiv = (mpllcon_value & ((1<<20) -1)) >> 12;
       pdiv = (mpllcon_value & ((1<<10)-1)) >>4;
       sdiv = (mpllcon_value & ((1<<2)-1)) >> 0;   //我个人觉得 >> 0 很有意义。比不加强。
 
//see manual P237
       mpll = (mdiv+8) * Fin;
       mpll /=(pdiv+2);
       mpll >>= sdiv;
 
       printk("in s3c2410_get_mpll_bob_version() , mpll = %u\n",mpll);
      
       return mpll;
 
}
 
void __init s3c2410_init_clocks(int xtal)   //Õa¸öxtal¾íêÇ»ù±¾μÄêäèëÆμÂê12MHz
{
 
       u32 mpll = 0;
       u32 clock_mpllcon = 0;
       u32 fclk = 0;
       u32 hclk =0;
       u32 pclk = 0;
 
       u32 HDIVN1 = 0;
       u32 HDIVN = 0;
       u32 PDIVN = 0;
 
      
       clock_mpllcon = ioread32(S3C2410_MPLLCON);
      
       mpll = s3c2410_get_pll_bob_version((u32)xtal,clock_mpllcon);
 
       fclk = mpll;
 
       if(HDIVN1 = ioread32(S3C2410_CLKDIVN) & (1<<2))
       {
              hclk = pclk = fclk/4;  //
       }
       else {
              hclk = (HDIVN = ioread32(S3C2410_CLKDIVN) & (1<<1) )? fclk/2:fclk;
              pclk = (PDIVN = ioread32(S3C2410_CLKDIVN) & (1<<0) )? hclk/2:hclk;
       }
 
       printk("fclk = %u, hclk=%u, pclk=%u\n",fclk,hclk,pclk);
 
      
 
。。。。
 
 
+++++++++++++++++++++++++++++++++++++++++++++++++++
 
然后再对照作者的程序的着两个函数, 对比 看看差距在哪里???只有找出差距, 才能提高自己!
 
 
 
 
static inline unsigned int
s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
{
       unsigned int mdiv, pdiv, sdiv;
       uint64_t fvco;
//作者用了一些宏 ,但是这么简单的操作 ,弄两次似乎不是很好。这就没什么说得了, 个人喜好不同, 不算差距。
       mdiv = pllval >> S3C2410_PLLCON_MDIVSHIFT;
       pdiv = pllval >> S3C2410_PLLCON_PDIVSHIFT;
       sdiv = pllval >> S3C2410_PLLCON_SDIVSHIFT;
 
       mdiv &= S3C2410_PLLCON_MDIVMASK;
       pdiv &= S3C2410_PLLCON_PDIVMASK;
       sdiv &= S3C2410_PLLCON_SDIVMASK;
 
       fvco = (uint64_t)baseclk * (mdiv + 8);
       do_div(fvco, (pdiv + 2) << sdiv);
 
       return (unsigned int)fvco;
}
 
 
void __init s3c2410_init_clocks(int xtal)  
{
       unsigned long tmp;
       unsigned long fclk;
       unsigned long hclk;
       unsigned long pclk;  //干吗都声明成 unsigned long ,实际上 ,unsigned int 就足够了(当然int与long长度相同)
//更好的办法是  用 u32 来表示, 因为 32 bit 肯定够了。 作者的移植性不好。
 
       /* now we've got our machine bits initialised, work out what
        * clocks we've got */
 
       fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);  //用 __raw_readl() 更是勉强,事上 , kernel早就不推荐用 __raw_readl ()了, 应该 用 ioread32()
 
       tmp = __raw_readl(S3C2410_CLKDIVN); //同上
 
       /* work out clock scalings */
/* 这里功能上就少了一个: if(HDIVN1 = ioread32(S3C2410_CLKDIVN) & (1<<2))  ,按照datasheet :
 
HDIVN1
[2]
Special bus clock ratio available. (1:4:4) 0: Reserved 1: HCLK has the clock same as the FCLK/4. PCLK has the clock same as the FCLK/4. Note: If this bit is "0b1", HDIVN and PDIVN must be set "0b0".
 
写程序的时候要体现出来这样的判断
0
HDIVN
[1]
0: HCLK has the clock same as the FCLK. 1: HCLK has the clock same as the FCLK/2.
0
PDIVN
[0]
0: PCLK has the clock same as the HCLK. 1: PCLK has the clock same as the HCLK/2.
0
 
应该要判断 bit[2] 的, 但是作者仅仅判断了 bit0和bit1 ,就是不对的。
 
 
*/
//少了对 HDIVN1 的判断。
       hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);
       pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c delay 编程 div
相关文章推荐