Agilex™ F シリーズ FPGA 開発キットで Linux を動かす

# はじめに

Agilex™ には HPS (Hard Processor System) が搭載された SoC FPGA タイプのデバイスがあります。
HPS は通常 Linux を動作させて使うことが多く、Linux のビルド、起動方法は RocketBoards.org に記載があります。

- [Agilex™ SoC GSRD (Golden System Reference Design)](https://www.rocketboards.org/foswiki/Documentation/AgilexSoCGSRD)

これは [インテル® Agilex™ F シリーズ・トランシーバー SoC 開発キット](https://www.intel.co.jp/content/www/jp/ja/products/details/fpga/development-kits/agilex/f-series-transceiver.html)  での情報なので、他のボードで Linux を動作させる場合は、上記を参考にしたポーティングが必要になります。
今回、[インテル® Agilex™ F シリーズ FPGA 開発キット](https://www.intel.co.jp/content/www/jp/ja/products/details/fpga/development-kits/agilex/f-series.html) への GSRD のポーティングと Linux 起動を試しました。他の Agilex™ ボードで Linux 動作させる際の参考になればと思います。
使用した環境は以下の通りです。
- インテル® Qauarts® Prime Pro Edition Version 22.3
- OS : CentOS Linux release 7.9.2009 (Core)
  - ソフトウェアビルドは、Docker 上 Ubuntu 20.04 LTS で実行
  - 参考情報として Windows11 WSL2 を用いたビルドも試行 
- ボード : インテル® Agilex™ F シリーズ FPGA 開発キットES 版
   - 搭載デバイス : AGFB014R24A2E3VR0
   - DIMM モジュール : Micron DDR4 SDRAM PC4-2133
![agilex-f-series-devboard](
https://www.intel.co.jp/content/dam/www/central-libraries/us/en/images/agilex-f-series-devboard-top1.png.rendition.intel.web.1072.603.png)
引用元: https://www.intel.co.jp/content/www/jp/ja/products/details/fpga/development-kits/agilex/f-series.html

# もくじ
- [1. 環境構築](#1-環境構築)
  - [1.1. Ubuntu on CentOS Docker](#11-ubuntu-on-centos-docker) 
  - [1.2. Ubuntu on Windows WSL](#12-ubuntu-on-windows-wsl)
  - [1.3. ARM コンパイラツールチェーン](#13-arm-コンパイラツールチェーン)
- [2. ハードウェアビルド](#2-ハードウェアビルド)
  - [2.1. GHRD デザイン生成](#21-ghrd-デザイン生成)
  - [2.2. EMIF 修正](#22-emif-修正)
  - [2.3. 合成](#23-合成)
- [3. ソフトウェアビルド](#3-ソフトウェアビルド)
  - [3.1. GSRD ビルド準備](#31-gsrd-ビルド準備)
  - [3.2. GSRD ビルド実行](#32-gsrd-ビルド実行)
- [4. 起動確認](#4-起動確認)
  - [4.1. ブートローダーまでの起動確認](#41-ブートローダーまでの起動確認)
  - [4.2. SD カード Linux 起動](#42-sd-カード-linux-起動)
  - [4.3. QSPI Linux 起動](#43-qspi-linux-起動)
- [5. Appendix](#5-appendix)
  - [5.1. ES 版ボード用ワークアラウンド](#51-ES-版ボード用ワークアラウンド)
    - [5.1.1. Quarts® Prime v20.4 の使用](#511-quarts-prime-v204-の使用)
    - [5.1.2. U-boot-spl の差し替え](#512-u-boot-spl-の差し替え)
  - [5.2. EMIF Debug Toolkit](#52-emif-debug-toolkit)
- [6. まとめ](#6-まとめ)

# 1. 環境構築
Quartus® Prime は CentOS ホストマシン（もしくは Windows）にインストール済みという前提で、ハードウェアの合成実行にはそれをそのまま使用します。  
一方、ソフトウェアのビルド実行には Agilex™ SoC GSRD の手順に合わせて、Ubuntu 20.04 LTS を使用します。Ubuntu 20.04 LTS 環境を準備するには、CentOS 上では Docker、Windows 上では WSL が利用できます。  

以降、ビルド実行の TOP ディレクトリを、`~/agilex_gsrd` として説明します。

```shell: TOP ディレクトリ生成
mkdir ~/agilex_gsrd
cd ~/agilex_gsrd
export TOP_FOLDER=$(pwd)
```

## 1.1. Ubuntu on CentOS Docker 
CentOS 上で　Docker を用いて Ubuntu 20.04 LTS を利用する方法を示します。なお、Docker は導入済み、ユーザーを docker グループに追加済み、としています。  
- 参考情報 : [Install Docker Engine on CentOS](https://docs.docker.com/engine/install/centos/)  

`Dockerfile` を任意のディレクトリ（例えば、`$TOP_FOLDER`）に作成して、Docker イメージを生成します。

```dockerfile: Dockerfile
FROM ubuntu:20.04

ENV DEBCONF_NOWARNINGS=yes

RUN apt-get update && \
    apt-get install -y tzdata && \
    apt-get install -y locales && locale-gen en_US.UTF-8
ENV TZ=Asia/Tokyo
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

RUN apt-get install -y \
    gawk wget git diffstat unzip texinfo gcc build-essential chrpath \
    socat cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping \
    python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint3 xterm python3-subunit \
    mesa-common-dev zstd liblz4-tool
RUN apt-get install -y \
    gcc-multilib python libncurses-dev flex bison openssl libssl-dev sudo

ARG USER_NAME
ARG GROUP_NAME
ARG UID
ARG GID
ARG TOP_FOLDER

RUN groupadd -g $GID $GROUP_NAME && \
    useradd -s /bin/bash -u $UID -g $GID -m $USER_NAME && \
    gpasswd -a $USER_NAME sudo && \
    echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
USER $USER_NAME
RUN mkdir -p $TOP_FOLDER

ENV ARCH arm64
ENV CROSS_COMPILE aarch64-none-linux-gnu-
ENV TOP_FOLDER $TOP_FOLDER
ENV PATH $TOP_FOLDER/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin:$PATH
```

```shell: Docker イメージ生成
cd <Dockerfile のあるディレクトリ>
docker build . -t intelfpga-linux-build:$(id -u -n) \
--build-arg USER_NAME=$(id -u -n) \
--build-arg UID=$(id -u) \
--build-arg GROUP_NAME=$(id -g -n) \
--build-arg GID=$(id -g) \
--build-arg TOP_FOLDER=$TOP_FOLDER
```

Ubuntu 20.04 LTS の Docker コンテナを起動します。

```shell: Docker コンテナ生成 & 起動 & 接続
docker run --name agilex-linux-build-22.3-$(id -u -n) -u $(id -u -n) -v $TOP_FOLDER:$TOP_FOLDER -it intelfpga-linux-build:$(id -u -n) /bin/bash
```

Ubuntu 20.04 LTS の Docker コンテナのコンソールが表示されます。

一旦、`exit` として、コンテナを停止して CentOS ホストマシンに戻ります。再度、起動 & 接続する場合は以下です。

```shell: Docker コンテナ起動 & 接続
docker start -ai agilex-linux-build-22.3-$(id -u -n)
```

上記 Dockerfile では、Agilex™ SoC GSRD の実行環境の設定と合わせて、ホストマシンと同じユーザーを作成しています。ユーザを作成しているのは、
- ホストマシン上の TOP ディレクトリをマウントして、共通のディレクトリでデータのやり取りを簡単に行うため  
- root のまま Yocto Linux のビルドを実行するとエラー停止するため  

が理由です。  
※実行を簡単にするためにユーザー情報を Docker イメージに埋め込んで TAG で区別しましたが、一般的な方法ではないかもしれません。別の方法については[こちらの Qiita 記事](https://qiita.com/yohm/items/047b2e68d008ebb0f001)が参考になります。

## 1.2. Ubuntu on Windows WSL
Windows 環境を使っている場合でも WSL (Windows Subsystem on Linux) を利用することで容易に Ubuntu 20.04 LTS を導入することができます。なお、バージョンに WSL1 と WSL2 があり、今回は WSL2 で試行しましたが、WSL1 でも同様に実行可能です。  
- 参考情報：[WSL を使用して Windows に Linux をインストールする](https://learn.microsoft.com/ja-jp/windows/wsl/install)

Windows 上での実行では、ソフトウェアビルドだけでなく、ハードウェアビルドでも make コマンドを利用して Quartus® Prime を実行するため Linux 系環境を使います。  
WSL で Windows にインストールした Quartus® Prime 実行ファイルの .exe を取り除いたファイル名のリンクを作成して PATH を通します。これにより WSL 環境から、Windows 上の Quartus® Prime をシームレスに使用できます。  
以下では、Quarts® Prime のデフォルトのインストールパスを指定していますが、環境に合わせて適宜修正をして下さい。

```shell: WSL から Windows 上の Quartus® Prime を利用する設定
ORG_QUARTUS_DIR=/mnt/c/intelFPGA_pro/22.3/
NEW_QUARTUS_DIR=~/intelFPGA_pro/22.3/
mkdir -p $NEW_QUARTUS_DIR/quartus/bin $NEW_QUARTUS_DIR/qsys/bin
ls -1 $ORG_QUARTUS_DIR/quartus/bin64/*.exe | xargs basename -a -s .exe | \
xargs -n1 -I{} ln -s $ORG_QUARTUS_DIR/quartus/bin64/{}.exe  $NEW_QUARTUS_DIR/quartus/bin/{}
ls -1 $ORG_QUARTUS_DIR/qsys/bin/*.exe      | xargs basename -a -s .exe | \
xargs -n1 -I{} ln -s $ORG_QUARTUS_DIR/qsys/bin/{}.exe       $NEW_QUARTUS_DIR/qsys/bin/{}
export PATH=$NEW_QUARTUS_DIR/qsys/bin:$NEW_QUARTUS_DIR/quartus/bin:$PATH
```

ハードウェアビルドを実行するディレクトリは、Windows アプリケーションからアクセス可能な、例えば `/mnt/c/` 以下に生成する点に注意が必要です。 ここでは `/mnt/c/Users/<User Name>/agilex_gsrd` としました。

```shell:WSL 上ハードウェアビルド実行用 TOP ディレクトリ生成
mkdir -p /mnt/c/Users/<User Name>/agilex_gsrd
cd /mnt/c/Users/<User Name>/agilex_gsrd
export HW_TOP_FOLDER=$(pwd)
ln -s $HW_TOP_FOLDER/ghrd-socfpga $TOP_FOLDER/ghrd-socfpga
```
※ `ghrd-socfpga` は後述のハードウェアビルド用のディレクトリです。あらかじめ `$TOP_FOLDER` 以下にリンクを張ってアクセスできるようにしています。

Agilex™ SoC GSRD の手順と同様に必要なパッケージをインストールします。

```shell:WSL で必要なパッケージインストール
sudo hwclock -s && sudo apt update
sudo apt install -y wsl dos2unix
sudo apt install -y gawk wget git diffstat unzip texinfo gcc build-essential chrpath \
socat cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping \
python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint3 xterm python3-subunit \
mesa-common-dev zstd liblz4-tool
sudo apt install -y gcc-multilib python libncurses-dev flex bison openssl libssl-dev swig bc kmod
```

## 1.3. ARM コンパイラツールチェーン
CentOS ホストマシン上、もしくは Windows WSL 上に ARM コンパイラツールチェーンを導入し、環境設定をします。

```shell: ARM コンパイラツールチェーン導入
cd $TOP_FOLDER
wget https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/\
gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz
tar xf gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz
rm -f gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz
export PATH=$TOP_FOLDER/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin:$PATH
export ARCH=arm64
export CROSS_COMPILE=aarch64-none-linux-gnu-
```


# 2. ハードウェアビルド
Agilex™ SoC GSRD 手順に従うと、GHRD (Golden **Hardware** Reference Design) が生成されます。ボードのポーティングをするには、ピン配置、クロック、リセットをターゲットボードに合わせ込む必要があります。  
GitHub 上の [Agilex™ GHRD README.md](https://github.com/altera-opensource/ghrd-socfpga/tree/QPDS-22.3pro-21.1std/agilex_soc_devkit_ghrd#readme) を見ると、`Supported Board` として `Intel Agilex F-Series Transceiver-SoC Development Kit` と `Intel Agilex F-Series FPGA Development Kit` が選択可能でした。幸い今回のターゲットボードはサポートされており、こちらを利用できました。  
未サポートのボードをポーティングする場合は、生成したデザインの HPS のペリフェラル機能を変更する、ピン配置を変更する、といったマニュアル修正をボードに合わせて実施する必要があります。

## 2.1. GHRD デザイン生成
以降のハードウェアビルドは、ホストマシンのCentOS 上（もしくは、Windows WSL の Ubuntu 20.04 LTS 上）で実行します。  
GHRD (Golden **Hardware** Reference Design) を取得します。`DEVICE` 環境変数は、使用環境に合わせて変更が必要です。 

```shell:GHRD 取得
cd $TOP_FOLDER
# cd $HW_TOP_FOLDER # for WSL
git clone https://github.com/altera-opensource/ghrd-socfpga.git
cd ghrd-socfpga
git checkout -b QPDS-22.3pro-21.1std QPDS-22.3pro-21.1std
cd agilex_soc_devkit_ghrd
export DEVICE=AGFB014R24A2E3VR0
```

デフォルトの GHRD は、各種機能を含むフルセット構成です。Nios® V や FPGA 内のネットワーク (Tripple Speed Ethernet) が含まれており、IP ライセンスの取得が必要でエラーになることがあります。エラー回避とポーティングのしやすさを考慮して、できるだけ最小構成のデザインで生成しました。ターゲットボードの変更、各種機能の有効／無効の選択は、make 実行時の変数設定で変更可能です。

GHRD の qsys ファイルとプロジェクトを生成します。

```shell:GHRD デザイン生成
cd $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd
make scrub_clean_all
make BOARD_TYPE=pcie_devkit QUARTUS_DEVICE=$DEVICE BOARD_PWRMGT=linear ENABLE_HPS_EMIF_ECC=0 ENABLE_NIOSV_SUBSYS=0 HPS_ENABLE_SGMII=0 generate_from_tcl
```

qsf ファイル内の Power Managemnet 設定を確認します。詳細は「Intel® Agilex™ F-Series FPGA Development Kit User Guide」の「[6.1. Add SmartVID settings in the QSF file](https://www.intel.com/content/www/us/en/docs/programmable/683024/current/add-smartvid-settings-in-the-qsf-file.html)」に記載があります。今回使用したデバイスは ES -3V のため、以下の修正が必要でした。

```tcl: qsf 修正
# 修正前
set_global_assignment -name USE_HPS_COLD_RESET SDM_IO12
set_global_assignment -name PWRMGT_PAGE_COMMAND_ENABLE OFF
set_global_assignment -name PWRMGT_SLAVE_DEVICE_TYPE ED8401
set_global_assignment -name PWRMGT_LINEAR_FORMAT_N "-13"
# ↓
# 修正後
set_global_assignment -name USE_HPS_COLD_RESET SDM_IO13
set_global_assignment -name PWRMGT_PAGE_COMMAND_ENABLE ON
set_global_assignment -name PWRMGT_SLAVE_DEVICE_TYPE OTHER
set_global_assignment -name PWRMGT_LINEAR_FORMAT_N "-12"
```

## 2.2. EMIF 修正
ターゲットボードは、ユーザーが DDR4 DIMM ソケットに DIMM モジュールを適宜装着する構成です。ES 版ボードのため DIMM モジュールが付属しておらず、手元にあった Micron 社製 8GB PC4-2133 DIMM モジュールを装着しました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922360/8f7fe290-4b92-273a-be5f-6412985c3697.jpeg" width=40%>

装着した DIMM に合わせて、EMIF (External Memory Interface) IF の設定を変更します。
- 参考情報：[EMIF デザイン & デバッグ・ガイドライン](https://www.macnica.co.jp/business/semiconductor/articles/intel/129749/)

DIMM モジュールのデータシートは、Micron 社のサイトから入手しました。
- [DDR4 SDRAM UDIMM MTA16ATF1G64AZ – 8GB](https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/modules/unbuffered_dimm/ddr4/atf16c1gx64az.pdf?rev=fda048e4eaa941d9b73da055b32a3c68)
- [4Gb: x4, x8, x16 DDR4 SDRAM](https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/dram/ddr4/4gb_ddr4_dram.pdf?rev=a4122900efb84963a0d9207033a5a286) ※ Base device: MT40A512M8 の詳細データシート

``` shell: GHRD qsysデザインオープン
cd $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd
make QUARTUS_DEVICE=$DEVICE qsys_edit
```

qsys デザイン上 `emif_hps` の パラメータを修正します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922360/38e8892c-97cd-9802-e1a7-66f61f6a3a52.png" width=55%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922360/9ed9176b-be88-2b22-0822-9c1c3c2db60c.png" width=32%>

top モジュールの外部ピンに EMIF の一部のピンが不足するため追加します。この辺りは使用する DIMM モジュールに応じて調整が必要になります。

```verilog:ghrd_agilex_top.v
// 修正前
output   wire [0:0]    emif_hps_mem_mem_cke,
output   wire [0:0]    emif_hps_mem_mem_cs_n,
output   wire [0:0]    emif_hps_mem_mem_odt,
// ↓
// 修正後
output   wire [1:0]    emif_hps_mem_mem_cke,
output   wire [1:0]    emif_hps_mem_mem_cs_n,
output   wire [1:0]    emif_hps_mem_mem_odt,
```

```tcl:ghrd_agfb014r24a2e3vr0.qsf
# 追加
set_location_assignment PIN_M17 -to emif_hps_mem_mem_bg[1]
set_location_assignment PIN_N14 -to emif_hps_mem_mem_cke[1]
set_location_assignment PIN_L12 -to emif_hps_mem_mem_cs_n[1]
set_location_assignment PIN_P15 -to emif_hps_mem_mem_odt[1]
```
変更した EMIF 設定が実機上で正しく動作するかの確認方法は後述します。

## 2.3. 合成
ハードウェアデザインの合成を実行します。

```shell: GHRD 合成
cd $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd
make QUARTUS_DEVICE=$DEVICE sof
```

完了後、Quartus® Prime を起動して結果を確認する方法は以下です。

```shell: Quartus® Prime 起動
cd $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd
make QUARTUS_DEVICE=$DEVICE quartus_edit
```

`$TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd/output_files` 内に `ghrd_${DEVICE,,}.sof` と `ghrd_${DEVICE,,}_hps_debug.sof` ファイルが生成されます。
`ghrd_${DEVICE,,}_hps_debug.sof` ファイルには HPS 上の On-chip RAM で動作する簡単なソフトウェアがコンパイルされて埋め込まれています。HPS を起動するソフトウェアが含まれない sof ファイルは、次の rbf ファイル生成でエラーになるためです。  
このソフトウェアは、以降で生成される U-boot-spl に置き換えられます。  

なお、あらかじめ ARM コンパイラツールチェーンへのパスが通っていないと、`ghrd_${DEVICE,,}_hps_debug.sof` が生成されません。このファイルのみを生成するコマンドは以下の通りです。

```shell: hps_debug.sof 生成
export PATH=$TOP_FOLDER/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin:$PATH
export ARCH=arm64
export CROSS_COMPILE=aarch64-none-linux-gnu-
cd $TOP_FOLDER
make QUARTUS_DEVICE=$DEVICE output_files/ghrd_${DEVICE,,}_hps_debug.sof
```

Yocto Linux のビルドで指定する rbf (Raw Binary File) ファイルを生成します。

```console:rbf ファイル生成
cd $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd/output_files
quartus_pfg -c ghrd_${DEVICE,,}_hps_debug.sof \
  agilex_gsrd_ghrd.jic \
  -o device=MT25QU02G \
  -o flash_loader=$DEVICE \
  -o mode=ASX4 \
  -o hps=1
```

# 3. ソフトウェアビルド
ビルドするソフトウェアには、U-Boot, Arm Trusted Firmware, Linux Kernel, Yocto rootfs があります。Agilex™ SoC GSRD 手順には、GSRD (Golden **Software** Reference Design) を使って、全てのソフトウェアをまとめて数回のコマンド実行でビルドする方法が記載されています。  

ソフトウェアのビルドは Docker 上、もしくは Windows WSL 上の Ubuntu 20.04 LTS で実行します。

```shell: Docker コンテナ起動 & 接続
docker start -ai agilex-linux-build-22.3-$(id -u -n)
```

# 3.1. GSRD ビルド準備
GSRD (Golden **Softdware** Reference Design) を取得し、ビルド準備をします。

```shell: GSRD 取得 & Yocto ビルド準備
cd $TOP_FOLDER
git clone --recursive -b kirkstone https://github.com/altera-opensource/gsrd_socfpga
cd gsrd_socfpga
source agilex-gsrd-build.sh
build_setup
```

WORKSPACE 環境変数などが設定されます。ビルド環境設定を再実行する場合は以下のコマンドを実行します。

```shell: Yocto ビルド環境設定のみの再実行
cd $TOP_FOLDER/gsrd_socfpga
source agilex-gsrd-build.sh
source ./poky/oe-init-build-env agilex-gsrd-rootfs/
```

ハードウェアビルドで生成した rbf ファイルを Yocto レシピに配置します。

```sehll: rbf ファイル 配置
CORE_RBF=$WORKSPACE/meta-intel-fpga-refdes/recipes-bsp/ghrd/files/agilex_gsrd_ghrd.core.rbf
ln -s $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd/output_files/agilex_gsrd_ghrd.core.rbf $CORE_RBF
```

Yocto レシピを修正します。

```shell: Yocto レシピ修正
OLD_URI="\${GHRD_REPO}\/agilex_gsrd_\${ARM64_GHRD_CORE_RBF};name=agilex_gsrd_core"
NEW_URI="file:\/\/agilex_gsrd_ghrd.core.rbf"
sed -i "s/$OLD_URI/$NEW_URI/g" $WORKSPACE/meta-intel-fpga-refdes/recipes-bsp/ghrd/hw-ref-design.bb
CORE_SHA=$(sha256sum $CORE_RBF | cut -f1 -d" ")
OLD_SHA="SRC_URI\[agilex_gsrd_core\.sha256sum\] = .*"
NEW_SHA="SRC_URI[agilex_gsrd_core.sha256sum] = \"$CORE_SHA\""
sed -i "s/$OLD_SHA/$NEW_SHA/g" $WORKSPACE/meta-intel-fpga-refdes/recipes-bsp/ghrd/hw-ref-design.bb
```

削除した TSE (Tripple Speed Ethernet) のデバイスツリーに関する記述をコメントアウトします。

```shell:デバイスツリー修正
cd $TOP_FOLDER/gsrd_socfpga
sed 's/sed -i.*socfpga_agilex_ghrd_sgmii.dtsi/#&/' meta-intel-fpga-refdes/recipes-bsp/device-tree/device-tree.bb
```

# 3.2. GSRD ビルド実行

Yocto のビルドを実行します。

```shell: Yocto ビルド実行
cd $TOP_FOLDER/gsrd_socfpga 
bitbake_image
```
ここで一部のパッケージのエラーが出た際は、何度か `bitbake_image` コマンドを再実行しました。  

生成ファイルをパッケージします。

```shell:Yocto ビルド結果パッケージ
cd $TOP_FOLDER/gsrd_socfpga 
package
```

成功すると `$TOP_FOLDER/gsrd_socfpga/agilex-gsrd-images/` ディレクトリ以下に、ビルドされたソフトウェアのファイル群が格納されます。  
`exit` として、Docker コンテナを終了します。

Docker コンテナ、イメージが不要になった場合は、次のコマンドで削除できます。

```shell: Docker コンテナ & イメージ削除
docker rm agilex-linux-build-22.3-$(id -u -n)
docker rmi intelfpga-linux-build:$(id -u -n)
```

# 4. 起動確認
起動確認のコマンド実行は、CentOS のホストマシンもしくは、Windows 上で実行します。  シリアルポートを接続して、HPS 上の Linux のコンソールを表示できるようにします。  

```shell: CentOS でのシリアルポート接続
sudo screen /dev/ttyUSB0 115200
```

`/dev/ttyUSB0` のデバイスファイルは環境に合わせて適宜修正が必要です。例えば `dmesg` コマンドの出力に `FTDI USB Serial Device converter now attached to ttyUSB0` のようなメッセージがあるので参考にします。
シリアルポートの入出力を示す LED が確認できる場合は、適当なキー入力をして LED が点滅するか、といったことでも所望の接続になっているかを判断できます。

Windows でシリアルポートのコンソールを使用する場合は、TeraTerm などのシリアル接続ターミナルソフトウェアが使用できます。

## 4.1. ブートローダーまでの起動確認
ブートローダー（U-boot-spl）までは HPS の On-chip RAM 上で動作するので、sof ファイルに埋め込んで動作確認が可能です。

```shell:ブートローダー付き sof ファイル生成
cd $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd/output_files
quartus_pfg -c \
-o hps_path=$TOP_FOLDER/gsrd_socfpga/agilex-gsrd-images/u-boot-agilex-socdk-gsrd-atf/u-boot-spl-dtb.hex \
ghrd_${DEVICE,,}.sof ghrd_uboot.sof
```

一旦、JTAG 経由で sof をコンフィグレーションして、動作を確認します。  
ボード上の MSEL 設定 DIP スイッチは、JTAG モード（ON-ON-ON-ON）に設定します。

```shell:ブートローダ付き sof ファイルのコンフィグレーション
cd $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd/output_files
quartus_pgm -c 1 -m jtag -o "p;ghrd_uboot.sof@1"
```

シリアル接続したコンソールに起動ログが出力されます。

```consol:ブートローダーまでの起動ログ
U-Boot SPL 2022.04-21230-gfcf317324c-dirty (Oct 19 2022 - 15:53:48 +0900)
Reset state: Cold
MPU          1000000 kHz
L4 Main       400000 kHz
L4 sys free   100000 kHz
L4 MP         200000 kHz
L4 SP         100000 kHz
SDMMC          50000 kHz
DDR: 8192 MiB
QSPI: Reference clock at 400000 kHz
WDT:   Started watchdog@ffd00200 with servicing (10s timeout)
Trying to boot from MMC1
Card did not respond to voltage select! : -110
spl: mmc init failed with error: -95
SPL: failed to boot from all boot devices
### ERROR ### Please RESET the board ### 
```

ここで何もメッセージが出力されない、起動しないなどエラーが発生する場合は、ハードウェア、ブートローダーに不備があるので、修正します。筆者環境でも、ES 版ボードを使用しているためか、各種ワークアラウンドが必要でした。適用したワークアラウンドの詳細は後述します。

## 4.2. SD カード Linux 起動
SD カードに Linux イメージを書き込みます。Centos の場合は、`dd` コマンドを使用します。対象の SD カードのデバイスファイルを `/dev/sdx` とします。

```shell:SD カードへの Linux イメージ書き込み
cd $TOP_FOLDER/gsrd_socfpga/agilex-gsrd-images
sudo dd if=gsrd-console-image-agilex.wic of=/dev/sdx bs=1M 
sudo sync
```

Windows では、[Win32DiskImager](https://sourceforge.net/projects/win32diskimager/) を使って、Linux イメージの SD カードへの書き込みができます。

Linux イメージの入った SD カードをボードに挿入し、ブートローダー付きの sof ファイルを JTAG 経由でプログラムします。Linux が起動すると、コンソールが出力されます。

```console: Linux 起動ログ
U-Boot SPL 2022.04-21230-gfcf317324c-dirty (Oct 20 2022 - 10:43:57 +0900)
Reset state: Cold
MPU          1000000 kHz
L4 Main	      400000 kHz
L4 sys free   100000 kHz
L4 MP         200000 kHz
L4 SP         100000 kHz
SDMMC          50000 kHz
DDR: 8192 MiB
QSPI: Reference clock at 400000 kHz
WDT:   Started watchdog@ffd00200 with servicing (10s timeout)
Trying to boot from MMC1
## Checking hash(es) for config board-4 ... OK
## Checking hash(es) for Image atf ... crc32+ OK
## Checking hash(es) for Image uboot ... crc32+ OK
## Checking hash(es) for Image fdt-0 ... crc32+ OK
NOTICE:  BL31: v2.7.0(release):QPDS22.3_REL_GSRD_PR
NOTICE:  BL31: Built : 08:58:24, Sep  9 2022


U-Boot 2022.04 (Sep 20 2022 - 03:43:28 +0000)socfpga_agilex

CPU:   Intel FPGA SoCFPGA Platform (ARMv8 64bit Cortex-A53)
Model: SoCFPGA Agilex SoCDK
DRAM:  8 GiB
Core:  22 devices, 21 uclasses, devicetree: separate
WDT:   Started watchdog@ffd00200 with servicing (10s timeout)
NAND:  denali-nand-dt nand@ffb90000: timeout while waiting for irq 0x2000
denali-nand-dt nand@ffb90000: reset not completed.
...
[  OK  ] Started User Login Management.
[   17.945395] cfg80211: Loading compiled-in X.509 certificates for regulatory database
[   17.962981] cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
[   17.975196] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2
[   17.983873] platform regulatory.0: Falling back to sysfs fallback for: regulatory.db
[  OK  ] Started Network Configuration.
[   18.276576] socfpga-dwmac ff800000.ethernet eth0: PHY [stmmac-0:04] driver [Micrel KSZ9031 Gigabit PHY] (irq=POLL)
[   18.290591] socfpga-dwmac ff800000.ethernet eth0: Register MEM_TYPE_PAGE_POOL RxQ-0
[   18.314273] socfpga-dwmac ff800000.ethernet eth0: No Safety Features support found
[   18.322161] socfpga-dwmac ff800000.ethernet eth0: IEEE 1588-2008 Advanced Timestamp supported
[   18.332247] socfpga-dwmac ff800000.ethernet eth0: registered PTP clock
[   18.341584] socfpga-dwmac ff800000.ethernet eth0: configuring for phy/rgmii link mode
[  OK  ] Started Telephony service.
[   19.314737] Bluetooth: Core ver 2.22
[   19.324134] NET: Registered PF_BLUETOOTH protocol family
[   19.331471] Bluetooth: HCI device and connection manager initialized
[   19.338223] Bluetooth: HCI socket layer initialized
[   19.347948] Bluetooth: L2CAP socket layer initialized
[   19.353546] Bluetooth: SCO socket layer initialized
[  OK  ] Started Connection service.
[  OK  ] Reached target Network.
         Starting Avahi mDNS/DNS-SD Stack...
         Starting WPA supplicant...
         Starting Hostname Service...
[  OK  ] Started Avahi mDNS/DNS-SD Stack.
[  OK  ] Started Hostname Service.


Poky (Yocto Project Reference Distro) 4.0.4 agilex ttyS0

agilex login: root

Last login: Thu Apr 28 22:45:37 +0000 2022 on /dev/ttyS0.
root@agilex:~# 
```

JTAG 経由での sof ファイルのコンフィグレーションで Linux　起動が確認ができれば、QSPI flash から起動するための jic ファイルを生成して flash に書き込みます。

```shell:jic ファイル生成 & 書き込み
cd $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd/output_files
quartus_pfg -c ghrd_${DEVICE,,}.sof ghrd.jic \
  -o hps_path=$TOP_FOLDER/gsrd_socfpga/agilex-gsrd-images/u-boot-agilex-socdk-gsrd-atf/u-boot-spl-dtb.hex \
  -o device=MT25QU02G \
  -o flash_loader=${DEVICE} \
  -o mode=ASX4 \
  -o hps=1
quartus_pgm -c 1 -m jtag -o "pvi;ghrd.hps.jic"
```

電源断の後、ボード上の MSEL 設定 DIP スイッチを QSPI モード（ON-OFF-OFF-ON）に設定し、電源を再投入すると Linux が起動します。

## 4.3. QSPI Linux 起動
SD カードを使用せず、QSPI flash のみを使用して Linux を起動する方法を示します。  
ビルドしたソフトウェアバイナリを QSPI flash の適切なアドレスに配置した jic ファイルを生成する、という手順になります。配置情報は、Rocketboards.org にアップロードされているファイルを利用します。詳細は、Agilex™ SoC GSRD 手順の[Booting from QSPI](https://www.rocketboards.org/foswiki/Documentation/AgilexSoCGSRD#Building_QSPI_Flash_Image)を参照して下さい。


```shell:QSPI ブート用jicファイル生成
cd $TOP_FOLDER
mkdir qspi-boot && cd qspi-boot
ln -s $TOP_FOLDER/ghrd-socfpga/agilex_soc_devkit_ghrd/output_files/ghrd_${DEVICE,,}.sof fpga.sof
ln -s $TOP_FOLDER/gsrd_socfpga/agilex-gsrd-images/u-boot-agilex-socdk-gsrd-atf/u-boot-spl-dtb.hex spl.hex
ln -s $TOP_FOLDER/gsrd_socfpga/agilex-gsrd-images/u-boot-agilex-socdk-gsrd-atf/u-boot.itb u-boot.bin
ln -s $TOP_FOLDER/gsrd_socfpga/agilex-gsrd-images/u-boot-agilex-socdk-gsrd-atf/boot.scr.uimg bootscr.bin
ln -s $TOP_FOLDER/gsrd_socfpga/agilex-gsrd-images/kernel.itb kernel.bin
ln -s $TOP_FOLDER/gsrd_socfpga/agilex-gsrd-images/console-image-minimal-agilex.jffs2 rootfs.bin
wget https://rocketboards.org/foswiki/pub/Documentation/AgilexSoCGSRD/flash_image.pfg
quartus_pfg -c flash_image.pfg
```

`$TOP_FOLDER/qspi-boot/flash_image.hps.jic` が生成されます。

ボード上の MSEL 設定 DIP スイッチを、JTAG モード（ON-ON-ON-ON）にして、jic ファイルを flash に書き込みます。

```shell:jic ファイル書き込み
cd $TOP_FOLDER/qspi-boot
quartus_pgm -c 1 -m jtag -o "pvi;flash_image.hps.jic"
```

電源断の後、ボード上の MSEL 設定 DIP スイッチを QSPI モード（ON-OFF-OFF-ON）に設定し、SD カードを抜き、電源再投入すると QSPI flash から Linux が起動します。


# 5. Appendix
## 5.1. ES 版ボード用ワークアラウンド
ES 版ボードのためと思われるのですが、各種ワークアラウンドを適用しないと正常起動しませんでした。環境依存、ツールバージョン依存の点もありますが、何かの役に立つ可能性を考慮して共有します。

### 5.1.1. Quarts® Prime v20.4 の使用
ES 版ボードの対応バージョンは、Quarts® Prime v20.4 となっています。可能な限り最新の Quarts® Prime バージョンを使いたいのですが、v20.4 より新しいバージョンを使用するとデバイスの電源が正常に投入されず、動作しませんでした。  
この状況を回避するためにデザインの生成および合成は、Quarts® Prime v22.3 を使用し、いくつかのプログラムのみ Quarts® Prime v20.4 を使用しました。  
具体的には、`quartus_pfg` コマンド、`quartus_pgm` コマンドの実行のみ、Quarts® Prime v20.4 を使用しました。バージョンを混在して使用することは、本来、適切な使い方ではないのですが、やむを得ず上記の対応で動作を確認しました。

### 5.1.2. U-boot-spl の差し替え
`gsrd_socfpga` でビルドされる `u-boot-spl-dtb.hex` を使用したところ、正常に動作しませんでした。これも ES 版ボードのためと推測していますが、明確な原因究明までには至っていません。 
ワークアラウンドとして、以下に記載のブートローダーのビルド手順を使って生成した `u-boot-spl-dtb.hex` に差し替えて、動作を確認しました。
- [Building Bootloader for Stratix 10 and Agilex](https://www.rocketboards.org/foswiki/Documentation/BuildingBootloader)

Arm Trusted Firmware, U-Boot のソースコードを別途取得して、ビルドします。
ソフトウェアのビルドは全て Dokcer もしくは Windows WSL 上の Ubuntu 20.04 LTS で作業をします。

```shell:Docker コンテナ起動 & 接続
docker start -ai agilex-linux-build-22.3-$(id -u -n)
```

Arm Trusted Firmware ソースコードを取得、ビルドします。

```shell: Arm Trusted Firmware 取得 & ビルド
cd $TOP_FOLDER
git clone https://github.com/altera-opensource/arm-trusted-firmware
cd arm-trusted-firmware
git checkout -b socfpga_v2.7.0 -t origin/socfpga_v2.7.0
make bl31 PLAT=agilex DEPRECATED=1
cd ..
```
`$TOP_FOLDER/arm-trusted-firmware/build/agilex/release/bl31.bin` が生成されます。

U-Boot ソースコードを取得します。

```shell: U-Boot 取得
cd $TOP_FOLDER
git clone https://github.com/altera-opensource/u-boot-socfpga
cd u-boot-socfpga
# comment out next line to use the latest default branch
git checkout -b socfpga_v2022.04 -t origin/socfpga_v2022.04
```

```shell: U-Boot ビルド設定修正
cd $TOP_FOLDER/u-boot-socfpga
# enable dwarf4 debug info, for compatibility with arm ds
sed -i 's/PLATFORM_CPPFLAGS += -D__ARM__/PLATFORM_CPPFLAGS += -D__ARM__ -gdwarf-4/g' arch/arm/config.mk
# use 'Image' for kernel image instead of 'kernel.itb'
sed -i 's/kernel\.itb/Image/g' include/configs/socfpga_soc64_common.h
# only boot from SD, do not try QSPI and NAND
# sed -i 's/u-boot,spl-boot-order.*/u-boot\,spl-boot-order = \&mmc;/g' arch/arm/dts/socfpga_agilex_socdk-u-boot.dtsi
# disable NAND in the device tree
sed -i '/&nand {/!b;n;c\\tstatus = "disabled";' arch/arm/dts/socfpga_agilex_socdk-u-boot.dtsi
# remove the NAND configuration from device tree
sed -i '/images/,/binman/{/binman/!d}' arch/arm/dts/socfpga_agilex_socdk-u-boot.dtsi

# link to atf
ln -s $TOP_FOLDER/arm-trusted-firmware/build/agilex/release/bl31.bin .
```

`$TOP_FOLDER/u-boot-socfpga` 以下に `config-fragment-agilex`  ファイルを作成します。

```none:config-fragment-agilex
# - Disable NAND/UBI related settings from defconfig. 
CONFIG_NAND_BOOT=n
CONFIG_SPL_NAND_SUPPORT=n
CONFIG_CMD_NAND_TRIMFFS=n
CONFIG_CMD_NAND_LOCK_UNLOCK=n
CONFIG_NAND_DENALI_DT=n
CONFIG_SYS_NAND_U_BOOT_LOCATIONS=n
CONFIG_SPL_NAND_FRAMEWORK=n
CONFIG_CMD_NAND=n
CONFIG_MTD_RAW_NAND=n
CONFIG_CMD_UBI=n
CONFIG_CMD_UBIFS=n
CONFIG_MTD_UBI=n
CONFIG_ENV_IS_IN_UBI=n
CONFIG_UBI_SILENCE_MSG=n
CONFIG_UBIFS_SILENCE_MSG=n
# - Disable distroboot and use specific boot command. 
CONFIG_DISTRO_DEFAULTS=n
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT_HUSH_PS2="> "
CONFIG_USE_BOOTCOMMAND=y
CONFIG_BOOTCOMMAND="load mmc 0:1 \${loadaddr} ghrd.core.rbf;fpga load 0 \${loadaddr} \${filesize};bridge enable;run mmcload;run linux_qspi_enable;run rsu_status;run mmcboot"
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_DOS_PARTITION=y
CONFIG_SPL_DOS_PARTITION=y
CONFIG_CMD_PART=y
CONFIG_SPL_CRC32=y
CONFIG_LZO=y
CONFIG_CMD_DHCP=y
```
U-Boot をビルドします。

```shell: U-Boot ビルド
cd $TOP_FOLDER/u-boot-socfpga
# build U-Boot
make clean && make mrproper
make socfpga_agilex_defconfig
# Use created custom configuration file to merge with the default configuration obtained in .config file. 
./scripts/kconfig/merge_config.sh -O ./ ./.config ./config-fragment-agilex
make -j 48
cd ..
```
`$TOP_FOLDER/u-boot-socfpga/spl/u-boot-spl-dtb.hex` が生成されます。今回は、ここで生成したファイルを適用して動作確認しました。

## 5.2. EMIF Debug Toolkit
EMIF の設定を、DIMM モジュールに合わせて行いますが、この設定に不備があると、正常に動作できません。  
EMIF Debug Toolkit を使用すれば、キャリブレーション状態など、内部詳細を確認できますが、HPS に接続される EMIF IP は `EMIF for HPS Intel Agilex FPGA IP` で、通常の EMIF IP と違って、Debug Tookit で確認することができませんでした。  
ただし、HPS に接続される DIMM モジュールは FPGA 側でも使用可能なので、FPGA 側のデバッグ用デザインを Example Design を利用して作成し、Debug Toolkit で動作確認を行いました。具体的な手順は以下の通りです。

1. IP Catalog から `External Memory Interfaces Intel Agilex FPGA IP` を選択。Platform Designer が起動する。
1. 設定パラメータをデータシートから設定。`Target Development Kit` に適したものがあれば選択可能。
1. `Generate Example Design` として、EMIF の Example Design を生成する。
1. Example Design の ピン配置などを適宜修正して、合成実行。
1. 実機上にコンフィグレーションして、System Console から EMIF Debug Toolkit にアクセス。キャリブレーションが PASS しているか、などを確認する。

以上により、対象 DIMM モジュールが正しく設定されて、所望の動作をしていることを確認できます。

# 6. まとめ
Agilex™ SoC GSRD 手順をもとに、GSRD を [インテル® Agilex™ F シリーズ FPGA 開発キット](https://www.intel.co.jp/content/www/jp/ja/products/details/fpga/development-kits/agilex/f-series.html) に移植して、Linux の起動を確認しました。移植に必要となった環境構築、デザイン変更、ビルドコマンドについて、具体的な手順を示しました。他の Agilex™ ボードの HPS で Linux 動作させる際の参考になれば幸いです。