Orange Pi 5 (RK3588S) 用にU-BootとLinuxカーネルをコンパイルして起動するまで (Arch Linux Arm AArch64)

# 1. 前提条件
1. タイトルからわかる通り上級者向けです
2. すでにx86_64のArch Linux PCを持っていること
3. PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND (文鎮化しても知りません)

# 2. その他
* 他のrockchipベースのSBCでもこの手順とだいたい同じので動くのがあるはず
* RK3588SのHDMI出力はまだアップストリームでサポートされていません
    * Collaboraさんの人たちが頑張ってくれています: https://gitlab.collabora.com/hardware-enablement/rockchip-3588/linux/-/issues/5

# 3. 必要事項
### 3.1. Orange Pi 5
おいしそうですね

### 3.2. U-Boot
```
[/mnt/work] $ git clone https://github.com/u-boot/u-boot.git
```

### 3.3. Orange Pi用 Arch Linux Arm プリコンパイル済みのイメージ
https://github.com/7Ji/orangepi5-archlinuxarm/releases

`ArchLinuxARM-aarch64-OrangePi5-*-base.img.gz` を落としましょう。
Linuxをコンパイルするときに使います。

ここでは`/mnt/work/image`にダウンロードしたとして解説します。

### 3.4. 汎用AArch64用 Arch Linux Arm プリコンパイル済みのイメージ
http://os.archlinuxarm.org/os/ArchLinuxARM-aarch64-latest.tar.gz

コンパイルするU-Bootとカーネルをこのイメージと合体させます。
ここでは`/mnt/work/image`にダウンロードしたとして解説します。

# 4. あったらいいな
### 4.1. シリアルコンバーター
シリアルコンバーターがないとブートができなかったときになぜ詰まっているのかが把握できません。
これさえあればU-Bootのコンソールにもアクセスできます。

### 4.2. SPI Flashを書き換えるためのツール郡
SPI Flashをこの先の手順でイレースするときが来ますが、もしSDカードにうまくU-Bootが書き込まれていない場合半文鎮化状態、そして/もしくはストックのイメージに戻すことが不可能になります。
その場合、SPI Flashに再度書き込みする必要があります。

http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/service-and-support/Orange-pi-5.html

上記からダウンロードします。
`Official tools > Android and Linux image writing tool > MiniLoader` からこの２つをダウンロードします。
 * MiniLoaderAll.bin
 * rkspi_loader.img

これより先は`/mnt/work/spi`に保存したとして説明します。

`rkdeveloptool`自体も落としておきます。
Arch Linuxの場合そのままの名前でAURに存在するので、お好きなAURヘルパーで落としてください。

# 5. U-Bootをコンパイルする
### 5.1. クロスコンパイル用のGCCをインストールする
```
[/mnt/work/u-boot] # pacman -S aarch64-linux-gnu-gcc
```

### 5.2. U-BootをOrange Pi 5 (RK3588S) 用にビルドする
```
[/mnt/work/u-boot] $ make distclean
[/mnt/work/u-boot] $ make ARCH=arm CROSS_COMPILE="aarch64-linux-gnu-" orangepi-5-rk3588s_defconfig
[/mnt/work/u-boot] $ make ARCH=arm CROSS_COMPILE="aarch64-linux-gnu-"
```

# 6. Linuxカーネルをコンパイルする
### 6.1. Orange Pi 5 用のSDカードを準備する
```
[/mnt/image] # gunzip -dc /mnt/work/image/ArchLinuxARM-aarch64-OrangePi5-*-base.img.gz | sudo dd if=/dev/stdin of=/dev/sdX bs=64k status=progress
$ sync
```

### 6.2. Orange Pi 5を起動する
Orange Pi 5用のArch Linux Armのデフォルトユーザーは以下の通りです:
* ユーザー名: `alarm`
* パスワード: `alarm_please_change_me`

デフォルトで`systemd-networkd.service`と`systemd-resolved.service`や`sshd.service`が有効になっています。
SSHかシリアルで接続します。

### 6.3. makepkgでLinuxパッケージを作成する

