u-boot

转载uboot目录结构
转载uboot源码分析
转载移植uboot-2012.4

最简单的bootloader的编写步骤:

  1. 初始化硬件:关看门狗、设置时钟、初始化SDRAM、初始化NAND FLASH
  2. 如果bootloader比较大,要把它重定位到SDRAM
  3. 把内核从NAND FLASH读到SDRAM
  4. 设置"要传给内核的参数"
  5. 跳转执行内核

start.S

#define S3C2440_MPLL_200MHZ (0x5c<<12)|(1<<4)|(0x02<<0)
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
#define MEM_CTL_BASE  0x48000000  //sdram控制器基址

.text
.global _start
_start:

/*关看门狗,把0写入WTCON*/
	 ldr r0,=0x53000000
	 mov r1,#0
	 str r1,[r0]


/*设置时钟  , CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */
	ldr r0,=0x4c000014
	mov r1,#0x05
	str r1,[r0]

    /* 设置CPU工作于异步模式 */
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
	mcr p15,0,r0,c1,c0,0
	
	/* 设置MPLLCON(0x4C000004) */
	ldr r0, =0x4C000004
	ldr r1, =S3C2440_MPLL_400MHZ
	str r1, [r0]

	/* 启动icache,提高启动速度 */
	mrc p15, 0, r0, c1, c0, 0
	orr r0, r0, #(1<<12)  /* r0 = r0 or (1<<12) */
	mcr p15, 0, r0, c1, c0, 0	
	
/*初始化SDRAM*/
	ldr r0,=MEM_CTL_BASE
	adr r1,sdram_config//获得地址
	add r3,r0,#(13*4)//r3=r0+52
      1:
  	ldr r2,[r1],#4 //r2=[r1],r1+4
  	str r2,[r0],#4 //[r0]=r2,r0+4
  	cmp r0,r3
  	bne 1b

/*重定位*/
	ldr sp,=0x34000000
	bl copy_code_to_sdram
	bl clean_bss
	
/*执行main*/
	ldr lr,=halt//main执行完后返回地址
	ldr pc,=main//绝对跳转-》sdram
	
halt:
	b halt

sdram_config:
	.long 0x22011110	 //BWSCON
	.long 0x00000700	 //BANKCON0
	.long 0x00000700	 //BANKCON1
	.long 0x00000700	 //BANKCON2
	.long 0x00000700	 //BANKCON3  
	.long 0x00000700	 //BANKCON4
	.long 0x00000700	 //BANKCON5
	.long 0x00018005	 //BANKCON6
	.long 0x00018005	 //BANKCON7
	.long 0x008C04F4	 // REFRESH
	.long 0x000000B1	 //BANKSIZE
	.long 0x00000030	 //MRSRB6
	.long 0x00000030	 //MRSRB7
	

init.c

/* NAND FLASH控制器 */
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)0x4E000004))
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
#define NFADDR (*((volatile unsigned char *)0x4E00000C))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
#define NFSTAT (*((volatile unsigned char *)0x4E000020))

/* GPIO */
#define GPHCON              (*(volatile unsigned long *)0x56000070)
#define GPHUP               (*(volatile unsigned long *)0x56000078)

/* UART registers*/
#define ULCON0              (*(volatile unsigned long *)0x50000000)
#define UCON0               (*(volatile unsigned long *)0x50000004)
#define UFCON0              (*(volatile unsigned long *)0x50000008)
#define UMCON0              (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0            (*(volatile unsigned long *)0x50000010)
#define UTXH0               (*(volatile unsigned char *)0x50000020)
#define URXH0               (*(volatile unsigned char *)0x50000024)
#define UBRDIV0             (*(volatile unsigned long *)0x50000028)

/* 115200,8n1 */
void uart0_init()
{
	GPHCON  |= 0xa0;    // GPH2,GPH3用作TXD0,RXD0
    GPHUP   = 0x0c;     // GPH2,GPH3内部上拉

    ULCON0  = 0x03;     // 8N1(8个数据位,无较验,1个停止位)
    UCON0   = 0x05;     // 查询方式,UART时钟源为PCLK
    UFCON0  = 0x00;     // 不使用FIFO
    UMCON0  = 0x00;     // 不使用流控
    UBRDIV0 = 26; // 波特率为115200
	
	/* 设置波特率 */
	/* UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
	 *  UART clock = 50M
	 *  UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26
	 */
}
void putc(unsigned char c)
{
	/* UTRSTAT0  UTXH0 */
	while (!(UTRSTAT0 & (1<<2)));
	UTXH0 = c;
}
void puts(char *s)
{
	while (*s)
	{
		putc(*s);
		s++;
	}
}

