Ultra96 向け Debian GNU/Linux (v2018.2版) の構築(U-Boot編)

## はじめに

Ultra96 に Debian GNU/Linux (v2018.2版) を構築する方法について、具体的な方法をいくつかに分けて説明します。

 * [Introduction](https://qiita.com/ikwzm/items/5ae07792143d8018bfea)
 * [Boot Loader](https://qiita.com/ikwzm/items/9c78e83298906447fe5d)
   - [Sample FPGA Design](https://qiita.com/ikwzm/items/0489b02962c6f0455783)
   - [FSBL   (First Stage Boot Loader)](https://qiita.com/ikwzm/items/fe9d6abda60660fc2f87)
   - [PMUFW  (Platform Manager Unit Firmware)](https://qiita.com/ikwzm/items/00024adf956696dd51c6)
   - [BL31   (ARM Trusted Firmware Boot Loader state 3-1)](https://qiita.com/ikwzm/items/3c0d735cd3a605d269f3)
   - __U-Boot(この記事)__
   - [BOOT.BIN](https://qiita.com/ikwzm/items/af4420edd262e14feef9)
 * [Linux Kernel](https://qiita.com/ikwzm/items/02af5ac78a558c910e84)
 * [Debian9 Root File System](https://qiita.com/ikwzm/items/be06b07e26cbf05fec2b)

この記事では、Ultra96 の Boot Loader で使うための U-Boot の構築について説明をします。

## u-boot の構築

### 必要な環境

* gcc-aarch64-linux-gnu

### Boot Loader 構築環境の準備

次の URL から git clone でリポジトリをダウンロードして v2018.2.1 をチェックアウトします。

 * [https://github.com/ikwzm/ZynqMP-FPGA-Linux](https://github.com/ikwzm/ZynqMP-FPGA-Linux)

```console
shell$ git clone git://github.com/ikwzm/ZynqMP-FPGA-Linux
shell$ cd ZynqMP-FPGA-Linux
shell$ git checkout v2018.2.1
```

### ソースコードのダウンロード

U-Boot のソースコードを以下の URL からダウンロードします。今回は U-Boot 本家からではなく、Xilinx が提供してる u-boot-xlnx を使います。

* [https://github.com/Xilinx/u-boot-xlnx.git](https://github.com/Xilinx/u-boot-xlnx.git)

```console
shell$ cd target/Ultra96/build-v2018.2
shell$ git clone https://github.com/Xilinx/u-boot-xlnx.git u-boot-xlnx-v2018.2
```

### xilinx-v2018.2 をチェックアウト

u-boot-xlnx の xilinx-v2018.2 というタグをチェックアウトして xilinx-v2018.2-ultra96 という作業用のブランチを作ります。

```console
shell$ cd u-boot-xlnx-v2018.2
shell$ git checkout -b xilinx-v2018.2-ultra96 xilinx-v2018.2
```

### Ultra96 用の各種ファイルを追加

Ultra96 用のファイルを追加してコミットします。追加するファイルの詳細は後述します。

```console
shell$ patch -p1 < ../../../../files/u-boot-xlnx-v2018.2-ultra96.diff
shell$ git add arch/arm/dts/zynqmp-ultra96.dts
shell$ git add board/xilinx/zynqmp/zynqmp-ultra96/psu_init_gpl.c
shell$ git add board/xilinx/zynqmp/zynqmp-ultra96/psu_init_gpl.h
shell$ git add configs/xilinx_zynqmp_ultra96_defconfig
shell$ git add include/configs/xilinx_zynqmp_ultra96.h
shell$ git add --update
shell$ git commit -m "patch for Ultra96"
shell$ git tag -a xilinx-v2018.2-ultra96-0 -m "release xilinx-v2018.2-ultra96 release 0"
```

### ブート時にメニューを表示させる

U-Boot の起動時にメニューを表示させるようにパッチをあてます。

```console
shell$ patch -p1 < ../../../../files/u-boot-xlnx-v2018.2-ultra96-bootmenu.diff
shell$ git add --update
shell$ git commit -m "[update] for boot menu command"
shell$ git tag -a xilinx-v2018.2-ultra96-1 -m "release xilinx-v2018.2-ultra96 release 1"
```

詳細は次の記事を参考にしてください。

 * [「ZYBO用U-Bootでブート時にメニューを表示させる」@Qiita](https://qiita.com/ikwzm/items/c7932ebd1a7b40919241)

### 構築の準備

環境変数を設定します。アーキテクチャ(ARCH)に arm (arm64じゃないことに注意)を指定します。ここでは、クロスコンパイルに使うツールチェーン(CROSS_COMPILE) に aarch64-linux-gnu-を指定します。この変数は構築する環境にあわせてください。その後、Ultra96 用のコンフィギュレーション定義ファイルを使って構築の準備をします。

```console
shell$ cd u-boot-xlnx-v2018.2
shell$ export ARCH=arm
shell$ export CROSS_COMPILE=aarch64-linux-gnu-
shell$ make xilinx_zynqmp_ultra96_defconfig
```

### u-boot の構築

```console
shell$ make
```

### Copy u-boot.elf

無事に u-boot.elf が出来たら、それを target/Ultra96/build-v2018.2 にコピーします。

```console
shell$ cp u-boot.elf target/Ultra96/build-v2018.2/u-boot.elf
```

## ファイルの説明

ここでは U-Boot を Ultra96 にポーティングする際に新たに追加したファイルの説明をします。

### configs/xilinx_zynqmp_ultra96_defconfig

U-Boot のコンフィギュレーション定義ファイルです。実はこのファイルの中身は u-boot-xlnx にすでにある xilinx_zynqmp_zcu100_revC_defconfig 等とそう変わるところはありません。異なっている箇所は CONFIG_SYS_CONFIG_NAME、CONFIG_IDENT_STRING、CONFIG_DEFAULT_DEVICE_TREE、CONFIG_MENU_SHOW だけです。CONFIG_MENU_SHOW はブート時にメニューを表示させるための設定です。

なお、xilinx_zynqmp_ultra96_defconfig には CONFIG_OF_EMBED=y が設定されています。つまり、U-Boot 用のデバイスツリーは外部ファイルではなく U-Boot の中に組み込まれています。

### arch/arm/dts/zynqmp-ultra96.dts

U-Boot 用のデバイスツリーです。実はこのデバイスツリーは Linux Kernel を起動するデバイスツリーとまったく同じものです。このデバイスツリーの説明は Linux Kernel のところで説明します。

### include/configs/xilinx_zynqmp_ultra96.h

U-Boot コンフィギュレーション定義ファイルに記述できない各種定数を定義しているファイルです。このファイルには次の定数が設定されています。

```C:include/configs/xilinx_zynqmp_ultra96.h
/*
 * Configuration for Xilinx ZynqMP Ultra96
 */

#ifndef __CONFIG_ZYNQMP_ULTRA96_H
#define __CONFIG_ZYNQMP_ULTRA96_H

/* FIXME Will go away soon */
#define CONFIG_SYS_I2C_MAX_HOPS		1
#define CONFIG_SYS_NUM_I2C_BUSES	9
#define CONFIG_SYS_I2C_BUSES	{ \
				{0, {I2C_NULL_HOP} }, \
				{0, {{I2C_MUX_PCA9548, 0x75, 0} } }, \
				{0, {{I2C_MUX_PCA9548, 0x75, 1} } }, \
				{0, {{I2C_MUX_PCA9548, 0x75, 2} } }, \
				{0, {{I2C_MUX_PCA9548, 0x75, 3} } }, \
				{0, {{I2C_MUX_PCA9548, 0x75, 4} } }, \
				{0, {{I2C_MUX_PCA9548, 0x75, 5} } }, \
				{0, {{I2C_MUX_PCA9548, 0x75, 6} } }, \
				{0, {{I2C_MUX_PCA9548, 0x75, 7} } }, \
				}


/* #define CONFIG_ZYNQ_I2C1 */ /* FIXME for 96 compatible bitstream */
#define CONFIG_SYS_I2C_ZYNQ

#define CONFIG_USB_HOST_ETHER
#define CONFIG_USB_ETHER_ASIX

/* #define CONFIG_MMC_TRACE */
/* #define CONFIG_ZYNQ_SDHCI_MAX_FREQ 15000000 */

#include <configs/xilinx_zynqmp.h>

#endif /* __CONFIG_ZYNQMP_ULTRA96_H */
```

### common/Kconfig

```common/Kconfig``` に config MENU_SHOW エントリを追加しています。これはブート時にメニューを表示させるための設定です。```configs/xilinx_zynqmp_ultra96_defconfig``` で CONFIG_MENU_SHOW を定義するためには、Kconfig にこのエントリが必要です。

```diff
diff --git a/common/Kconfig b/common/Kconfig
index 4da095a..4f234bf 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -184,6 +184,13 @@ config BOOTDELAY
 
 	  See doc/README.autoboot for details.
 
+config MENU_SHOW
+	bool "Show menu when automatically booting"
+	depends on AUTOBOOT
+	select CMD_BOOTMENU
+	help
+	  Show menu when automatically booting.
+
 config USE_BOOTARGS
 	bool "Enable boot arguments"
 	help
```

### include/configs/xilinx_zynqmp.h

ブート時にメニューを表示させるために ```include/configs/xilinx_zynqmp.h``` の ```CONFIG_EXTRA_ENV_SETTINGS``` を次のように修正します。具体的には ```"sd_uEnvtxt_load"``` 変数を追加し、```"uenvboot"``` 変数を修正します。さらに ```CONFIG_PREBOOT``` を次のように修正します。具体的には ```"sd_uEnvtxt_load"``` 変数を実行するようにします。これにより、プリブート時に ```uEnv.txt``` の内容を取り込むようになります。


```diff
diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h
index 59caeae..16dd174 100644
--- a/include/configs/xilinx_zynqmp.h
+++ b/include/configs/xilinx_zynqmp.h
@@ -161,6 +161,12 @@
 	"importbootenv=echo Importing environment from SD ...; " \
 		"env import -t ${loadbootenv_addr} $filesize\0" \
 	"sd_uEnvtxt_existence_test=test -e mmc $sdbootdev:$partid /uEnv.txt\0" \
+        "sd_uEnvtxt_load=" \
+		"if run sd_uEnvtxt_existence_test; then " \
+			"run loadbootenv; " \
+			"echo Loaded environment from ${bootenv}; " \
+			"run importbootenv; " \
+		"fi\0" \
 	"sata_root=if test $scsidevs -gt 0; then setenv bootargs $bootargs root=/dev/sda rw rootfstype=ext4; fi\0" \
 	"sataboot=load scsi 0 80000 boot/Image && load scsi 0 $fdt_addr boot/system.dtb && booti 80000 - $fdt_addr\0" \
 	"veloce=fdt addr f000000 && fdt resize" \
@@ -173,11 +179,6 @@
 		  "sf read $kernel_addr $kernel_offset $kernel_size && " \
 		  "booti $kernel_addr - $fdt_addr\0" \
 	"uenvboot=" \
-		"if run sd_uEnvtxt_existence_test; then " \
-			"run loadbootenv; " \
-			"echo Loaded environment from ${bootenv}; " \
-			"run importbootenv; " \
-		"fi; " \
 		"if test -n $uenvcmd; then " \
 			"echo Running uenvcmd ...; " \
 			"run uenvcmd; " \
@@ -229,7 +230,7 @@
 	DFU_ALT_INFO
 #endif
 
-#define CONFIG_PREBOOT		"run setup"
+#define CONFIG_PREBOOT		"run setup && run sd_uEnvtxt_load"
 
 /* Monitor Command Prompt */
 /* Console I/O Buffer Size */
```


### board/xilinx/zynqmp/zynqmp-uz3eg-iocc/psu_init_gpl.[ch]

これらファイルは[「Ultra96 向け Debian GNU/Linux (v2018.2版) の構築(Sample FPGA Design編)」@Qiita](https://qiita.com/ikwzm/items/0489b02962c6f0455783)で作ったハードウェア情報の中に入っています。ただし、U-Boot でハードウェア情報に含まれるファイルが必要になるのは u-boot.spl をビルドする場合です。今回は u-boot.spl は使いませんので、一度作っておいたファイルを使いまわしても問題ありません。