UltraZed 向け Debian GNU/Linux (v2018.2版) の構築(Linux Kernel編)


## はじめに

UltraZed-EG スターターキットに Debian GNU/Linux (v2018.2版) を構築する方法について、具体的な方法をいくつかに分けて説明します。

 * [Introduction](https://qiita.com/ikwzm/items/5b657ebd8895945c4eae)
 * [Boot Loader](https://qiita.com/ikwzm/items/a0dfef6355cf839ebc08)
   - [Sample FPGA Design](https://qiita.com/ikwzm/items/aae6e17e7d08b089e010)
   - [FSBL   (First Stage Boot Loader)](https://qiita.com/ikwzm/items/a94c79d78b89fc2e31f8)
   - [PMUFW  (Platform Manager Unit Firmware)](https://qiita.com/ikwzm/items/06aeaa22e9b25d21ef88)
   - [BL31   (ARM Trusted Firmware Boot Loader state 3-1)](https://qiita.com/ikwzm/items/4735be0fbdd1e51c7c59)
   - [U-Boot](https://qiita.com/ikwzm/items/2a7006b6c70c8fa397dc)
   - [BOOT.BIN](https://qiita.com/ikwzm/items/d0482bf8bfc7912ff746)
 * __Linux Kernel(この記事)__
 * [Debian9 Root File System](https://qiita.com/ikwzm/items/a0e88798ed29b30fa003)

この記事では、ZynqMP の Linux Kernel について説明をします。

## 注意

Linux Kernel では 起動時に ATF(ARM Trusted Firmware) のバージョンをチェックしています。Debian GNU/Linux (v2018.2版) で構築する Linux Kernel 4.14.0 (xilinx-v2018.2) では ATF(ARM Trusted Firmware) のバージョンは v1.0 である必要があります。これ以外のバージョンでは Kernel が Panic を起こして起動出来ないので注意してください。

## Linux Kernel の構築

### 必要な環境

* gcc-aarch64-linux-gnu

### Linux Kernel 構築環境の準備

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

 * [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.0
```

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

Linux Kernel のソースコードを以下の URL からダウンロードします。今回は Linux のメインラインからではなく、Xilinx が提供してる linux-xlnx を使います。

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

```console
shell$ git clone https://github.com/Xilinx/linux-xlnx.git linux-xlnx-v2018.2-zynqmp-fpga
```

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

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

```console
shell$ cd linux-xlnx-v2018.2-zynqmp-fpga
shell$ git checkout -b linux-xlnx-v2018.2-zynqmp-fpga refs/tags/xilinx-v2018.2
```

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

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

```console
shell$ patch -p1 < ../files/linux-xlnx-v2018.2-zynqmp-fpga.diff
shell$ git add --update
shell$ git add arch/arm64/boot/dts/xilinx/zynqmp-uz3eg-iocc.dts
shell$ git commit -m "[patch] for linux-xlnx-v2018.2-zynqmp-fpga."
```

### ヘッダーパッケージにホスト用の実行ファイルが含まれてしまう問題

チェックアウトした xilinx-v2018.2 には、Debain のパッケージを作る際に arm64 用ではなくクロスコンパイルを実行したプラットフォーム用のパッケージが出来てしまう問題があります。そのための修正を追加します。この件の詳細は後述します。

```console
shell$ patch -p1 < ../files/linux-xlnx-v2018.2-builddeb.diff
shell$ git add --update
shell$ git commit -m "[update] scripts/package/builddeb to add tools/include and postinst script to header package"
```

### FPGA のロード時に raw ファイルをロード出来るように修正

チェックアウトした xilinx-v2018.2 には、FPGA のロード時に raw ファイルを指定するとフリーズするという問題があります。ここではその修正を追加します。この件の詳細は後述します。

```console
shell$ patch -p1 < ../files/linux-xlnx-v2018.2-zynqmp-fpga-patch.diff
shell$ git add --update
shell$ git commit -m "[patch] drivers/fpga/zynqmp-fpga.c for load raw file format"
```

### タグとバージョン番号の設定

```console
shell$ git tag -a xilinx-v2018.2-zynqmp-fpga -m "release xilinx-v2018.2-zynqmp-fpga"
shell$ echo 0 > .version
```

### 構築の準備

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

````console
shell$ cd linux-xlnx-v2018.2-zynqmp-fpga
shell$ export ARCH=arm64
shell$ export CROSS_COMPILE=aarch64-linux-gnu-
shell$ make xilinx_zynqmp_defconfig
````

### カーネルと Debian パッケージの構築

````console
shell$ export DTC_FLAGS=--symbols
shell$ make deb-pkg
````

### 構築したカーネルのイメージとデバイスツリーを target/UltraZed-EG-IOCC/boot にコピー

無事にカーネルのイメージ(arch/arm64/boot/Image) と UltraZed-EG-IOCC 用のデバイスツリー(arch/arm64/boot/dts/xilinx/zynqmp-uz3eg-iocc.dtb) が出来たら、それを target/UltraZed-EG-IOCC/boot にコピーします。その際、作ったカーネルのバージョン等をわかりやすくするため名前を変更しておきます。
また、dtc(Device Tree Compiler) を使って、デバイスツリーのバイナリファイル (devicetree-4.14.0-xlnx-v2018.2-fpga-zynqmp-uz3eg-iocc.dtb) をデバイスツリーのソースファイル (devicetree-4.14.0-xlnx-v2018.2-fpga-zynqmp-uz3eg-iocc.dts) に戻しておきます。何かデバイスツリーを変更したい時は、このデバイスツリーソースファイルを修正して dtc でデバイスツリーバイナリファイルにコンパイルしてください。
なお、[「デバイスツリーにシンボル情報を埋め込む」](https://qiita.com/ikwzm/items/03d518b7c46d1ee49943)で説明したように、古いバージョンの dtc では --symbols オプションをサポートしていない場合があります。その場合は Linux Kernel をビルドした時にホスト用に生成された dtc (scripts/dtc/dtc) を使ってコンパイルすると良いでしょう。

```console
shell$ cp arch/arm64/boot/Image ../target/UltraZed-EG-IOCC/boot/image-4.14.0-xlnx-v2018.2-zynqmp-fpga
shell$ cp arch/arm64/boot/dts/xilinx/zynqmp-uz3eg-iocc.dtb ../target/UltraZed-EG-IOCC/boot/devicetree-4.14.0-xlnx-v2018.2-fpga-zynqmp-uz3eg-iocc.dtb
shell$ ./scripts/dtc/dtc -I dtb -O dts --symbols -o ../target/UltraZed-EG-IOCC/boot/devicetree-4.14.0-xlnx-v2018.2-fpga-zynqmp-uz3eg-iocc.dts ../target/UltraZed-EG-IOCC/boot/devicetree-4.14.0-xlnx-v2018.2-fpga-zynqmp-uz3eg-iocc.dtb
```

## Linux Kernel の起動

### uEnv.txt

[「UltraZed 向け Debian GNU/Linux (v2018.2版) の構築(U-Boot編)」](https://qiita.com/ikwzm/items/2a7006b6c70c8fa397dc) で構築した U-Boot は、起動の際、ストレージに uEnv.txt があればそれを読み込みます。そして ```uenvcmd``` 変数が定義されていれば、その変数で定義されている内容を実行します。そこで uEnv.txt に、この記事で構築したカーネルのイメージとデバイスツリーを指定して実行するように記述します。


```text:target/UltraZed-EG-IOCC/boot/uEnv.txt
linux_img_load_cmd=fatload mmc 1 $kernel_addr image-4.14.0-xlnx-v2018.2-zynqmp-fpga
linux_dtb_load_cmd=fatload mmc 1 $fdt_addr    devicetree-4.14.0-xlnx-v2018.2-zynqmp-fpga-uz3eg-iocc.dtb
linux_set_boot_cmd=setenv bootargs console=ttyPS0,115200 root=/dev/mmcblk1p2 rw rootwait uio_pdrv_genirq.of_id=generic-uio
linux_boot_img_cmd=booti $kernel_addr - $fdt_addr
uenvcmd=run linux_img_load_cmd && run linux_dtb_load_cmd && run linux_set_boot_cmd && run linux_boot_img_cmd

bootmenu_0=Boot Default=boot
```

 * ```linux_img_load_cmd``` 変数に ```mmc 1``` (SD-Card の FAT file system)から image-4.14.0-xlnx-v2018.2-zynqmp-fpga をメモリ上の ```$kernel_addr``` で指定されたアドレスにロードするコマンドを記述。
 * ```linux_dtb_load_cmd``` 変数に ```mmc 1``` (SD-Card の FAT file system)から devicetree-4.14.0-xlnx-v2018.2-zynqmp-fpga-uz3eg-iocc.dtb をメモリ上の ```$fdt_addr``` で指定されたアドレスにロードするコマンドを記述。
 * ```linux_set_boot_cmd``` 変数に ```bootargs``` 変数を設定するコマンドを記述。
 * ```bootargs``` には root file system として ```/dev/mmcblk1p2``` (SD-Card の第2パーティション) を指定。
 * ```linux_boot_img_cmd``` 変数に ```booti``` コマンドを使ってメモリ上にロードされたカーネルをブートするコマンドを記述。
 * ```uenvcmd``` 変数に上記各種変数をコマンドとして実行するように記述。
 * ```bootmenu_0``` 変数にブートメニューの最初の選択肢のタイトルと実行するコマンドを記述。

Zynq と異なるのは、ブートするカーネルのイメージが Linux kernel ARM boot executable zImage 形式ではなく、arm64 Linux Image 形式であることです。arm64 用に構築した U-Boot には arm64 Linux Image 形式のイメージをブートするためのコマンド ```booti``` があるので、そちらを使います。

## ファイルの説明

ここでは linux-xlnx を ZynqMP 用に構築する際に新たに追加したファイルおよび修正したファイルの説明をします。

### arch/arm64/configs/xilinx_zynqmp_defconfig

ZynqMP 用のコンフィギュレーション定義ファイルです。基本的には linux-xlnx にすでにある xilinx_zynqmp_defconfig と同じですが、Device Tree Overlay を使うために ```CONFIG_OF_OVERLAY=y```を、さらに Device Tree Overlay を Configuration File System から行うために ```CONFIG_OF_CONFIGFS=y``` を新たに追加しています。

### arch/arm64/boot/dts/xilinx/zynqmp-uz3eg-iocc.dts

UltraZed-EG-IOCC 用のデバイスツリーです。実はこれと同じデバイスツリーを U-Boot のビルド時にも流用しています。

<details><summary>arch/arm64/boot/dts/xilinx/zynqmp-uz3eg-iocc.dts</summary><div>

```dts:arch/arm64/boot/dts/xilinx/zynqmp-uz3eg-iocc.dts
/dts-v1/;

#include "zynqmp.dtsi"
#include "zynqmp-clk-ccf.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
#include <dt-bindings/phy/phy.h>

/ {
	model = "ZynqMP UltraZed-EG IO Carrier Card";
	compatible = "xlnx,zynqmp-uz3eg-iocc", "xlnx,zynqmp";

	aliases {
		ethernet0 = &gem3;
		serial0 = &uart0;
		serial1 = &uart1;
		spi0 = &qspi;
	};

	chosen {
		bootargs = "earlycon clk_ignore_unused";
		stdout-path = "serial0:115200n8";
	};

	memory {
		device_type = "memory";
		reg = <0x0 0x0 0x0 0x80000000>;
	};

	cpus {
	};

	amba_pl: amba_pl@0 {
		#address-cells = <2>;
		#size-cells = <2>;
		compatible = "simple-bus";
		ranges ;
	};
};

&dcc {
	status = "okay";
};

&fpd_dma_chan1 {
	status = "okay";
};

&fpd_dma_chan2 {
	status = "okay";
};

&fpd_dma_chan3 {
	status = "okay";
};

&fpd_dma_chan4 {
	status = "okay";
};

&fpd_dma_chan5 {
	status = "okay";
};

&fpd_dma_chan6 {
	status = "okay";
};

&fpd_dma_chan7 {
	status = "okay";
};

&fpd_dma_chan8 {
	status = "okay";
};

&gem3 {
	status = "okay";
	xlnx,ptp-enet-clock = <0x0>;
	phy-mode = "rgmii-id";
	phy-handle = <&phy9>;
	phy9: phy@9 {
		reg = <0x9>;
		ti,rx-internal-delay = <0x8>;
		ti,tx-internal-delay = <0xa>;
		ti,fifo-depth = <0x1>;
		ti,rxctrl-strap-worka;
	};
};

&gpio {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_gpio_default>;
};

&gpu {
	status = "okay";
};

&i2c1 {
	status = "okay";
	clock-frequency = <400000>;
	pinctrl-names = "default", "gpio";
	pinctrl-0 = <&pinctrl_i2c1_default>;
	pinctrl-1 = <&pinctrl_i2c1_gpio>;
	scl-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>;
	sda-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>;
};

&pinctrl0 {
	status = "okay";

	pinctrl_i2c1_default: i2c1-default {
		mux {
			groups = "i2c1_6_grp";
			function = "i2c1";
		};

		conf {
			groups = "i2c1_6_grp";
			bias-pull-up;
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};
	};

	pinctrl_i2c1_gpio: i2c1-gpio {
		mux {
			groups = "gpio0_24_grp", "gpio0_25_grp";
			function = "gpio0";
		};

		conf {
			groups = "gpio0_24_grp", "gpio0_25_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};
	};

	pinctrl_dpaux0_default: dpaux0-default {
		mux {
			groups = "dpaux0_0_grp";
			function = "dpaux0";
		};

		conf {
			groups = "dpaux0_0_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};
	};

	pinctrl_uart0_default: uart0-default {
		mux {
			groups = "uart0_8_grp";
			function = "uart0";
		};

		conf {
			groups = "uart0_8_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};

		conf-rx {
			pins = "MIO34";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO35";
			bias-disable;
		};
	};

	pinctrl_uart1_default: uart1-default {
		mux {
			groups = "uart1_8_grp";
			function = "uart1";
		};

		conf {
			groups = "uart1_8_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};

		conf-rx {
			pins = "MIO33";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO32";
			bias-disable;
		};
	};

	pinctrl_sdhci0_default: sdhci0-default {
		mux {
			groups = "sdio0_0_grp";
			function = "sdio0";
		};

		conf {
			groups = "sdio0_0_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
			bias-disable;
		};
	};

	pinctrl_sdhci1_default: sdhci1-default {
		mux {
			groups = "sdio1_pc_0_grp";
			function = "sdio1_pc";
		};

		conf {
			groups = "sdio1_pc_0_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
			bias-disable;
		};

		mux-cd {
			groups = "sdio1_cd_0_grp";
			function = "sdio1_cd";
		};

		conf-cd {
			groups = "sdio1_cd_0_grp";
			bias-high-impedance;
			bias-pull-up;
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};

		mux-wp {
			groups = "sdio1_wp_0_grp";
			function = "sdio1_wp";
		};

		conf-wp {
			groups = "sdio1_wp_0_grp";
			bias-high-impedance;
			bias-pull-up;
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};
	};

	pinctrl_usb0_default: usb0-default {
		mux {
			groups = "usb0_0_grp";
			function = "usb0";
		};

		conf {
			groups = "usb0_0_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};

		conf-rx {
			pins = "MIO52", "MIO53", "MIO55";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
			       "MIO60", "MIO61", "MIO62", "MIO63";
			bias-disable;
		};
	};

	pinctrl_gem3_default: gem3-default {
		mux {
			function = "ethernet3";
			groups = "ethernet3_0_grp";
		};

		conf {
			groups = "ethernet3_0_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};

		conf-rx {
			pins = "MIO70", "MIO71", "MIO72", "MIO73", "MIO74",
									"MIO75";
			bias-high-impedance;
			low-power-disable;
		};

		conf-tx {
			pins = "MIO64", "MIO65", "MIO66", "MIO67", "MIO68",
									"MIO69";
			bias-disable;
			low-power-enable;
		};

		mux-mdio {
			function = "mdio3";
			groups = "mdio3_0_grp";
		};

		conf-mdio {
			groups = "mdio3_0_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
			bias-disable;
		};
	};

	pinctrl_gpio_default: gpio-default {
		mux {
			function = "gpio0";
			groups = "gpio0_23_grp",
			         "gpio0_36_grp", "gpio0_37_grp", "gpio0_38_grp", "gpio0_39_grp",
				 "gpio0_40_grp", "gpio0_41_grp", "gpio0_42_grp";
		};

		conf {
			groups = "gpio0_23_grp",
			         "gpio0_36_grp", "gpio0_37_grp", "gpio0_38_grp", "gpio0_39_grp",
				 "gpio0_40_grp", "gpio0_41_grp", "gpio0_42_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};

		conf-pull-up {
			pins = "MIO23", "MIO26", "MIO31",
			       "MIO36", "MIO37", "MIO38", "MIO39",
			       "MIO40", "MIO41", "MIO42";
			bias-pull-up;
		};

		mux-sw {
			function = "gpio0";
			groups = "gpio0_26_grp";
		};

		conf-sw {
			groups = "gpio0_26_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};

		mux-led {
			function = "gpio0";
			groups = "gpio0_31_grp";
		};

		conf-led {
			groups = "gpio0_31_grp";
			slew-rate = <SLEW_RATE_SLOW>;
			io-standard = <IO_STANDARD_LVCMOS18>;
		};
	};
};

&qspi {
	status = "okay";
	is-dual = <1>;
	num-cs = <1>;
	spi-rx-bus-width = <0x4>;
	spi-tx-bus-width = <0x4>;
	flash@0 {
		compatible = "n25q512a", "micron,m25p80";
		spi-tx-bus-width = <0x1>;
		spi-rx-bus-width = <0x4>;
		reg = <0x0>;
		#address-cells = <0x1>;
		#size-cells = <0x1>;
		spi-max-frequency = <0x66ff300>;

		partition@0x00000000 {
			label = "boot";
			reg = <0x0 0x100000>;
		};

		partition@0x00100000 {
			label = "bootenv";
			reg = <0x100000 0x40000>;
		};

		partition@0x00140000 {
			label = "kernel";
			reg = <0x140000 0x1600000>;
		};
	};
};

&rtc {
	status = "okay";
};

&sata {
	status = "okay";
	/* SATA OOB timing settings */
	ceva,p0-cominit-params = /bits/ 8 <0x18 0x40 0x18 0x28>;
	ceva,p0-comwake-params = /bits/ 8 <0x06 0x14 0x08 0x0E>;
	ceva,p0-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>;
	ceva,p0-retry-params = /bits/ 16 <0x96A4 0x3FFC>;
	ceva,p1-cominit-params = /bits/ 8 <0x18 0x40 0x18 0x28>;
	ceva,p1-comwake-params = /bits/ 8 <0x06 0x14 0x08 0x0E>;
	ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>;
	ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>;
	phy-names = "sata-phy";
	phys = <&lane1 PHY_TYPE_SATA 1 1 125000000>;
};

&sdhci0 {
	status = "okay";
	clock-frequency = <199998000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sdhci0_default>;
	xlnx,mio_bank = <0x0>;
	disable-wp;
};

&sdhci1 {
	status = "okay";
	clock-frequency = <199998000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sdhci1_default>;
	xlnx,mio_bank = <0x1>;
	max-frequency = <50000000>;
	no-1-8-v;
	disable-wp;
};

&serdes {
	status = "okay";
};

&uart0 {
	status = "okay";
	device_type = "serial";
	port-number = <0>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart0_default>;
};

&uart1 {
	status = "okay";
	device_type = "serial";
	port-number = <1>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart1_default>;
};

&usb0 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_usb0_default>;
};

&dwc3_0 {
	status = "okay";
	dr_mode = "host";
	snps,usb3_lpm_capable;
	phy-names = "usb3-phy";
	phys = <&lane0 PHY_TYPE_USB3 0 0 26000000>;
	maximum-speed = "super-speed";
};

&watchdog0 {
	status = "okay";
};

&xilinx_ams {
	status = "okay";
};

&ams_ps {
	status = "okay";
};

&ams_pl {
	status = "okay";
};

&zynqmp_dpsub {
	status = "okay";
	phy-names = "dp-phy0","dp-phy1";
	phys =  <&lane3 PHY_TYPE_DP 0 3 27000000>,
		<&lane2 PHY_TYPE_DP 1 3 27000000>;
};

&zynqmp_dp_snd_codec0 {
	status = "okey";
};

&zynqmp_dp_snd_pcm0 {
	status = "okey";
};

&zynqmp_dp_snd_pcm1 {
	status = "okey";
};

&zynqmp_dp_snd_card0 {
	status = "okey";
};

&xlnx_dpdma {
	status = "okay";
};

```

</div></detalis>

この Device Tree の詳細について以下の節で説明します。

#### sdhci0 および sdhci1 に disable-wp

これは[「UltraZed で SD Card が書き込み不可になってしまう問題」](https://qiita.com/ikwzm/items/179af88949ae1b5d1460) で説明したとおりです。もともとは Avnet のボード設定ファイルに問題があったのですが、もうすでにそのボード設定ファイルを使ったデザインがあり、もしそのデザインを使って FSBL を作ったら SD Card が書き込み不可になってしまってブートに失敗してしまいます。その予防策として、あえて、Device Tree にも disable-wp を追加しています。

```dts:arch/arm64/boot/dts/xilinx/zynqmp-uz3eg-iocc.dts
&sdhci0 {
	status = "okay";
	clock-frequency = <199998000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sdhci0_default>;
	xlnx,mio_bank = <0x0>;
	disable-wp;
};

&sdhci1 {
	status = "okay";
	clock-frequency = <199998000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sdhci1_default>;
	xlnx,mio_bank = <0x1>;
	max-frequency = <50000000>;
	no-1-8-v;
	disable-wp;
};
```

#### Ethernet の Phy の物理アドレス

当初、Phy の物理アドレスは[「UltraZed™-EG SOM Hardware User Guide Version 1.1」](http://zedboard.org/sites/default/files/documentations/5264-UG-AES-ZU3EGES-1-SOM-G-v1-1-V1.pdf)の「2.5.1 Ethernet PHY Strapping Resistors」の記述に基づいて ```<0x01>``` を設定していましたが、認識されませんでした。どうやら物理アドレスは ```<0x09>``` が正しいようです。

```dts:arch/arm64/boot/dts/xilinx/zynqmp-uz3eg-iocc.dts
&gem3 {
	status = "okay";
	xlnx,ptp-enet-clock = <0x0>;
	phy-mode = "rgmii-id";
	phy-handle = <&phy9>;
	phy9: phy@9 {
		reg = <0x9>;
		ti,rx-internal-delay = <0x8>;
		ti,tx-internal-delay = <0xa>;
		ti,fifo-depth = <0x1>;
		ti,rxctrl-strap-worka;
	};
};
```

#### ヘッダーパッケージにホスト用の実行ファイルが含まれてしまう問題

詳細は以下の記事を参照してください。

 * [「クロスコンパイルした Debian GNU/Linux でデバイスドライバをセルフコンパイルする際の注意点」@Qiita](https://qiita.com/ikwzm/items/e31ecb099d0d50cb027c)

このパッチを当てる差分ファイルが次に示す files/linux-xlnx-v2018.2-builddeb.diff です。

<details><summary>files/linux-xlnx-v2018.2-builddeb.diff</summary><div>

```diff:files/linux-xlnx-v2018.2-builddeb2.diff
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 0bc8747..515963f 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -313,7 +313,7 @@ fi
 
 # Build kernel header package
 (cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles"
-(cd $srctree; find arch/*/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles"
+(cd $srctree; find arch/*/include include tools/include scripts -type f) >> "$objtree/debian/hdrsrcfiles"
 (cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles"
 (cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles"
 if grep -q '^CONFIG_STACK_VALIDATION=y' $KCONFIG_CONFIG ; then
@@ -330,6 +330,15 @@ mkdir -p "$destdir"
 (cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be
 ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build"
 rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles"
+mkdir -m 755 -p "$kernel_headers_dir/DEBIAN"
+cat <<EOF >> $kernel_headers_dir/DEBIAN/postinst
+#!/bin/sh -e
+
+make -C /usr/src/linux-headers-$version scripts
+
+EOF
+
+chmod 755 $kernel_headers_dir/DEBIAN/postinst
 
 cat <<EOF >> debian/control
 
```

</div></detalis>

### FPGA のロード時に raw ファイルをロード出来るように修正

チェックアウトした xilinx-v2018.2 には、FPGA のロード時に raw ファイルを指定するとフリーズするという問題がありました。ここではその修正を追加します。具体的には ATF(ARM Trusted Firmware) に渡す3番目の引数にファイルサイズを示す物理メモリ上のアドレスを指定します。

このパッチを当てる差分ファイルが次に示す files/linux-xlnx-v2018.2-zynqmp-fpga-patch.diff です。

<details><summary>files/linux-xlnx-v2018.2-zynqmp-fpga-patch.diff</summary><div>

```diff:files/linux-xlnx-v2018.2-zynqmp-fpga-patch.diff
diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c
index b0c482f..4a91d64 100644
--- a/drivers/fpga/zynqmp-fpga.c
+++ b/drivers/fpga/zynqmp-fpga.c
@@ -48,7 +48,8 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
 {
 	struct zynqmp_fpga_priv *priv;
 	char *kbuf;
-	size_t dma_size;
+	size_t kbuf_size;
+	size_t algn_size = (size + (sizeof(u32)-1)) & (~(sizeof(u32)-1));
 	dma_addr_t dma_addr;
 	int ret;
 	const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
@@ -59,25 +60,30 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
 	priv = mgr->priv;
 
 	if (mgr->flags & IXR_FPGA_ENCRYPTION_EN)
-		dma_size = size + ENCRYPTED_KEY_LEN;
+		kbuf_size = algn_size + ENCRYPTED_KEY_LEN;
 	else
-		dma_size = size;
+		kbuf_size = algn_size + sizeof(u32);
 
-	kbuf = dma_alloc_coherent(priv->dev, dma_size, &dma_addr, GFP_KERNEL);
+	kbuf = dma_alloc_coherent(priv->dev, kbuf_size, &dma_addr, GFP_KERNEL);
 	if (!kbuf)
 		return -ENOMEM;
 
 	memcpy(kbuf, buf, size);
 
-	if (mgr->flags & IXR_FPGA_ENCRYPTION_EN)
-		memcpy(kbuf + size, mgr->key, ENCRYPTED_KEY_LEN);
+	if (mgr->flags & IXR_FPGA_ENCRYPTION_EN) {
+		memcpy(kbuf + algn_size, mgr->key, ENCRYPTED_KEY_LEN);
+        }
+	else {
+		u32* size_ptr = (u32*)(kbuf + algn_size);
+		*size_ptr = (u32)size;
+	}
 
 	__flush_cache_user_range((unsigned long)kbuf,
-				 (unsigned long)kbuf + dma_size);
+				 (unsigned long)kbuf + kbuf_size);
 
-	ret = eemi_ops->fpga_load(dma_addr, dma_addr + size, mgr->flags);
+	ret = eemi_ops->fpga_load(dma_addr, dma_addr + algn_size, mgr->flags);
 
-	dma_free_coherent(priv->dev, dma_size, kbuf, dma_addr);
+	dma_free_coherent(priv->dev, kbuf_size, kbuf, dma_addr);
 
 	return ret;
 }
```

</div></detalis>

## 参考

 * [「UltraZed で SD Card が書き込み不可になってしまう問題」@Qiita](https://qiita.com/ikwzm/items/179af88949ae1b5d1460)
 * [「UltraZed™-EG SOM Hardware User Guide Version 1.1」](http://zedboard.org/sites/default/files/documentations/5264-UG-AES-ZU3EGES-1-SOM-G-v1-1-V1.pdf)
 * [「クロスコンパイルした Debian GNU/Linux でデバイスドライバをセルフコンパイルする際の注意点」@Qiita](https://qiita.com/ikwzm/items/e31ecb099d0d50cb027c)