基于S3C2440的bootloader详细分析(2)

本文深入分析了S3C2440处理器的启动过程,包括硬件初始化、时钟配置、串口设置等关键步骤,并介绍了相关的寄存器配置和函数实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第二阶段代码详细分析

void Main(void)         //第八个函数

{

char *mode;       //定义一个指针变量mode,这个指针指向的内容为char

int i,j;

U8 key;       //U8unsigned char型,在def.h里定义

U32 mpll_val;  //U32unsigned int型,在def.h里定义

    

#if ADS10     //#define  ADS10  1,在Option.h里定义

__rt_lib_init();  //for ADS 1.0

/*

调用_rt_lib_init()初始化引用的库函数,在ADS1.2的环境中,如果在C入口没有调用编译器的链接库(__main),那么在C程序一开始要调用该函数以初始化运行时的函数库,以保证对ADS提供的某些库函数能够正常调用。从这个函数开始,我们已经在C语言环境下了

*/

#endif

Port_Init();     //2440lib.c里定义,GPIO口定义

/*

S3C2440130个管脚。可以通过软件配置每个管脚的功能来满足系统及外设的要求。所以在程序开始之前,你必须定义每个管脚的配置。

端口初始化,设置GPA/B/C/D/E/F/G/H/J相应的管脚,EXTINT0/1/2/3   

*/

Isr_Init();      //第十一个函数,初始化中断服务程序

/*

设置中断服务程序,初始化。

把所有中断设置为IRQ模式,屏蔽所有中断请求

*/

i = search_params();  //  nand_lowlevel.c里定义,查询启动参数,这个函数比较难理解

j=2;   //有效的j值为2

if(boot_params.display_mode.val==2) j=3;       //TV mod,这里是lcd模式

        //{"displayM",  0}, //0= lcd 1=vga 2=tv

switch(j) {

case 0://240

key = 14;

mpll_val = (112<<12)|(4<<4)|(1);

break;

case 1://320

key = 14;

mpll_val = (72<<12)|(1<<4)|(1);

break;

case 2://400

key = 14;

mpll_val = (92<<12)|(1<<4)|(1);  //mpll_val,倍频因子

break;

case 3://420!!!

key = 14;

mpll_val = (97<<12)|(1<<4)|(1);

break;

default:

key = 14;

mpll_val = (92<<12)|(1<<4)|(1);

break;

}

#if 1

//init FCLK=400M, so change MPLL first

ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

   //2440lib.c里定义,用于CPU及其他外围器件工作频率设置

/*

ChangeMPllValue改变MPLLCON的值,MPLL的值影响FCLK。但是设置MPLL,在2440init.s已经完成了,也是FCLK=400Mhz.UPLL2440init.s里设置了。

*/

ChangeClockDivider(key, 12);   

/*

设置MPLLCON后,得到FCLK的值。再设置CLKDIVN,得到HCLKPCLK的值,使得FCLK:HCLK:PCLK=1:4:8。如果FCLK:HCLK!=1:1,还要执行,MMU_SetAsyncBusMode()。同2440init.s一样

*/

//2440lib.c里定义

cal_cpu_bus_clk();  //第七个函数计算FCLKHCLKPCLKUCLKcpu_freq

// #define MEGA (1000000),在Option里已经定义

if(PCLK<(40*MEGA))

   {

ChangeClockDivider(key, 11);//2440lib.c里定义

cal_cpu_bus_clk();

   }

#else

cal_cpu_bus_clk();

#endif

consoleNum=boot_params.serial_sel.val&3;  // Uart 1 select for debug.

if(consoleNum>1)consoleNum=0;

Uart_Init(0,115200/*boot_params.serial_baud.val*/);

    //UART初始化。此函数定义在2440lib.c

Uart_Select(consoleNum);

//S3C2440共有三个UART。在2440lib.c的静态变量whichUart=consoleNum。在此选择UART0

//Uart_Select(consoleNum) 默认用串口0,如果用户要用别的串口的话请修改这里

MMU_Init();//MMU.C里定义,内存存储管理

Uart_SendByte('\n');  //发送字节函数,在2440lib.c里定义

#if 1

Uart_Printf(" +------------------------------------------------------------+\n");

Uart_Printf(" |   TE/OK2440 Bootloader VER-5.1    www.witech.com.cn |\n");

Uart_Printf(" |------------------------------------------------------------|\n");

Uart_Printf(" |------------------------------------------------------------|\n");

Uart_Printf(" |CPU ID is 0x%                |\n", rGSTATUS1);

if(i==-1) 

      {

Uart_Printf(" |  Fail to found boot params!      |\n");

save_params();

  }

Uart_Printf(" |FCLK=%dMHz,HCLK=%dMHz,PCLK=%dMHz, CPU is running at %dMHz|\n",FCLK/MEGA, HCLK/MEGA, PCLK/MEGA, cpu_freq/MEGA);

Uart_Printf(" |UPLL=%dMHz, UCLK=%dMHz                                      |\n", UPLL/MEGA, UCLK/MEGA);

Uart_Printf(" |Serial port %d, Baud rate is %d.                         |\n", boot_params.serial_sel.val, boot_params.serial_baud.val);

Uart_Printf(" |OS image stored in %s Flash.                              |\n","NAND");

Uart_Printf(" |Autoboot delay is %d seconds.                                |\n", boot_params.boot_delay.val);

VGA_init();  //CH7026_IIC.c里定义 ,显示屏初始化

if(boot_params.boot_delay.val)    //boot_params.boot_delay.val==2

init_autorun_timer(boot_params.boot_delay.val);

Uart_Printf(" +------------------------------------------------------------+\n");

#else

Uart_Printf("FEILING 2440 Bootloader VER-5.0    www.witech.com.cn\n");

if(i==-1) 

     {

Uart_Printf("Fail to found boot params!\n");

save_params();

 }

Uart_Printf("Autoboot delay is %d seconds.\n", boot_params.boot_delay.val);

VGA_init();

if(boot_params.boot_delay.val)

init_autorun_timer(boot_params.boot_delay.val);//初始化延时函数

#endif

/*

rMISCCR2440addr.h中定义。其原型为 #define rMISCCR (*(volatile unsigned *)0×56000080)0×56000080为寄存器MISCCR的地址值。

*(volatile unsigned *)0×56000080 含义:因为()优先级高于*,所以先执行(volatile unsigned *)0×56000080 这个表示将0×56000080强制转化为指针类型,指针指向的类型是unsigned,指针存放的地址为0×56000080。也就是说指针指向寄存器MISCCR。然后在执行()外面的*,表示取出指针所指向的值。

     整个表达式,就是取出寄存器MISCCR中存放的值。但rMISCCR的值改变,寄存器MISCCR中的值也随着改变。

    清零MISCCR[3],即use USB1 as device

    rMISCCR=rMISCCR&~(1<<3); // USBD is selected instead of USBH1

    清零MISCCR[13],USB port1 suspend mode=normal mode

    rMISCCR=rMISCCR&~(1<<13); // USB port 1 is enabled.

*/

rMISCCR=rMISCCR&~(1<<3); // USBD is selected instead of USBH1 

rMISCCR=rMISCCR&~(1<<13); // USB port 1 is enabled.

//extern volatile int isUsbdSetConfiguration;

isUsbdSetConfiguration=0;

rDSC0 = 0x2aa;

rDSC1 = 0x2aaaaaaa;

if(0) 

      {

int i;

volatile U16 *p = (volatile U16 *)0x08000000;

p[3] = 0xbf;

p[2] = 0;

p[3] = 0;

p[2] = 1;

printf("dr2=0x%04x\n", p[2]);

for(i=0; i<8; i++)

printf("0x%08x\n", p[i]);

}

//ISR_STARTADDRESS=0x33ff_ff00

//将值(0x33ff_ff00+0xf0)的值,载入到pISR_SWI的地址中(0x33ff_ff00+0×8

pISR_SWI=(_ISR_STARTADDRESS+0xf0);//for pSOS

Led_Display(0x6);  //2440lib.c里定义

#if USBDMA   //Option.h里定义为真

mode="DMA";

#else

mode="Int";

#endif

Clk0_Disable();  //第十九个函数

Clk1_Disable();  //第二十个函数

/*

GPH9设置为input,其值为10时,管脚功能是CLKOUT0

    Clk0_Disable();

GPH10设置为input,其值为10时,管脚功能是CLKOUT1

    Clk1_Disable();

*/

mpll_val = rMPLLCON;  //2440addr.h里定义

Lcd_Tft_LTV350QV_F05_Init();    //by pht.Lcd.c里定义

download_run=1; //The default menu is the Download & Run mode.

while(1)

{

if(menuUsed==1)Menu();

WaitDownload();

}

}