void nand_init(void)
{
#define TACLS   0
#define TWRPH0  1
#define TWRPH1  0
	/* 设置时序 */
	NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
	/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
	NFCONT = (1<<4)|(1<<1)|(1<<0);	
}

void nand_select(void)
{
	NFCONT &= ~(1<<1);	
}

void nand_deselect(void)
{
	NFCONT |= (1<<1);	
}

void nand_cmd(unsigned char cmd)
{
	volatile int i;
	NFCMMD = cmd;
	for (i = 0; i < 10; i++);
}

void nand_addr(unsigned int addr)
{
	unsigned int col  = addr % 2048;
	unsigned int page = addr / 2048;
	volatile int i;

	NFADDR = col & 0xff;
	for (i = 0; i < 10; i++);
	NFADDR = (col >> 8) & 0xff;
	for (i = 0; i < 10; i++);
	
	NFADDR  = page & 0xff;
	for (i = 0; i < 10; i++);
	NFADDR  = (page >> 8) & 0xff;
	for (i = 0; i < 10; i++);
	NFADDR  = (page >> 16) & 0xff;
	for (i = 0; i < 10; i++);	
}

void nand_page(unsigned int page)
{
	volatile int i;
	
	NFADDR  = page & 0xff;
	for (i = 0; i < 10; i++);
	NFADDR  = (page >> 8) & 0xff;
	for (i = 0; i < 10; i++);
	NFADDR  = (page >> 16) & 0xff;
	for (i = 0; i < 10; i++);	
}

void nand_col(unsigned int col)
{
	volatile int i;

	NFADDR = col & 0xff;
	for (i = 0; i < 10; i++);
	NFADDR = (col >> 8) & 0xff;
	for (i = 0; i < 10; i++);
}

void nand_wait_ready(void)
{
	while (!(NFSTAT & 1));
}

unsigned char nand_data(void)
{
	return NFDATA;
}
/*判断坏块*/
int nand_bad(unsigned int addr)
{
	unsigned int col  = 2048;
	unsigned int page = addr / 2048;
	unsigned char val;

    /* 1. 选中 */
	nand_select();	
	/* 2. 发出读命令00h */
	nand_cmd(0x00);
	/* 3. 发出地址(分5步发出) */
	nand_col(col);
	nand_page(page);	
	/* 4. 发出读命令30h */
	nand_cmd(0x30);
	/* 5. 判断状态 */
	nand_wait_ready();
	/* 6. 读数据 */
	val = nand_data();	
	/* 7. 取消选中 */		
	nand_deselect();

	if (val != 0xff)
		return 1;  /* bad blcok */
	else
		return 0;
}

void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{	
	int col = addr % 2048;
	int i = 0;	
	while (i < len)
	{

		if (!(addr & 0x1FFFF) && nand_bad(addr)) /* 一个block只判断一次 */
		{
			addr += (128*1024);  /* 跳过当前block */
			continue;
		}

		/* 1. 选中 */
		nand_select();
		/* 2. 发出读命令00h */
		nand_cmd(0x00);
		/* 3. 发出地址(分5步发出) */
		nand_addr(addr);
		/* 4. 发出读命令30h */
		nand_cmd(0x30);
		/* 5. 判断状态 */
		nand_wait_ready();
		/* 6. 读数据 */
		for (; (col < 2048) && (i < len); col++)
		{
			buf[i] = nand_data();
			i++;
			addr++;
		}	
		col = 0;
		/* 7. 取消选中 */		
		nand_deselect();	
	}
}

int isBootFromNorFlash(void)
{
	volatile int *p = (volatile int *)0;
	int val;

	val = *p;
	*p = 0x12345678;
	if (*p == 0x12345678)
	{
		/* 写成功, 是nand启动 */
		*p = val;
		return 0;
	}
	else
	{	/* NOR不能像内存一样写 */
		return 1;
	}
}

