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
#I.MX6 SD卡启动系统烧写脚本
#version v1.1
#Author QQ1252699831
#company 广州星翼电子科技有限公司

#version v1.0 2019.10.26
#version v1.1 2020.11.7 1.添加判断文件系统是否存在/lib/modules目录的功能,再解压模块
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默认值
Uboot='u-boot-imx6ull-14x14-ddr512-emmc.imx'

#execute执行语句成功与否打印
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): " number
if [ -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
#这里防止选错设备,否则会影响Ubuntu系统的启动
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 enter

#格式化前要卸载
for i in `ls -1 "$device"?`; do
echo "卸载 device '$i'"
umount "$i" 2>/dev/null
done

#执行格式化$device
execute "dd if=/dev/zero of=\"$device\" bs=1024 count=1024"

#第一个分区为64M用来存放设备树与内核镜像文件,因为设备树与内核都比较小,不需要太大的空间
#第二个分区为SD卡的总大小-64M,用来存放文件系统
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

#第一个分区创建为Fat32格式
echo "格式化 ${device}1 ..."
if [ -b "${PARTITION1}" ]; then
mkfs.vfat -F 32 -n "boot" "${PARTITION1}"
else
echo "错误: /dev下找不到 SD卡 boot分区"
fi
#第二个分区创建为ext3格式
echo "格式化${device}2 ..."
if [ -b "${PARTITION2}" ]; then
mkfs.ext3 -F -L "rootfs" "${PARTITION2}"
else
echo "错误: /dev下找不到 SD卡 rootfs分区"
fi

while [ ! -e "$device" ]
do
sleep 1
echo "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 1
echo "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/$$/"
#execute "cp $sdkdir/boot/alientek.bmp /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 1
#解压文件系统到文件系统分区
#挂载文件系统分区
execute "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完成!"

#判断是否存在这个目录,如果不存在就为文件系统创建一个modules目录
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卡启动系统烧写完成!"

之后的烧录我们将 ubootdtbzimage 文件放在 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 update
sudo 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_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- 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-dev
sudo apt-get purge libfdt-dev

编译完成之后发现生成了 u-boot.imxu-boot.binu-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 #0, OK
mmc0 is current device
Net: Board Net Initialization Failed
No ethernet found.
Normal Boot
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0 is current device
switch to partitions #0, OK
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,内核还是原本的文件。

alt text

可以看到虽然系统可以使用了,但是 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_ga
make 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)

之后再次替换,结果如下:

alt text

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 #0, OK
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