stdlf
分类:
2009-09-04 22:19:36
我所分析的uboot代码是基于恒丰锐科的s3c44b0x开发板,不是做广告,因为我现在在用这个板子。
由于本人能力有限,所做的工作如有纰漏,请原谅,谢谢指正。
/*
* S3C44B0 CPU specific code
*/
#include
#include
#include
static void s3c44b0_flush_cache(void) //刷新cache
{
volatile int i;
/* flush cycle 它用一个for循环进行内部的缓冲区初始化,由于S3C44B0决定每次读写都是按16字节进行的。因此,这里的i就是不断地加16个字节*/
for(i=0x10002000;i<0x10004800;i+=16)//缓存在使用内部ram映射区域为tag0,1,2,3还有LRU,这些都是按字(32b)访问的,地址为
//0x10002000--0x100047f0 由于按16字节读写i<0x10004800也可以,详细参考cpu说明书
{
*((int *)i)=0x0; //全部写0
}
}
int cpu_init (void) //初始化cpu函数, 该处理器没有使用IRQ和FIQ机制,所以不需要建立中断栈了
{
icache_enable(); /* 在里面调用了函数icache_enable(),它就是用来初始化S3C44B0的缓冲区,并且启用CPU缓冲区。因为CPU在加电之
后,它的初始化值是不启用内部的8K缓冲区的,必须由程序进行设置 。见77行*/
return 0;
}
int cleanup_before_linux (void) //载入linux之前所做的工作
{
/*在调用linux之前应该启用cache,这样可以加快linux内核的解压缩
cache memory should be enabled before calling
Linux to make the kernel uncompression faster
*/
icache_enable(); //清空缓冲区,启用缓存
disable_interrupts (); //禁用中断
return 0;
}
void reset_cpu (ulong addr)//复位cpu
{
/*
reset the cpu using watchdog
*/
/* Disable the watchdog.禁用看门狗*/
WTCON&=~(1<<5); //第五位清零
/* set the timeout value to a short time...设置一个超时值 */
WTCNT = 0x1; //看门狗定时器计数寄存器
/* Enable the watchdog. 启用看门狗*/
WTCON|=1;
WTCON|=(1<<5); //第5位置1
while(1) {
/*NOP*/
}
}
int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
extern void reset_cpu (ulong addr); //调用外部函数reset_cpu
disable_interrupts ();
reset_cpu (0);
/*NOTREACHED*/
return (0);
}
void icache_enable (void)
{
ulong reg;
//清空内存的缓冲区.
s3c44b0_flush_cache();
/*初始化缓冲区,设置非缓冲区的起始地址和结束地址。
第一个寄存器指明下面的地址不要缓存,低16位是起始地址,高16位是结束地址。并且空间大小都是以4K为界。0x0000:0000 - 0x0C00:0000
Init cache
Non-cacheable area (everything outside RAM)
0x0000:0000 - 0x0C00:0000 因为不是所有内存都需要进行缓冲的,比
如读取外面的IO,就不需要进行缓冲;读取FLASH也不需要因此,设置第一个非缓冲区的起始地址为NCACHBE0 =
0xC0000000,这个值里的低16位是起始地址0x0000,它的32位地址就是从0x00000000开始。它的高16位是结束地址
0Xc000,它的32位地址就是从0Xc0000000结束。*/
NCACHBE0 = 0xC0000000; //只设置第一个非缓冲区
NCACHBE1 = 0x00000000;
/*
Enable chache 设置SYSCFG寄存器启用8K缓冲区。S3C44B0X的Cache提供完整的Cache使能和禁止操作模式。
能够通过设置SYSCFG寄存器中CM域中的值为01或11来使能Cache(其中,01为使能4KB Cache, 11为使能8 KB Cache),
而通过清除SYSCFG寄存器中[2:1]域为0来禁止Cache功能 */
reg = SYSCFG;
reg |= 0x00000006; /* 8kB */
SYSCFG = reg;
}
void icache_disable (void) //禁用cache
{
ulong reg;
reg = SYSCFG;
reg &= ~0x00000006; /* 8kB 清除SYSCFG寄存器中[2:1]域为0来禁止Cache功能*/
SYSCFG = reg;
}
int icache_status (void)
{
return 0;
}
void dcache_enable (void)
{
icache_enable();
}
void dcache_disable (void)
{
icache_disable();
}
int dcache_status (void)
{
return dcache_status();
}
/*
RTC stuff
*/
#include
#ifndef BCD2HEX
#define BCD2HEX(n) ((n>>4)*10+(n&0x0f)) //转化公式
#endif
#ifndef HEX2BCD
#define HEX2BCD(x) ((((x) / 10) << 4) + (x) % 10)
#endif
void rtc_get (struct rtc_time* tm)
{
RTCCON |= 1; //RTC读写允许位=1,允许。
tm->tm_year = BCD2HEX(BCDYEAR); //BCD to HEX
tm->tm_mon = BCD2HEX(BCDMON);
tm->tm_wday = BCD2HEX(BCDDATE);
tm->tm_mday = BCD2HEX(BCDDAY);
tm->tm_hour = BCD2HEX(BCDHOUR);
tm->tm_min = BCD2HEX(BCDMIN);
tm->tm_sec = BCD2HEX(BCDSEC);
if (tm->tm_sec==0) {
/* we have to re-read the rtc data because of the "one second deviation" problem */
/* see RTC datasheet for more info about it 必须重读RTC,因为有1秒偏差问题,详细请查看RTC资料*/
tm->tm_year = BCD2HEX(BCDYEAR);
tm->tm_mon = BCD2HEX(BCDMON);
tm->tm_mday = BCD2HEX(BCDDAY);
tm->tm_wday = BCD2HEX(BCDDATE);
tm->tm_hour = BCD2HEX(BCDHOUR);
tm->tm_min = BCD2HEX(BCDMIN);
tm->tm_sec = BCD2HEX(BCDSEC);
}
RTCCON &= ~1; //禁用,不允许读写
if(tm->tm_year >= 70) //以1970年为界。
tm->tm_year += 1900;
else
tm->tm_year += 2000;
}
void rtc_set (struct rtc_time* tm) //设置实时时钟
{
if(tm->tm_year < 2000)
tm->tm_year -= 1900;
else
tm->tm_year -= 2000;
RTCCON |= 1;
BCDYEAR = HEX2BCD(tm->tm_year);
BCDMON = HEX2BCD(tm->tm_mon);
BCDDAY = HEX2BCD(tm->tm_mday);
BCDDATE = HEX2BCD(tm->tm_wday);
BCDHOUR = HEX2BCD(tm->tm_hour);
BCDMIN = HEX2BCD(tm->tm_min);
BCDSEC = HEX2BCD(tm->tm_sec);
RTCCON &= 1;
}
//复位实时时钟
void rtc_reset (void)
{
RTCCON |= 1;
BCDYEAR = 0;
BCDMON = 0;
BCDDAY = 0;
BCDDATE = 0;
BCDHOUR = 0;
BCDMIN = 0;
BCDSEC = 0;
RTCCON &= 1;
}