分析部分

1、 boot_paramsbootpara.h里定义

typedef struct {

ParamItem start;

//ParamItem cpu_clk;

ParamItem boot_delay;

ParamItem serial_sel;

ParamItem AppRun_addr;

ParamItem serial_baud;

ParamItem machine;

ParamItem run_addr;

ParamItem root_sel;

ParamItem tty_sel;

ParamItem display_sel;

ParamItem display_mode;

ParamItem initrd_addr;

ParamItem initrd_len;

ParamItem mem_cfg;

//ParamItem devfs_sel;

//ParamItem osstor;

ParamItem user_params;

char string[128];

unsigned int bpage[50];

} BootParams;

BootParams boot_params = {

{"auto-run", 3}, //0=boot without parameters,1=boot with parameters

//{"cpuclk",   2}, //0=200M, 1=300M, 2=400M, 3=440M

{"rundelay", 0}, //0 seconds

{"serial",   0}, //0=serial port 0, 1=serial port 1

{"AppRunAddr",   0x32000000},

{"baudrate", 115200},

{"machine",  193},

{"runAddr",  0x30201000},

{"rootfs",   3},

{"tty",      0},

{"displayS",  0}, //0=320*240  1=640*480 2 = 800*600

{"displayM",  0}, //0= lcd 1=vga 2=tv

{"initrdA",  0x30200000},

{"initrdL",  0x02000000},

{"memsize",  0x04000000},

//{"devfs",    1},

//{"ostore",   0}, //0=nand, 1=nor

{"userpara", sizeof(DEFAULT_USER_PARAMS)},

DEFAULT_USER_PARAMS,

{0}

};

