IMX6ULL 移植 本篇的目的是为了学习 linux 驱动的整个流程,先尝试烧录正点原子的原厂代码,我们这里采用 SD 卡启动。
正点原子在源码目录下已经有了相关的烧录文件,由于笔者是 linux 环境,不能使用 NXP 提供的 mfgtool, 好在原子提供了制作 SD 卡系统的脚本,路径如下:
1 【正点原子】阿尔法Linux开发板(A盘)-基础资料/05、开发工具/04、正点原子MFG_TOOL出厂固件烧录工具/mfgtool/Profiles/Linux/OS Firmware/files
就是这个 imx6mksdboot.sh 文件。我们需要一些改变,这里直接替换成我的脚本即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 #! /bin/sh VERSION="1.1" usage (){ echo " 用法: `basename $1 ` [选项] <(必选)-device> <(可选)-flash> <(可选)-ddrsize> 用法示例: sudo ./imx6mksdboot.sh -device /dev/sdd sudo ./imx6mksdboot.sh -device /dev/sdd -flash emmc -ddrsize 512 命令选项: -device SD卡块设备节点 (例如/dev/sdx) -flash 请选择开发板Flash类型(emmc | nand) -ddrsize 请选择DDR大小 (512 | 256) 可选选项: --version 打印版本信息. --help 打印帮助信息. " exit 1 } Uboot='u-boot-imx6ull-14x14-ddr512-emmc.imx' execute (){ cmd="$1 " sh -c "$cmd " >/dev/null if [ $? -ne 0 ]; then echo echo "错误: 执行 $cmd " echo exit 1 fi } version (){ echo echo "`basename $1 ` version $VERSION " echo "I.MX6 SD卡制卡脚本" echo exit 0 } arg=$# if [ $arg -ne 6 ];then number=1 while [ $# -gt 0 ]; do case $1 in --help | -h) usage $0 ;; -device) shift ; device=$1 ; shift ; ;; --version) version $0 ;; *) copy="$copy $1 " ; shift ; ;; esac done test -z $device && usage $0 echo "" echo "根据下面的提示,补全缺省的参数-flash -ddrsize" read -p "请选择开发板参数,输入数字1~4,按Enter键确认 1.-flash emmc,-ddrsize 512 2.-flash emmc,-ddrsize 256 3.-flash nand,-ddrsize 512 4.-flash nand,-ddrsize 256 输入数字1~4(default 1): " numberif [ -z $number ];then echo "使用默认参数:EMMC版本,DDR大小为512MB" else case $number in 1) echo '您已经选择开发板参数为:EMMC版本,DDR大小为512MB' Uboot='u-boot-imx6ull-14x14-ddr512-emmc.imx' ;; 2) echo '您已经选择开发板参数为:EMMC版本,DDR大小为256MB' Uboot='u-boot-imx6ull-14x14-ddr256-emmc.imx' ;; 3) echo '您已经选择开发板参数为:NAND FLASH版本,DDR大小为512MB' Uboot='u-boot-imx6ull-14x14-ddr512-nand-sd.imx' ;; 4) echo '您已经选择开发板参数为:NAND FLASH版本,DDR大小为256MB' Uboot='u-boot-imx6ull-14x14-ddr256-nand-sd.imx' ;; *) echo '输入的参数有误,退出制卡' ;exit ; ;; esac fi else while [ $# -gt 0 ]; do case $1 in --help | -h) usage $0 ;; -device) shift ; device=$1 ; shift ; ;; -flash) shift ; flash=$1 ; shift ; ;; -ddrsize) shift ; ddrsize=$1 ; shift ; ;; --version) version $0 ;; *) copy="$copy $1 " ; shift ; ;; esac done if [ $flash = "emmc" -a $ddrsize = "512" ];then Uboot='u-boot-imx6ull-14x14-ddr512-emmc.imx' echo '您已经选择开发板参数为:EMMC版本,DDR大小为512MB' elif [ $flash = "emmc" -a $ddrsize = "256" ];then Uboot='u-boot-imx6ull-14x14-ddr256-emmc.imx' echo '您已经选择开发板参数为:EMMC版本,DDR大小为256MB' elif [ $flash = "nand" -a $ddrsize = "512" ];then Uboot='u-boot-imx6ull-14x14-ddr512-nand-sd.imx' echo '您已经选择开发板参数为:NAND FLASH版本,DDR大小为512MB' elif [ $flash = "nand" -a $ddrsize = "256" ];then Uboot='u-boot-imx6ull-14x14-ddr256-nand-sd.imx' echo '您的开发板参数为:NAND FLASH版本,DDR大小为256MB' else echo '参数有误!' usage $0 fi fi sdkdir="$PWD " set -- "$sdkdir " /filesystem/*.tar.*rootfs_archive="$1 " if [ ! -d "$sdkdir " ]; then echo "错误: $sdkdir 目录不存在" exit 1 fi if [ ! -e "$rootfs_archive " ]; then echo "错误: $sdkdir /filesystem/ 下找不到文件系统压缩包" exit 1 fi if [ ! -f "$sdkdir /boot/zImage" ]; then echo "错误: $sdkdir /boot/ 下找不到 zImage" exit 1 fi if [ ! -b "$device " ]; then echo "错误: $device 不是一个块设备文件" exit 1 fi devbase=$(basename "$device " ) removable=$(cat "/sys/block/$devbase /removable" 2>/dev/null) if [ "$device " = '/dev/sda' ] && [ "$removable " != "1" ];then echo "请不要选择sda设备,/dev/sda通常是您的Ubuntu硬盘! 继续操作你的系统将会受到影响!脚本已自动退出" exit 1 fi echo "即将进行制作SD系统启动卡,大约花费几分钟时间,请耐心等待!" echo "************************************************************" echo "* 注意:这将会清除$device 所有的数据 *" echo "* 在脚本执行时请不要将$device 拔出 *" echo "* 请按<Enter>确认继续 *" echo "************************************************************" read enterfor i in `ls -1 "$device " ?`; do echo "卸载 device '$i '" umount "$i " 2>/dev/null done execute "dd if=/dev/zero of=\"$device \" bs=1024 count=1024" cat << END | fdisk -H 255 -S 63 $device n p 1 +64M n p 2 t 1 c a 1 w END PARTITION1=${device} 1 if [ ! -b "${PARTITION1} " ]; then PARTITION1=${device} 1 fi PARTITION2=${device} 2 if [ ! -b "${PARTITION2} " ]; then PARTITION2=${device} 2 fi echo "格式化 ${device} 1 ..." if [ -b "${PARTITION1} " ]; then mkfs.vfat -F 32 -n "boot" "${PARTITION1} " else echo "错误: /dev下找不到 SD卡 boot分区" fi echo "格式化${device} 2 ..." if [ -b "${PARTITION2} " ]; then mkfs.ext3 -F -L "rootfs" "${PARTITION2} " else echo "错误: /dev下找不到 SD卡 rootfs分区" fi while [ ! -e "$device " ]do sleep 1echo "wait for $device appear" done echo "正在烧写${Uboot} 到${device} " execute "dd if=\"$sdkdir /boot/$Uboot \" of=\"$device \" bs=1024 seek=1 conv=fsync" sync echo "烧写${Uboot} 到${device} 完成!" echo "正在准备复制..." echo "正在复制设备树与内核到${device} 1,请稍候..." execute "mkdir -p /tmp/sdk/$$" while [ ! -e "${device} 1" ]do sleep 1echo "wait for ${device} 1 appear" done execute "mount \"${device} 1\" /tmp/sdk/$$" execute "cp -r \"$sdkdir \"/boot/*${flash} *.dtb /tmp/sdk/$$/" execute "cp -r \"$sdkdir /boot/zImage\" /tmp/sdk/$$/" sync echo "复制设备树与内核到${device} 1完成!" if [ "$copy " != "" ]; then echo "Copying additional file(s) on ${device} p1" execute "cp -r \"$copy \" /tmp/sdk/$$" fi echo "卸载${device} 1" execute "umount /tmp/sdk/$$" sleep 1execute "mkdir -p /tmp/sdk/$$" execute "mount \"${device} 2\" /tmp/sdk/$$" echo "正在解压文件系统到${device} 2 ,请稍候..." rootfs=`ls -1 filesystem/*.tar.*` execute "tar jxfm \"$rootfs \" -C /tmp/sdk/$$" sync echo "解压文件系统到${device} 2完成!" if [ ! -e "/tmp/sdk//lib/modules/" ];then mkdir -p /tmp/sdk/lib/modules/fi echo "正在解压模块到${device} 2/lib/modules/ ,请稍候..." modules=`ls -1 modules/*.tar.*` execute "tar jxfm \"$modules \" -C /tmp/sdk/$$/lib/modules/" sync echo "解压模块到${device} 2/lib/modules/完成!" echo "卸载${device} 2" execute "umount /tmp/sdk/$$" execute "rm -rf /tmp/sdk/$$" sync echo "SD卡启动系统烧写完成!"
之后的烧录我们将 uboot,dtb,zimage 文件放在 boot 目录即可。
这里我由于是准备烧录 SD 卡,命令如下。
1 ./imx6mksdboot.sh -device /dev/sda -flash emmc -ddrsize 512
注意: -device /dev/<设备> 这里要十分注意,不然可能会破坏系统
烧录完毕之后上电即可。
1 准备 我们先将文件准备好。
1 2 $ ls gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf linux-imx-rel_imx_4.1.15_2.1.0_ga uboot-imx-rel_imx_4.1.15_2.1.0_ga
目前先针对 uboot 移植,这是 NXP 的原版代码,我们需要根据自己的开发板进行适配。
在本机上安装依赖。
1 2 3 sudo apt updatesudo apt install -y u-boot-tools device-tree-compiler \ bison flex libssl-dev make bc build-essential
2 移植 2.1 uboot 初编译 1 2 3 4 cd uboot-imx-rel_imx_4.1.15_2.1.0_gamake ARCH=arm CROSS_COMPILE=../gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- mrproper make ARCH=arm CROSS_COMPILE=../gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig make ARCH=arm CROSS_COMPILE=../gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -j$(nproc )
过程中由于本机已经安装了一些软件可能导致头文件冲突而报错,比如我这里发现的报错。
由于 uboot 本身自带了一套 libfdt,这里的路径自动优先使用了我本机的,于是把本机的先删除掉。
1 2 sudo apt-get remove libfdt-devsudo apt-get purge libfdt-dev
编译完成之后发现生成了 u-boot.imx,u-boot.bin,u-boot
1 2 $ ls u-boot* u-boot u-boot.bin u-boot.cfg u-boot.imx u-boot.lds u-boot.map u-boot-nodtb.bin u-boot.srec u-boot.sym
我们将编译好的 imx 文件替换掉原烧录程序的 imx 就可以了。
1 2 3 4 $ pwd <路径>/【正点原子】阿尔法Linux开发板(A盘)-基础资料/05、开发工具/04、正点原子MFG_TOOL出厂固件烧录工具/mfgtool/Profiles/Linux/OS Firmware/files $ mv boot/u-boot-imx6ull-14x14-ddr512-emmc.imx boot/u-boot-imx6ull-14x14-ddr512-emmc.imx.bak $ cp -ar /home/jvle/Desktop/works/IMX6ULL/porting/uboot-imx-rel_imx_4.1.15_2.1.0_ga/u-boot.imx boot/u-boot-imx6ull-14x14-ddr512-emmc.imx
之后进入 uboot 可能报错如下。这是提示不能找到对应的设备树,我们设置一下就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 Welcome to minicom 2.9 OPTIONS: I18n Port /dev/ttyUSB0, 21:07:46 Press CTRL-A Z for help on special keys U-Boot 2016.03 (Jun 12 2026 - 22:09:07 +0800) CPU: Freescale i.MX6ULL rev1.1 69 MHz (running at 396 MHz) CPU: Industrial temperature grade (-40C to 105C) at 43C Reset cause: POR Board: MX6ULL 14x14 EVK I2C: ready DRAM: 512 MiB MMC: FSL_SDHC: 0, FSL_SDHC: 1 *** Warning - bad CRC, using default environment Display: TFT43AB (480x272) Video: 480x272x24 In: serial Out: serial Err: serial switch to partitions mmc0 is current device Net: Board Net Initialization Failed No ethernet found. Normal Boot Hit any key to stop autoboot: 0 switch to partitions mmc0 is current device switch to partitions mmc0 is current device reading boot.scr ** Unable to read file boot.scr ** reading zImage 6792136 bytes read in 378 ms (17.1 MiB/s) Booting from mmc ... reading imx6ull-14x14-evk.dtb ** Unable to read file imx6ull-14x14-evk.dtb ** Kernel image @ 0x80800000 [ 0x000000 - 0x67a3c8 ] Starting kernel ...
临时设置一下设备树文件,并且我们加载一下镜像并启动。
1 2 3 setenv fdt_file imx6ull-14x14-emmc-7-1024x600-c.dtb run loadimage run mmcboot
结果如下:
我们并没有替换 linux kernel,内核还是原本的文件。
可以看到虽然系统可以使用了,但是 LCD 的显示依然存在问题。因为原版本的 uboot 是会初始化 LCD 并显示开机 logo 的,这里并没有显示。笔者猜测这里的 LCD 在内核当中再次进行了初始化,因此可以正常显示,但是在 uboot 当中并没有显示。
修改 uboot 的驱动一般都是在 xxx.h 和 xxx.c 两个文件当中,xxx 是板子的名称。
这里我们修改 uboot-imx-rel_imx_4.1.15_2.1.0_ga/board/freescale/mx6ullevk/mx6ullevk.c 的内容。
这部分决定了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 struct display_info_t const displays [] = {{ .bus = MX6UL_LCDIF1_BASE_ADDR, .addr = 0 , .pixfmt = 24 , .detect = NULL , .enable = do_enable_parallel_lcd, .mode = { .name = "TFT7016" , .xres = 1024 , .yres = 600 , .pixclock = 19531 , .left_margin = 140 , .right_margin = 160 , .upper_margin = 20 , .lower_margin = 12 , .hsync_len = 20 , .vsync_len = 3 , .sync = 0 , .vmode = FB_VMODE_NONINTERLACED } } };
然后修改 uboot-imx-rel_imx_4.1.15_2.1.0_ga/include/configs/mx6ullevk.h。
将所有的 panel=TFT43AB 都替换为 panel=TFT7016。
这部分决定了:
uboot 是否初始化 LCD
是否显示 logo。
再次重新编译 uboot。
1 2 3 cd uboot-imx-rel_imx_4.1.15_2.1.0_gamake ARCH=arm CROSS_COMPILE=../gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- mx6ull_14x14_evk_defconfig make ARCH=arm CROSS_COMPILE=../gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -j$(nproc )
之后再次替换,结果如下:
2.2 linux 初编译 1 2 3 4 5 cd linux-imx-rel_imx_4.1.15_2.1.0_ga/make ARCH=arm CROSS_COMPILE=../gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- mrproper make ARCH=arm CROSS_COMPILE=../gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- imx_v7_defconfig make ARCH=arm CROSS_COMPILE=../gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -j$(nproc ) zImage make ARCH=arm CROSS_COMPILE=../gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -j$(nproc ) imx6ull-14x14-evk-emmc.dtb
在烧录目录(【正点原子】阿尔法Linux开发板(A盘)-基础资料/05、开发工具/04、正点原子MFG_TOOL出厂固件烧录工具/mfgtool/Profiles/Linux/OS Firmware/files)下将编译完成的设备树和内核拷贝过去。
1 2 3 $ cp -ar /home/jvle/Desktop/works/IMX6ULL/porting/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/boot/dts/imx6ull-14x14-evk-emmc.dtb boot/my-emmc-sd.dtb $ mv boot/zImage boot/zImage/bak $ cp -ar /home/jvle/Desktop/works/IMX6ULL/porting/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/boot/zImage boot/zImage
之后启动 uboot。我们观察到,确实将刚编译的设备树和内核替换进了 SD 卡。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 => printenv mmcdev mmcpart mmcroot image fdt_file mmcdev=0 mmcpart=1 mmcroot=/dev/mmcblk0p2 rootwait rw image=zImage fdt_file=undefined => mmc dev switch to partitions mmc0 is current device => fatls mmc 1:1 6785480 zimage 39459 imx6ull-14x14-emmc-4.3-480x272-c.dtb 39459 imx6ull-14x14-emmc-4.3-800x480-c.dtb 39459 imx6ull-14x14-emmc-7-800x480-c.dtb 39459 imx6ull-14x14-emmc-7-1024x600-c.dtb 39459 imx6ull-14x14-emmc-10.1-1280x800-c.dtb 40295 imx6ull-14x14-emmc-hdmi.dtb 40203 imx6ull-14x14-emmc-vga.dtb 8 file(s), 0 dir (s) => fatls mmc 0:1 40381 imx6ull-14x14-emmc-10.1-1280x800-c.dtb 40381 imx6ull-14x14-emmc-4.3-480x272-c.dtb 40381 imx6ull-14x14-emmc-4.3-800x480-c.dtb 40381 imx6ull-14x14-emmc-7-1024x600-c.dtb 40381 imx6ull-14x14-emmc-7-800x480-c.dtb 41217 imx6ull-14x14-emmc-hdmi.dtb 41125 imx6ull-14x14-emmc-vga.dtb 36093 my-emmc-sd.dtb 6680392 zimage 9 file(s), 0 dir (s)
之后启动。
1 2 3 4 5 6 7 => setenv fdt_file my-emmc-sd.dtb => echo $fdt_file my-emmc-sd.dtb => run loadimage reading zImage 6680392 bytes read in 372 ms (17.1 MiB/s) => run mmcboot
会发现黑屏了,因为我们目前没有给显示屏适配驱动。
根文件系统 TODO