KV260 の ブートファームウェアを更新

## はじめに

Kria KV 260 Vision AI Starter Kit (以下 KV260) の System On Module(以下 SOM) 上には QSPI に接続されたフラッシュメモリがあります。[『KV260 が Linux をブートするまでのシーケンス』](https://qiita.com/ikwzm/items/aca938c98b636c0048bc) で説明したように、KV260 のプライマリーブートデバイスは、この QSPI 上のフラッシュメモリです。この記事では、このフラッシュメモリ上にあるブートファームウェア (BOOT.BIN) を更新する方法について説明します。

## ファームウェアイメージ (BOOT.BIN) の入手

KV260 用のファームウェアイメージは以下のページの「Boot Firmware Updates」にダウンロードリンクがあります。ダウンロードリンクからログインしてダウンロードしてください。

 * [「Kria K26 SOM」 Xilinx Wiki / Board and Kits](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/1641152513/Kria+K26+SOM)

なお、私が動作を確認したのは、2022年7月現在、2021.1 Boot FW Update_2 です。なお、2022年7月現在、このページに 2022.1 Boot FW Update もありますが、このファームウェアだと KV260 ではブートしませんでした。なにか問題があるのかもしれません。

|Kria Boot FW Image      | Description | Kits Supported | Download Link |
|:-----------------------|:------------|:---------------|---------------|
|2021.1 Boot FW Update 2 | KV260 boot FW update to address potential platform SW reboot induced failure. <p> Behavior is reboot is not successful as PS power domain is unintentionally disabled. <p> NOTE: This update is atomic (does not required Update 1 to be installed prior) | KV260 | [Xilinx download - 2021.1_update2_BOOT.BIN](https://www.xilinx.com/member/forms/download/xef.html?filename=2021.1_update2_BOOT.BIN) |

## ファームウェアイメージ更新ツールのインストール

Petalinux や 公式 Ubuntu など、Xilinx が提供している Linux ではすでに xmutil スクリプトや image_update コマンドがインストールされている場合があります。もしインストールされている場合はこれらを使います。

私が提供している ZynqMP-FPGA-Linux や ZynqMP-FPGA-Ubuntu20.04 ではデフォルトではインストールされていません。そこで、これらのツールを Debian のパッケージとして以下の Github で公開しています。ただし、あくまでも非公式な Debian パッケージですので使用に注意してください。

 * https://github.com/ikwzm/xmutil-dpkg
   + fru-print_1.0.0_all.deb
   + zynqmp-image-update_2022.1.2_arm64.deb

なお、image_update コマンドは Xilinx が Github で公開されています。

 * https://github.com/Xilinx/linux-image_update

## ファームウェアイメージの更新

### 正常にブートするファームウェアのバックアップ

念のため、正常にブートしているファームウェアをファイルに保存しておきます。
まず、現時点でブートに使われたファームウェアを image_update コマンドの -p オプションで確認します。

```console
shell$ sudo image_update -p
Image A: Bootable
Image B: Bootable
Requested Boot Image: Image A
Last Booted Image: Image A
XilinxSom_QspiImage_v1.1_20210422

ImageA Revision Info: Not defined
ImageB Revision Info: Not defined
```

Last Booted Image が Image A になっているので、Image A の内容をファイルに書き込みます。Image A のデバイス名は /dev/mtd5 です。詳細は[『KV260 の QSPI フラッシュメモリをのぞいてみる』](https://qiita.com/ikwzm/items/67902c8e1446c13e8d81) を参照してください。

```console
shell$ sudo dd if=/dev/mtd5 of=boot_ok.bin bs=1024
13312+0 records in
13312+0 records out
13631488 bytes (14 MB, 13 MiB) copied, 2.9342 s, 4.6 MB/s
```

### ファームウェアイメージを現在使用していない方のパーティションに書き込む

[『KV260 の QSPI フラッシュメモリをのぞいてみる』](https://qiita.com/ikwzm/items/67902c8e1446c13e8d81) で説明したように、KV260 の QSPI のフラッシュメモリには Image A と Image B の２ヶ所の BOOT.BIN を格納する場所があります。現在、どちらの Image を使ってブートしたかは、QSPI のフラッシュメモリの Persistent Register パーティションに格納されています。

image_update コマンドは、まず Persistent Register を読んで、現在ブートに使われていない方のパーティションに指定したファイルを新たな BOOT.BIN として書き込みます。具体的には次のようにします。

```console
shell$ sudo image_update -i 2021.1_update2_BOOT.BIN
Marking last booted image as bootable
Reading Image..
Marking target image non bootable
Writing Image..
Marking target image as non bootable and requested image
2021.1_update2_BOOT.BIN updated successfully
```

ちなみに上記コマンド実行直後の Persistent Register は次のようになっていました。

```console
shell$ sudo image_update -p
Image A: Bootable
Image B: Non Bootable
Requested Boot Image: Image B
Last Booted Image: Image A
XilinxSom_QspiImage_v1.1_20210422

ImageA Revision Info: Not defined
ImageB Revision Info: Not defined
```

Last Booted Image は現在のブートに使用されているブートイメージを示しています。Last Booted Image が Image A だったので、新しいブートイメージは Image B に書き込まれました。その際、Image B はブート可能かどうかまだわからないため、Image B は Non Bootable になっています。
Requested Boot Image は次の電源投入時にブートを試すブートイメージを示しています。ここでは新しいブートイメージを書き込んだ Image B が選択されています。

### 電源を落とす

このまま一度電源を落とします。なお、リブートではダメです。必ず一度電源を落としてください。

```console
shell$ sudo systemctl poweroff
```

### 電源を投入する

電源を投入して KV260 をブートします。順調ならば正常に KV260 が起動して Linux が起動するはずです。
Linux が起動したならば、image_update コマンドの -p オプションで現在の状況を確認してみます。

```console
shell$ sudo image_update -p
Image A: Bootable
Image B: Non Bootable
Requested Boot Image: Image B
Last Booted Image: Image B
XilinxSom_QspiImage_v1.1_20210422

ImageA Revision Info: Not defined
ImageB Revision Info: Not defined
```

Last Booted Image が Image B になっています。まだ Image B は Non Bootable になっていることに注目してください。


### 新たなファームウェアとして登録する

無事にブートしたならば、image_update コマンドの -v オプションを使って、Last Booted Image(今回の場合は Image B) を Bootable に変更します。

```console
shell$ sudo image_update -v
Marking last booted image as bootable
```

image_update コマンドの -p オプションで確認してみると次のように Last Booted Image(今回の場合は Image B) が Bootable に変更されています。

```console
shell$ sudo image_update -p
Image A: Bootable
Image B: Bootable
Requested Boot Image: Image B
Last Booted Image: Image B
XilinxSom_QspiImage_v1.1_20210422

ImageA Revision Info: Not defined
ImageB Revision Info: Not defined
```

これで無事にファームウェアの更新が終了しました。

## ファームウェアイメージの更新に失敗した場合の復帰方法

例えば、[「Kria K26 SOM」 Xilinx Wiki / Board and Kits](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/1641152513/Kria+K26+SOM) から 2022.1 Boot FW Update をダウンロードしてファームウェアとして書き込んだとします。

```console
shell$ sudo image_update -i BOOT_xilinx-k26-starterkit-v2022.1-05140151_update1.BIN
Marking last booted image as bootable
Reading Image..
Marking target image non bootable
Writing Image..
Marking target image as non bootable and requested image
BOOT_xilinx-k26-starterkit-v2022.1-05140151_update1.BIN updated successfully
```

この状態で電源を落とした後、再び電源を投入すると、次のようにブートに失敗しました。

```console
Release 2022.1   Apr 11 2022  -  09:29:50
MultiBootOffset: 0x40
Reset Mode      :       System Reset
Platform: Silicon (4.0), Running on A53-0 (64-bit) Processor, Device Name: XCZUUNKNEG
QSPI 32 bit Boot Mode
FlashID=0x20 0xBB 0x20
OTICE:  BL31: v2.6(release):xlnx_rebase_v2.6_2022.1
NOTICE:  BL31: Built : 03:46:40, Mar 24 2022


U-Boot 2022.01 (May 12 2022 - 17:12:22 +0000)

CPU:   ZynqMP
Silicon: v3
Detected name: zynqmp-smk-k26-xcl2g-rev1-sck-kv-g-rev1
Model: ZynqMP SMK-K26 Rev1/B/A
Board: Xilinx ZynqMP
DRAM:  4 GiB
PMUFW:  v1.1
Xilinx I2C FRU format at nvmem0:
 Manufacturer Name: XILINX
 Product Name: SMK-K26-XCL2G
 Serial No: XFL1F5B1N4KP
 Part Number: 5057-01
 File ID: 0x0
 Revision Number: 1
Xilinx I2C FRU format at nvmem1:
 Manufacturer Name: XILINX
 Product Name: SCK-KV-G
 Serial No: XFL1H5XVI24G
 Part Number: 5066-01
 File ID: 0x0
 Revision Number: 1
EL Level:       EL2
Chip ID:        xck26
NAND:  0 MiB
MMC:   mmc@ff170000: 1
Loading Environment from nowhere... OK
In:    serial
Out:   serial
Err:   serial
Bootmode: QSPI_MODE
Reset reason:   SOFT
Net:
ZYNQ GEM: ff0e0000, mdio bus ff0e0000, phyaddr 1, interface rgmii-id
PHY reset timed out
eth0: ethernet@ff0e0000
gpio: pin gpio@ff0a000038 (gpio 38) value is 0
gpio: pin gpio@ff0a000038 (gpio 38) value is 1
starting USB...
Bus usb@fe200000: Register 2000440 NbrPorts 2
Starting the controller
USB XHCI 1.00
scanning bus usb@fe200000 for devices... XHCI timeout on event type 33... cannot recover.
BUG at drivers/usb/host/xhci-ring.c:481/xhci_wait_for_event()!
BUG!
```

### ブートに失敗したらリセットボタンを押す

ここで慌てず騒がず、KV260 のリセットボタンを押します。そうすると、前回正常にブートしたファームウェアでもって起動します。

```console
Xilinx Zynq MP First Stage Boot Loader
Release 2021.1   Jun  6 2021  -  07:07:32
NOTICE:  ATF running on XCK26/silicon v4/RTL5.1 at 0xfffea000
NOTICE:  BL31: v2.4(release):xlnx_rebase_v2.4_2021.1
NOTICE:  BL31: Built : 08:27:07, Apr 28 2021


U-Boot 2021.01 (Jun 01 2021 - 11:54:06 +0000)

Model: ZynqMP SMK-K26 Rev1/B/A
Board: Xilinx ZynqMP
DRAM:  4 GiB
PMUFW:  v1.1
Xilinx I2C FRU format at nvmem0:
 Manufacturer Name: XILINX
 Product Name: SMK-K26-XCL2G
 Serial No: XFL1F5B1N4KP
 Part Number: 5057-01
 File ID: 0x0
 Revision Number: 1
Xilinx I2C FRU format at nvmem1:
 Manufacturer Name: XILINX
 Product Name: SCK-KV-G
 Serial No: XFL1H5XVI24G
 Part Number: 5066-01
 File ID: 0x0
 Revision Number: 1
EL Level:       EL2
Chip ID:        xck26
NAND:  0 MiB
MMC:   mmc@ff170000: 1
Loading Environment from SPIFlash... SF: Detected n25q512a with page size 256 Bytes, erase size 64 KiB, total 64 MiB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Bootmode: QSPI_MODE
Reset reason:   SOFT
Net:   No ethernet found.
Hit any key to stop autoboot:  0
    :
    :
    :
```

ブート直後の Persistent Register は次のようになっていました。

```console
shell$ sudo image_update -p
Image A: Non Bootable
Image B: Bootable
Requested Boot Image: Image A
Last Booted Image: Image B
XilinxSom_QspiImage_v1.1_20210422

ImageA Revision Info: XilinxSOM_BootFW_20220514

ImageB Revision Info: Not defined
```

Requested Boot Image が Image A かつ Image A が Non bootable になっているので、ブートに失敗したブートファームウェアは Image A であることがわかります。

また、Last Booted Image が Image B かつ Image B が Bootable になっているので、この時点でブートしたブートファームウェアは Image B であることがわかります。


### 正常にブートするファームウェアを書き込む

この状態で電源を落とした後、再び電源を投入すると、またブートに失敗します。
そこで正常にブートするファームウェアを書き込みます。

```console
shell$ sudo image_update -i 2021.1_update2_BOOT.BIN
Marking last booted image as bootable
Reading Image..
Marking target image non bootable
Writing Image..
Marking target image as non bootable and requested image
2021.1_update2_BOOT.BIN updated successfully
```

```console
shell$ sudo image_update -p
Image A: Non Bootable
Image B: Bootable
Requested Boot Image: Image A
Last Booted Image: Image B
XilinxSom_QspiImage_v1.1_20210422

ImageA Revision Info: Not defined
ImageB Revision Info: Not defined
```

Requested Boot Image が Image A に かつ Image A が Non Bootabule になっていることから、前回ブートに失敗した Image A に新しいファームウェアが書き込まれたことがわかります。

### 電源を落とす

このまま一度電源を落とします。なお、リブートではダメです。必ず一度電源を落としてください。

```console
shell$ sudo systemctl poweroff
```

### 電源を投入する

電源を投入して KV260 をブートします。今度は正常にブートするはずです。
Linux が起動したならば、image_update コマンドの -p オプションで現在の状況を確認してみます。

```console
shell$ sudo image_update -p
Image A: Non Bootable
Image B: Bootable
Requested Boot Image: Image A
Last Booted Image: Image A
XilinxSom_QspiImage_v1.1_20210422

ImageA Revision Info: Not defined
ImageB Revision Info: Not defined
```

Last Booted Image が Image A になっています。ただし、まだ Image A は Non Bootable になっていることに注意してください。

### 新たなファームウェアとして登録する

無事にブートしたならば、image_update コマンドの -v オプションを使って、Last Booted Image(今回の場合は Image A) を Bootable に変更します。

```console
shell$ sudo image_update -v
Marking last booted image as bootable
```
image_update コマンドの -p オプションで確認してみると次のように Last Booted Image(今回の場合は Image A) が Bootable に変更されています。

```console
shell$ sudo image_update -p
Image A: Bootable
Image B: Bootable
Requested Boot Image: Image A
Last Booted Image: Image A
XilinxSom_QspiImage_v1.1_20210422

ImageA Revision Info: Not defined
ImageB Revision Info: Not defined
```

これで無事にファームウェアの復帰が終了しました。

## 参考

 * [「Boot Firmware Overvier」](https://xilinx.github.io/kria-apps-docs/bootfw/build/html/docs/bootfw_overview.html#)
 * [「Kria K26 SOM」 Xilinx Wiki / Board and Kits](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/1641152513/Kria+K26+SOM)
 * [「IMPORTANT!!! KV260 Boot Firmware Update Alert」Xilinx Forum](https://support.xilinx.com/s/question/0D52E000073zG4MSAU/important-kv260-boot-firmware-update-alert?language=ja)
 * [『KV260 が Linux をブートするまでのシーケンス』@Qiita](https://qiita.com/ikwzm/items/aca938c98b636c0048bc)
 * [『KV260 の QSPI フラッシュメモリをのぞいてみる』@Qiita](https://qiita.com/ikwzm/items/67902c8e1446c13e8d81)
 * https://github.com/ikwzm/xmutil-dpkg
 * https://github.com/Xilinx/linux-image_update