void copy_code_to_sdram(void)
{
	/* 要从lds文件中获得 __code_start, __bss_start
	 * 然后从0地址把数据复制到__code_start */
	extern int __code_start, __bss_start;

	volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
	volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
	volatile unsigned int *src = (volatile unsigned int *)0;
	unsigned int len = (unsigned int)(&__bss_start) - (unsigned int)(&__code_start);

	if (isBootFromNorFlash())
	{
		while (dest < end)
		{
			*dest++ = *src++;
		}
	}
	else
	{
		nand_init();
		nand_read((unsigned int)src, (unsigned char *)dest, len);
	}
}

void clean_bss(void)
{
	/* 要从lds文件中获得 __bss_start, _end*/
	extern int _end, __bss_start;

	volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
	volatile unsigned int *end = (volatile unsigned int *)&_end;

	while (start <= end)
	{
		*start++ = 0;
	}
}

u-boot.s

#include "setup.h"

extern void uart0_init();
extern void puts(const char *s);
extern void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);

static struct tag *params;

int strlen(char *str)
{
	int i=0;
	while(str[i])
	{
		i++;
	}
	return i;
}

void strcpy (char *dest,const char *src)
{
	while((*dest++=*src++)!='\0');
}

void  setup_start_tag()
{
	params = (struct tag *) 0x30000100;//tag存放的位置
		/*tag头部*/
	params->hdr.tag = ATAG_CORE;//标记0x54410001,标签列表开始标志
	params->hdr.size = tag_size (tag_core);//整个结构体大小:头加联合体

	params->u.core.flags = 0;
	params->u.core.pagesize = 0;
	params->u.core.rootdev = 0;
	params = tag_next (params);
}

void setup_memory_tags ()
{		/*内存参数*/
		params->hdr.tag = ATAG_MEM;//内存信息标签
		params->hdr.size = tag_size (tag_mem32);

		params->u.mem.start = 0x30000000;//内存起始地址
		params->u.mem.size = 64*1024*1024;//内存大小64M

		params = tag_next (params);	
}

void  setup_commandline_tag(char *cmdline)
{   /*命令行参数*/
	int len=strlen(cmdline)+1;

	params->hdr.tag = ATAG_CMDLINE;//command line字符串标签
	params->hdr.size =(sizeof (struct tag_header) + len+3) >> 2;//向4取整>>2/除4

	strcpy (params->u.cmdline.cmdline, cmdline);
	params = tag_next (params);
}

void setup_end_tag()
{
	params->hdr.tag = ATAG_NONE;//标签列表结束标志
	params->hdr.size = 0;
}

int main()
{	
	void (*theKernel)(int zero,int arch,unsigned int params);

	/*0、帮内核设置串口,内核启动时会打印信息*/
	uart0_init();
	
	/*1、从nand flash里把内核读入内存(sdram)*/
	puts("Copy kernel from nand\n\r");
	nand_read((unsigned int)0x60000+64,(unsigned char *)0x30008000,(unsigned int)0x200000);

	/*设置参数*/
	puts("Set boot params\n\r");
	setup_start_tag();
	setup_memory_tags ();
	setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
	setup_end_tag();
	
	/*跳转到内核执行,传参数给内核*/
	puts("Jump kernel\n\r");
	theKernel=(void(*)(int,int,unsigned int))0x30008000;
	theKernel(0,362,0x30000100);//s3c2440机器ID,参数的位置
		/*  mov r0,#0
			ldr r1,=362
			ldr r2,=0x30000100
		    mov pc, #0x30008000
		程序不再回到这*/
	return -1;
}

uboot.lds

SECTIONS
{
	. = 0x33f80000;
	__code_start = .;
	. = ALIGN(4);
	.text      :
	{
	  *(.text)
	}
	. = ALIGN(4);
	.rodata : { *(.rodata) }
	. = ALIGN(4);
	.data : { *(.data) }
	. = ALIGN(4);
	__bss_start = .;
	.bss : { *(.bss) *(.COMMON) }
	_end = .;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值