在U-Boot-2009-03移植笔记(点亮第一展灯)中,我们初始化好了sdram,点亮了第一盏灯。在本文中,我们将移植好nandflash启动的驱动代码。
对于S3C2440,有一个steppingston,在CPU上电的时候,由硬件将Nandflash的前4KB代码拷贝到片内的SRAM中,并且内部SRAM被映射到地址0x0,于是我们的代码才能被cpu执行。
但问题是我们的代码肯定不止4KB,所以我们必须自己写代码,把nandflash中的剩余代码拷贝到内存中,然后让CPU跳转到对应的内存地址执行。
设置堆栈指针,为C语言准备运行环境
1 /*设置堆栈*/ 2 ldr sp, DW_STACK_START 3 mov fp,#0
注意第二行引用了DW_STACK_START标号,我们定义在标号_start_armboot后面
1 _start_armboot: .word start_armboot 2 DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
第二行的STACK_BASE和STACK_SIZE都定义在include/configs/xinna2440.h中
1 #define STACK_BASE 0x33f00000 //定义堆栈的地址 2 #define STACK_SIZE 0x8000 //堆栈的长度大小
设置好了堆栈指针,下面我们只需要初始化好Nandflash之后,就可以读取数据,存到sdram中了。
初始化NandFlash
我们在board/xinna2440/文件夹下,增加nand_op.c文件,然后修改board/xinna2440/Makefile,添加对nand_op.c的编译
1 COBJS := xinna2440.o flash.o nand_op.o
编辑board/xinna2440/nand_op.c,添加以下文件,我们的板子上用的是K9F2G08U0A,2KB一页,共64MB大小。 1 /*
2 * board/samsung/reille2440/nand_read.c 3 * 4 * (C) Copyright 2011 5 * reille <http://blog.csdn.net/reille/> <[email protected]> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 */ 13 #include <config.h> 14 #define NF_BASE 0x4E000000 //Nand Flash配置寄存器基地址 15 #define __REGb(x) (*(volatile unsigned char *)(x)) 16 #define __REGi(x) (*(volatile unsigned int *)(x)) 17 #if 0 18 #define NFCONF __REGi(NF_BASE + 0x0 ) //通过偏移量还是得到配置寄存器基地址 19 #define NFCONT __REGi(NF_BASE + 0x4 ) //通过偏移量得到控制寄存器基地址 20 #define NFCMD __REGb(NF_BASE + 0x8 ) //通过偏移量得到指令寄存器基地址 21 #define NFADDR __REGb(NF_BASE + 0xC ) //通过偏移量得到地址寄存器基地址 22 #define NFDATA __REGb(NF_BASE + 0x10) //通过偏移量得到数据寄存器基地址 23 #define NFSTAT __REGb(NF_BASE + 0x20) //通过偏移量得到状态寄存器基地址 24 #endif 25 26 #define NFCONF (*(volatile unsigned int *)(NF_BASE + 0X0)) 27 #define NFCONT (*(volatile unsigned short *)(NF_BASE + 0x4)) 28 #define NFCMD (*(volatile unsigned short *)(NF_BASE + 0X8)) 29 #define NFADDR (*(volatile unsigned short *)(NF_BASE + 0xc)) 30 #define NFDATA (*(volatile unsigned char *)(NF_BASE + 0x10)) 31 #define NFSTAT (*(volatile unsigned char *)(NF_BASE + 0x20)) 32 33 34 #define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1)) //Nand片选使能 35 #define NAND_CHIP_DISABLE (NFCONT |= (1<<1)) //取消Nand片选 36 #define NAND_CLEAR_RB (NFSTAT |= (1<<2)); 37 #define NAND_DETECT_RB { while(! (NFSTAT&(1<<2)) );} 38 #define NAND_SECTOR_SIZE 2048 39 #define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1) 40 #if 0 41 #define DEBUGN printf 42 #else 43 #define DEBUGN(x, args ...) {} 44 #endif 45 46 /* low level nand read function */ 47 #define GPBCON (*(volatile unsigned long *)0x56000010) 48 #define GPBDAT (*(volatile unsigned long *)0x56000014) 49 50 #define GPACON (*(volatile unsigned long *)0x56000000) 51 52 void nand_wait_ll(void) 53 { 54 int k; 55 while(!(NFSTAT & 1)) 56 for(k = 0; k < 20; k++); 57 return; 58 // NAND_DETECT_RB 59 } 60 61 void nand_reset_ll(void) 62 { 63 NAND_CHIP_ENABLE; //选中Nand片选 64 // NAND_CLEAR_RB 65 NFCMD = 0xff; 66 nand_wait_ll(); 67 // NAND_CLEAR_RB 68 NAND_CHIP_DISABLE; //取消片选信号 69 } 70 71 72 unsigned char nand_read_id(unsigned char*mc,unsigned char *dc,unsigned char *pc) 73 { 74 int i=0; 75 unsigned char res; 76 NAND_CHIP_ENABLE; //选中Nand片选 77 NFCMD = 0x90; 78 for(i = 0;i < 100;i++); 79 NFADDR = 0 & 0xFF; 80 NFADDR = (0 >> 9) & 0xFF; 81 NFADDR = (0 >> 17) & 0xFF; 82 NFADDR = (0 >> 25) & 0xFF; 83 for(i = 0;i < 100;i++); 84 nand_wait_ll(); 85 *mc = NFDATA; 86 *dc = NFDATA; 87 res = NFDATA; 88 *pc = NFDATA; 89 NAND_CHIP_DISABLE; //取消片选信号 90 return *mc; 91 } 92 93 void nand_init_ll(void) 94 { 95 int TACLS = 3; 96 int TWRPH0 = 7; 97 int TWRPH1 = 7; 98 int i = 0; 99 //配置gpio 100 // GPACON = (GPACON &~(0x3f << 17)) | ( 0x3f << 17); 101 GPACON = GPACON | (0x3f << 17); 102 NFCONF = (TACLS << 12) | (TWRPH0 << 8) | (TWRPH1 << 4) | (0 << 0); 103 104 NFCONT = (0 << 13) | (0 << 12) | ( 0 << 10) | (0 << 9) | (0 << 8) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 1) | (1 << 0); 105 106 nand_reset_ll(); 107 } 108 109 #if 0 110 int nand_write_ll(void) 111 { 112 int i = 0x90000; 113 unsigned char j = 0; 114 NAND_CHIP_ENABLE; //选中Nand片选 115 NFCMD = 0x80; 116 117 NFADDR = 0x00; 118 NFADDR = 0x00; 119 NFADDR = i & 0xFF; 120 NFADDR = (i >> 8) & 0xFF; 121 NFADDR = (i >> 16) & 0xFF; 122 for(j = 0; j < 100;j++); 123 124 125 NFCMD = 0x10; 126 nand_wait_ll(); 127 128 for(j = 0 ; j < 100; j++) 129 { 130 NFDATA = j; 131 } 132 NFCMD = 0x10; 133 nand_wait_ll(); 134 135 NAND_CHIP_DISABLE; //取消片选信号 136 return 0; 137 } 138 #endif 139 140 static void write_addr(unsigned int addr) 141 { 142 int col,page,i; 143 col = addr & NAND_BLOCK_MASK; 144 page = addr & NAND_SECTOR_SIZE; 145 146 NFADDR = col & 0xff; 147 for(i = 0; i < 10; i++); 148 NFADDR = (col >> 8) & 0x0f; 149 for(i = 0; i < 10; i++); 150 151 152 NFADDR = page & 0xFF; 153 for(i = 0; i < 10; i++); 154 NFADDR = (page >> 8) & 0xFF; 155 for(i = 0; i < 10; i++); 156 157 NFADDR = (page >> 16) & 0x01; 158 for(i = 0; i < 10; i++); 159 } 160 161 static nand_read_page_ll(unsigned char *buf,unsigned long pageaddr) 162 { 163 int i = 0; 164 NAND_CHIP_ENABLE; //选中Nand片选 165 166 //发出READ0指令 167 NFCMD = 0; 168 169 //对Nand进行寻址 170 NFADDR = 0x00; 171 NFADDR = 0x00; 172 NFADDR = pageaddr & 0xff; 173 NFADDR = (pageaddr >> 8) & 0xff; 174 NFADDR = (pageaddr >> 16) & 0xff; 175 176 NFCMD = 0x30; 177 nand_wait_ll(); 178 179 for(i=0; i < NAND_SECTOR_SIZE; i++) 180 buf[i] = NFDATA; 181 182 NAND_CHIP_DISABLE; //取消片选信号 183 } 184 185 int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) 186 { 187 int pageaddr = 0; 188 for(pageaddr = 0; pageaddr < 100;pageaddr++) 189 { 190 nand_read_page_ll(buf,pageaddr); 191 buf += NAND_SECTOR_SIZE; 192 } 193 return 0; 194 } 195
写好了nand_flash驱动之后,我们在start.S中调用,将u-boot自身,从nandflash读到sdram中。
1 bl nand_init_ll /*调用nandflash初始化函数*/ 2 3 ldr r0, =TEXT_BASE /*指定uboot在内存中的地址,这个宏定义在board/xinna2440/config.mk中,默认是0x33f80000*/ 4 mov r1, #0x0 /*从nandflash的0地址读取*/ 5 mov r2, #0x30000 /*读取长度*/ 6 7 bl nand_read_ll /*开始循环读取*/ 8 tst r0, #0x0 /*判断函数返回值*/ 9 beq ok_nand_read 10 11 bad_nand_read: 12 loop2: b loop2 /*读取出错,死循环*/ 13 14 ok_nand_read: 15 mov r0,#0 16 ldr r1,=TEXT_BASE 17 mov r2,#0x400 18 /*读取成功,以下代码用于校验内存数据和sram中的数据是否一样*/ 19 20 go_next: 21 ldr r3, [r0], #4 22 ldr r4, [r1], #4 23 teq r3, r4 24 bne notmatch 25 subs r2, r2, #4 26 beq stack_setup 27 bne go_next 28 29 notmatch: /*数据不一致,死循环*/ 30 loop3: b loop3 /* infinite loop */
至此,我们添加了从nandflash启动u-boot的代码,我们在后面添加一个点灯代码,点亮led1和led2。
1 loo: 2 ldr r4,=0x56000010 3 ldr r5,=( 1 << 10) | (1 << 12) 4 str r5,[r4] 5 6 ldr r4,=0x56000014 7 ldr r5,=~(( 1 << 5) | ( 1 << 6)) 8 str r5,[r4] 9 b loo
烧到板子跑,发现led1和led2并没有像我们所预期的被点亮,是什么原因呢?下回分解!