Linux学习 :移植U-boot_2012.04.01到JZ2440开发板
一.下载U-boot源码:ftp://ftp.denx.de/pub/u-boot/
二.uboot的启动过程:
部分硬件初始化——>加载完整uboot到RAM——>跳转到第二阶段入口开始执行,整个过程最重要的两个文件:
/arch/arm/cpu/arm920t/start.S,涉及到特定硬件设备的读写寄存器操作以及特定体系结构的汇编语言(中断、时钟等)。
board/samsung/smdk2440/lowlevel_init.S,完成底层的初始化(内存控制器等)。
具体流程如下:
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.编译:make smdk2410_config && make
2.源码修改,移植到JZ2440开发板:
①新建一个单板:(之后通过 make smdk2440_config 配置)
cp -rf board/samsung/smdk2410 board/samsung/smdk2440
cp include/configs/smdk2410.h include/configs/smdk2440.h
修改boards.cfg ,仿照2410增加: (较新版的u-boot源码已经去掉boadrs.cfg,而是使用make menuconfig配置,config文件在configs目录下)
smdk2440 arm arm920t - samsung s3c24x0
原来的代码在链接时加了"-pie"选项, 使得u-boot.bin里多了"*(.rel*)", "*(.dynsym)",使得程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K)
因此可以注释掉 arch/arm/config.mk 该参数:LDFLAGS_u-boot += -pie -> #LDFLAGS_u-boot += -pie
②设置PLL的时钟操作在/board/samsung/smdk2440/smdk2410.c的 board_early_init_f 函数中,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);
在/arch/arm/cpu/arm920t/start.S中再设置:
/* IRQ stack memory (calculated at run-time) + 8 bytes */ .globl IRQ_STACK_START_IN IRQ_STACK_START_IN: .word 0x0badc0de //添加: .globl base_sp base_sp: .long 0
//修改:
#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 /* CONFIG_S3C24X0 */ /* * we do sys-critical inits only at reboot, * not when booting from ram! */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) /* sp = 30000f80 */ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ bl nand_init_ll mov r0, #0 //ldr r1, =_start ldr r1, _TEXT_BASE ldr r2, _bss_start_ofs bl copy_code_to_sdram bl clear_bss ldr pc, =call_board_init_f /* 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 /* 重新设置栈 */ /* 调用第2阶段的代码 */ bl board_init_r
修改arch/arm/lib/board.c 的 board_init_f 函数如下:
unsigned int board_init_f(ulong bootflag) //修改返回值为id { bd_t *bd; init_fnc_t **init_fnc_ptr; gd_t *id; ulong addr, addr_sp; extern ulong base_sp; //栈指针 #ifdef CONFIG_PRAM ulong reg; #endif bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f"); /* Pointer is writable since we allocated a register for it */ gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07); /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory"); memset((void *)gd, 0, sizeof(gd_t)); gd->mon_len = _bss_end_ofs; #ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ gd->fdt_blob = _binary_dt_dtb_start; #elif defined CONFIG_OF_SEPARATE /* FDT is at end of image */ gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE); #endif /* Allow the early environment to override the fdt address */ gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); } } #ifdef CONFIG_OF_CONTROL /* For now, put this check after the console is ready */ if (fdtdec_prepare_fdt()) { panic("** CONFIG_OF_CONTROL defined but no FDT - please see " "doc/README.fdt-control"); } #endif debug("monitor len: %08lX\n", gd->mon_len); /* * Ram is setup, size stored in gd !! */ debug("ramsize: %08lX\n", gd->ram_size); #if defined(CONFIG_SYS_MEM_TOP_HIDE) /* * Subtract specified amount of memory to hide so that it won't * get "touched" at all by U-Boot. By fixing up gd->ram_size * the Linux kernel should now get passed the now "corrected" * memory size and won't touch it either. This should work * for arch/ppc and arch/powerpc. Only Linux board ports in * arch/powerpc with bootwrapper support, that recalculate the * memory size from the SDRAM controller setup will have to * get fixed. */ gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE; #endif addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; #ifdef CONFIG_LOGBUFFER #ifndef CONFIG_ALT_LB_ADDR /* reserve kernel log buffer */ addr -= (LOGBUFF_RESERVE); debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr); #endif #endif #ifdef CONFIG_PRAM /* * reserve protected RAM */ reg = getenv_ulong("pram", 10, CONFIG_PRAM); addr -= (reg << 10); /* size is in kB */ debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr); #endif /* CONFIG_PRAM */ #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) /* reserve TLB table */ addr -= (4096 * 4); /* round down to next 64 kB limit */ addr &= ~(0x10000 - 1); gd->tlb_addr = addr; debug("TLB table at: %08lx\n", addr); #endif /* round down to next 4 kB limit */ addr &= ~(4096 - 1); debug("Top of RAM usable for U-Boot at: %08lx\n", addr); #ifdef CONFIG_LCD #ifdef CONFIG_FB_ADDR gd->fb_base = CONFIG_FB_ADDR; #else /* reserve memory for LCD display (always full pages) */ addr = lcd_setmem(addr); gd->fb_base = addr; #endif /* CONFIG_FB_ADDR */ #endif /* CONFIG_LCD */ /* * 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; /* addr = _TEXT_BASE */ debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr); #ifndef CONFIG_SPL_BUILD /* * reserve memory for malloc() arena */ addr_sp = addr - TOTAL_MALLOC_LEN; debug("Reserving %dk for malloc() at: %08lx\n", TOTAL_MALLOC_LEN >> 10, addr_sp); /* * (permanently) allocate a Board Info struct * and a permanent copy of the "global" data */ addr_sp -= sizeof (bd_t); bd = (bd_t *) addr_sp; gd->bd = bd; debug("Reserving %zu Bytes for Board Info at: %08lx\n", sizeof (bd_t), addr_sp); #ifdef CONFIG_MACH_TYPE gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */ #endif addr_sp -= sizeof (gd_t); id = (gd_t *) addr_sp; debug("Reserving %zu Bytes for Global Data at: %08lx\n", sizeof (gd_t), addr_sp); /* setup stackpointer for exeptions */ gd->irq_sp = addr_sp; #ifdef CONFIG_USE_IRQ addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); debug("Reserving %zu Bytes for IRQ stack at: %08lx\n", CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp); #endif /* leave 3 words for abort-stack */ addr_sp -= 12; /* 8-byte alignment for ABI compliance */ addr_sp &= ~0x07; #else addr_sp += 128; /* leave 32 words for abort-stack */ gd->irq_sp = addr_sp; #endif debug("New Stack Pointer is: %08lx\n", addr_sp); #ifdef CONFIG_POST post_bootmode_init(); post_run(NULL, POST_ROM | post_bootmode_get(0)); #endif gd->bd->bi_baudrate = gd->baudrate; /* Ram ist board specific, so move it to board code ... */ dram_init_banksize(); display_dram_config(); /* and display it */ gd->relocaddr = addr; gd->start_addr_sp = addr_sp; gd->reloc_off = addr - _TEXT_BASE; debug("relocation Offset is: %08lx\n", gd->reloc_off); memcpy(id, (void *)gd, sizeof(gd_t)); base_sp = addr_sp; //relocate_code(addr_sp, id, addr); return (unsigned int)id; /* NOTREACHED - relocate_code() does not return */ }
修改 include/common.h 的patch如下:
/* arch/$(ARCH)/lib/board.c */ -void board_init_f (ulong) __attribute__ ((noreturn)); -void board_init_r (gd_t *, ulong) __attribute__ ((noreturn)); +unsigned int board_init_f (ulong) ; +void board_init_r (gd_t *, ulong) ;
修改 include/configs/smdk2440.h :
#define CONFIG_SYS_TEXT_BASE 0x33f00000 //重定义代码段基地址 ... /*注释以下部分:*/ //#define CONFIG_USB_OHCI //#define CONFIG_USB_KEYBOARD //#define CONFIG_USB_STORAGE //#define CONFIG_DOS_PARTITION ... //#define CONFIG_RTC_S3C24X0 ... //#define CONFIG_BOOTP_BOOTFILESIZE //#define CONFIG_BOOTP_BOOTPATH //#define CONFIG_BOOTP_GATEWAY //#define CONFIG_BOOTP_HOSTNAME ... //#define CONFIG_CMD_DATE //#define CONFIG_CMD_DHCP ... //#define CONFIG_CMD_USB ... /*修改终端信息*/ #define CONFIG_SYS_PROMPT "U-boot-2012# " ... /*定义*/ #define CONFIG_CMD_NAND_YAFFS //支持nand write.yaffs #define CONFIG_BOOTARGS "console=ttySAC0 root=/dev/mtdblock3"
//后面用了ubi文件系统所以参数设置如下:
//bootargs=console=ttySAC0,115200 ubi.mtd=3 root=ubi0:rootfs rootfstype=ubifs
#define CONFIG_BOOTCOMMAND "nand read 30000000 kernel;bootm 30000000" /*修改*/ #define CONFIG_SYS_MAX_FLASH_SECT (128)
#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 0x40000 #define CONFIG_ENV_SIZE 0x20000 #define CONFIG_ENV_RANGE CONFIG_ENV_SIZE ...
//设置mtd分区为:uboot:256k; params:128k; kernel:4m; rootfs:余下大小; #define CONFIG_CMD_MTDPARTS #define CONFIG_MTD_DEVICE #define MTDIDS_DEFAULT "nand0=jz2440-0" #define MTDPARTS_DEFAULT "mtdparts=jz2440-0:256k(u-boot)," \ "128k(params)," \ "4m(kernel)," \ "-(rootfs)" \ //注释掉原来文件系统部分定义: #if 0 #define CONFIG_CMD_FAT #define CONFIG_CMD_EXT2 #define CONFIG_CMD_UBI #define CONFIG_CMD_UBIFS #define CONFIG_CMD_MTDPARTS #define CONFIG_MTD_DEVICE #define CONFIG_MTD_PARTITIONS #define CONFIG_YAFFS2 #define CONFIG_RBTREE #endif
③添加 board/samsung/smdk2440/init.c 供start.S调用,内容如下:
/* 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_ll(unsigned int addr, unsigned char *buf, unsigned int len); static 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_ll((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_ll(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); } static void nand_select(void) { NFCONT &= ~(1<<1); } static void nand_deselect(void) { NFCONT |= (1<<1); } static void nand_cmd(unsigned char cmd) { volatile int i; NFCMMD = cmd; for (i = 0; i < 10; i++); } static 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++); } static void nand_wait_ready(void) { while (!(NFSTAT & 1)); } static unsigned char nand_data(void) { return NFDATA; } void nand_read_ll(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(); }
修改Makefile增加编译 init.c :
COBJS := smdk2410.o init.o
④.内存控制器的设置值改为如下:/board/samsung/smdk2440/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
⑤设置串口波特率(get_HCLK函数),修改 /include/configs/smdk2440.h(拷贝的2410) 的宏定义为 CONFIG_S3C2440:
//#define CONFIG_S3C2410 /* specifically a SAMSUNG S3C2410 SoC */ #define CONFIG_S3C2440 ... #define CONFIG_SYS_MAX_FLASH_SECT (128)
⑥支持NOR-FLASH: 在 /drivers/mtd/jedec_flash.c 的 jedec_table[] 中增加一项匹配板子上的NOR-Flash厂商ID和设备ID:
/* JZ2440使用的MT29LV160DB */ { .mfr_id = (u16)MX_MANUFACT, /* 厂家ID */ .dev_id = 0X2249, /* 设备ID */ .name = "MXIC MT29LV160DB", .uaddr = { /* NOR flash看到解锁地址 */ [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), } }, },
Ps: 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。
⑦支持NAND-FLASH:
修改 include/configs/smdk2440.h :
//根据配置定义对应的宏:
#ifdef CONFIG_S3C2410 #define CONFIG_NAND_S3C2410 #define CONFIG_SYS_S3C2410_NAND_HWECC #else #define CONFIG_NAND_S3C2440 #define CONFIG_SYS_S3C2440_NAND_HWECC #endif
仿照 drivers/mtd/nand/s3c2410_nand.c 编写s3c2440_nand.c:
/* * (C) Copyright 2006 OpenMoko, Inc. * Author: Harald Welte <laforge@openmoko.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include <common.h> #include <nand.h> #include <asm/arch/s3c24x0_cpu.h> #include <asm/io.h> #define S3C2410_NFCONF_EN (1<<15) #define S3C2410_NFCONF_512BYTE (1<<14) #define S3C2410_NFCONF_4STEP (1<<13) #define S3C2410_NFCONF_INITECC (1<<12) #define S3C2410_NFCONF_nFCE (1<<11) #define S3C2410_NFCONF_TACLS(x) ((x)<<8) #define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) #define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) #define S3C2410_ADDR_NALE 4 #define S3C2410_ADDR_NCLE 8 #ifdef CONFIG_NAND_SPL /* in the early stage of NAND flash booting, printf() is not available */ #define printf(fmt, args...) static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) { int i; struct nand_chip *this = mtd->priv; for (i = 0; i < len; i++) buf[i] = readb(this->IO_ADDR_R); } #endif /* ctrl : 表示做什么, 选中芯片/取消选中, 发命令还是发地址 * * dat : 命令值或地址值 */ static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl) { struct s3c2440_nand *nand = s3c2440_get_base_nand(); if (ctrl & NAND_CLE) { /* 发命令 */ writeb(dat, &nand->nfcmd); } else if(ctrl & NAND_ALE) { /* 发地址 */ writeb(dat, &nand->nfaddr); } } static int s3c2440_dev_ready(struct mtd_info *mtd) { struct s3c2440_nand *nand = s3c2440_get_base_nand(); debug("dev_ready\n"); return readl(&nand->nfstat) & 0x01; } static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr) { struct s3c2440_nand *nand = s3c2440_get_base_nand(); switch (chipnr) { case -1: /* 取消选中 */ nand->nfcont |= (1<<1); break; case 0: /* 选中 */ nand->nfcont &= ~(1<<1); break; default: BUG(); } } 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; }
Makefile添加编译:
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
另外 drivers/mtd/nand/nand_util.c 修改patch如下:
@@ -515,7 +515,9 @@ return -EINVAL; } - if (!need_skip && !(flags & WITH_DROP_FFS)) { + + /* 并且标志没有yaffs*/ + if (!need_skip && !(flags & WITH_DROP_FFS) && !(flags & WITH_YAFFS_OOB) ) { rval = nand_write (nand, offset, length, buffer); if (rval == 0) return 0; @@ -553,7 +555,7 @@ ops.len = pagesize; ops.ooblen = nand->oobsize; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OOB_RAW; ops.ooboffs = 0; pages = write_size / pagesize_oob; @@ -564,7 +566,7 @@ ops.oobbuf = ops.datbuf + pagesize; rval = nand->write_oob(nand, offset, &ops); - if (!rval) + if (rval) break; offset += pagesize;
可以修改 drivers/mtd/cfi_flash.c 关闭调试:
#include <mtd/cfi_flash.h> #include <watchdog.h> //#define DEBUG 1 //#define _DEBUG 1
⑧支持DM9000网卡:
启动uboot,打印出Net: CS8900-0,而我们的网卡是DM9000,于是在代码中搜索“Net:”,定位到common/board_r.c的initr_net函数,一路追踪eth_initialize, eth_common_init,一直到 \board\samsung\smdk2440(拷贝的2410)\smdk2410.c的board_eth_init函数:
- int board_eth_init(bd_t *bis)
- {
- int rc = 0;
- #ifdef CONFIG_CS8900
- rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
- #endif
- return rc;
- }
这里是对CS8900进行了初始化,我们要对DM9000进行初始化,通过查看drivers/net/Makefile,发现要包含dm9000x.c的文件,要定义CONFIG_DRIVER_DM9000这个宏,我们也要注释掉CONFIG_CS8900宏。同时查看dm9000x.c,里面有一个dm9000_initialize函数,于是仿照cs8900来写dm9000的初始化函数,修改smdk2410.c:
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; }
配置文件smdk2440.h(拷贝的2410)修改如下:
/* * 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:4d:e4:f4
保存,编译,烧写,启动Uboot,网卡正常启动。设置一下开发板ip:set ipaddr 192.168.0.2。网线连接开发板和路由器,ping一下主机ip:
ping 192.168.0.100,能够Ping通。再试试能不能用tftp下载文件,
set serverip 192.168.0.100
tftp 30000000 u-boot.bin
使用tftp下载文件也成功,至此,DM9000网卡已经支持。
问题:
新的uboot可能在不插串口线时无法自动启动内核,因为串口引脚没接上拉电阻导致误认为有按键输入而进入了uboot模式,可以修改uboot源码默认只在输入空格进入uboot,可以参考如下path:
diff -urN u-boot-2012.04.01/common/main.c u-boot-2012.04.01_4m/common/main.c --- u-boot-2012.04.01/common/main.c 2012-04-25 06:22:50.000000000 -0700 +++ u-boot-2012.04.01_4m/common/main.c 2018-11-15 02:20:44.351768306 -0800 @@ -226,9 +226,10 @@ */ if (bootdelay >= 0) { if (tstc()) { /* we got a key press */ - (void) getc(); /* consume input */ + //(void) getc(); /* consume input */ puts ("\b\b\b 0"); - abort = 1; /* don't auto boot */ + if(' ' == getc())/* if got space */ + abort = 1; /* don't auto boot */ } }
-end-
posted on 2016-09-19 22:47 sheldon_blogs 阅读(3835) 评论(2) 编辑 收藏 举报