Ultra96-V2でAPUからRPUへプログラムをロードして実行する

# はじめに
 [Ultra96-V2](https://japan.xilinx.com/products/boards-and-kits/1-vad4rl.html)には、APUにCortex-A53が4個、RPUにCortex-R5が2個搭載されています。
これまで自分は、RPUは使わず、APUにPetalinux + Ubuntu20.04のシステムをロードして使っていました。
そこで今回、APUからRPUにプログラム(Lチカ)をロードして実行するということをやってみます。

# 環境・ツール
- Petalinux 2020.2
- APU ユーザランド: Ubuntu20.04
- Xilinx Vitis IDE v2022.2.0 (RPUコア用ベアメタルプログラム開発用)

# 前提条件
[Vivado](https://japan.xilinx.com/products/design-tools/vivado.html)で生成したUltra96-V2のハードウェアファイル(.xsa)が用意されている。

# RPU用Lチカプログラムの作成
Vitisを起動し、[File -> New -> Application Project...]を選択しプロジェクトを作成。

用意した.xsaファイルを読み込む。
![qiita1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404447/2339e019-f139-4344-0e8a-f5a14a3fa0dd.png)

led_blinkという名前でプロジェクトを作る。
![qiita2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404447/f4904ad2-46df-2dd3-51cd-aa73752233fa.png)

![qiita3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404447/b0841d42-960d-6c1e-bb8c-13c4f319a0e6.png)

Hello Worldのテンプレートを選択。
![qiita4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404447/39826561-2d8e-bafa-0688-ed17626d6463.png)

プロジェクトが生成されたら、helloworld.cを編集。

```c:helloworld.c
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "sleep.h"
#include "xgpiops.h"

int main()
{
	init_platform();

	XGpioPs instXGpioPs;
	XGpioPs_Config *configxGpioPs;

	configxGpioPs = XGpioPs_LookupConfig(XPAR_PSU_GPIO_0_DEVICE_ID);
	XGpioPs_CfgInitialize(&instXGpioPs, configxGpioPs, configxGpioPs->BaseAddr);

	XGpioPs_SetDirectionPin(&instXGpioPs, 20, 1);
	XGpioPs_SetDirectionPin(&instXGpioPs, 19, 1);
	XGpioPs_SetDirectionPin(&instXGpioPs, 18, 1);
	XGpioPs_SetDirectionPin(&instXGpioPs, 17, 1);

	XGpioPs_SetOutputEnablePin(&instXGpioPs, 20, 1);
	XGpioPs_SetOutputEnablePin(&instXGpioPs, 19, 1);
	XGpioPs_SetOutputEnablePin(&instXGpioPs, 18, 1);
	XGpioPs_SetOutputEnablePin(&instXGpioPs, 17, 1);

	while(1)
	{
		XGpioPs_WritePin(&instXGpioPs, 20, 1);
		sleep(1);
		XGpioPs_WritePin(&instXGpioPs, 19, 1);
		sleep(1);
		XGpioPs_WritePin(&instXGpioPs, 18, 1);
		sleep(1);
		XGpioPs_WritePin(&instXGpioPs, 17, 1);
		sleep(1);

		XGpioPs_WritePin(&instXGpioPs, 17, 0);
		sleep(1);
		XGpioPs_WritePin(&instXGpioPs, 18, 0);
		sleep(1);
		XGpioPs_WritePin(&instXGpioPs, 19, 0);
		sleep(1);
		XGpioPs_WritePin(&instXGpioPs, 20, 0);
		sleep(1);
	}
}
```

次に、アプリケーション用にDDRメモリを予約するために、lscript.ldファイルのメモリレジスタを更新する。
psu_r5_ddr_0_MEM_0の値を以下のように編集。

![qiita5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404447/7c9b7a8f-dd07-b671-eb3b-8d27e2b87d5a.png)

[Project -> Buuild Project]を実行。
ビルドが成功すると、led_blink.elfが生成される。

# Petalinux側の対応

## PetalinuxにLチカファームウェアを追加するレシピを作成

Petlinux アプリケーション レシピを作成する
```bash:
$ cd {Petalinux Project Path}
$ petalinux-create -t apps --template install -n led-blink --enable
```

Vitisで作成したled_blink.elfをproject-spec/meta-user/recipes-apps/led-blink/files/ 以下にコピーする。

また、led-blink.bbを以下のように編集。

```led-blink.bb
#
# This file is the led-blink recipe.
#

SUMMARY = "Simple led-blink application"
SECTION = "PETALINUX/apps"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "file://led_blink.elf \
	"

S = "${WORKDIR}"
INSANE_SKIP_${PN} = "arch"

FILES_${PN} += "/lib/firmware/"

do_install() {
	install -d ${D}/lib/firmware
	install -m 0644 ${S}/led_blink.elf ${D}/lib/firmware/led_blink.elf
}
```

## Device Treeの修正

続いて、project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsiに以下を記述。

```system-user.dtsi
/ {
    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        rpu0vdev0vring0: rpu0vdev0vring0@3ed40000 {
            no-map;
            reg = <0x0 0x3ed40000 0x0 0x4000>;
        };
        rpu0vdev0vring1: rpu0vdev0vring1@3ed44000 {
            no-map;
            reg = <0x0 0x3ed44000 0x0 0x4000>;
        };
        rpu0vdev0buffer: rpu0vdev0buffer@3ed48000 {
            no-map;
            reg = <0x0 0x3ed48000 0x0 0x100000>;
        };
        rproc_0_reserved: rproc@3ed00000 {
            no-map;
            reg = <0x0 0x3ed00000 0x0 0x40000>; // Vitisで指定したのと同じ領域
        };
    };

    zynqmp-rpu {
        compatible = "xlnx,zynqmp-r5-remoteproc-1.0";
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        core_conf = "split";
        reg = <0x0 0xFF9A0000 0x0 0x10000>;
        r5_0: r5@0 {
            #address-cells = <2>;
            #size-cells = <2>;
            ranges;
            memory-region = <&rproc_0_reserved>, <&rpu0vdev0buffer>, <&rpu0vdev0vring0>, <&rpu0vdev0vring1>;
            pnode-id = <0x7>;
            mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>;
            mbox-names = "tx", "rx";
            tcm_0_a: tcm_0@0 {
                reg = <0x0 0xFFE00000 0x0 0x10000>;
                pnode-id = <0xf>;
            };
            tcm_0_b: tcm_0@1 {
                reg = <0x0 0xFFE20000 0x0 0x10000>;
                pnode-id = <0x10>;
            };
        };
    };

    zynqmp_ipi1 {
        compatible = "xlnx,zynqmp-ipi-mailbox";
        interrupt-parent = <&gic>;
        interrupts = <0 29 4>;
        xlnx,ipi-id = <7>;
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;
        /* APU<->RPU0 IPI mailbox controller */
        ipi_mailbox_rpu0: mailbox@ff90000 {
            reg = <0xff990600 0x20>,
                  <0xff990620 0x20>,
                  <0xff9900c0 0x20>,
                  <0xff9900e0 0x20>;
            reg-names = "local_request_region",
                        "local_response_region",
                        "remote_request_region",
                        "remote_response_region";
            #mbox-cells = <1>;
            xlnx,ipi-id = <1>;
        };
    };
};
```

## Kernel configurationの確認

```bash
$ petalinux-config -c kernel
```

・Device Drivers --->
Remoteproc drivers --->
\<*> Support for Remote Processor subsystem
\<M> ZynqMP_r5 remoteproc support

## rootfsの設定

```
$ petalinux-config -c rootfs
```

- apps ---> led-blink [*]
- Filesystem Packages ---> misc ---> sysfsutils ---> libsysfs [*]
- Filesystem Packages ---> libs ---> libmetal ---> libmetal [*]
- Petalinux Package Groups ---> packagegroup-petalinux-openamp ---> packagegroup-petalinux-openamp [*]

テスト用アプリも有効化しておく。
- Filesystem Packages ---> misc ---> openamp-fw-echo-testd ---> openamp-fw-echo-testd [*]
- Filesystem Packages ---> misc ---> openamp-fw-mat-muld ---> openamp-fw-mat-muld [*]
- Filesystem Packages ---> misc ---> openamp-fw-rpc-demo ---> openamp-fw-rpc-demo [*]

## Petalinuxのビルドとimageの作成

```
$ petalinux-build

$  petalinux-package --boot --fsbl images/linux/zynqmp_fsbl.elf --pmufw images/linux/pmufw.elf --fpga images/linux/system.bit --u-boot --force
```

# Ultra96-V2上での実行

```bash
$ lsmod
zynqmp_r5_remoteproc    20480  0

$ cd /lib/firmware

$ echo led_blink.elf > /sys/class/remoteproc/remoteproc0/firmware
$ echo start > /sys/class/remoteproc/remoteproc0/state
```

これで、自作したLチカプログラムをRPUコアにロードし、実行することができた。
プログラムの停止は以下のようにする。

```bash
$ echo stop > /sys/class/remoteproc/remoteproc0/state
```

## テスト用アプリの実行
ついでにテスト用アプリも動かしてみる。

```bash
$ echo image_echo_test > /sys/class/remoteproc/remoteproc0/firmware
$ echo start > /sys/class/remoteproc/remoteproc0/state
$ echo_test
$ echo stop > /sys/class/remoteproc/remoteproc0/state

$ echo image_matrix_multiply > /sys/class/remoteproc/remoteproc0/firmware
$ echo start > /sys/class/remoteproc/remoteproc0/state
$ mat_mul_demo
$ echo stop > /sys/class/remoteproc/remoteproc0/state
```

# 参考URL
- [OpenAMP in Xilinx MPSoC FPGA- Running Petalinux & Baremetal](https://www.hackster.io/LogicTronix/openamp-in-xilinx-mpsoc-fpga-running-petalinux-baremetal-e025ca)
- [HOW To resolve : Files/directories were installed but not shipped in any package:](https://stackoverflow.com/questions/68542598/how-to-resolve-files-directories-were-installed-but-not-shipped-in-any-package)
- [Ultra96V2のPLでLEDチカを行う(VitisのHello worldから起動編)](https://qiita.com/Ryuz/items/a89279a2c77bfe0ad677)
- [Ultra96V2(ZynqMP) のPS⇔PL間性能計測](https://ryuz.hatenablog.com/entry/2020/11/14/110011)
- [OpenAMP on ZYBO (Zynq) 1回目: とりあえずサンプルを動かす](https://qiita.com/iwatake2222/items/ff46792eb107d978cd0b)
- [Ultra96v2 で OpenAMP を動かすためにやったこと。](https://qiita.com/daiki0321/items/ccfe416d7f0c0fa3ad42)