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

 给你指一个方向或者说是方法, 可以提高自己编程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)   //Õö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);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值