2

void ChangeClockDivider(int hdivn_val,int pdivn_val)

{

int hdivn=2, pdivn=0;

     // hdivn_val (FCLK:HCLK)ratio hdivn

     // 11           1:1       (0)

     // 12           1:2       (1)

     // 13           1:3       (3) 

     // 14           1:4       (2)

     // pdivn_val (HCLK:PCLK)ratio pdivn

     // 11           1:1       (0)

     // 12           1:2       (1)

switch(hdivn_val) {

case 11: hdivn=0; break;

case 12: hdivn=1; break;

case 13:

case 16: hdivn=3; break;

case 14: 

case 18: hdivn=2; break;

}

3、 第七个函数

static void cal_cpu_bus_clk(void)

{

U32 val;

U8 m, p, s;

val = rMPLLCON;

m = (val>>12)&0xff;

p = (val>>4)&0x3f;

s = val&3;

//(m+8)*FIN*2 不要超出32位数!

FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;  //计算FCLK

val = rCLKDIVN;

m = (val>>1)&3;

p = val&1;

val = rCAMDIVN;

s = val>>8;

//判断HCLKFCLK的比例

switch (m) {

case 0:

HCLK = FCLK;

break;

case 1:

HCLK = FCLK>>1;

break;

case 2:

if(s&2)

HCLK = FCLK>>3;

else

HCLK = FCLK>>2;

break;

case 3:

if(s&1)

HCLK = FCLK/6;

else

HCLK = FCLK/3;

break;

}

if(p)

PCLK = HCLK>>1;

else

PCLK = HCLK;

if(s&0x10)

cpu_freq = HCLK;

else

cpu_freq = FCLK;

val = rUPLLCON;

m = (val>>12)&0xff;

p = (val>>4)&0x3f;

s = val&3;

UPLL = ((m+8)*FIN)/((p+2)*(1<<s));

if(UPLL==96*MEGA)

rCLKDIVN |= 8; //UCLK=UPLL/2

UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;

}

4

int VGA_init(void)

{

int ret;

IIC_IO_init();

if(!boot_params.display_mode.val)return 0;//TV mode

ret = check_CH7026() ;

if (ret) {

printk(" |Can't find VGA chip !                                       |\n");

return ret;

}

printk(" |Initial VGA now, Please wait...                             |\n");

// Write CH7026_RegMap.rem to registers of CH7026:

CH7026_config();

// Power up CH7026:

CH7026_sccb_sendbyte(0x04, CH7026_sccb_receivebyte(0x04)&0xfe);//// set bit 0 to '0'

/*

// Memory initializaion:

if ( !CH7026_MemInit() )

{

printk("CH7026 Memory init can not be completed.\n");

}

CH7026_sccb_sendbyte(0x09, CH7026_sccb_receivebyte(0x09)|0x09);

// Start running:

CH7026_sccb_sendbyte(0x06, CH7026_sccb_receivebyte(0x06) & 0xFE); // set bit 0 to 0.

*/

//printk("{ 0x%02x, 0x%02x },\n", 0x06, CH7026_sccb_receivebyte(0x06));

return 0;

}

5

static void init_autorun_timer(int sec)

{

U32 val = (PCLK>>4)/100-1;

autorun_10ms = sec*100;

pISR_TIMER4 = (U32)autorun_proc;

rTCFG0 &= ~(0xff<<8);

rTCFG0 |= 3<<8; //prescaler = 3+1

rTCFG1 &= ~(0xf<<16);

rTCFG1 |= 1<<16; //mux = 1/4

rTCNTB4 = val;

rTCON &= ~(0xf<<20);

rTCON |= 7<<20; //interval, inv-off, update TCNTB4&TCMPB4, start timer 4

rTCON &= ~(2<<20); //clear manual update bit

EnableIrq(BIT_TIMER4);

}

6

void Led_Display(int data)

{

          //Active is low.(LED On)

          // GPF6  GPF5   GPF4   GPF3

          //nLED_3 nLED2 nLED_1 nLED_0

//    rGPFDAT = (rGPFDAT & 0xf) | !((data & 0xf)<<4);

    rGPFDAT = (rGPFDAT & ~(0xf<<3)) | ((~data & 0xf)<<3);    

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值