#### 6.3.1. 必要条件を揃える
```
[alarm] # pacman -S xmlto docbook-xsl kmod inetutils bc git uboot-tools dtc make gcc flex bison fakeroot
[alarm] $ git clone https://github.com/MeemeeLab/PKGBUILD-linux-aarch64-rockchip.git && cd PKGBUILD-linux-aarch64-rockchip
```
今回はカスタムされたPKGBUILDを使用します。
Arch Linux Armの`linux-aarch64`にはなぜかRK3588Sのサポートはあるものの電源管理機能が有効になっていないため`rootfs`のマウントができません。
このレポジトリは以下の変更が加えられています:
 * chromebookのサポートをドロップ
 * rockchipのSPIドライバを有効 (`CONFIG_MFD_RK8XX_SPI`)

#### 6.3.2. makepkg.confを変更する
```
[alarm] # vim /etc/makepkg.conf
```
MAKEFLAGSに8コアすべて使用するように設定します。
```
MAKEFLAGS="-j8"
```

#### 6.3.3. カーネルをビルドする
```
[PKGBUILD-linux-aarch64-rockchip#alarm] $ makepkg
```

#### 6.3.4. ビルドしたカーネルを移動
```
[/mnt/work/kernel] $ scp alarm@0.0.0.0:/path/to/PKGBUILD-linux-aarch64-rockchip/linux-aarch64-rockchip-*.tar.xz /mnt/work/kernel/
```
次は自作U-BootとカーネルをインストールするためにSDカードをフォーマットします。
ビルドしたカーネルをPCに移動させましょう。

### 6.4. SPI Flashをイレースする
ここでOrange Pi 5のブートシーケンスを書いておきます。
Orange Pi 5は最初にSPI Flashと呼ばれる表面実装済みの16MBのROMからU-Bootなどを起動します。
イメージ自体が十分に小さければLinux自体もSPI Flashに書き込めて、SDカードがいらないそうです (公式OpenWrtイメージなど)
もしこの手順が失敗したらSDカードから起動しようとします。

出荷時状態ではU-BootがSPI Flashに書き込まれています。
自作のU-BootをSDに書き込んでもSPI Flashから起動するため、SPI Flashをイレースする必要があります。

