linux2.4内核启动流程简述及2410主频修改

内核版本2.4.18

一、linux2.4内核启动流程

arch/arm/boot/compressed/head.s ----->调用arch/arm/boot/compressed/misc.c的decompress_kernel()
函数解压内核。---->arch/arm/kernel/head-armv.s 初始化 --->
init/main.c的asmlinkage void __init start_kernel(void)

 

二、修改2410linux主频

(1)代码修改

在内核启动之时切换CPU主频arch/arm/boot/compressed/head.S,代码如下(主频设为264M):
        ldr  r8, =0x4C000000
        ldr  r9, =0xffffff
        str  r9, [r8]

        ldr  r8, =0x4C000014
        mov  r9, #3
        str  r9, [r8]

        ldr  r8, =0x4C000004
        ldr  r9, =0xa8021
        str  r9, [r8]

        ldr  r8, =0x50000028
        ldr  r9, =0x23
        str  r9, [r8]

 

(2)问题及bug。若将2410的主频设为266M等其他,内核启动都会停在:

Uncompressing Linux......................................................................................................................... done, booting the kernel.

网上很多人遇到的情况与此不同,很多都是启动参数配置错误导致或CPU的id与内核不匹配导致。

此因修改了2410的主频原因导致,根本原因不是2410(尾数为20)不能支持这么高的频率

也不是内存clk频率过高而导致的不稳定。而是kernel的start_kernel()函数中对timer的

初始化有bug。

./arch/arm/kernel/time.c:void __init time_init(void)

include/asm-arm/arch-s3c2410/time.h:static inline void setup_timer(void)

在第二个函数中代码修改如下:

-----------------

static inline void setup_timer(void)
{
    struct timer_counts *timer_count = count_values;
    unsigned long pclk;

    gettimeoffset = s3c2410_gettimeoffset;
    set_rtc = s3c2410_set_rtc;
    xtime.tv_sec = s3c2410_get_rtc_time();

    /* set timer interrupt */
    /*TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(15) | TCFG0_PRE0(0));*/

    TCFG0 = (15<<8)|32;

    pclk = s3c2410_get_bus_clk(GET_PCLK)/1000;

/*(TCFG0_DZONE(0) | TCFG0_PRE1(30) | TCFG0_PRE0(((pclk/2000000)-1)));*/

    //while (timer_count != 0) {   //---------------fix bug------------leaven
    while(timer_count->freq != 0){
        if (pclk == timer_count->freq) {
            printk("DEBUG: timer count %d\n", timer_count->count);
            TCNTB4 = timer_count->count;
            break;
        }
        timer_count++;
    }

    //if (timer_count == 0) {   //------------------fix bug---------leaven
    if(timer_count->freq==0){
            /* Error, assume that PCLK is 50 Mhz */
        TCNTB4 = 15626;    /* down-counter, maximum value is 65535 (2^16) */
    }

    TCON = (TCON_4_AUTO | TCON_4_UPDATE | COUNT_4_OFF);   
    timer_irq.handler = s3c2410_timer_interrupt;
    setup_arm_irq(IRQ_TIMER4, &timer_irq);
    TCON = (TCON_4_AUTO | COUNT_4_ON);
}

-----------------

从如下代码中可以看到linux2410默认支持的主频是有限的,如要设置自己的频率需要加入新的成员至数组中:

-----------------

/*
* priod = (prescaler value + 1) * (divider value) * buffer count / PCLK = 10 ms
*
* e.g.; PCLK = 50 Mhz
* 10 ms = (15 + 1) * 2 * 15625 / (50000 * 1000)
* 15626 = 10 ms * (50000 * 1000) / 2 / (15 + 1)
*
* Other values
*  5156 = 10 ms * ( 16.5 * 1,000,000) / 2 / (15+1)
*  6250 = 10 ms * ( 20 * 1,000,000) / 2 / (15+1)
* 10312 = 10 ms * ( 33 * 1,000,000) / 2 / (15+1)
* 20625 = 10 ms * ( 66 * 1,000,000) / 2 / (15+1) //for 264M
* 21875 = 10 ms * ( 70 * 1,000,000) / 2 / (15+1)
* 23437 = 10 ms * ( 75 * 1,000,000) / 2 / (15+1)
* 25000 = 10 ms * ( 80 * 1,000,000) / 2 / (15+1)
* 28125 = 10 ms * ( 90 * 1,000,000) / 2 / (15+1)
* 31250 = 10 ms * ( 100 * 1,000,000) / 2 / (15+1)
*/
struct timer_counts count_values[] = {
    {  16500,     5156 },
    {  20000,     6250 },
    {  33000,    10312 },
    {  50000,    15626 },
    {  66000,    20625 },
    {  70000,    21875 },
    {  75000,    23437 },
    {  80000,    25000 },
    {  90000,    28125 },
    { 100000,    31250 },
    {      0,        0 }    /* last entry */
};

-----------------

arch/arm/kernel/Makefile中对time.c的编译十分特别,别的都是*.o 而其为time.module

你可能感兴趣的:(linux)