参看:DAVINCI DM365-DM368开发攻略——U-BOOT-2010.12及UBL的移植
参看:DAVINCI DM365-DM368开发攻略——linux-2.6.32的移植
一、介绍u-boot-2010.12的特点
u-boot-2010.12的架构组织越来越向LINUX架构靠拢,这是U-BOOT的发展趋势。DM36x的UBOOT源码放在dvsdk_dm368_4_02_00_06\psp的下面,文件夹叫u-boot-2010.12-rc2-psp03.01.01.39,太长了,我们直接u-boot-2010.12。这个u-boot-2010.12支持YAFFS2、UBI等文件系统,支持SD卡、USB、VIDEO等驱动,支持lzma和lzo的内核镜像压缩,还有经典的linux shell命令支持模式,就是tab等的妙用,就是在”U-boot >”提示符下键入和LINUX 开发主机上一样的命令,当然这个命令很少,而且有些命令是用户自己加的。相对以前的u-boot-1.3.4版本等版本,这个新U-BOOT把很多平台的配置脚本给去掉了。
二、u-boot-2010.12的移植
DAVINCI芯片系列的UBOOT移植大同小异,比较简单。
1、首先修改:Makefile:
第140行:#examples/standalone \
第141行:#examples/api
第246行: #LIBS += api/libapi.o
等一下我们就可以把一些不相关的文件夹给删除掉,给u-boot-2010.12瘦身。
第323行:ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND) u-boot.img
后面增加u-boot.img,这个u-boot.img就是我们要烧写到NAND里边的BIN文件,可以被UBL给BOOT起来的文件,因为u-boot.img是通过u-boot-2010.12\tools下的mkimage的工具生产的,带有头header的文件,这些头信息能被UBL给识别,所以才能烧写到NAND FLASH或NOR FLASH里边去。而u-boot.bin是没有增加文件头部信息的文件,不能被UBL直接给BOOT起来。u-boot.bin只能使用软件BOOT,比如: tftp 0x82080000 u-boot.bin ;go 0x82080000。
最重要的地方修改:第350行:-a $(CONFIG_SYS_TEXT_BASE) -e 0x81080000 \
或者-a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE)\
刚开始这个-e 0是错误的,我们把U-BOOT-2010.12的entrypoint定义到0x81080000,这个DDR的地址是在u-boot-2010.12\board\davinci\dm365evm\config.mk
CONFIG_SYS_TEXT_BASE = 0x81080000
这个-e(entrypoint)不能是0,否则无法被UBL给BOOT起来。
第953行是不需要改动的:
davinci_dm365evm_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm926ejs dm365evm davinci davinci
DM368也是使用同样的dm365evm名字。
2、开始删除一些不相关的文件夹
u-boot-2010.12\api文件夹
u-boot-2010.12\examples
u-boot-2010.12\nand_spl
u-boot-2010.12\onenand_ipl
u-boot-2010.12\arch\里的只保留arm文件夹
u-boot-2010.12\ arch\arm\cpu文件夹里,只保留arm926ejs
u-boot-2010.12\ arch\arm\cpu\arm926ejs文件夹里,只保留davinci文件夹,我们只删除文件夹,旁边的cpu.c和Makefile不要删除,等等;
u-boot-2010.12\board里边,只保留davinci文件夹,其他统统删除掉;
u-boot-2010.12\board\davinci\里,只保留dm365evm和common,其他删除;
u-boot-2010.12\include\configs里,只保留davinci_dm365evm.h,其他文件和文件夹删除掉;
通过上面的操作,我们的u-boot-2010.12简化多了。
3、修改最重要的davinci_dm365evm.h
在u-boot-2010.12\include\configs里,davinci_dm365evm.h
修改#define CONFIG_SYS_NAND_MAX_CHIPS 1,把以前的2改成1,表示本系统只支持1片NAND FLASH;
把#define CONFIG_BOOTCOMMAND "if mmc rescan 0; then if fatload mmc 0 0x80600000 boot.scr; then source 0x80600000; else fatload mmc 0 0x80700000 uImage; bootm 80700000; fi; fi"给注释掉,我们不想用SD卡保存内核的BIN文件uImage;
然后定义#define CONFIG_BOOTCOMMAND "run nand_boot",表示从NAND FLASH 读取内核;
修改UBOOT的BOOTARGS参数:#define CONFIG_BOOTARGS \
"console=ttyS0,115200n8 mem=60M noinitrd rw ip=192.168.1.188:192.168.1.252:192.168.1.1:255.255.255.0 root=/dev/nfs nfsroot=192.168.1.252:/home/davinci/dm368/dvsdk_dm368_4_02_00_06/filesystem/dm368rootfs,nolock"
我们这里提到mem=60M,是有根据的,我们板子是128M-BTYE,因为后面的DVSDK4.02里边的encodedecode等例子需要用到CMEM,这个和DM6446类似,所以定义为60M。
见dvsdk_dm368_4_02_00_06\filesystem\dvsdk-dm368-evm-rootfs解压后的etc\init.d\loadmodule-rc文件:
# Default DM368 EVM Memory Map
#
# Start Addr Size Description
# -------------------------------------------
# 0x00001000 32K ARM TCM memory
# 0x80000000 48 MB Linux
# 0x83000000 12 MB Video driver memory (Linux)
# 0x83C00000 68 MB CMEM
# 0x88000000 BOTTOM ADDRESS
load () {
modprobe cmemk phys_start=0x83C00000 phys_end=0x88000000 allowOverlap=1 phys_start_1=0x00001000 phys_end_1=0x00008000 pools_1=1x28672 useHeapIfPoolUnavailable=1
modprobe irqk
modprobe edmak
modprobe dm365mmap
mknod /dev/dm365mmap c `awk "\\$2==\"dm365mmap\" {print \\$1}" /proc/devices` 0
}
有些人定义CMEM共享内存小一点的话,那么这个值可以比60M大。后面的参数就是使用静态固定IP的NFS SERVER路径,进行NFS调试;
增加
#define CONFIG_IPADDR 192.168.1.188
#define CONFIG_SERVERIP 192.168.1.252
#define CONFIG_ETHADDR 00:03:55:88:00:00
定义板子自己的IP和MAC,这个MAC在保证和其他网络设备MAC不冲突的前提下,自己调试的时候顺便分配。SERVERIP就是我们LINUX开发环境的主机IP地址,主要用做TFTP和NFS调试。
#define CONFIG_EXTRA_ENV_SETTINGS \
"eraseenv=nand erase 0x00060000 0x00020000\0" \
"eraseall=nand erase 0x00000000 0x08000000\0" \
"updateuboot=tftp 0x84000000 dm368_uboot.bin;nand erase 80000 80000;nand write 84000000 80000 80000\0" \
"updatecore=tftp 0x84000000 dm368_kernel.bin;nand erase 0x00100000 0x00480000;nand write 84000000 100000 300000\0" \
"nand_boot=nboot 0x80700000 0 0x100000;bootm\0" \
"tftp_boot=tftpboot 0x80700000 dm368_kernel.bin;bootm\0"
这个很精典,我以前在DM6446上面U-BOOT-2009.03的移植上说过,在u-boot->的提示下,使用run 命令,就可以批量自动做一些操作。CONFIG_EXTRA_ENV_SETTINGS这个在u-boot-2010.12\common\env_common.c 和u-boot-2010.12\common\env_embedded.c有使用。你尽管在这里定义就可以了。
run eraseenv表示擦除u-boot的参数;
run eraseall表示擦除整片NAND;
run updateuboot表示通过TFTP烧写dm368_uboot.bin到板子上;
run updatecore表示烧写内核文件,300000表示内核BIN的大小,我们这里直接定死,3M的内核BIN文件长度够用了,当然,你可以根据内核大小的动态长度改变烧写方法;
TFTP先下载BIN文件(uImage)到DDR 的0x84000000地址,然后烧写到自己定义的分区上,这个和内核linux-2.6.32.17的分区是一一对应的,这点很重要;
"nand_boot=nboot 0x80700000 0 0x100000;bootm\0";内核放在NAND的0x100000,我们使用run nand_boot进行板级内核启动;
"tftp_boot=tftpboot 0x80700000 dm368_kernel.bin;bootm\0"使用TFTP进行内核软件启动,编译调试内核;
在run eraseenv中,我们使用0x00060000作为U-BOOT参数存放的偏移地址,长度使用128K-BYTE,所以在第183行处开始:
#ifdef CONFIG_NAND_DAVINCI
#define CONFIG_ENV_SIZE (128 << 10) /* 128KiB */ //128K-byte for evn
#define CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_OFFSET 0x00060000
#undef CONFIG_ENV_IS_IN_FLASH
#endif
顺便说一下,我们一般不建议在U-BOOT里边通过TFTP下载和烧写至少几十M的文件系统,我们尽量简化U-BOOT的功能,因为我们产品的重点是在LINUX内核,所有的开发、应用、升级程序都是基于LINUX内核上的,所以我们建议通过LINUX内核驱动来烧写文件系统,这是后话。
4、使能使用tab键功能
这个功能就是能在U-boot->的命令提示符下使用tab键,所以说
在davinci_dm365evm.h里一定要在“#define CONFIG_SYS_HUSH_PARSER”的上一行或下一行定义CONFIG_AUTO_COMPLETE;
在u-boot-2010.12\common\command.c里,第165行,把“#if 0”改成“#if 1”;
在u-boot-2010.12\common\env_common.c里,第247行把“#if 0”改成“#if 1”;
5、增加GPIO驱动的功能和修改一些BUG
复位外围芯片,比如采用GPIO控制网口芯片复位,在u-boot-2010.12\board\davinci\dm365evm\dm365evm.c的board_init()函数,增加GPIO的复位驱动,对一些外围的芯片复位一下;
在u-boot-2010.12\common\cmd_nvedit.c里,第227行,把“((strcmp (name, "ethaddr") == 0)”用“(0”,这样就能任意修改保存在网口MAC地址ethaddr;
6、开始编译
在u-boot-2010.12\arch\arm的config.mk里
#CROSS_COMPILE ?= arm-linux-
CROSS_COMPILE = arm-none-linux-gnueabi-
我们使用Code Sourcery ARM GCC Tool Chain的Sourcery G++ Lite 2009q1-203 for ARM GNU/Linux。
注意,除了UBL在UBL的文件夹内部编译外,其他的DVSDK的文件包u-boot,linux,dm365mm,irq ,edma,ceexamples,dmai,还有psp_examples,等等,都是在dvsdk_dm368_4_02_00_06的目录下编译,具体见dvsdk_dm368_4_02_00_06的Makefile。
u-boot的编译是:make u-boot,make u-boot_clean等等;
我们也可以在这个目录下自己生产一个build_uboot.sh的命令
#build u-boot in dvsdk4_02
make u-boot
chmod 777 /home/davinci/dm368/dvsdk_dm368_4_02_00_06/psp/u-boot-2010.12/u-boot.img
cp -f /home/davinci/dm368/dvsdk_dm368_4_02_00_06/psp/u-boot-2010.12/u-boot.img /tftpboot/dm368_uboot.bin
或者再增加build_uboot_all.sh
#build u-boot in dvsdk4_02
make u-boot_clean
make u-boot
chmod 777 /home/davinci/dm368/dvsdk_dm368_4_02_00_06/psp/u-boot-2010.12/u-boot.img
cp -f /home/davinci/dm368/dvsdk_dm368_4_02_00_06/psp/u-boot-2010.12/u-boot.img /tftpboot/dm368_uboot.bin
使用sh文件帮你做工,要多养成这样的习惯。
基本上,你的板子网口OK的话,可以通过TFTP把UBOOT烧进去吧,通过仿真器或者其他方式烧写,我们公司一般不用仿真器烧写,直接使用uart boot的方式烧写,自己写个uart boot的东西,好好看看dvsdk_dm368_4_02_00_06\psp\flash-utils的包里的东西,这里就保留吧。
三、介绍linux-2.6.32:
Linux-2.6.32的网上介绍:增添了虚拟化内存 de-duplicacion、重写了 writeback 代码、改进了 Btrfs 文件系统、添加了 ATI R600/R700 3D 和 KMS 支持、CFQ 低传输延迟时间模式、perf timechart 工具、内存控制器支持 soft limits、支持 S+Core 架构、支持 Intel Moorestown 及其新的固件接口、支持运行时电源管理、以及新的驱动;这些本人不懂,但是本人只注意到常用的LINUX操作系统RADHAT Enterprise 6,ubuntu-10.04,debian 6.0稳定版本,这些都是使用linux-2.6.32这个版本,智能手机就更多了,android手机(经典版本HTC-G7手机使用linux-2.6.32.15和android 2.2版本结合),因为只有从linux-2.6.32以后,才能发挥android系统的优势;不过单核的DM368无论是432MHz还是新出的500多MHz,跑android系统非常困难,只能跑QT,这里不讨论;
本人写内核的环境和路径都是基于前两篇文章的基础上进行的,先从dvsdk_dm368_4_02_00_06\下的Rules.make和Makefile开始,见Rules.make第45行,
LINUXKERNEL_INSTALL_DIR=$(DVSDK_INSTALL_DIR)/psp/linux-2.6.32.17
很明显我们把内核名字改成linux-2.6.32.17,原来解压安装出来的名字太长了,所以要在Rules.make第45行改一下;Makefile是编译的脚本,TI把整个DVSDK4.02的开发环境统一整合在一起,体现在这个Makefile,看完这个Makefile,就应该知道如何编译整个DVSDK里所有的软件包,内核编译的命令见143行开始;在dvsdk_dm368_4_02_00_06\目录下使用make linux,make linux_config, make linux_clean等命令编译内核;
四、开始移植:从删除多余的文件夹和文件开始:
1、dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm/configs
只保留davinci_dm365_defconfig
图-1
然后按上图-1,先使用默认的config文件进行内核配置,
cp arch/arm/configs/davinci_dm365_defconfig .config
注意路径;
2、删除非ARM芯片平台的处理器
进入dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch,保留arm,um,x86三个文件夹,其他文件删除掉;
然后进入dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/um文件夹,只保留scripts文件夹,其他删除掉,包括那几个文件Kconfig等文件也删除掉;
继续进入dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/x86文件夹,只保留include和mm文件夹,和几个文件,其他文件夹删除掉见下图-2:
图-2
继续进入dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm文件夹,保留mach-davinci文件夹和保留下图的文件夹和文件,其他带mach-删除吧,占空间,又占备份时压缩的时间,
图-3
上图-3就是dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm目录下删除后的结果显示;
3、修改dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm/Makefile,
从第120行开始,#machine-$(CONFIG_ARCH_AAEC2000) := aaec2000
一直到172行,
#machine-$(CONFIG_ARCH_MXC91231) := mxc91231
只保留machine-$(CONFIG_ARCH_DAVINCI) := davinci,其他全部使用”#”给屏蔽掉,我们只要machine-$(CONFIG_ARCH_DAVINCI) := davinci
第176行到第184统统使用”#”给屏蔽掉,不要这些芯片平台;
4、修改dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm/Kconfig
从第707行开始,一直到793行,这些全部使用“#”给屏蔽掉,保留第795行的source "arch/arm/mach-davinci/Kconfig",然后继续把第797到805行使用“#”给屏蔽掉;
经过上面的删除,使用tar jcf 或 tar zcf压缩的linux-2.6.32.17降到51M,比没有删除的减小近一半的大小;我们追求简洁,思路清晰;其实还有很多地方可以删除的,大家慢慢体会,包括include,driver里边的老掉牙的设备,这里就不啰嗦了;删除后记得把对应的Kconfig和Makefile给屏蔽掉;
五、开始从内核配置
图-4
因为前面已经做了cp arch/arm/configs/davinci_dm365_defconfig .config我们按上图指定的路径使用make linux_config,这样就看到熟悉的内核配置界面,见下图-5:
图-5
我们按顺序一个一个配置,当然,很多配置选项都是使用TI davinci_dm365_defconfig配置好的,我们对它们进行分析、裁剪、修改,
进入“General setup”配置
图-6
上图是我们多选了RAM disk文件系统支持的压缩方式,默认是使用gzip生产RAM DISK文件系统,你也可以使用bzip2和LZMA(压缩率比前面两个高);
图-7
进入“System Type”配置,上面按TI 原来的配置,
图-8
然后直接进入“TI Davinci Implementations”,按上面的选择,最后面的27000000表示你的主芯片晶振是27MHz还是24MHz,本公司的是24MHz晶振,我们就把27000000改成24000000;
图-9
返回图-5,进入“Networking support”,你的系统如果没有WIFI等无线模块,这个无线的“wireless”协议可以不选;
图-10
主要对“Networking options”进行配置,这里基本上就是IPV4和IPV6的协议配置,我们按TI原来的选择,带“M”选项也可以使用“*”编译进内核,而不是模块;
图-11
图-12
返回图-5进入“Device Drivers”,这是配置内核的重点,见图-11和图-12,
图-13
按顺序先对NAND FLASH分区MTD进行配置,直接参考TI 默认的配置;
图-14
图-14 RAM/ROM/FLASH及下面3个使用TI默认的配置,
图-15
进入“NAND device Support”的配置,一定要选择“Support NAND on Davinci SoC”,
图-16
这是2.6.32新的特性,开始支持UBI文件系统,UBI文件系统的出现,可以让JFFS2,YAFFS2退出市场,跑android系统,必须用到,这里我们可以不选,也可以选,根据你的板子要使用什么样的文件系统;
图-17
返回图-11进入“Block devices”配置,我们直接使用TI的配置,
图-18
返回图-11进入“SCSI device support”的配置,选择这个来支持U盘,否则你的U盘无法被DM368板子识别,我们一般把DM368 USB设置HOST模式;
图-19
返回图-11进入“Network device support”的配置,一般的RJ45网口选择“10M or 100Mbit”,DM368不支持1000Mbit,无线“Wireless LAN”你不需要的话可以不选;“PPP”这个可以不选,而有时要支持3G的模块的时候,PPP协议(见图-10的配置)和设备支持要选择;
图-20
进入“10M or 100Mbit”,选择“TI Davinci EMAC Support;
图-21
返回图-11进入“Input device support”,这选择是否支持鼠标键盘触摸屏等输入,我们这边用不上,直接不选;
图-22
返回图-11进入“Char device”,一定要选择DM365 IPIPE,IMP Previewer,IMP Resizer,这个到时候调试视频采集程序需要用到Previewer、Resizer等DAVINCI技术;
图-23
在图-22中,选择进入“Serial driver”,这里就是DM368的串口配置了,DM368支持UART0 和UART1,UART1和其他GPIO复用,小心分配使用硬件资源,和DM6446一样,都是8250的驱动,而DM6446可以配置3个UART;
图-24
返回图-11进入“I2C Support”,这个没得说,肯定使用选上的,
图-25
TI开发板使用的I2C扩展芯片,我们不需要,所以External就不要了,只选上“Davinci I2C driver”;
图-26
返回图-11进入“SPI Support”,如果你的板子没有外接SPI接口的芯片,这里可以不选;
图-27
返回图-11进入“GPIO Support”,TI使用芯片扩展更多的GPIO脚,我们不需要,可以不选;
图-28
返回图-11进入“Watchdog Timer Support”,凡是使用软件看门狗的,都需要选上这个,DM368和DM6446这些芯片都支持软件看门狗,注意选择是“Davinci watchdog”;
图-29
返回图-11进入 “Multimedia support”,多媒体支持,这个就是Davinci的重点,
图-30
按TI默认的选择,MT9P031 500万像素的SERSEOR可以选上,你有其他公司的SENSOR,也可以参考MT9P031的方法加入你SENSOR的驱动,然后修改linux-2.6.32.17\drivers\media\video里边的Makefile和Kconfig文件就OK了;
图-31
然后从图-30的“encoders/decoders and xxxx”进去选择TVP5146,高清Ypbpr输出THS7303,TH7353芯片的选择支持,我们公司使用TVP5158,本人把它加入内核编译,所以这里显示TVP5158,TVP7002我们没有使用,所以不用选;
图-32
返回图-11进入“Graphics Suppor”,这个就是选择支持TFT3.5, TFT4.3寸LCD屏的驱动,也就是通过RGB接口支持屏的输出,我板子不支持,可以选择也可以按TI默认的设置;
图-33
返回图-11进入“Sound card Suppor”,声卡选择,
图-34
DM368主芯片上带有音频功能的模块,直接按TI的设置,
图-35
返回图-11进入“USB Suppor”,我们把DM368跑的LINUX系统当作HOST来使用,“HID Support”是支持鼠标键盘之类的东西,可以选也可以不要;基本上采用TI的默认配置
图-36
这里选择支持U盘,这个和前面说过的SCSI Spport是对应的;
图-37
返回图-11进入“MMC/SD/SDIO Suppor”,linux-2.6.32的SD卡驱动完全支持32G的容量,DM368支持两个SD卡接口0和1,使用SD0基本不需要什么移植,使用SD1内核驱动注意使用SD1卡时,复用的GPIO脚就不需要了;
图-38
返回图-11进入“Real Time Clock”,DM368支持片上的RTC时钟,即“TI Davinci RTC”,我们自己的板子支持外部RTC时钟芯片PCF8563,根据外设选择;
图-39
返回图-5进入“File systems”,对需要支持的文件系统进行选择,选择EXT2/EXT3/EXT4文件系统是在断电对存储设备保护和日志恢复的情况下,比FAT32好多了,比如把SD卡格式化成EXT3/EXT4比FAT32更好用;
图-40
其他保留TI的配置,
图-41
进入“DOS/FAT/NT”文件系统的支持,按上面的选择,NTFS没有用过,不知在嵌入式是否好用,这里选择的目的是能够使用U盘等等存储设备;
图-42
进入“Pseudo filesystems”,保留TI的默认配置;
图-43
图-44
进入“Miscellaneous filesystems”,配置NAND FLASH支持的文件系统,YAFFS2的文件系统是本人下载然后按patch就行移植的,TI原来没有,选择YAFF2,JFFS2,还有cramfs,SquashFS,UBI文件系统目前没有验证,有时间再试试,刚才提到的都是最常用的嵌入式NAND文件系统,就是要烧进NAND FLASH的;
图-45
图-45就是NFS文件系统的设置,我们在板子上运行的是NFS client模式,即客户端,而开发环境是NFS SERVER端;里边的SMB(SAMBA)在板子上不需要支持,我们去掉不选;
图-46
图-46就是选择内核支持的语言;
然后备份配置:在dvsdk_dm368_4_02_00_06目录下
#cp psp/linux-2.6.32.17/.config psp/linux-2.6.32.17/dm368_20111227.config
注意路径,凡是使用make distclean和make linux_clean命令后,.config不存在,这时我们就必须使用:
#cp psp/linux-2.6.32.17/dm368_20111227.config psp/linux-2.6.32.17/.config注意.config的“.”,这样整个内核配置基本结束;
六、分析和修改代码:
1、mach-davinci\board-dm365-evm.c
这个是DM368内核移植重点的地方,系统初始化函数都在这里,而外部设备初始化在各自的驱动文件里;打开第156行 #define NAND_BLOCK_SIZE SZ_128K
同时屏蔽/*#define NAND_BLOCK_SIZE SZ_512K*/ 这个是4K-PAGE NAND FLASH
因为我们公司的板子都是使用2K-PAGE的NAND FLASH,512字节的NAND不适合新的文件系统,慢慢会被淘汰;
修改NAND FLASH的分区,
static struct mtd_partition davinci_nand_partitions[] = {
{
/* UBL (a few copies) plus U-Boot */
.name = "bootloader",
.offset = 0x80000,
.size = 3 * NAND_BLOCK_SIZE,
.mask_flags =0,
/* tongye:.mask_flags = MTD_WRITEABLE, *//* force read-only */
}, {
/* U-Boot environment */
.name = "params",
.offset = 0xe0000,
.size = 1 * NAND_BLOCK_SIZE,
.mask_flags = 0,
}, {
.name = "kernel",
.offset = 0x100000,
.size = SZ_4M+SZ_512K,
.mask_flags = 0,
}, {
.name = "basefs",
.offset = 0x100000+SZ_4M+SZ_512K,
.size = SZ_32M-SZ_4M,
.mask_flags = 0,
/* tongye:28M-byte for ramdisk,cramfs,squashfs rootfs*/
}, {
.name = "userfs",
.offset = 0x100000+SZ_32M+SZ_512K,
.size = SZ_64M+SZ_16M,
.mask_flags = 0,
/*tongye:80M-byte for jffs2,yaffs2 rootfs*/
}, {
.name = "userdata",
.offset = SZ_64M+SZ_32M+SZ_16M+SZ_1M+SZ_512K,
.size = 0x8000000-SZ_64M-SZ_32M-SZ_16M-SZ_1M-SZ_512K,
.mask_flags = 0,
}
/* two blocks with bad block table (and mirror) at the end */
};
UBL的代码放在0x20000~0x40000的位置,一般NAND FLASH前面5个BLOCK出现坏块的几率非常小,在产品中一般很少去维护更新UBL,所以没有把UBL单独分一个分区;而其他空间出现坏块的几率比较大,所以给U-BOOT分3~4个BLOCK够用了,内核分5M-BYTE也够用,而U-BOOT参数分1~2个BLOCK,本公司直接放到0x60000~0x80000的空间也可以,没有规定;后面的文件系统分区就根据你裁剪的文件系统、文件系统的类型进行大小分区;
static struct i2c_board_info i2c_info[] = {
/* {
I2C_BOARD_INFO("dm365evm_keys", 0x25),
},
{
I2C_BOARD_INFO("24c256", 0x50),
.platform_data = &eeprom_info,
},
*/
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),
},
{
I2C_BOARD_INFO("ths7303", 0x2c),
},
/*{
I2C_BOARD_INFO("PCA9543A", 0x73),
},*/
{
I2C_BOARD_INFO("pcf8563", 0x51),
},
};
上面这个结构就是看看你的I2C总线带什么样的设备,根据你的I2C设备地址,添加到这里,这样才能调用到设备初始化函数;从上面的修改看出,我们的板子不需要AT24C256这些EEPROM芯片,可以干掉;
static void dm365evm_reset_imager(int rst)
{
u8 val;
//tongye
#if 0
val = __raw_readb(cpld + CPLD_POWER) | BIT(3) | BIT(11) | BIT(19) | BIT(27);
__raw_writeb(val, (cpld + CPLD_POWER));
val = __raw_readb(cpld + CPLD_MUX) | BIT(6) | BIT(14) | BIT(22) | BIT(30);
__raw_writeb(val, (cpld + CPLD_MUX));
/* Reset bit6 of CPLD_IMG_DIR2 */
val = __raw_readb(cpld + CPLD_IMG_DIR2) & ~BIT(6);
__raw_writeb(val, (cpld + CPLD_IMG_DIR2));
/* Set bit5 of CPLD_IMG_MUX5 */
val = __raw_readb(cpld + CPLD_IMG_MUX5) | BIT(5);
__raw_writeb(val, (cpld + CPLD_IMG_MUX5));
/* Reset bit 0 of CPLD_IMG_MUX5 */
val = __raw_readb(cpld + CPLD_IMG_MUX5) & ~BIT(0);
__raw_writeb(val, (cpld + CPLD_IMG_MUX5));
#endif
/**
* Configure GPIO40 to be output and high. This has dependency on MMC1
*/
#if 1
davinci_cfg_reg(DM365_PWM3_G85);
davinci_cfg_reg(DM365_PWM3_G86);
gpio_request(85, "sensor_reset");
gpio_request(86, "sensor_standby");
gpio_direction_output(85, 0);
gpio_direction_output(86, 0);
gpio_set_value(85,1);
gpio_set_value(86,1);
mdelay(15); 头文件要加上#include
gpio_set_value(85,0);
gpio_set_value(86,0);
mdelay(25);
gpio_set_value(85,1);
gpio_set_value(86,1);
mdelay(25);
#else
davinci_cfg_reg(DM365_GPIO40);
gpio_request(40, "sensor_reset");
if (rst)
gpio_direction_output(40, 1);
else
gpio_direction_output(40, 0);
#endif
}
上面的函数修改:我们不需要CPLD,所以屏蔽掉,我们直接使用GPIO控制MT9P031 SENSOR的复位和STANDBY信号;
static struct vpfe_subdev_info vpfe_sub_devs[] = {
{
.module_name = "tvp5158",
.grp_id = VPFE_SUBDEV_TVP5146,
.num_inputs = ARRAY_SIZE(tvp5158_inputs),
.inputs = tvp5158_inputs,
.routes = tvp5158_routes,
.can_route = 1,
.ccdc_if_params = {
.if_type = VPFE_BT656,
.hdpol = VPFE_PINPOL_POSITIVE,
.vdpol = VPFE_PINPOL_POSITIVE,
},
.board_info = {
I2C_BOARD_INFO("tvp5158", 0x5B),
.platform_data = &tvp5158_pdata,
},
},
{
.module_name = "tvp7002",
.grp_id = VPFE_SUBDEV_TVP7002,
.num_inputs = ARRAY_SIZE(tvp7002_inputs),
.inputs = tvp7002_inputs,
.ccdc_if_params = {
.if_type = VPFE_BT1120,
.hdpol = VPFE_PINPOL_POSITIVE,
.vdpol = VPFE_PINPOL_POSITIVE,
},
.board_info = {
I2C_BOARD_INFO("tvp7002", 0x5c),
.platform_data = &tvp7002_pdata,
},
},
{
.module_name = "ths7353",
.grp_id = VPFE_SUBDEV_TVP7002,
.board_info = {
I2C_BOARD_INFO("ths7353", 0x2e),
},
},
{
.module_name = "mt9p031",
.is_camera = 1,
.grp_id = VPFE_SUBDEV_MT9P031,
.num_inputs = ARRAY_SIZE(mt9p031_inputs),
.inputs = mt9p031_inputs,
.ccdc_if_params = {
.if_type = VPFE_RAW_BAYER,
.hdpol = VPFE_PINPOL_POSITIVE,
.vdpol = VPFE_PINPOL_POSITIVE,
},
.board_info = {
I2C_BOARD_INFO("mt9p031", 0x48),
/* this is for PCLK rising edge */
.platform_data = (void *)1,
},
}
};
TI的DM368开发板同时支持TVP5146、TVP7002、MT9P031;TVP5146代表标清复合视频输入采集芯片(D1格式),TVP7002代表复合视频YPbPr的高清输入采集芯片,MT9P031代表500万像素的SENSOR采集;
/* Set the input mux for TVP7002/TVP5146/MTxxxx sensors */
static int dm365evm_setup_video_input(enum vpfe_subdev_id id)
{
const char *label;
u8 mux, resets;
//Jingbo
/////mux = __raw_readb(cpld + CPLD_MUX);
////mux &= ~CPLD_VIDEO_INPUT_MUX_MASK;
////resets = __raw_readb(cpld + CPLD_RESETS);
switch (id) {
case VPFE_SUBDEV_TVP5146:
mux |= CPLD_VIDEO_INPUT_MUX_TVP5146;
resets &= ~BIT(0);
label = "tvp5158 SD";
dm365evm_reset_imager(0);
break;
case VPFE_SUBDEV_MT9P031:
mux |= CPLD_VIDEO_INPUT_MUX_IMAGER;
resets |= BIT(0); /* Put TVP5146 in reset */
label = "HD imager";
dm365evm_reset_imager(1);
/* Switch on pca9543a i2c switch */
////if (have_imager())
////dm365evm_enable_pca9543a(1);
break;
case VPFE_SUBDEV_TVP7002:
resets &= ~BIT(2);
mux |= CPLD_VIDEO_INPUT_MUX_TVP7002;
label = "tvp7002 HD";
break;
default:
return 0;
}
////__raw_writeb(mux, cpld + CPLD_MUX);
////__raw_writeb(resets, cpld + CPLD_RESETS);
pr_info("EVM: switch to %s video input\n", label);
return 0;
}
上面的函数去掉CPLD的东西,这个视频采集芯片的选择是和U-BOOT的参数一一对应的,在U-BOOT bootargs的参数里,加入davinci_capture.device_type=0表示使用TVP5146采集,davinci_capture.device_type=1表示使用MT9P031采集,davinci_capture.device_type=2表示使用TVP7002采集,内核读取U-BOOT的参数,会在初始化确定是否调用什么样的采集芯片驱动;所以我们在内核配置的时候,可以同时选上三种芯片;
static void __init evm_init_i2c(void)
{
davinci_init_i2c(&i2c_pdata);
#if 0
if (have_imager())
i2c_add_driver(&pca9543a_driver);
#endif
i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
}
这个pca9543a I2C切换芯片我们不需要;
static void __init evm_init_cpld(void)
{
u8 mux, resets;
const char *label;
struct clk *aemif_clk;
struct davinci_soc_info *soc_info = &davinci_soc_info;
/* Make sure we can configure the CPLD through CS1. Then
* leave it on for later access to MMC and LED registers.
*/
aemif_clk = clk_get(NULL, "aemif");
if (IS_ERR(aemif_clk))
return;
clk_enable(aemif_clk);
#if 0
if (request_mem_region(DM365_ASYNC_EMIF_DATA_CE1_BASE, SECTION_SIZE,
"cpld") == NULL)
goto fail;
cpld = ioremap(DM365_ASYNC_EMIF_DATA_CE1_BASE, SECTION_SIZE);
if (!cpld) {
release_mem_region(DM365_ASYNC_EMIF_DATA_CE1_BASE,
SECTION_SIZE);
fail:
pr_err("ERROR: can't map CPLD\n");
clk_disable(aemif_clk);
return;
}
/* External muxing for some signals */
mux = 0;
/* Read CPLD version number */
soc_info->cpld_version = __raw_readb(cpld + CPLD_VERSION);
/* Read SW5 to set up NAND + keypad _or_ OneNAND (sync read).
* NOTE: SW4 bus width setting must match!
*/
if ((__raw_readb(cpld + CPLD_SWITCH) & BIT(5)) == 0) {
/* external keypad mux */
mux |= BIT(7);
platform_add_devices(dm365_evm_nand_devices,
ARRAY_SIZE(dm365_evm_nand_devices));
} else {
/* no OneNAND support yet */
}
/* Leave external chips in reset when unused. */
resets = BIT(3) | BIT(2) | BIT(1) | BIT(0);
/* ... and ENET ... */
dm365evm_emac_configure();
soc_info->emac_pdata->phy_mask = DM365_EVM_PHY_MASK;
soc_info->emac_pdata->mdio_max_freq = DM365_EVM_MDIO_FREQUENCY;
resets &= ~BIT(3);
/* ... and AIC33 */
resets &= ~BIT(1);
/* Static video input config with SN74CBT16214 1-of-3 mux:
* - port b1 == tvp7002 (mux lowbits == 1 or 6)
* - port b2 == imager (mux lowbits == 2 or 7)
* - port b3 == tvp5146 (mux lowbits == 5)
*
* Runtime switching could work too, with limitations.
*/
if (have_imager()) {
label = "HD imager";
mux |= CPLD_VIDEO_INPUT_MUX_IMAGER;
/* externally mux MMC1 to imager */
mux |= BIT(6);
dm365evm_reset_imager(1);
} else {
/* we can use MMC1 ... */
dm365evm_mmc_configure();
davinci_setup_mmc(1, &dm365evm_mmc_config);
if (have_tvp7002()) {
mux |= CPLD_VIDEO_INPUT_MUX_TVP7002;
resets &= ~BIT(2);
label = "tvp7002 HD";
} else {
/* default to tvp5146 */
mux |= CPLD_VIDEO_INPUT_MUX_TVP5146;
resets &= ~BIT(0);
label = "tvp5158 SD";
dm365evm_reset_imager(0);
}
}
__raw_writeb(mux, cpld + CPLD_MUX);
__raw_writeb(resets, cpld + CPLD_RESETS);
#else
platform_add_devices(dm365_evm_nand_devices,
ARRAY_SIZE(dm365_evm_nand_devices));
/* ... and ENET ... */
dm365evm_emac_configure();
soc_info->emac_pdata->phy_mask = DM365_EVM_PHY_MASK;
soc_info->emac_pdata->mdio_max_freq = DM365_EVM_MDIO_FREQUENCY;
//if (have_imager())
{
dm365evm_reset_imager(1);
//pr_info("EVM: reset mt9p031 imager\n");
}
//pr_info("EVM: %s video input\n", label);
#endif
/* REVISIT export switches: NTSC/PAL (SW5.6), EXTRA1 (SW5.2), etc */
}
上面的函数很重要,除去掉CPLD的东西外,一定要把
platform_add_devices(dm365_evm_nand_devices,
ARRAY_SIZE(dm365_evm_nand_devices));
保留,否则你的内核启动的时候,根本没有NAND的驱动和分区显示;
dm365evm_emac_configure();也肯定要的,否则没有网络驱动叫LINUX吗?TI就是通过CPLD来控制一些外设,CPLD比较贵,不适合低成本大批量生产,所以我们去掉了;
static __init void dm365_evm_init(void)
{
dm365evm_gpio_configure(); //tongye:copy it here
evm_init_i2c();
davinci_serial_init(&uart_config);
dm365evm_emac_configure();
dm365evm_usb_configure();
davinci_setup_mmc(0, &dm365evm_mmc_config);
/* maybe setup mmc1/etc ... _after_ mmc0 */
evm_init_cpld();
dm365_init_asp(&dm365_evm_snd_data);
//dm365_init_rtc();
//dm365_init_ks(&dm365evm_ks_data);
//dm365_init_spi0(BIT(0), dm365_evm_spi_info,
//ARRAY_SIZE(dm365_evm_spi_info));
//dm365_init_tsc2004();
dm365evm_gpio_configure();
}
这个函数就是对MMC/SD、USB、等接口进行初始化了,tsc2004这个是触摸屏的芯片,dm365evm_gpio_configure()里边我们添加了很多GPIO的初始值定义;
2、修改mach-davinci\dm365.c
这个要和arch\arm\mach-davinci\include\mach\mux.h配合看,
好好看看mux_config dm365_pins这个定义,这个DM368的管脚复用非常复杂,使能某个功能,那么对应的另外的功能就不能用了,因此要非常小心对待,特别是和GPIO复用;
后面这些源码介绍就是提示和分析了:
drivers\char\里有dm365_ipipe.c
、imp_common.c、imp_previewer.c、imp_resizer.c、等文件;
drivers\i2c\busses\里有i2c-davinci.c
重点介绍:drivers\media\video\里有V4L2的接口驱动;
drivers\media\video\mt9p031.c,tvp514x.c,tvp7002.c;
drivers\media\video\davinci\里东西就很多了,dm365_ccdc.c、vpfe_capture.c
drivers\net\里有davinci_emac.c
drivers\usb\musb\里davinci.c
GPIO的使用,一直没有搞清楚这个新内核为什么老是隔段时间对U盘复位,和2.6.18不一样,搞得U盘一直成功列举设备,然后用重新复位分配新USB DEVIDE 地址;
drivers\watchdog\里有davinci_wdt.c
第32行#define DEFAULT_HEARTBEAT 2 //tongye removed 60s
应用程序只有一使用open打开设备,WDG就生效,2秒钟不喂狗就软件复位;
linux-2.6.32.17\sound\soc\codecs有tlv320aicxx.c等音频芯片驱动;
linux-2.6.32.17sound\soc\davinci里有PCM、I2S等驱动;
接显示屏drivers\video\davincifb.c,这个要和drivers\media\video\davinci\的vpbe_encoder.c、davinci_display.c、davinci_osd.c啊等等VPBE接口的文件对应;
最后在dvsdk_dm368_4_02_00_06目录下加个编译脚本build_linux.sh:
#!/bin/sh
make linux
chmod 777 /home/davinci/dm368/dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm/boot/uImage
cp -f /home/davinci/dm368/dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm/boot/uImage /tftpboot/dm368_kernel.bin
直接./ build_linux.sh,就可以在/tftpboot的目录下得到dm368_kernel.bin,在板子上,通过U-BOOT烧写内核,先调试通NFS,在上篇U-BOOT的移植文章介绍到U-BOOT的NFS参数定义,这里不啰嗦;
七、内核检查
检查支持什么文件系统 (我们使用的是ubifs)
make menuconfig
File systems --->
[*] Miscellaneous filesystems --->
支持NFS
make menuconfig
File systems --->
[*] Network File Systems --->
make menuconfig
Device Drivers-->Network device Support-->PHY Device support and infrastructure-->Drivers for DAVICOM Phy