开发环境:Ubuntu 12.04
开发板:JZ2440 256M NandFlash 64M SDRAM
交叉编译器:arm-linux-gcc-4.3.2
u-boot:u-boot-2012.04.01
|
最近在学习BootLoader,移植u-boot-2012.04.01到JZ2440开发板,现在把移植过程记录下来,一来梳理思路,二来方便以后更进一步学习。
一、 u-boot分析过程
a、 初始化硬件:关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH
b、如果bootloader比较大,要把它重定位到SDRAM
c、把内核从NAND FLASH读到SDRAM
d、设置"要传给内核的参数"
e、跳转执行内核
具体代码分析
1、set the cpu to SVC32 mode
2、turn off the watchdog
3、mask all IRQs by setting all bits in the INTMR
4、设置时钟比例
5、设置内存控制器
6、设置栈,调用C函数board_init_f
7、调用函数数组init_sequence里的各个函数
7.1 board_early_init_f : 设置系统时钟、设置GPIO
......................................
8、重定位代码
8.1 从NOR FLASH把代码复制到SDRAM
8.2 程序的链接地址是0,访问全局变量、静态变量、调用函数时是使"基于0地址编译得到的地址",现在把程序复制到了SDRAM,需要修改代码,把"基于0地址编译得到的地址"改为新地址。
8.3 程序里有些地址在链接时不能确定,要到运行前才能确定:fixabs
9、clear_bss
10、调用C函数board_init_r:第2阶段的代码
二、初始编译
1、 解压 u-boot-2012.04.01.tar.bz2
tar xjf u-boot-2012.04.01.tar.bz2
进入解压后文件目录
cd u-boot-2012.04.01
2、在解压后文件目录下根据靠近的单板,配置
make smdk2410_config
make
这个时候编译完成后是不能在JZ2440上正常运行
三、建立自己的单板,定制适合自己单板的bootloader
1、新建一个单板
cd board/samsung/ cp smdk2410 smdk2440 -rf cd ../../include/configs/ cp smdk2410.h smdk2440.h
修改boards.cfg
仿照2410,添加2440
smdk2410 arm arm920t - samsung s3c24x0
添加
smdk2440 arm arm920t - samsung s3c24x0
make , 烧写调试
2、根据需求进一步配置
make menuconfig
3、修改Makefile ,开头指定架构和编译器
ARCH=arm
CROSS_COMPILE=arm-linux-
4、修改uboot代码,适合单板
uboot里先以60MHZ的时钟计算参数来设置内存控制器,但是MPLL还未设置
处理措施: 把MPLL的设置放到start.S里,取消board_early_init_f里对MPLL的设置
a、设置PLL的时钟的函数在_main中的board_init_f中初始化函数列表中的 boad_early_init_f 中,设置MPLL倍频值。它应该要在设置分频系数和初始化内存控制器之前来设置。
做如下修改: 在smdk2410.c文件中找到设置MPLL部分的代码,注释掉。
/* to reduce PLL lock time, adjust the LOCKTIME register */ //writel(0xFFFFFF, &clk_power->locktime); /* configure MPLL */ //writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV, // &clk_power->mpllcon);
然后在start.S中再设置MPLL
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01)) #if 0 /* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ ldr r0, =CLKDIVN mov r1, #3 str r1, [r0] #else /* 2. 设置时钟 400MHz */ ldr r0, =0x4c000014 // mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1 mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8 str r1, [r0] /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */ mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */ orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */ mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */ #define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01)) /* MPLLCON = S3C2440_MPLL_200MHZ */ ldr r0, =0x4c000004 ldr r1, =S3C2440_MPLL_400MHZ str r1, [r0] /* 启动ICACHE */ mrc p15, 0, r0, c1, c0, 0 @ read control reg orr r0, r0, #(1<<12) mcr p15, 0, r0, c1, c0, 0 @ write it back #endif
关闭看门狗、关中断
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01)) #if 0 /* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ ldr r0, =CLKDIVN mov r1, #3 str r1, [r0] #else /* 2. 设置时钟 400MHz */ ldr r0, =0x4c000014 // mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1 mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8 str r1, [r0] /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */ mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */ orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */ mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */ #define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01)) /* MPLLCON = S3C2440_MPLL_200MHZ */ ldr r0, =0x4c000004 ldr r1, =S3C2440_MPLL_400MHZ str r1, [r0] /* 启动ICACHE */ mrc p15, 0, r0, c1, c0, 0 @ read control reg orr r0, r0, #(1<<12) mcr p15, 0, r0, c1, c0, 0 @ write it back #endif 关闭看门狗、关中断 #ifdef CONFIG_S3C24X0 /* turn off the watchdog */ # if defined(CONFIG_S3C2400) # define pWTCON 0x15300000 # define INTMSK 0x14400008 /* Interrupt-Controller base addresses */ # define CLKDIVN 0x14800014 /* clock divisor register */ #else # define pWTCON 0x53000000 # define INTMSK 0x4A000008 /* Interrupt-Controller base addresses */ # define INTSUBMSK 0x4A00001C # define CLKDIVN 0x4C000014 /* clock divisor register */ # endif ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] /* * mask all IRQs by setting all bits in the INTMR - default */ mov r1, #0xffffffff ldr r0, =INTMSK str r1, [r0] # if defined(CONFIG_S3C2410) ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, [r0] # endif #endif
b、内存控制器的设置值改为如下
在/board/samsung/smdk2410/lowlevel_init.S文件中做一下修改
SMRDATA: #if 0 .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) .word 0x32 .word 0x30 .word 0x30 #else .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 #endif
c、设置串口波特率(get_HCLK函数),乱码,查看串口波特率的设置,发现在get_HCLK里没有定义CONFIG_S3C2440宏
处理措施:在include/configs/smdk2440.h中
//#define CONFIG_S3C2410 /* specifically a SAMSUNG S3C2410 SoC */ //#define CONFIG_SMDK2410 /* on a SAMSUNG SMDK2410 Board */ #define CONFIG_S3C2440 /* specifically a SAMSUNG S3C2440 SoC */ #define CONFIG_SMDK2440 /* on a SAMSUNG SMDK2440 Board */
d、修改UBOOT支持NAND启动,原来的代码在链接时加了"-pie"选项, 使得u-boot.bin里多了"*(.rel*)", "*(.dynsym)"
使得程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K)
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie 去掉这行
把init.c放入board/samsung/smdk2440目录,修改Makefile,使init.c编译进去
修改smdk2440.h ,修改CONFIG_SYS_TEXT_BASE为0x33f80000
#define CONFIG_SYS_TEXT_BASE 0x33f00000
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) #define TXD0READY (1<<2) void nand_read(unsigned int addr, unsigned char *buf, unsigned int len); 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(unsigned char *src, unsigned char *dest, unsigned int len) { int i = 0; /* 如果是NOR启动 */ if (isBootFromNorFlash()) { while (i < len) { dest[i] = src[i]; i++; } } else { //nand_init(); 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 /* 设置时序 */ 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_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; /* 1. 选中 */ nand_select(); while (i < len) { /* 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(); } #define PCLK 50000000 // init.c中的clock_init函数设置PCLK为50MHz #define UART_CLK PCLK // UART0的时钟源设为PCLK #define UART_BAUD_RATE 115200 // 波特率 #define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1) /* * 初始化UART0 * 115200,8N1,无流控 */ void uart0_init(void) { 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 = UART_BRD; // 波特率为115200 } /* * 发送一个字符 */ void putc(unsigned char c) { /* 等待,直到发送缓冲区中的数据已经全部发送出去 */ while (!(UTRSTAT0 & TXD0READY)); /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */ UTXH0 = c; } void puts(char *str) { int i = 0; while (str[i]) { putc(str[i]); i++; } } void puthex(unsigned int val) { /* 0x1234abcd */ int i; int j; puts("0x"); for (i = 0; i < 8; i++) { j = (val >> ((7-i)*4)) & 0xf; if ((j >= 0) && (j <= 9)) putc('0' + j); else putc('A' + j - 0xa); } }
修改start.S
修改board_init_f, 把relocate_code去掉
修改链接脚本: 把start.S, init.c, lowlevel.S等文件放在最前面,
在./arch/arm/cpu/u-boot.lds文件中
修改为
board/samsung/smdk2440/libsmdk2440.o
e、代码重定位
修改board.c文件中的board_init_f函数如下
/* * reserve memory for U-Boot code, data & bss * round down to next 4 kB limit */ //addr -= gd->mon_len; //addr &= ~(4096 - 1); addr = CONFIG_SYS_TEXT_BASE;
base_sp = addr_sp; //relocate_code(addr_sp, id, addr); return ( unsigned int )id; /* NOTREACHED - relocate_code() does not return */
f、支持NOR-FLASH: 在drivers\mtd\jedec_flash.c 加上新的型号, jedec_table[] 中增加一项匹配板子上的NOR-Flash厂商ID和设备ID
static const struct amd_flash_info jedec_table[] = { #ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8 { .mfr_id = (u16)SST_MANUFACT, .dev_id = SST39LF020, .name = "SST 39LF020", .uaddr = { [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ }, .DevSize = SIZE_256KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x01000,64), } }, #endif #ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8 { .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29LV040B, .name = "AMD AM29LV040B", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000,8), } }, { .mfr_id = (u16)SST_MANUFACT, .dev_id = SST39LF040, .name = "SST 39LF040", .uaddr = { [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x01000,128), } }, { .mfr_id = (u16)STM_MANUFACT, .dev_id = STM_ID_M29W040B, .name = "ST Micro M29W040B", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000,8), } }, { .mfr_id = (u16)MX_MANUFACT, .dev_id = MX29LV040, .name = "MXIC MX29LV040", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000, 8), } }, { .mfr_id = (u16)WINB_MANUFACT, .dev_id = W39L040A, .name = "WINBOND W39L040A", .uaddr = { [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000, 8), } }, { .mfr_id = (u16)AMIC_MANUFACT, .dev_id = A29L040, .name = "AMIC A29L040", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000, 8), } }, { .mfr_id = (u16)EON_MANUFACT, .dev_id = EN29LV040A, .name = "EON EN29LV040A", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000, 8), } }, #endif #ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16 { .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29F400BB, .name = "AMD AM29F400BB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_512KiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions= 4, .regions = { ERASEINFO(0x04000, 1), ERASEINFO(0x02000, 2), ERASEINFO(0x08000, 1), ERASEINFO(0x10000, 7), } }, { .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29LV400BB, .name = "AMD AM29LV400BB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_512KiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions= 4, .regions = { ERASEINFO(0x04000,1), ERASEINFO(0x02000,2), ERASEINFO(0x08000,1), ERASEINFO(0x10000,7), } }, { .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29LV800BB, .name = "AMD AM29LV800BB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_1MiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions= 4, .regions = { ERASEINFO(0x04000, 1), ERASEINFO(0x02000, 2), ERASEINFO(0x08000, 1), ERASEINFO(0x10000, 15), } }, { .mfr_id = (u16)STM_MANUFACT, .dev_id = STM29F400BB, .name = "ST Micro M29F400BB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_512KiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions = 4, .regions = { ERASEINFO(0x04000, 1), ERASEINFO(0x02000, 2), ERASEINFO(0x08000, 1), ERASEINFO(0x10000, 7), } }, #endif //JZ2440 { .mfr_id = (u16)MX_MANUFACT, .dev_id = 0x2249, .name = "MXIC MX29LV160DB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_2MiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 4, .regions = { ERASEINFO(16*1024,1), ERASEINFO(8*1024,2), ERASEINFO(32*1024,1), ERASEINFO(64*1024,31), } } };
在上面代码中最后增加JZ2440的Nor flash
在smdk2440.h 中修改
#define CONFIG_SYS_MAX_FLASH_SECT (128)
验证是否支持Nor flash
flinfo : 查看flash信息,RO块通过"protect off all"指令后擦写。 测试一下norflash能否正确读写,用以下u-boot命令: cp.b 0 30000000 80 cmp.b 0 30000000 80 发现读norflash没有问题。再用以下几条命令测试写norflash: mw.b 30000000 12 3 protect off all erase 0 ffff cp.b 30000000 0 3 md.b 0 3 发现也是121212;因此写norflash成功,至此u-boot已经支持JZ2440开发板的norflash。 |
g、修改UBOOT支持NAND FLASH
修复了重定时留下来的BUG:SP要重新设置,在start.S文件中做如下修改
/* Set stackpointer in internal RAM to call board_init_f */ call_board_init_f: ldr r0,=0x00000000 bl board_init_f /* unsigned int的值存在r0,正好给board_init_r作为参数用 */ ldr r1,_TEXT_BASE ldr sp,base_sp /* 调用第二阶段的代码 */ bl board_init_r .globl base_sp base_sp: .long 0
启动cache后就初始化nandflash
#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ bl nand_init_ll
修改:include/configs/smdk2440.h: #define CONFIG_CMD_NAND,把drivers\mtd\nand\s3c2410_nand.c复制为s3c2440_nand.c
修改此文件里代码如下:将以s3c2410开头函数名或变量名修改为以s3c2440开头
static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *chip = mtd->priv; struct s3c2440_nand *nand = s3c2440_get_base_nand(); if( ctrl&NAND_CLE) { /* 发命令 */ writeb(cmd,&nand->nfcmd); } else if( ctrl&NAND_ALE) { /* 发地址 */ writeb(cmd,&nand->nfaddr); } }
int board_nand_init(struct nand_chip *nand) { u_int32_t cfg; u_int8_t tacls, twrph0, twrph1; struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); struct s3c2440_nand *nand_reg = s3c2440_get_base_nand(); debug("board_nand_init()\n"); writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon); /* initialize hardware */ #if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING) tacls = CONFIG_S3C24XX_TACLS; twrph0 = CONFIG_S3C24XX_TWRPH0; twrph1 = CONFIG_S3C24XX_TWRPH1; #else tacls = 4; twrph0 = 8; twrph1 = 8; #endif #if 0 cfg = S3C2410_NFCONF_EN; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); #endif /* 设置时序 */ cfg = ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4); writel(cfg, &nand_reg->nfconf); /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ writel((1<<4)|(1<<1)|(1<<0), &nand_reg->nfcont); /* initialize nand_chip data structure */ nand->IO_ADDR_R = (void *)&nand_reg->nfdata; nand->IO_ADDR_W = (void *)&nand_reg->nfdata; nand->select_chip = s3c2440_nand_select; /* read_buf and write_buf are default */ /* read_byte and write_byte are default */ #ifdef CONFIG_NAND_SPL nand->read_buf = nand_read_buf; #endif /* hwcontrol always must be implemented */ nand->cmd_ctrl = s3c2440_hwcontrol; nand->dev_ready = s3c2440_dev_ready; #ifdef CONFIG_S3C2410_NAND_HWECC nand->ecc.hwctl = s3c2410_nand_enable_hwecc; nand->ecc.calculate = s3c2410_nand_calculate_ecc; nand->ecc.correct = s3c2410_nand_correct_data; nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; #else nand->ecc.mode = NAND_ECC_SOFT; #endif #ifdef CONFIG_S3C2410_NAND_BBT nand->options = NAND_USE_FLASH_BBT; #else nand->options = 0; #endif debug("end of nand_init\n"); return 0; }
h、支持DM9000网卡
启动uboot,打印出Net: CS8900-0,而我们的网卡是DM9000,于是在代码中搜索“Net:”,定位到common/board_r.c的initr_net函数,一路追踪eth_initialize, eth_common_init,一直到 board\samsung\smdk2440\smdk2440.c的board_eth_init函数,这里是对CS8900进行了初始化,我们要对DM9000进行初始化,通过查看drivers/net/Makefile,发现要包含dm9000x.c的文件,要定义CONFIG_DRIVER_DM9000这个宏,我们也要注释掉CONFIG_CS8900宏。同时查看dm9000x.c,里面有一个dm9000_initialize函数,于是仿照cs8900来写dm9000的初始化函数。
#ifdef CONFIG_CMD_NET int board_eth_init(bd_t *bis) { int rc = 0; #ifdef CONFIG_CS8900 rc = cs8900_initialize(0, CONFIG_CS8900_BASE); #endif #ifdef CONFIG_DRIVER_DM9000 rc = dm9000_initialize(&bis); #endif return rc; } #endif
配置文件smdk2440.h修改如下:
/* * Hardware drivers */ #if 0 #define CONFIG_CS8900 /* we have a CS8900 on-board */ #define CONFIG_CS8900_BASE 0x19000300 #define CONFIG_CS8900_BUS16 /* the Linux driver does accesses as shorts */ #else #define CONFIG_DRIVER_DM9000 #define CONFIG_DM9000_BASE 0x20000000 #define DM9000_IO CONFIG_DM9000_BASE #define DM9000_DATA CONFIG_DM9000_BASE + 4 #endif
设置CONFIG_ETHADDR宏,根据自己情况配置
#define CONFIG_ETHADDR 00:0c:29:8d:73:b1
保存,编译,烧写,启动Uboot,网卡正常启动。
四、nand flash 分区
在smdk2440.h文件中,修改以下代码
#if 0 #define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000) #define CONFIG_ENV_IS_IN_FLASH #define CONFIG_ENV_SIZE 0x10000 /* allow to overwrite serial and ethaddr */ #define CONFIG_ENV_OVERWRITE #endif #define CONFIG_ENV_IS_IN_NAND #define CONFIG_ENV_OFFSET 0x00040000 #define CONFIG_ENV_SIZE 0x20000 #define CONFIG_ENV_RANGE CONFIG_ENV_SIZE #define CONFIG_CMD_MTDPARTS #define CONFIG_MTD_DEVICE #define MTDIDS_DEFAULT "nand0=jz2440-0" /* 哪一个设备 */ #define MTDPARTS_DEFAULT "mtdparts=jz2440-0:256k(bootloader)," \ "128k(params)," \ "4m(kernel)," \ "-(rootfs)" \
至此u-boot的移植基本完成。