嵌入式软件工程师&&太极拳
全部博文(548)
分类: LINUX
2011-02-20 20:24:23
2010_6_30:(张国威) u-boot-2009.11 u-boot的版本 make smdk2440_config make make clean make distclean 彻底的清除,配置文件等全会删除掉,删除的很干净 u-boot的Makefile的架构: 控制哪个目录被编译:如果想编译drivers/dma,就要在主makefile里添加LIBS += drivers/dma/libdma.a 这样就会调用drivers/dma下的makefile编译出libdma.a文件,最后主makefile把所有依赖的.a文件链接起来 控制哪个文件被编译:在每个子目录里的makefile里有COBJS-$(变量) = main.o 这样的语句,如果$(变量)=y 才会编译main.c文件 make smdk2410_config 配置开发板的编译环境,后面跟相对应的开发板名称_config 找到在主Makefile smdk2410_config规则,依赖unconfig 就是把配置过的文件删除掉 调用mkconfig Shell脚本生成include/config.h和include/config.mk文件 config.mk: 这些都是在主Makefile调用mkconfig传的参数,如果在哪把参数改了,这里也会改了,而这些会被Makefile调用引用这些变量,这样就会在这输入什么平台就会到以此平台命名的文件夹里编译,其它也同样 ARCH = arm 指定平台 CPU = arm920t CPU类型 BOARD = smdk2410 板子型号 VENDOR = samsung 板子厂商 SOC = s3c24x0 片上系统 config.h: 传什么板子型号,就包含include/configs/板子型号.h ,然后makefile里包含config.h头文件,这样就实现什么板子就什么配置 凡是有defined(CONFIG_S3C2410)就|| defined(CONFIG_S3C2440), 因为2410有的功能2440都有,所以除了2440和2410不同处修改,其它的或上2440就可以了 2440和2410基本一样,所以在2410的基础上改出2440,为了方便不需要在smdk2440_config里定义2440的宏,还是用2410的宏,只要把和2440不同代码处删除写成2440用的代码就行了 2410和2440的不同处: GPIO:(部分寄存器不一样) include/s3c24x0.h 对应手册把寄存器过一遍 clock_power: board/samsung/smdk2410/smdk2410.c 把#define M_MDIV 0xA1改成 #define M_MDIV 0x7f 因为2440的主时钟频率是400.5MHz 把#define U_M_MDIV 0x48改成#define U_M_MDIV 0x38 把USB时钟频率改成2440的 把gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;改成gd->bd->bi_arch_number = MACH_TYPE_S3C2440; MACH_TYPE_S3C2440是u-boot给内核传参传的机器类型,到include/asm/mach-types.h里找板子对应的机器类型 cpu/arm920t/s3c24x0/speed.c 把get_PLLCLK函数的return 改成: 获取MPLL值的函数 if (pllreg == MPLL) return ((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s)); 这个算2440的MPLL else return ((CONFIG_SYS_CLK_FREQ * m) / (p << s)); 这个是算2410的MPLL 把get_HCLK函数的return 改成: 获取HCLK值函数 if (clk_power->CLKDIVN & 0x6) { if ((clk_power->CLKDIVN & 0x6) == 2) return (get_FCLK() / 2); if ((clk_power->CLKDIVN & 0x6) == 6) return ((clk_power->CLKDIVN & 0x100) ? get_FCLK() / 6 : get_FCLK() / 3); if ((clk_power->CLKDIVN & 0x6) == 4) return ((clk_power->CLKDIVN & 0x200) ? get_FCLK() /8 : get_FCLK() / 4); return (get_FCLK()); } else return (get_FCLK()); nand flash: 因为2440和2410 nand flash的寄存器不一样,所以怎么操作读写nand flash不一样,所以要改读写操作的代码 drivers/mtd/nand/s3c2410_nand.c 2410和2440的寄存器不同,所以先把寄存器的值变了 把最前面定义的宏删除改成: #define S3C2410_NFCONT_EN (1 << 0) #define S3C2410_NFCONT_INITECDC (1 << 4) #define S3C2410_NFCONT_nFCE (1 << 1) #define S3C2410_NFCONF_MAINECCLOCK (1 << 5) #define S3C2410_NFCONF_TACLS(x) ((x) << 12) #define S3C2410_NFCONF_TWRPH0(x) ((x) << 8) #define S3C2410_NFCONF_TWRPH1(x) ((x) << 4) #define S3C2410_ADDR_NALE 0x08 #define S3C2410_ADDR_NCLE 0x0c 在全局加上:ulong IO_ADDR_W = S3C2410_NAND_BASE; 得到nand flash 控制器的基地址 在s3c2410_hwcontrol函数里: 把NFCONF改成NFCONT,因为2410里NFCONF在2440里NFCONT设置 把struct nand_chip *chip = mtd->priv;和 ulong IO_ADDR_W = (ulong)nand;和chip->IO_ADDR_W = (void *)IO_ADDR_W;注释掉 把writeb(cmd, chip->IO_ADDR_W);改成writeb(cmd, (void *)IO_ADDR_W); 在s3c2410_dev_ready函数里也同上把NFCONF改成NFCONT 在board_nand_init函数里把时序换成2440的: twrph0 = 4; twrph1 = 2; tacls = 0; cfg = 0; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3c2410_NFCONF_TWRPH1(twrph1 - 1); writel(cfg, &nand_reg->NFCONF); cfg = (0 << 13) | (0 << 12) | (0 << 10) | (0 << 9) | (0 << 8) | (0 << 6) | (0 << 5) | (1 << 4) | (0 << 1) | (1 << 0); writel(cfg, &nand_reg->NFCONT); nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; Start.S 向量表 清cpsr改成SVC管理模式 这个不做也可以,因为默认就是管理模式 关看门狗 这步绝对要做的,要不然就重启了 屏蔽所有中断,设置INTMSK和SUBINTMSK 这个不做也行,因为默认为关闭的 设置时钟 设置总线模式 设置倍频 设置CP15 初始化内存 设置nand flash启动 把nand flash上0地址的u-boot.bin拷贝到内存上,拷到内存哪里可以在board/samsung/smdk2410/config.mk里看到,这里面设置了拷贝到内存哪的基地址,拷贝的长度通过u-boot.lds链接脚本里设置段标签来算出来,代码段,只读段,数据段都要拷贝,BSS段不用拷,所以用bss_start减去代码段的text_start就是要拷贝的长度,然后自己写nand read命令把nand flash 0地址的u-boot.bin读到内存上,因为nand read命令是用C写的,所以要设置临时栈基地址,读完后再把CPU里的SRAM 4K数据和刚拷贝到内存的前4K数据对比,因为都是从nand flash 0地址拷贝的数据,所以前4K数据应该完全相同,所以如果对比不同就死循环 设置栈基地址,Malloc的长度 清bss段为零,BSS段要保证为0 跳到start_armboot 因为初始化内存和nand read都是跳到其它地方执行,如果没有保证初始化内存和nand read的代码在4K以内,就会跳到其它地方就挂了,所以要修改u-boot.lds链接脚本: .text : { cpu/arm920t/start.o (.text) 初始化内存文件路径 (.text) nand read文件路径(.text) * (.text) } 这样就可以保证它们都在4K以内 因为u-boot的大部分的代码是在内存上运行的,所以如果自己写bootloadler,这里链接的时候要写内存上的基地址,这个地址是要把u-boot拷贝到内存的哪就是哪个地址,这样的话就会有问题了,在前4K代码里如果用到某些数据的时候,而链接的时候是以内存上的地址为起始链接的,所以直接访问就出错了,所以这里要采用地址偏移的方法来访问,即链接的时候的基地址减去现在要访问的地址就得到了偏移值,如果采用偏移的方法,就不可以使用全局变量,因为全局变量是固定的地址,所以访问的话就会出错,用b跳转命令就是采用pc偏移来找 DM9000x的移植: drivers/net/dm9000x.c 把有关phy的全部注释 static u16 phy_read(int); static void phy_write(int, u16); 把上面两个函数的声明和实现都注释掉 在dm9000_halt函数里把RESET devie下面的PHY相关的四句也注释掉 下面把打印__func__换成函数名即可: 把DM9000_DMP_PACKET(__func__, packet, length);换成DM9000_DMP_PACKET("dm9000_send", packet, length); 把DM9000_DBG("%s\n", __func__);改成DM9000_DGB("%s\n", "dm9000_halt"); 把DM9000_DMP_PACKET(__func__, rdptr, RxLen);改成DM9000_DMP_PACKET("dm9000_rx", rdptr, RxLen); 如果改了上面下载到板子ping会很慢或tftp会很慢的话,提示could not establish link,就把dm9000_init函数里while(!(phy_read(1) & 0x20))开头到最后return上面都注释掉就可以了,相对应把没有用到的变量也注释掉 u-boot给内核传参: tftp 30008000 uImage 下载内核到内存30008000上 bootm 30008000 跳到30008000执行启动内核 u-boot怎么知道现在要启动的内核文件是什么内核? 所以内核文件前面有64字节的头信息,所以u-boot来读这个头信息就知道什么内核,内核的入口地址等 这个头信息是u-boot提拱工具加上去的,不是内核 mkimage -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -n "linux kernel" -d ./zImage uImage -A 指定什么平台 -O 指定什么系统 -T 指定镜像文件类型 -C 指定镜像文件压缩类型,这里写none -a 指定内核存放地址 -e 指定内核入口地址 -n 指定镜像文件名字 -d 要准备加头的文件路径和生成后文件的路径,中间用空格隔开 这里也不是一定要转换,如果用的不是u-boot或自己写u-boot想写死地址等,就不需要转换 bootm也是命令,所以看bootm命令的实现,bootm命令执行的函数为do_bootm,do_bootm读内核头信息,调用对应的内核设置参数函数,linux就会调用do_bootm_linux函数,这个函数就是启动内核函数,在lib_arm/bootm.c文件里 do_bootm_linux: void (*kernel)(int, int, unsigned int); 这个函数指针就是内核的入口函数,给内核传参就是这个函数的参数,但是因为参数有可能会很多,为了灵活传参,所以这里只是传一个地址,而这个地址里放内核的参数,内核拿到这个地址就去此地址里读参数即可;第一个参数无意义,内核规定死为0,第二个参数为机器码,机器码对应板子,这个是内核决定的,第三个参数为要给内核传的参数的地址,所以要先在参数地址哪把参数写好,参数怎么写这是内核来决定的,所以要按内核规定格式来写,内核才能认识 参数格式: board/samsung/smdk2410/smdk2410.c gd->bd->bi_boot_params = 0x30000100; 为给内核传的参数保存的地址,要改就改这地方 每个参数就是用struct tag这个结构体来表示 struct tag_header 这个结构体放后面联合用什么内核参数类型的标识和此参数结构体的大小,那个标识内核规定的,看内核手册找,大小是struct tag这个的大小 union 这个联合里放内核参数的类型 struct tag_core 这个为起始参数,内核规定少不了 struct cmdline 这个放给内核传的参数,所以这个也是少不了,这个参数的大小是要传的参数的大小加struct tag_header的大小,因为要4个字节对齐,所以要再加4,要只多不少 struct mem32 设置内存的参数 u-boot里添加命令: U_Boot_CMD( 命令名称, 命令最多的参数, 按回车要不要重复上次命令,(0为不重复,1为重复) 命令执行的函数名, (命令执行的函数) 短错误提示信息, (一般错误提示) 长错误提示信息, (加--help等参数提示信息) );