Zynq UltraScale+でQSPIとSDブートができない問題

#はじめに
皆さんはZynqが好きですか？Zynqを使おうとしてQSPIとSDブートができなくなった話を書きます。

デバッグで高級LEDチカチカをしようとした際に起こった出来事です。

1週間ぐらい悩みに悩んでようやく解決できたので、教訓として残しておきます。

#症状
ZynqはCPU側（PS)とロジック側（PL)の二種類に分かれそれぞれが独立しつつも互いに相互利用できる優秀なFPGAです。

Vivado側でPS側のハードウェアとLチカ用のロジックを生成し、Zynq用のIP Blockを作成し、bitファイルを生成。
その後にXilinxのSDKにてサンプルプログラムであるHello Worldを作成しJATGにて書き込みを行ったところUARTに何も表示されず。
謎なのはPS側からPL側に100MHzのクロックを取り出し、Lチカ用の分周回路を生成したわけですが、超高級Lチカが正常に動作しているという点。

単にUARTの調子が悪いのかと思い、QSPIやSDにBOOT.binを作成し書き込むも、PS_ERROR_OUTのDONEが立って正常起動に失敗する現象に陥りました。

#調査
BOOT.binにはFSBL、ロジックのハードウェア情報（bitファイル)、アプリケーション（elfファイル）が書き込まれているのですが、どうやらFSBLの部分でコケている可能性が高いと考え、FSBLのデバッグ情報を書き出す設定を行いました。

```c++:xfsbl_debug.h
/**
 * Debug levels for FSBL
 */
#define DEBUG_PRINT_ALWAYS    (0x00000001U)    /* unconditional messages */
#define FSBL_DEBUG_INFO 1
#define DEBUG_GENERAL	      (0x00000002U)    /* general debug  messages */
#define DEBUG_INFO	      (0x00000004U)    /* More debug information */
#define DEBUG_DETAILED	      (0x00000008U)    /* More debug information */
```

##FSBLのデバッグ結果
再度BOOT.binを書き込みUART経由でFSBLのデバッグ情報を表示したところ、PLのハードウェア情報(bitstream)を読み出す段階で起動に失敗している事が判明。

```
詑譬Xilinx Zynq MP First Stage Boot Loader
Release 2018.3   Dec 18 2019  -  16:40:27
Reset Mode      :       System Reset
Platform: Silicon (4.0), Cluster ID 0x80000000
Running on A53-0 (64-bit) Processor, Device Name: XCZU4CG
Processor Initialization Done
================= In Stage 2 ============
SD0 Boot Mode
SD: rc= 0
File name is BOOT.BIN
Multiboot Reg : 0x0
Image Header Table Offset 0x8C0
*****Image Header Table Details********
Boot Gen Ver: 0x1020000
No of Partitions: 0x3
Partition Header Address: 0x440
Partition Present Device: 0x0
Initialization Success
======= In Stage 3, Partition No:1 =======
UnEncrypted data Length: 0x1DBEEF
Data word offset: 0x1DBEEF
Total Data word length: 0x1DBEEF
Destination Load Address: 0xFFFFFFFF
Execution Address: 0x0
Data word offset: 0x72C0
Partition Attributes: 0x26
Destination Device is PL, changing LoadAddress
Non authenticated Bitstream download to start now
DMA transfer done
XFSBL_ERROR_BITSTREAM_LOAD_FAIL
Partition 1 Load Failed, 0x37
================= In Stage Err ============
Fsbl Error Status: 0x0
```

どうやらPL情報はPCAP-DMAによりPS-DDRに内容を展開するらしく、基板上にはDDR4が搭載されているのですがそこに問題があるのではということになりました。

##Zynq MP DRAM Tests
DDR4が正常に動作しているかを知るために、テストプログラムを作ることにしました。

Xilinx SDKのサンプルプログラムにはDDRのテスト用のプログラムが存在します。（というか知らなかった）
作成方法としてはFSBLと同様にプロジェクト作成画面から、Zynq MP DRAM Testsを選択するだけです。
勝手にコンパイルまでしてくれるので、後はJTAG経由で書き込むだけです。

![Zynq MP DRAM Tests.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99702/4e108282-f272-32e0-9663-02b1eeea6162.png)

#結果
結論からすると16MBですら動いていませんでした。