もし万が一消去後起動できなくなった場合、[Appendix 2. 半文鎮化状態からのリカバリー](#appendix-2-半文鎮化状態からのリカバリー) を実行してください。
MaskROMやrkdeveloptoolは SDカードがない・SPI Flashが空 の状態でも使用できます。

#### 6.4.1. dd を使う
もしSDカードに起動可能なLinuxがあるなら、内部からSPI Flashをクリアできます。
```
[alarm] # dd if=/dev/zero of=/dev/mtdblock
```
ただこの方法はおすすめしません。
もしSDカードにU-Bootがうまく書き込めていない場合、半文鎮化状態になります。
この状態からリカバリーするために [#4.2. SPI Flashを書き換えるためのツール郡](#42-spi-flashを書き換えるためのツール郡) のツール群が必要になります。
rkdeveloptoolを使う方法が今後リカバリーをする場合の環境テストにもなって無難でしょう。

#### 6.4.2. rkdeveloptool を使う
まず最初にMaskROMブートをしましょう: [Appendix 1. MaskROMモードで起動する](#appendix-1-maskromモードで起動する)

rkdeveloptoolでSPI Flashをイレースします。
```
# rkdevtool ef
```

# 7. SDカードイメージを作成する
### 7.1. パーティションを作成
```
# fdisk /dev/sdX
```
```
Welcome to fdisk (util-linux 2.39.3).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): o
Created a new DOS disklabel with disk identifier 0x425cd15b.

Command (m for help): p
Disk /dev/sdX: 28.96 GiB, 31096569856 bytes, 60735488 sectors
Disk model: Storage Device  
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x425cd15b

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-60735487, default 2048): 32768
Last sector, +/-sectors or +/-size{K,M,G,T,P} (32768-60735487, default 60735487): 

Created a new partition 1 of type 'Linux' and of size 28.9 GiB.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```
ファーストセクターを`32768`に設定していることに注意してください。

### 7.2. U-Bootを書き込む
```
# dd if=/mnt/work/u-boot/idbloader.img of=/dev/sdX seek=64
# dd if=/mnt/work/u-boot/u-boot.itb of=/dev/sdX seek=16384
```

### 7.3. rootfsを準備する
#### 7.3.1. フォーマット
```
# mkfs.ext4 /dev/sdX1
```

#### 7.3.2. Arch Linux ARMを展開する
```
# mount /dev/sdX1 /mnt/sd
# bsdtar -xpf /mnt/work/image/ArchLinuxARM-aarch64-latest.tar.gz -C /mnt/sd
```

#### 7.3.3. U-Boot ブートスクリプトを作成する
```
# vim /mnt/sd/boot/boot.txt
```
新規作成し中身を以下にしましょう。
```
setenv console ttyS2,1500000

if test -n ${distro_bootpart}; then setenv bootpart ${distro_bootpart}; else setenv bootpart 1; fi
part uuid ${devtype} ${devnum}:${bootpart} uuid
setenv bootargs console=${console} root=PARTUUID=${uuid} rw rootwait

if load ${devtype} ${devnum}:${bootpart} ${kernel_addr_r} /boot/Image; then
if load ${devtype} ${devnum}:${bootpart} ${fdt_addr_r} /boot/dtbs/${fdtfile}; then
    if load ${devtype} ${devnum}:${bootpart} ${ramdisk_addr_r} /boot/initramfs-linux.img; then
        booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};
    else
        booti ${kernel_addr_r} - ${fdt_addr_r};
    fi;
fi;
fi
```

最後にscrファイルを作成します:
```
# mkimage -A arm64 -O linux -T script -C none -n "U-Boot boot script" -d /mnt/sd/boot/boot.txt /mnt/sd/boot/boot.scr
```

#### 7.3.4. カーネルをインストールする
```
# pacman --sysroot /mnt/sd /mnt/work/kernel/linux-aarch64-rockchip-*-aarch64.pkg.tar.xz
```
`linux-aarch64`パッケージを置換するかと聞かれたら`y`を選択します。

### 7.4. sync
```
$ sync
```

# 8. 起動
### 8.1. ログイン
この状態で、Orange Pi 5はSDカードからブートできるはずです。
Orange Pi 5を起動します。

これも同様、ネットワークやSSHは初期設定済みです。
SSHやシリアルモニターでログインします。

デフォルトの汎用AArch64 Arch Linux Armユーザーは以下のとおりです:
 * root
   * ユーザー名: `root`
   * パスワード: `root`
 * alarm
   * ユーザー名: `alarm`
   * パスワード: `alarm`

### 8.2. 初期設定
#### 8.2.1. mkinitcpio
カーネルを変更して`initramfs`を更新していないため、念の為更新します:
```
# mkinitcpio -P
```

#### 8.2.2. Pacman
鍵を初期化し、システムを更新します。

```
# pacman-key --init
# pacman-key --populate
# sudo pacman -Syu
```

# 9. Linuxを堪能します
これより以下はリンクからから参照される付随です。

# Appendix 1. MaskROMモードで起動する
Orange Pi 5の基板上にMaskROMと書かれたボタンがあるので長押ししながら電源プラグを入れます。
コンピューター側で`rkdeveloptool`を実行して確認します:
```
$ rkdeveloptool ld
```
```
DevNo=1	Vid=0x2207,Pid=0x350b,LocationID=102	Maskrom
```
のように表示されたらOrange Pi 5はMaskROM状態です。

# Appendix 2. 半文鎮化状態からのリカバリー
まず最初にMaskROMブートをしましょう: [Appendix 1. MaskROMモードで起動する](#appendix-1-maskromモードで起動する)

まず、`rkdeveloptool`用のローダーを読み込ませます。
```
# rkdeveloptool db /mnt/work/spi/MiniLoaderAll.bin
```

この状態でSPI Flashの情報が読めるはずです:
```
# rkdeveloptool rfi
```
```
Flash Info:
	Manufacturer: SAMSUNG, value=00
	Flash Size: 16 MB
	Flash Size: 32768 Sectors
	Block Size: 64 KB
	Page Size: 2 KB
	ECC Bits: 0
	Access Time: 40
	Flash CS: Flash<0> 
```

`rkdeveloptool`でストックU-Bootを書き込みます。
```
# rkdeveloptool wl 0 rkspi_loader.img
```

必要であれば再起動します
```
# rkdeveloptool rd
```