mini2440之动手写简易bootloader

2019-04-14 19:14发布

Bootloader 它的终极使命就是启动内核,它的主要工作:在上电之后在硬件上进行一系列的初始化,为Linux内核启动铺路。具体的就是设置看门狗、设置系统时钟、初始化SDRAM与NANDflash控制器、代码重定位等,最后将内核从nandflash上拷贝到内存中,传递参数,跳转执行。 一、创建start.S文件 .text .global _start _start: /* close the watchdog */ ldr r0, =0x53000000 mov r1, #0 str r1, [r0] /* close the watchdog */ @关闭看门狗 @数据手册:WTCON 0x53000000 R/W Watchdog timer control register /* set the clock */ ldr r0, =0x4c000014 mov r1, #0x03; @ FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1 str r1, [r0] mrc p15, 0, r1, c1, c0, 0 /* read */ orr r1, r1, #0xc0000000 /* set asynchronous bus mode */ mcr p15, 0, r1, c1, c0, 0 /* write */ ldr r0, =0x4c000004 ldr r1, =((0x5c<<12)|(0x01<<4)|(0x02)) @MPLL:200MHz str r1, [r0] /* set the clock */ @设置系统时钟 @如果HDIVN不是0,CPU的总线模式应该设置成asynchronous bus mode /* enable the ICACHE */ mrc p15, 0, r0, c1, c0, 0 @ read control register orr r0, r0, #(1<<12) mcr p15, 0, r0, c1, c0, 0 @ write back /* enable the ICACHE */ @使能高速缓存,为系统提速,此段可不要,但程序执行速度要慢 /* init the SDRAM */ ldr r0, =0x48000000 @MEM_CTL_BASE adr r1, config /* sdram config address */ add r3, r0, #(52) @13*4 1: ldr r2, [r1], #4 str r2, [r0], #4 cmp r0, r3 bne 1b /* init the SDRAM */ @初始化SDRAM @根据数据手册对与SDRAM有关的13个寄存器进行配置 /* relocate */ ldr sp, =0x34000000 bl nand_init mov r0, #0 ldr r1, =_start ldr r2, =__bss_start sub r2, r2, r1 bl copy_code_to_sdram bl clear_bss /* relocate */ @把bootloader本身的代码从nandflash复制到它的链接地址去 /* go to main */ ldr lr, =halt ldr pc, =main halt: b halt /* go to main */ @跳转到main函数执行 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文件 /* nandflash controller */ #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) #define TXD0READY (1<<2) void nand_read(unsigned int addr, unsigned char *buf, unsigned int len); void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len) { nand_read((unsigned int)src, dest, len); } void clear_bss(void) { extern int __bss_start, __bss_end; int *p = &__bss_start; for (; p < &__bss_end; p++) *p = 0; } void nand_init(void) { #define TACLS 0 #define TWRPH0 1 #define TWRPH1 0 /* sequence */ NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); /* enable controller,init ECC,disable CS */ 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_wait_ready(void) { while (!(NFSTAT & 1)); } unsigned char nand_data(void) { return NFDATA; } void nand_read(unsigned int addr, unsigned char *buf, unsigned int len) { int col = addr % 2048; int i = 0; /* select */ nand_select(); while (i < len) { /* read cmd 00h */ nand_cmd(0x00); /* send addr */ nand_addr(addr); /* read cmd 30h */ nand_cmd(0x30); /* check */ nand_wait_ready(); /* read data */ for (; (col < 2048) && (i < len); col++) { buf[i] = nand_data(); i++; addr++; } col = 0; } /* deselect */ nand_deselect(); } #define PCLK 50000000 // PCLK:50MHz #define UART_CLK PCLK // UART0:PCLK #define UART_BAUD_RATE 115200 // baudrate #define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16))-1) /*115200,8N1,none*/ void uart0_init(void) { GPHCON |= 0xa0; // GPH2,GPH3:TXD0,RXD0 GPHUP = 0x0c; // GPH2,GPH3 pull up ULCON0 = 0x03; UCON0 = 0x05; UFCON0 = 0x00; UMCON0 = 0x00; UBRDIV0 = UART_BRD; // 115200 } void putc(unsigned char c) { while (!(UTRSTAT0 & TXD0READY)); UTXH0 = c; } void puts(char *str) { int i = 0; while (str[i]) { putc(str[i]); i++; } } 完成了 nandflash与串口的初始化。

三、创建boot.c文件 #include "setup.h" extern void uart0_init(void); extern void nand_read(unsigned int addr, unsigned char *buf, unsigned int len); extern void puts(char *str); extern void puthex(unsigned int val); static struct tag *params; void setup_start_tag(void) { params = (struct tag *)0x30000100; params->hdr.tag = ATAG_CORE; 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(void) { params->hdr.tag = ATAG_MEM; params->hdr.size = tag_size (tag_mem32); params->u.mem.start = 0x30000000; params->u.mem.size = 64*1024*1024; params = tag_next (params); } int strlen(char *str) { int i = 0; while (str[i]) { i++; } return i; } void strcpy(char *dest, char *src) { while ((*dest++ = *src++) != '