```
****************************************************************************
   Zynq MPSoC
   DRAM Diagnostics Test (A53)
****************************************************************************
   Select one of the options below:
   +--------------------------------------------------------------------+
   |  Memory Tests                                                      |
   +-----+--------------------------------------------------------------+
   | '0' | Test first 16MB region of DDR                                |
   | '1' | Test first 32MB region of DDR                                |
   | '2' | Test first 64MB region of DDR                                |
   | '3' | Test first 128MB region of DDR                               |
   | '4' | Test first 256MB region of DDR                               |
   | '5' | Test first 512MB region of DDR                               |
   | '6' | Test first 1GB region of DDR                                 |
   | '7' | Test first 2GB region of DDR                                 |
   | '8' | Test first 4GB region of DDR                                 |
   | '9' | Test first 8GB region of DDR                                 |
   | 'm' | Test user specified size in MB of DDR                        |
   | 'g' | Test user specified size in GB of DDR                        |
   +-----+--------------------------------------------------------------+
   |  Eye Tests                                                         |
   +-----+--------------------------------------------------------------+
   | 'r' | Perform a read eye analysis test                             |
   | 'w' | Perform a write eye analysis test                            |
   | 'c' | Perform a 2-D read eye analysis test                         |
   | 'e' | Perform a 2-D write eye analysis test                        |
   | 'a' | Print test start address                                     |
   | 'l' | Select Number of Iterations for Read/Write Eye Test          |
   | 't' | Specify test start address (default=0x0)                     |
   | 's' | Select the DRAM Rank (default=1)                             |
   +-----+--------------------------------------------------------------+
   |  Miscellaneous options                                             |
   +-----+--------------------------------------------------------------+
   | 'i' | Print DDR information                                        |
   | 'v' | Verbose Mode ON/OFF                                          |
   | 'o' | Toggle cache enable/disable                                  |
   | 'b' | Toggle between 32/64-bit bus widths                          |
   | 'q' | Exit the DRAM Test                                           |
   | 'h' | Print this help menu                                         |
   +-----+--------------------------------------------------------------+

        Bus Width = 64,   D-cache is enable,   Verbose Mode is OFF

 DDR ECC is DISABLED
 Enter 'h' to print help menu
 Enter Test Option:
0
Starting Memory Test...
16MB length - Address 0x0...
---------+--------+------------------------------------------------+-----------
  TEST   | ERROR  |          PER-BYTE-LANE ERROR COUNT             |  TIME
         | COUNT  |  #0 ,  #1 ,  #2 ,  #3 ,  #4 ,  #5 ,  #6 ,  #7  |  (sec)
---------+--------+------------------------------------------------+-----------
```

そこでIP BlockのDDR4の設定を見直した結果、JTAG経由でHello Wolrdが起動しました！！やったね！！
更にはQSPI、SDブートでも起動に成功したことから原因はDDR4の設定周りのミスであったことがわかりました。

```
栴Xilinx Zynq MP First Stage Boot Loader 
Release 2018.3   Dec 19 2019  -  18:10:08
Reset Mode	:	System Reset
Platform: Silicon (4.0), Cluster ID 0x80000000
Running on A53-0 (64-bit) Processor, Device Name: XCZU4CG
Processor Initialization Done 
================= In Stage 2 ============ 
QSPI 32 bit Boot Mode 
QSPI is in single flash connection
QSPI is using 4 bit bus
FlashID=0x1 0x2 0x20
SPANSION 512M Bits
Multiboot Reg : 0x0 
QSPI Reading Src 0x0, Dest FFFF1C40, Length EC0
.Image Header Table Offset 0x8C0 
QSPI Reading Src 0x8C0, Dest FFFD9150, Length 40
.*****Image Header Table Details******** 
Boot Gen Ver: 0x1020000 
No of Partitions: 0x3 
Partition Header Address: 0x440 
Partition Present Device: 0x0 
QSPI Reading Src 0x1100, Dest FFFD9190, Length 40
.QSPI Reading Src 0x1140, Dest FFFD91D0, Length 40
.QSPI Reading Src 0x1180, Dest FFFD9210, Length 40
.Initialization Success 
======= In Stage 3, Partition No:1 ======= 
UnEncrypted data Length: 0x1DBEEF 
Data word offset: 0x1DBEEF 
Total Data word length: 0x1DBEEF 
Destination Load Address: 0xFFFFFFFF 
Execution Address: 0x0 
Data word offset: 0x72C0 
Partition Attributes: 0x26 
QSPI Reading Src 0x1CB00, Dest 100000, Length 76FBBC
.Destination Device is PL, changing LoadAddress
Non authenticated Bitstream download to start now
DMA transfer done 
PL Configuration done successfully 
Partition 1 Load Success 
======= In Stage 3, Partition No:2 ======= 
UnEncrypted data Length: 0x2812 
Data word offset: 0x2812 
Total Data word length: 0x2812 
Destination Load Address: 0x0 
Execution Address: 0x0 
Data word offset: 0x1E31B0 
Partition Attributes: 0x116 
QSPI Reading Src 0x78C6C0, Dest 0, Length A048
.Partition 2 Load Success 
All Partitions Loaded 
================= In Stage 4 ============ 
PMU-FW is not running, certain applications may not be supported.
Protection configuration applied
Running Cpu Handoff address: 0x0, Exec State: 0
Exit from FSBL 
Hello World
```

#おわりに
今回の教訓としてはIP Block DesignでのDDR4の設定ミスが原因で引き起こしたものでした（我ながらお恥ずかしい）
この状態でも起動プロセスまで通ってしまうので、実機での作業まで行かないとわからないようなミスだったと言えます。しっかり設定は見直しましょう。

#参考資料
https://forums.xilinx.com/t5/ACAP-and-SoC-Boot-and/XFSBL-ERROR-BITSTREAM-LOAD-FAIL-error-with-Zynq-Ultrascale-RFSoC/td-p/944014