はじめに
Ultra96 に Debian GNU/Linux (v2018.2版) を構築する方法について、具体的な方法をいくつかに分けて説明します。
- Introduction
- Boot Loader
- Linux Kernel(この記事)
- Debian9 Root File System
この記事では 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.1 をチェックアウトします。
shell$ git clone git://github.com/ikwzm/ZynqMP-FPGA-Linux
shell$ cd ZynqMP-FPGA-Linux
shell$ git checkout v2018.2.1
ソースコードのダウンロード
Linux Kernel のソースコードを以下の URL からダウンロードします。今回は Linux のメインラインからではなく、Xilinx が提供してる linux-xlnx を使います。
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 という作業用のブランチを作ります。
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 用のファイルを追加してコミットします。追加するファイルの詳細は後述します。
shell$ patch -p1 < ../files/linux-xlnx-v2018.2-zynqmp-fpga.diff
shell$ git add --update
shell$ git add arch/arm64/boot/dts/xilinx/zynqmp-ultra96.dts
shell$ git commit -m "[patch] for linux-xlnx-v2018.2-zynqmp-fpga."
ヘッダーパッケージにホスト用の実行ファイルが含まれてしまう問題
チェックアウトした xilinx-v2018.2 には、Debain のパッケージを作る際に arm64 用ではなくクロスコンパイルを実行したプラットフォーム用のパッケージが出来てしまう問題があります。そのための修正を追加します。この件の詳細は後述します。
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 ファイルを指定するとフリーズするという問題があります。ここではその修正を追加します。この件の詳細は後述します。
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"
タグとバージョン番号の設定
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 用のコンフィギュレーション定義ファイルを使って構築の準備をします。
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 パッケージの構築
shell$ export DTC_FLAGS=--symbols
shell$ make deb-pkg
構築したカーネルのイメージとデバイスツリーを target/Ultra96/boot にコピー
無事にカーネルのイメージ(arch/arm64/boot/Image) と Ultra96 用のデバイスツリー(arch/arm64/boot/dts/xilinx/zynqmp-ultra96.dtb) が出来たら、それを target/Ultra96/boot にコピーします。その際、作ったカーネルのバージョン等をわかりやすくするため名前を変更しておきます。
また、dtc(Device Tree Compiler) を使って、デバイスツリーのバイナリファイル (devicetree-4.14.0-xlnx-v2018.2-zynqmp-fpga-ultra96.dtb) をデバイスツリーのソースファイル (devicetree-4.14.0-xlnx-v2018.2-zynqmp-fpga-ultra96.dts) に戻しておきます。何かデバイスツリーを変更したい時は、このデバイスツリーソースファイルを修正して dtc でデバイスツリーバイナリファイルにコンパイルしてください。
なお、「デバイスツリーにシンボル情報を埋め込む」で説明したように、古いバージョンの dtc では --symbols オプションをサポートしていない場合があります。その場合は Linux Kernel をビルドした時にホスト用に生成された dtc (scripts/dtc/dtc) を使ってコンパイルすると良いでしょう。
shell$ cp arch/arm64/boot/Image ../target/Ultra96/boot/image-4.14.0-xlnx-v2018.2-zynqmp-fpga
shell$ cp arch/arm64/boot/dts/xilinx/zynqmp-ultra96.dtb ../target/Ultra96/boot/devicetree-4.14.0-xlnx-v2018.2-zynqmp-fpga-ultra96.dtb
shell$ ./scripts/dtc/dtc -I dtb -O dts --symbols -o ../target/Ultra96/boot/devicetree-4.14.0-xlnx-v2018.2-zynqmp-fpga-ultra96.dts ../target/Ultra96/boot/devicetree-4.14.0-xlnx-v2018.2-zynqmp-fpga-ultra96.dtb
Linux Kernel の起動
uEnv.txt
「Ultra96 向け Debian GNU/Linux (v2018.2版) の構築(U-Boot編)」 で構築した U-Boot は、起動の際、ストレージに uEnv.txt があればそれを読み込みます。そして uenvcmd
変数が定義されていれば、その変数で定義されている内容を実行します。そこで uEnv.txt に、この記事で構築したカーネルのイメージとデバイスツリーを指定して実行するように記述します。
linux_kernel_image=image-4.14.0-xlnx-v2018.2-zynqmp-fpga
linux_fdt_image=devicetree-4.14.0-xlnx-v2018.2-zynqmp-fpga-ultra96.dtb
linux_boot_args=console=ttyPS0,115200 root=/dev/mmcblk0p2 rw rootwait uio_pdrv_genirq.of_id=generic-uio
linux_img_load_cmd=fatload mmc ${sdbootdev} ${kernel_addr} ${linux_kernel_image}
linux_fdt_load_cmd=fatload mmc ${sdbootdev} ${fdt_addr} ${linux_fdt_image}
linux_load_cmd=run linux_img_load_cmd && run linux_fdt_load_cmd
linux_boot_cmd=setenv bootargs ${linux_boot_args} && booti ${kernel_addr} - ${fdt_addr}
uenvcmd=run linux_load_cmd && run linux_boot_cmd
bootmenu_0=Boot Default=boot
-
linux_kernel_image
変数にカーネルのイメージのファイル名である image-4.14.0-xlnx-v2018.2-zynqmp-fpga を指定。 -
linux_fdt_image
変数にデバイスツリーファイル名である devicetree-4.14.0-xlnx-v2018.2-zynqmp-fpga-ultra96.dtb を指定。 -
linux_boot_args
変数に Linux をブートする際の引数を指定。- console として ttyPS0 をボーレートと共に指定。
- root file system として
/dev/mmcblk0p2
(SD-Card の第2パーティション) を指定。 - デバイスツリーオーバーレイで uio を指定出来るように
uio_pdrv_genirq.of_id=generic-uio
を指定。
-
linux_img_load_cmd
変数にsdbootdev
変数でしていされたデバイスからlinux_kernel_image
変数で指定されたカーネルイメージをメモリ上のkernel_addr
で指定されたアドレスにロードするコマンドを記述。 -
linux_dtb_load_cmd
変数にsdbootdev
変数でしていされたデバイスからlinux_fdt_image
変数で指定されたデバイスツリーをメモリ上のfdt_addr
で指定されたアドレスにロードするコマンドを記述。 -
linux_load_cmd
変数にlinux_img_load_cmd
とlinux_dtb_load_cmd
を実行するコマンドを記述。 -
linux_boot_cmd
変数にlinux_boot_args
変数で設定した bootargs を設定し、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-ultra96.dts
Ultra96 用のデバイスツリーです。実はこれと同じデバイスツリーを U-Boot のビルド時にも流用しています。
arch/arm64/boot/dts/xilinx/zynqmp-ultra96.dts
// SPDX-License-Identifier: GPL-2.0+
/*
* dts file for Xilinx ZynqMP Ultra96
*
*/
/dts-v1/;
#include "zynqmp.dtsi"
#include "zynqmp-clk-ccf.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
#include <dt-bindings/phy/phy.h>
/ {
model = "ZynqMP Ultra96";
compatible = "xlnx,zynqmp-ultra96", "xlnx,zynqmp";
aliases {
gpio0 = &gpio;
i2c0 = &i2c1;
rtc0 = &rtc;
serial0 = &uart1;
serial1 = &uart0;
serial2 = &dcc;
spi0 = &spi0;
spi1 = &spi1;
usb0 = &usb0;
usb1 = &usb1;
mmc0 = &sdhci0;
mmc1 = &sdhci1;
};
chosen {
bootargs = "earlycon";
stdout-path = "serial0:115200n8";
};
memory@0 {
device_type = "memory";
reg = <0x0 0x0 0x0 0x80000000>;
};
amba_pl: amba_pl@0 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges ;
};
gpio-keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
autorepeat;
sw4 {
label = "sw4";
gpios = <&gpio 23 GPIO_ACTIVE_LOW>;
linux,code = <KEY_POWER>;
gpio-key,wakeup;
autorepeat;
};
};
iio-hwmon {
compatible = "iio-hwmon";
io-channels = <&xilinx_ams 0>, <&xilinx_ams 1>, <&xilinx_ams 2>,
<&xilinx_ams 3>, <&xilinx_ams 4>, <&xilinx_ams 5>,
<&xilinx_ams 6>, <&xilinx_ams 7>, <&xilinx_ams 8>,
<&xilinx_ams 9>, <&xilinx_ams 10>,
<&xilinx_ams 11>, <&xilinx_ams 12>;
};
leds {
compatible = "gpio-leds";
ds2 {
label = "ds2";
gpios = <&gpio 20 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
ds3 {
label = "ds3";
gpios = <&gpio 19 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "phy0tx"; /* WLAN tx */
default-state = "off";
};
ds4 {
label = "ds4";
gpios = <&gpio 18 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "phy0rx"; /* WLAN rx */
default-state = "off";
};
ds5 {
label = "ds5";
gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "bluetooth-power";
};
vbus_det { /* U5 USB5744 VBUS detection via MIO25 */
label = "vbus_det";
gpios = <&gpio 25 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
};
ltc2954: ltc2954 { /* U7 */
compatible = "lltc,ltc2954", "lltc,ltc2952";
trigger-gpios = <&gpio 26 GPIO_ACTIVE_LOW>; /* INT line - input */
/* If there is HW watchdog on mezzanine this signal should be connected there */
watchdog-gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; /* MIO on PAD */
kill-gpios = <&gpio 34 GPIO_ACTIVE_LOW>; /* KILL signal - output */
};
wmmcsdio_fixed: fixedregulator-mmcsdio {
compatible = "regulator-fixed";
regulator-name = "wmmcsdio_fixed";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
sdio_pwrseq: sdio_pwrseq {
compatible = "mmc-pwrseq-simple";
reset-gpios = <&gpio 7 GPIO_ACTIVE_LOW>; /* WIFI_EN */
};
};
&dcc {
status = "okay";
};
&gpio {
status = "okay";
gpio-line-names = "UART1_TX", "UART1_RX", "UART0_RX", "UART0_TX", "I2C1_SCL",
"I2C1_SDA", "SPI1_SCLK", "WLAN_EN", "BT_EN", "SPI1_CS",
"SPI1_MISO", "SPI1_MOSI", "I2C_MUX_RESET", "SD0_DAT0", "SD0_DAT1",
"SD0_DAT2", "SD0_DAT3", "PS_LED3", "PS_LED2", "PS_LED1",
"PS_LED0", "SD0_CMD", "SD0_CLK", "GPIO_PB", "SD0_DETECT",
"VBUS_DET", "POWER_INT", "DP_AUX", "DP_HPD", "DP_OE",
"DP_AUX_IN", "INA226_ALERT", "PS_FP_PWR_EN", "PL_PWR_EN", "POWER_KILL",
"", "GPIO-A", "GPIO-B", "SPI0_SCLK", "GPIO-C",
"GPIO-D", "SPI0_CS", "SPI0_MISO", "SPI_MOSI", "GPIO-E",
"GPIO-F", "SD1_D0", "SD1_D1", "SD1_D2", "SD1_D3",
"SD1_CMD", "SD1_CLK", "USB0_CLK", "USB0_DIR", "USB0_DATA2",
"USB0_NXT", "USB0_DATA0", "USB0_DATA1", "USB0_STP", "USB0_DATA3",
"USB0_DATA4", "USB0_DATA5", "USB0_DATA6", "USB0_DATA7", "USB1_CLK",
"USB1_DIR", "USB1_DATA2", "USB1_NXT", "USB1_DATA0", "USB1_DATA1",
"USB1_STP", "USB1_DATA3", "USB1_DATA4", "USB1_DATA5", "USB1_DATA6",
"USB_DATA7", "WLAN_IRQ", "PMIC_IRQ", /* MIO end and EMIO start */
"", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "";
};
&gpu {
status = "okay";
};
&i2c1 {
status = "okay";
pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1_default>;
pinctrl-1 = <&pinctrl_i2c1_gpio>;
scl-gpios = <&gpio 4 GPIO_ACTIVE_HIGH>;
sda-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>;
clock-frequency = <100000>;
i2c-mux@75 { /* u11 */
compatible = "nxp,pca9548";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x75>;
i2csw_0: i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
label = "LS-I2C0";
};
i2csw_1: i2c@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
label = "LS-I2C1";
};
i2csw_2: i2c@2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
label = "HS-I2C2";
};
i2csw_3: i2c@3 {
#address-cells = <1>;
#size-cells = <0>;
reg = <3>;
label = "HS-I2C3";
};
i2csw_4: i2c@4 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x4>;
pmic: pmic@5e { /* Custom TI PMIC u33 */
compatible = "ti,tps65086";
reg = <0x5e>;
interrupt-parent = <&gpio>;
interrupts = <77 GPIO_ACTIVE_LOW>;
#gpio-cells = <2>;
gpio-controller;
};
};
i2csw_5: i2c@5 {
#address-cells = <1>;
#size-cells = <0>;
reg = <5>;
/* PS_PMBUS */
ina226@40 { /* u35 */
compatible = "ti,ina226";
reg = <0x40>;
shunt-resistor = <10000>;
/* MIO31 is alert which should be routed to PMUFW */
};
};
i2csw_6: i2c@6 {
#address-cells = <1>;
#size-cells = <0>;
reg = <6>;
/*
* Not Connected
*/
};
i2csw_7: i2c@7 {
#address-cells = <1>;
#size-cells = <0>;
reg = <7>;
/*
* usb5744 (DNP) - U5
* 100kHz - this is default freq for us
*/
};
};
};
&pinctrl0 {
status = "okay";
pinctrl_i2c1_default: i2c1-default {
mux {
groups = "i2c1_1_grp";
function = "i2c1";
};
conf {
groups = "i2c1_1_grp";
bias-pull-up;
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
};
pinctrl_i2c1_gpio: i2c1-gpio {
mux {
groups = "gpio0_4_grp", "gpio0_5_grp";
function = "gpio0";
};
conf {
groups = "gpio0_4_grp", "gpio0_5_grp";
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
};
pinctrl_sdhci0_default: sdhci0-default {
mux {
groups = "sdio0_3_grp";
function = "sdio0";
};
conf {
groups = "sdio0_3_grp";
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
bias-disable;
};
mux-cd {
groups = "sdio0_cd_0_grp";
function = "sdio0_cd";
};
conf-cd {
groups = "sdio0_cd_0_grp";
bias-high-impedance;
bias-pull-up;
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
};
pinctrl_sdhci1_default: sdhci1-default {
mux {
groups = "sdio1_2_grp";
function = "sdio1";
};
conf {
groups = "sdio1_2_grp";
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
bias-disable;
};
};
pinctrl_spi0_default: spi0-default {
mux {
groups = "spi0_3_grp";
function = "spi0";
};
conf {
groups = "spi0_3_grp";
bias-disable;
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
mux-cs {
groups = "spi0_ss_9_grp";
function = "spi0_ss";
};
conf-cs {
groups = "spi0_ss_9_grp";
bias-disable;
};
};
pinctrl_spi1_default: spi1-default {
mux {
groups = "spi1_0_grp";
function = "spi1";
};
conf {
groups = "spi1_0_grp";
bias-disable;
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
mux-cs {
groups = "spi1_ss_0_grp";
function = "spi1_ss";
};
conf-cs {
groups = "spi1_ss_0_grp";
bias-disable;
};
};
pinctrl_uart0_default: uart0-default {
mux {
groups = "uart0_0_grp";
function = "uart0";
};
conf {
groups = "uart0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO2";
bias-high-impedance;
};
conf-tx {
pins = "MIO3";
bias-disable;
};
};
pinctrl_uart1_default: uart1-default {
mux {
groups = "uart1_0_grp";
function = "uart1";
};
conf {
groups = "uart1_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO1";
bias-high-impedance;
};
conf-tx {
pins = "MIO0";
bias-disable;
};
};
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_usb1_default: usb1-default {
mux {
groups = "usb1_0_grp";
function = "usb1";
};
conf {
groups = "usb1_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO64", "MIO65", "MIO67";
bias-high-impedance;
};
conf-tx {
pins = "MIO66", "MIO68", "MIO69", "MIO70", "MIO71",
"MIO72", "MIO73", "MIO74", "MIO75";
bias-disable;
};
};
};
&rtc {
status = "okay";
};
/* SD0 only supports 3.3V, no level shifter */
&sdhci0 {
status = "okay";
no-1-8-v;
broken-cd; /* CD has to be enabled by default */
disable-wp;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sdhci0_default>;
xlnx,mio_bank = <0>;
};
&sdhci1 {
status = "okay";
bus-width = <0x4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sdhci1_default>;
xlnx,mio_bank = <0>;
non-removable;
disable-wp;
cap-power-off-card;
mmc-pwrseq = <&sdio_pwrseq>;
vqmmc-supply = <&wmmcsdio_fixed>;
#address-cells = <1>;
#size-cells = <0>;
wlcore: wifi@2 {
compatible = "ti,wl1831";
reg = <2>;
interrupt-parent = <&gpio>;
interrupts = <76 IRQ_TYPE_EDGE_RISING>; /* MIO76 WLAN_IRQ 1V8 */
};
};
&serdes {
status = "okay";
};
&spi0 { /* Low Speed connector */
status = "okay";
label = "LS-SPI0";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spi0_default>;
};
&spi1 { /* High Speed connector */
status = "okay";
label = "HS-SPI1";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spi1_default>;
};
&uart0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart0_default>;
bluetooth {
compatible = "ti,wl1831-st";
enable-gpios = <&gpio 8 GPIO_ACTIVE_HIGH>;
};
};
&uart1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1_default>;
};
/* ULPI SMSC USB3320 */
&usb0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb0_default>;
};
&dwc3_0 {
status = "okay";
dr_mode = "peripheral";
phy-names = "usb3-phy";
phys = <&lane2 PHY_TYPE_USB3 0 0 26000000>;
maximum-speed = "super-speed";
};
/* ULPI SMSC USB3320 */
&usb1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb1_default>;
};
&dwc3_1 {
status = "okay";
dr_mode = "host";
phy-names = "usb3-phy";
phys = <&lane3 PHY_TYPE_USB3 1 0 26000000>;
maximum-speed = "super-speed";
};
&watchdog0 {
status = "okay";
};
&zynqmp_dpsub {
status = "okay";
phy-names = "dp-phy0", "dp-phy1";
phys = <&lane1 PHY_TYPE_DP 0 1 27000000>,
<&lane0 PHY_TYPE_DP 1 1 27000000>;
};
&zynqmp_dp_snd_pcm0 {
status = "okay";
};
&zynqmp_dp_snd_pcm1 {
status = "okay";
};
&zynqmp_dp_snd_card0 {
status = "okay";
};
&zynqmp_dp_snd_codec0 {
status = "okay";
};
&xlnx_dpdma {
status = "okay";
};
&xilinx_ams {
status = "okay";
};
&ams_ps {
status = "okay";
};
もともと、このデバイスツリーは arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts が元になっています。zynqmp-zcu100-revC.dts との違いを説明します。
amba_pl@0 を追加
デバイスツリーオーバーレイを使って、各種デバイスドライバのロード/アンロードおよび PL のプログラムを行う際、そのターゲットとなるノードです。このノードは単なるノードで特に対応するデバイスドライバとかはありません。名前は何でも良かったのですが、UltraZed と同じノード名にしています。そうすれば UltraZed といろいろ兼用できて都合が良いからです。
amba_pl: amba_pl@0 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges ;
};
pinctrl_uart0_default の conf-rx と conf-tx の pins を交換
zynqmp-zcu100-revC.dts では conf-rx ノードの pins プロパティが "MIO3" に、conf-tx ノードの pins プロパティが "MIO2" に設定されていましたが、改めて Sample Design の I/O pin を調べてみるとどうも逆のようです。
pinctrl_uart0_default: uart0-default {
mux {
groups = "uart0_0_grp";
function = "uart0";
};
conf {
groups = "uart0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO2";
bias-high-impedance;
};
conf-tx {
pins = "MIO3";
bias-disable;
};
};
ZynqMP での pinctrl の ピンアサインについては次の記事を参考にしてください。
ヘッダーパッケージにホスト用の実行ファイルが含まれてしまう問題
詳細は以下の記事を参照してください。
このパッチを当てる差分ファイルが次に示す files/linux-xlnx-v2018.2-builddeb.diff です。
files/linux-xlnx-v2018.2-builddeb.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
FPGA のロード時に raw ファイルをロード出来るように修正
チェックアウトした xilinx-v2018.2 には、FPGA のロード時に raw ファイルを指定するとフリーズするという問題がありました。ここではその修正を追加します。具体的には ATF(ARM Trusted Firmware) に渡す3番目の引数にファイルサイズを示す物理メモリ上のアドレスを指定します。
このパッチを当てる差分ファイルが次に示す files/linux-xlnx-v2018.2-zynqmp-fpga-patch.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;
}