注意(2017年9月20日追記)
この記事は Linux Kernel 4.4 時点に投稿したものであり、古い内容が含まれています。Linux Kernel 4.10 以降、FPGA 関連は大きく進歩しました。詳しくは「Linux Kernel 4.10 でのFPGAのサポート事情」を参照してください。
はじめに
以下の記事で Device Tree Overlay と FPGA Manager に対応した FPGA+SoC+Linux の動作環境を紹介しました。
さらに、以下の記事でこのシステムを ZYBO と DE0-Nano-SoC に対応した実例を紹介しました。
- 「FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(ZYBO-Examples)」@Qiita
- 「FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(DE0-Nano-SoC-Examples)」@Qiita
上で紹介した実例では ZYBO と DE0-Nano-SoC で別々の SD-Card を用意していましたが、この記事では、1枚の SD-Card で ZYBO と DE0-Nano-SoC の2種類のボードで起動する方法を紹介します。
もともと、このデュアルブート方法は、次の資料に触発されたもので、おおいに参考にさせてもらいました。この場を借りてお礼を申し上げます。
- 石原ひでみ. 『第五章 ついに起動!デュアル・ブート SD カードの作り方』「FPGA マガジン No.12」57頁
追記
- 2017/1/14 に Linux Kernel のバージョンを v4.8.17 に更新しました。
- 2017/1/31 に udmabuf のバージョンを v0.6.0 に更新しました。
概要
- Hardware
- ZYBO : Xilinx Zynq-7000 ARM/FPGA SoC Trainer Board by Digilent
- DE0-Nano-SoC : Altera SoC FPGA Development Kit by terasic
- U-Boot v2016.03 (customized)
- Build for ZYBO and DE0-Nano-SoC
- Customized boot by uEnv.txt
- Customized boot by boot.scr
- Linux Kernel Version v4.4.7 or v4.8.17
- Available in both Xilinx-Zynq-7000 and Altera-SoC in a single image
- Enable Device Tree Overlay
- Enable FPGA Manager
- Debian8(jessie) Root File System
- Installed build-essential
- Installed device-tree-compiler
- Installed ruby ruby-msgpack ruby-serialport
- Installed u-boot-tools
- FPGA Device Drivers
- dtbocfg (Device Tree Blob Overlay Configuration File System)
- fpgacfg (FPGA Configuration Interface for Linux FPGA Manager Framework)
- fclkcfg (FPGA Clock Configuration Device Driver)
- udmabuf (User space mappable DMA Buffer)
- zptty (Pseudo TeleTYpewriter for FPGA Device)
- fpga-bridge (FPGA to/from HPS Bridge Driver for Altera SoCFPGA Devices)
インストール
ダウンロード
github から次のようにダウンロードしてください。
現時点の最新バージョンは v0.2.0 です。チェックアウトしてください。
なお、いくつかのイメージファイルはかなり大きいので、Git LFS(Large File Storage)を使っています。
お使いの環境に git-lfs がインストールされている必要があります。
shell$ git clone git://github.com/ikwzm/FPGA-SoC-Linux
shell$ cd FPGA-SoC-Linux
shell$ git checkout v0.3.3
shell$ git lfs pull
Build boot files
ZYBO 用のディレクトリと DE0-Nano-SoC 用のディレクトリから必要なファイルをデュアル・ブート用のディレクトリ(target/zynq-zybo-de0-nano-soc)にコピーします。
target/zynq-zybo-de0-nano-soc/Makefile を用意していますので活用してください。
shell$ cd target/zynq-zybo-de0-nano-soc/
shell$ make
mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "linux boot script" -d boot/boot.script boot/boot.scr
Image Name: linux boot script
Created: Fri Jan 13 17:05:07 2017
Image Type: ARM Linux Script (uncompressed)
Data Size: 1324 Bytes = 1.29 kB = 0.00 MB
Load Address: 00000000
Entry Point: 00000000
Contents:
Image 0: 1316 Bytes = 1.29 kB = 0.00 MB
cp ../zynq-zybo/boot/zImage-4.8.17-armv7-fpga boot/zImage-4.8.17-armv7-fpga
cp ../zynq-zybo/boot/boot.bin boot/boot.bin
cp ../zynq-zybo/boot/design_1_wrapper.bit boot/design_1_wrapper.bit
cp ../zynq-zybo/boot/devicetree-4.8.17-zynq-zybo.dtb boot/devicetree-4.8.17-zynq-zybo.dtb
cp ../zynq-zybo/boot/devicetree-4.8.17-zynq-zybo.dts boot/devicetree-4.8.17-zynq-zybo.dts
cp ../zynq-zybo/boot/u-boot.img boot/u-boot.img
cp ../de0-nano-soc//boot/devicetree-4.8.17-socfpga.dtb boot/devicetree-4.8.17-socfpga.dtb
cp ../de0-nano-soc//boot/devicetree-4.8.17-socfpga.dts boot/devicetree-4.8.17-socfpga.dts
cp ../de0-nano-soc//boot/DE0_NANO_SOC.rbf boot/DE0_NANO_SOC.rbf
cp ../de0-nano-soc//u-boot/u-boot-spl.sfp u-boot/u-boot-spl.sfp
cp ../de0-nano-soc//u-boot/u-boot.img u-boot/u-boot.img
ファイルの説明
デュアル・ブート用のディレクトリ(tareget/zynq-zybo-de0-nano-soc)には以下のようなファイルがあります。
- tareget/zynq-zybo-de0-nano-soc/
- boot/
- boot.bin : Stage 1 Boot Loader (for ZYBO U-boot-spl)
- u-boot.img : Stage 2 Boot Loader (for ZYBO U-boot image)
- uEnv.txt : U-Boot environment variables for set kernel version
- boot.script : U-Boot boot script (source)
- boot.scr : U-Boot boot script (binary)
- design_1_wrapper.bit : FPGA configuration file (for ZYBO)
- DE0_NANO_SOC.rbf : FPGA configuration file (for DE0-Nano-SoC)
- zImage-4.8.17-armv7-fpga : Linux Kernel Image
- devicetree-4.8.17-zynq-zybo.dtb : Linux Device Tree Blob (for ZYBO)
- devicetree-4.8.17-zynq-zybo.dts : Linux Device Tree Source (for ZYBO)
- devicetree-4.8.17-socfpga.dtb : Linux Device Tree Blob (for DE0-Nano-SoC)
- devicetree-4.8.17-socfpga.dts : Linux Device Tree Source (for DE0-Nano-SoC)
- u-boot/
- u-boot-spl.sfp : Stage 1 Boot Loader (for DE0-Nano-SoC U-boot-spl)
- u-boot.img : Stage 2 Boot Loader (for DE0-Nano-SoC U-boot image)
- boot/
- debian8-rootfs-vanilla.tgz : Debian8 Root File System (use Git LFS)
- linux-image-4.8.17-armv7-fpga_4.8.17-armv7-fpga-1_armhf.deb : Linux Image Package (use Git LFS)
- linux-headers-4.8.17-armv7-fpga_4.8.17-armv7-fpga-1_armhf.deb : Linux Headers Package (use Git LFS)
- fpga-soc-linux-drivers-4.8.17-armv7-fpga_0.0.3-1_armhf.deb : Device Drivers Package (use Git LFS)
SD-Card のフォーマット
SD-Card のパーティション1を FAT File System でファイルシステムを作ります。
SD-Card のパーティション2を ext3 File System でファイルシステムを作ります。
SD-Card のパーティション3を 特殊パーティション(パーティションタイプ=0xa2)にします。ファイルシステムは作りません。
フォーマット方法の詳細は『第五章 ついに起動!デュアル・ブート SD カードの作り方』「FPGA マガジン No.12」を参照してください。
SD-Card への書き込み
SD-Card のパーティション3(下の例では/dev/sdc3)に target/zynq-zybo-de0-nano-soc/u-boot/ 下のファイルイメージを dd を使って書き込みます。
SD-Card のパーティション1(下の例では/dev/sdc1)に target/zynq-zybo-de0-nano-soc/boot/ 下のファイルをコピーします。
SD-Card のパーティション2(下の例では/dev/sdc2)に debian8-rootfs-vanilla.tgz の中身を展開します。
また、展開したルートファイルシステムの home/fpga に fpga-soc-linux-drivers パッケージをあらかじめコピーしておくと良いでしょう。後から network 経由でコピーしてもかまいません。
shell# mount /dev/sdc1 /mnt/usb1
shell# mount /dev/sdc2 /mnt/usb2
shell# cp target/zynq-zybo-de0-nano-soc/boot/* /mnt/usb1
shell# dd if=target/zynq-zybo-de0-nano-soc/u-boot/u-boot-spl.sfp of=/dev/sdc3 bs=64k seek=0
shell# dd if=target/zynq-zybo-de0-nano-soc/u-boot/u-boot.img of=/dev/sdc3 bs=64k seek=4
shell# tar xfz debian8-rootfs-vanilla.tgz -C /mnt/usb2
shell# cp linux-image-4.8.17-armv7-fpga_4.8.17-armv7-fpga-1_armhf.deb /mnt/usb2/home/fpga
shell# cp linux-headers-4.8.17-armv7-fpga_4.8.17-armv7-fpga-1_armhf.deb /mnt/usb2/home/fpga
shell# cp fpga-soc-linux-drivers-4.8.17-armv7-fpga_0.0.3-1_armhf.deb /mnt/usb2/home/fpga
shell# umount mnt/usb1
shell# umount mnt/usb2
デバイスドライバパッケージのインストール
省略します。「FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(ブートイメージの提供)」 を参照してください。
デュアル・ブートのしくみ
1枚の SD-Card で ZYNQ と DE0-Nano-SoC の両方をブートするしくみに関しては『第五章 ついに起動!デュアル・ブート SD カードの作り方』を参照してください。
ここでは、U-Boot がスクリプトによって ZYBO と DE0-Nano-SoC でブート手順を切り替える手法の説明をします。
U-Boot の改良
https://github.com/ikwzm/FPGA-SoC-Linuxで用意した U-Boot には、ソースコードに少し細工がしてあります。
ZYBO 用の U-Boot のソースコードには次のようなパッチをあてています。
diff --git configs/zynq_zybo_defconfig configs/zynq_zybo_defconfig
index 7c23fec..8fc954e 100644
--- configs/zynq_zybo_defconfig
+++ configs/zynq_zybo_defconfig
@@ -22,3 +22,5 @@ CONFIG_DEBUG_UART_ZYNQ=y
CONFIG_DEBUG_UART_BASE=0xe0001000
CONFIG_DEBUG_UART_CLOCK=50000000
CONFIG_ZYNQ_QSPI=y
+# CONFIG_OF_SEPARATE is not set
+CONFIG_OF_EMBED=y
diff --git include/configs/zynq-common.h include/configs/zynq-common.h
index 982905d..fd50c69 100644
--- include/configs/zynq-common.h
+++ include/configs/zynq-common.h
@@ -227,10 +227,35 @@
"usbboot=if usb start; then " \
"echo Copying FIT from USB to RAM... && " \
"load usb 0 ${load_addr} ${fit_image} && " \
- "bootm ${load_addr}; fi\0" \
- DFU_ALT_INFO
-
-#define CONFIG_BOOTCOMMAND "run $modeboot"
+ "bootm ${load_addr}\0" \
+ "fi\0" \
+ "bootenv=uEnv.txt\0" \
+ "config=" CONFIG_DEFAULT_DEVICE_TREE "\0" \
+ "loadbootenv=load mmc 0 ${load_addr} ${bootenv}\0" \
+ "importbootenv=echo Importing environment from mmc ...;" \
+ "env import -t $load_addr $filesize\0" \
+ "loadbootscript=load mmc 0 ${load_addr} boot.scr\0" \
+ "bootscript=echo Running bootscript from mmc ...;" \
+ "source ${load_addr}\0" \
+ DFU_ALT_INFO
+
+#define CONFIG_BOOTCOMMAND \
+ "if mmc rescan; then " \
+ "echo SD/MMC found on device...;" \
+ "if run loadbootenv; then " \
+ "echo Loaded environment from ${bootenv};" \
+ "run importbootenv;" \
+ "fi;" \
+ "if test -n $uenvcmd; then " \
+ "echo Running uenvcmd ...;" \
+ "run uenvcmd;" \
+ "fi;" \
+ "if run loadbootscript; then " \
+ "run bootscript; " \
+ "fi; " \
+ "fi;" \
+ "run $modeboot"
+#define CONFIG_CMD_BOOTZ
#define CONFIG_BOOTDELAY 3 /* -1 to Disable autoboot */
#define CONFIG_SYS_LOAD_ADDR 0 /* default? */
DE0-Nano-SoC 用の U-Boot のソースコードには次のようなパッチをあてています。
diff --git include/configs/socfpga_de0_nano_soc.h include/configs/socfpga_de0_nano_soc.h
index cbc7396..1b68bdb 100644
--- include/configs/socfpga_de0_nano_soc.h
+++ include/configs/socfpga_de0_nano_soc.h
@@ -37,7 +37,22 @@
#define CONFIG_BOOTDELAY 3
#define CONFIG_BOOTFILE "fitImage"
#define CONFIG_BOOTARGS "console=ttyS0," __stringify(CONFIG_BAUDRATE)
-#define CONFIG_BOOTCOMMAND "run mmcload; run mmcboot"
+#define CONFIG_BOOTCOMMAND \
+ "if mmc rescan; then " \
+ "echo SD/MMC found on device...;" \
+ "if run loadbootenv; then " \
+ "echo Loaded environment from ${bootenv};" \
+ "run importbootenv;" \
+ "fi;" \
+ "if test -n $uenvcmd; then " \
+ "echo Running uenvcmd ...;" \
+ "run uenvcmd;" \
+ "fi;" \
+ "if run loadbootscript; then " \
+ "run bootscript; " \
+ "fi; " \
+ "fi;" \
+ "run mmcload; run mmcboot"
#define CONFIG_LOADADDR 0x01000000
#define CONFIG_SYS_LOAD_ADDR CONFIG_LOADADDR
@@ -65,6 +80,15 @@
"mmcload=mmc rescan;" \
"load mmc 0:1 ${loadaddr} ${bootimage};" \
"load mmc 0:1 ${fdt_addr} ${fdtimage}\0" \
+ "fpgadata=0x02000000\0" \
+ "bootenv=uEnv.txt\0" \
+ "config=" CONFIG_DEFAULT_DEVICE_TREE "\0" \
+ "loadbootenv=load mmc 0 ${loadaddr} ${bootenv}\0" \
+ "importbootenv=echo Importing environment from mmc ...;" \
+ "env import -t $loadaddr $filesize\0" \
+ "loadbootscript=load mmc 0 ${loadaddr} boot.scr\0" \
+ "bootscript=echo Running bootscript from mmc ...;" \
+ "source ${loadaddr}\0" \
/* The rest of the configuration is shared */
#include <configs/socfpga_common.h>
いずれのパッチも次のような修正をしています。
- config 変数に U-Boot ビルド時のボード名を設定する
- ブート時に uEnv.txt を読んで環境変数を設定する
- ブート時に uEnv.txt に uenvcmd 変数が設定されていた場合はこれを実行する
- ブート時に uenvcmd が無くて boot.scr があれば、boot.scr を実行する
uEnv.txt
uEnv.txt では Linux Kernel のバージョン番号を設定しています。
kernel_version=4.8.17
boot.scr
boot.scr は次のようなスクリプト(boot.script)を U-Boot 用にコンパイルしたものです。
if test $config = "zynq-zybo"; then
echo "Configuration for " $config
boot_image=zImage-$kernel_version-armv7-fpga
fdt_image=devicetree-$kernel_version-zynq-zybo.dtb
fpga_image=design_1_wrapper.bit
if fatload mmc 0 0x03000000 $fpga_image; then
fpga loadb 0 0x03000000 $filesize
mw.l 0xF8000008 0xDF0D
mw.l 0xF8000170 0x00100A00
mw.l 0xF8000004 0x767B
fi
fatload mmc 0 0x03000000 $boot_image
fatload mmc 0 0x02A00000 $fdt_image
setenv bootargs console=ttyPS0,115200 root=/dev/mmcblk0p2 rw rootwait uio_pdrv_genirq.of_id=generic-uio
if test $kernel_version = "4.8.17"; then
setenv bootargs $bootargs sdhci.debug_quirks=64
fi
bootz 0x03000000 - 0x02A00000
fi
if test $config = "socfpga_cyclone5_de0_nano_soc"; then
echo "Configuration for " $config
boot_image=zImage-$kernel_version-armv7-fpga
fdt_image=devicetree-$kernel_version-socfpga.dtb
fpga_image=DE0_NANO_SOC.rbf
if fatload mmc 0 $fpgadata $fpga_image; then
fpga load 0 $fpgadata $filesize
bridge enable
fi
fatload mmc 0 $loadaddr $boot_image
fatload mmc 0 $fdt_addr $fdt_image
setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait uio_pdrv_genirq.of_id=generic-uio
bootz $loadaddr - $fdt_addr
fi
U-Boot のビルド時に config 変数にボードの種類が設定されていて、この config 変数の値によってブートの手順を切り替えています。
uEnv.txt で kernel_verion 変数に Linux カーネルのバージョンを設定して、そのバージョンに対応したカーネルのイメージとデバイスツリーをロードするようにしています。
なお、Linux Kernel v4.8.17 には sdhci ドライバに問題があって、そのままでは ZYNQ では動きません。その回避策として bootargs に sdhci.debug_quirks=64 を追加しています。詳細は「Zynq + Linux Kernel 4.5(以降) で "mmc0: Timeout waiting for hardware interrupt" が起きる場合の対処方法」 を参照してください。
参考
-
「FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(ブートイメージの提供)」@Qiita
-
「FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(ZYBO-Examples)」@Qiita
-
「FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(DE0-Nano-SoC-Examples)」@Qiita
-
「Zynq + Linux Kernel 4.5(以降) で "mmc0: Timeout waiting for hardware interrupt" が起きる場合の対処方法」@Qiita
-
石原ひでみ. 『第五章 ついに起動!デュアル・ブート SD カードの作り方』「FPGA マガジン No.12」57頁