第二阶段代码详细分析
void Main(void) //第八个函数
{
char *mode; //定义一个指针变量mode,这个指针指向的内容为char型
int i,j;
U8 key; //U8是unsigned char型,在def.h里定义
U32 mpll_val; //U32是unsigned 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口定义
/*
S3C2440有130个管脚。可以通过软件配置每个管脚的功能来满足系统及外设的要求。所以在程序开始之前,你必须定义每个管脚的配置。
端口初始化,设置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.UPLL在2440init.s里设置了。
*/
ChangeClockDivider(key, 12);
/*
设置MPLLCON后,得到FCLK的值。再设置CLKDIVN,得到HCLK、PCLK的值,使得FCLK:HCLK:PCLK=1:4:8。如果FCLK:HCLK!=1:1,还要执行,MMU_SetAsyncBusMode()。同2440init.s一样
*/
//2440lib.c里定义
cal_cpu_bus_clk(); //第七个函数计算FCLK、HCLK、PCLK、UCLK、cpu_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
/*
rMISCCR在2440addr.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_params在bootpara.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;
//判断HCLK与FCLK的比例
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);
}