はじめに
UltraZed とは
UltraZed-EG スターターキットは Xilinx 社の Zynq UltraScale+ MPSoC(XCZU3EG-SFVA625) を搭載した UltraZed-EG-SOM と UltraZed IOキャリアカードで構成された Avnet 社のキットです。詳細は次の URL を参照してください。
この記事では、UltraZed で SD Card を使おうとすると、ライトプロテクションがかかってて書き込み不可になってしまう問題の対処方法を示します。
症状
UltaraZed でSD Card を使おうとすると、ライトプロテクションがかかってて書き込み不可になってしまいます。
そのため、SD Card のパーティションに Linux の Root FS を置いてマウントしようとすると、マウント出来ずにカーネルがパニックを起こして停止します。これは Linux が Root FS をマウントするためには書き込み可でなければならないからです。下記にマウントに失敗した時の Linux Kernel のログ(抜粋)を示します。mmcblk1 の認識時に "mmcblk1: mmc1:aaaa SL08G 7.40 GiB (ro)" となっている点に注意してください。"(ro)" は Ready Only を意味します。書き込み可ならば "(ro)" はつきません。
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.9.0-xilinx-v2017.2 (vk@ubuntu) (gcc version 6.2.1 20161016 (Linaro GCC 6.2-2016.11) ) #1 SMP Sun Oct 15 23:58:04 PDT 2017
:
(中略)
:
[ 2.970474] mmc1: new high speed SDHC card at address aaaa
[ 2.970690] mmcblk1: mmc1:aaaa SL08G 7.40 GiB (ro)
[ 2.971557] mmcblk1: p1 p2
:
(中略)
:
[ 3.285624] VFS: Cannot open root device "mmcblk0p2" or unknown-block(179,2): error -6
[ 3.293489] Please append a correct "root=" boot option; here are the available partitions:
[ 3.301818] 0100 65536 ram0 [ 3.305347] (driver?)
[ 3.307699] 0101 65536 ram1 [ 3.311566] (driver?)
[ 3.313921] 0102 65536 ram2 [ 3.317474] (driver?)
[ 3.319824] 0103 65536 ram3 [ 3.323371] (driver?)
[ 3.325727] 0104 65536 ram4 [ 3.329278] (driver?)
[ 3.331624] 0105 65536 ram5 [ 3.335181] (driver?)
[ 3.337531] 0106 65536 ram6 [ 3.341083] (driver?)
[ 3.343429] 0107 65536 ram7 [ 3.346985] (driver?)
[ 3.349337] 0108 65536 ram8 [ 3.352889] (driver?)
[ 3.355234] 0109 65536 ram9 [ 3.358791] (driver?)
[ 3.361141] 010a 65536 ram10 [ 3.364780] (driver?)
[ 3.367126] 010b 65536 ram11 [ 3.371394] (driver?)
[ 3.373746] 010c 65536 ram12 [ 3.377383] (driver?)
[ 3.379735] 010d 65536 ram13 [ 3.383368] (driver?)
[ 3.385723] 010e 65536 ram14 [ 3.389362] (driver?)
[ 3.391712] 010f 65536 ram15 [ 3.395346] (driver?)
[ 3.397706] b300 7438336 mmcblk0 [ 3.401514] driver: mmcblk
[ 3.404300] b301 250040 mmcblk0p1 00000000-01[ 3.409413]
[ 3.410891] b318 4096 mmcblk0rpmb [ 3.415056] (driver?)
[ 3.417406] b310 16384 mmcblk0boot1 [ 3.421652] (driver?)
[ 3.424003] b308 16384 mmcblk0boot0 [ 3.428249] (driver?)
[ 3.430595] b320 7761920 mmcblk1 [ 3.434411] driver: mmcblk
[ 3.437198] b321 524288 mmcblk1p1 d1fdbe62-01[ 3.442310]
[ 3.443794] b322 7233536 mmcblk1p2 d1fdbe62-02[ 3.448907]
[ 3.450385] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,2)
[ 3.458815] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.9.0-xilinx-v2017.2 #1
[ 3.465923] Hardware name: xlnx,zynqmp (DT)
[ 3.470088] Call trace:
[ 3.472526] [<ffffff8008088138>] dump_backtrace+0x0/0x198
[ 3.477905] [<ffffff80080882e4>] show_stack+0x14/0x20
[ 3.482939] [<ffffff80083de514>] dump_stack+0x94/0xb8
[ 3.487974] [<ffffff800812e980>] panic+0x114/0x25c
[ 3.492747] [<ffffff8008c110e8>] mount_block_root+0x198/0x270
[ 3.498475] [<ffffff8008c113f8>] mount_root+0x11c/0x134
[ 3.503682] [<ffffff8008c1157c>] prepare_namespace+0x16c/0x1b4
[ 3.509499] [<ffffff8008c10d14>] kernel_init_freeable+0x1c0/0x1e0
[ 3.515575] [<ffffff80089359a0>] kernel_init+0x10/0x100
[ 3.520782] [<ffffff8008082e80>] ret_from_fork+0x10/0x50
[ 3.526075] SMP: stopping secondary CPUs
[ 3.529982] Kernel Offset: disabled
[ 3.533452] Memory Limit: none
[ 3.536493] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,2)
原因
ZynqMP の SDIO I/F には WP(Write Protection) pin があります。この入力ピンを適切に設定していないと、何故か ZynqMP は Write Protection 状態と認識してしまいます。
Fig.1 ZynqMP Re-customize IP
この UI はちょっと紛らわしくて、普通は WP にチェックを入れないと Write Protection にならないと勘違いしてしまいますが、実はこの UI は単にピンの設定を行っているだけで、ピンの設定をしないとどうなるかは関係ないのです。で、何故か ZynqMP はこのピンを設定していないとWrite Protection 状態と認識してしまうのです。
Write Protection にならないようにするには、このピンを設定した上で MIO 44 を Low に接続するか、もしくはソフトウェアの方で Write Protection を無効にしなければなりません。
UltraZed ではどうなっているかと言うと、仕様上は次のようになっています。
Fig.2 UltraZed I/O Carrie Card User Guide
この図を見るかぎり、MIO44 ピンの入力は JP2 をオープンしている時は Low Level に、JP2 をクローズするとHigh Level になります。通常はJP2はオープンになっているので MIO44ピンの入力は Low Level となり問題ないと思われます。
ところが、Avnet が提供している UltraZed-EG-IOCC のボード設定ファイルを使って FPGA のデザインを行うと、何故か WP にチェックが入っていません。
Fig.3 ZynqMP Re-customize IP (ultrazed-3eg-iocc 1.0)
このボード設定ファイルを使って FPGA をデザインした場合、SD-Card が書き込み不可になってしまいます。
対処方法
その1 ボード設定ファイルを修正する
もともとボード設定ファイルに問題があるのだから、ボード設定ファイルを修正するのが基本的な解決方法です。Avnet が提供するボード設定ファイルは次のURL にあります。
このボード設定ファイル群は、 Vivado をインストールしたディレクトリの下のdata/boar/board_files に置かれます。その中の ultrazed_3eg_iocc/1.0/preset.xml に次の行を追加します。
<user_parameter name = "CONFIG.PSU__SD1__GRP_WP__ENABLE" value = "1" />
<user_parameter name = "CONFIG.PSU__SD1__GRP_WP__IO" value = "MIO 44" />
ただしこの方法は当然すでに作ってしまった FPGA デザインに関しては有効ではありません。例えばAvnet が提供しているチュートリアル用デザインなんかを再配置配線せずに使う場合はどうにもなりません。
その2 Vivado の Custmize IP で WP をチェックする
ボードファイルを修正するのはちょっと抵抗があるという人は、FPGA をデザインするときに忘れずに WP にチェックを入れてください。
Fig.4 ZynqMP Re-customize IP
その3 Linux のデバイスツリーで Write Protection を無効にする
これは Linux 限定ですが、デバイスツリーで SDIO の Write Protection を強制的に無効にすることが出来ます。この方法なら FPGA の再デザインは必要ありません。デバイスツリーの sdhci1 の記述を探し出して、disable-wp プロパティを追加します。
/dts-v1/;
/ {
:
(中略)
:
sdhci@ff170000 {
u-boot,dm-pre-reloc;
compatible = "xlnx,zynqmp-8.9a", "arasan,sdhci-8.9a";
status = "okay";
interrupt-parent = <0x4>;
interrupts = <0x0 0x31 0x4>;
reg = <0x0 0xff170000 0x0 0x1000>;
clock-names = "clk_xin", "clk_ahb";
xlnx,device_id = <0x1>;
#stream-id-cells = <0x1>;
iommus = <0xe 0x871>;
power-domains = <0x23>;
nvmem-cells = <0x1f>;
nvmem-cell-names = "soc_revision";
clocks = <0x3 0x37 0x3 0x1f>;
clock-frequency = <0xbebba30>;
xlnx,mio_bank = <0x1>;
max-frequency = <0x2faf080>;
no-1-8-v;
disable-wp;
linux,phandle = <0x69>;
phandle = <0x69>;
};
:
(中略)
:
};
参考
この問題は Xilinx のフォーラムでも話題となっていて、Linux のデバイスツリーを修正する方法が提案されています。
Avnet のフォーラムでもスレッドがありますが、このスレッドでも上の Xilinx のフォーラムを解決方法として提案されていて解決済みとなっています。
筆者はボードファイルの問題ではないかと Avnet のフォーラムにスレッドを立てましたが、UltraZed IO Carrier Card は WP pin を使っていないからボード設定ファイルを変更する必要は無いと言われてしまいました。どっちが正しいのでしょうか?
UltraZed に関する資料は次の通りです。