Linux

【Zynq7】4.Zyboz7ボードのデバイスツリー構築

1.記事一覧

記事は複数回に分けて投稿します。Zynq7020SoCで動作する、PetaLinuxを使わない素のLinuxを構築します。

ZynqMP(arm64版)はこちら

エッジArm Linux構築編(armv7l)

エッジArm Linux実践編(armv7l)

2.環境

開発PCUbuntu20.04, intel core i5 750 RAM 16G
DockerDocker Engine v23.0.0, Ubuntu20.04 base image
ターゲットボードDigilent Zybo z7-20 Rev.B.2(XC7Z020-1CLG400C, DDR3 1GB)
XilinxツールVitis 2022.2(現在最新2023/1)
XSCTコマンドラインツールを使用します。
DTG(Device Tree Generator)XilinxがGithubで提供するソースを使用。tag=xilinx_v2022.2
https://github.com/Xilinx/device-tree-xlnx/tree/xilinx_v2022.2
DTCデバイスツリーコンパイラ
Ubuntu18.04 apt install 版 v1.5.0
ZynqデータシートTRM(Technical Reference Manual)
https://docs.xilinx.com/v/u/en-US/ug585-Zynq-7000-TRM
Zybo z7 ボード回路図https://digilent.com/reference/_media/reference/programmable-logic/zybo-z7/zybo_z7_sch-public.pdf

u-boot、linux構築に引き続き、デバイスツリーのビルド環境にはDockerコンテナ環境を使用します。理由は私の開発PCではすでに別の開発環境が入っており、クリーンでないからです。再現性を高めるためなので、必ずしも使う必要はなく、直接開発PC上に環境構築しても問題ありません。

ただし、デバイスツリーソースファイル(.dts)を生成するXSCTコマンドラインツールを使うにはVitisがインストールされた環境が必要になります。故にコンテナ上では作業できません。旧XSDKのhsiツールはXSCTで代用できます。

3.ビルド環境の構築

3-1. デバイスツリーコンパイラのインストール

Bash
$ sudo apt install device-tree-compiler

3-2. DTG(Device Tree Generator)

XSCTコマンドで使用するため、ホスト上にgit cloneします。コンテナ上は不可です。コンテナから共有フォルダを通じてホストのworkフォルダ内の適当な場所にcloneします。

Bash
$ cd /home/share
$ mkdir devicetree_wk
$ cd devicetree_wk
$ git clone https://github.com/Xilinx/device-tree-xlnx.git
$ git checkout xilinx_rel_v2022.2

4.デバイスツリーソース生成

4-1. ハードウェアエクスポートファイルの準備

前記事のFSBLの構築でVIvadoからVitis向けにエクスポートしたプラットフォームファイル(.xsa)をDTG(Device Tree Generator)フォルダ直下にコピーします。

Bash
HostPC$ cp (Vitisプロジェクトpath)/プロジェクト名.vitis/design_1_wrapper.xsa (workdir path)/devicetree_wk/device-tree-xlnx/

4-2. デバイスツリーソース生成

VIvadoのハードウェア情報を素にZybo z7ボード用デバイスツリーソースを生成します。XSCTコマンドラインツールを起動します。

【追記】XSCTでcreatedtsコマンドを使用すると、DTGのclone、デバイスツリー生成、コンパイルを一発で行えます。ZymqMP版記事でやっています。

Bash
HostPC$ cd device-tree-xlnx
HostPC$ source /tools/Xilinx/Vitis/2022.2/settings64.sh
HostPC$ xsct
    xsct% hsi open_hw_design <プラットフォームファイル.xsa>
    xsct% hsi set_repo_path ./
    xsct% hsi create_sw_design device-tree -os device_tree -proc ps7_cortexa9_0
    xsct% hsi generate_target -dir <出力フォルダのpath>
    xsct% exit
HostPC$ 

実際の様子です。

Bash
user@userPC:~/work/zynq7linux/devicetree_wk/device-tree-xlnx$ xsct
rlwrap: warning: your $TERM is 'xterm-256color' but rlwrap couldn't find it in the terminfo database. Expect some problems.

Xilinx Software Commandline Tool (XSCT) v2022.2.0
**** SW Build 0 on 2022-10-13-12:09:36
** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.

xsct% hsi::open_hw_design design_1_wrapper.xsa
INFO: [Hsi 55-2053] elapsed time for repository (/tools/Xilinx/Vitis/2022.2/data/embeddedsw) loading 3 seconds
hsi::open_hw_design: Time (s): cpu = 00:00:03 ; elapsed = 00:00:05 . Memory (MB): peak = 657.699 ; gain = 25.980 ; free physical = 9587 ; free virtual = 14683
design_1_wrapper
xsct% hsi::set_repo_path ./
xsct% hsi::create_sw_design device-tree -os device_tree -proc ps7_cortexa9_0
device-tree
xsct% hsi::generate_target -dir my_dts
zocl:false
ext_platform:
WARNING: ps7_ethernet_0: No reset found
hsi::generate_target: Time (s): cpu = 00:00:08 ; elapsed = 00:00:09 . Memory (MB): peak = 659.344 ; gain = 1.645 ; free physical = 9561 ; free virtual = 14621
xsct% exit
exit
user@userPC:~/work/zynq7linux/devicetree_wk/device-tree-xlnx$

出力フォルダに以下が生成されています。

  • device-tree.mss
  • includeフォルダ
  • pcw.dtsi
  • skeleton.dtsi
  • system-top.dts
  • system.dts
  • zynq-7000.dtsi

5.デバイスツリー設定

各ファイルの役割です。

system-top.dtsデバイスツリーのトップ層、下2つのdtsiファイルをinclude。
zynq-7000.dtsizynq共通のデバイス情報。内容は固定。
pcw.dtsiVivadoのハードウェア情報から作られた個別のデバイス情報。

5-1. system-top.dtsの編集

編集前のsystem-top.dts

自動生成の3ファイルは再生成したときの差分管理が面倒なので、自身で記述するデバイスツリーのdtsiファイルのinclude文を末尾に記述します。
しかし、文法が一部間違っていてコンパイルエラーと警告が出るので先に修正します。

  • #include/include/に修正
  • memorymemory@0 に修正

【修正2023/9】文法の間違いでコンパイルエラーではなく、gccによるプリコンパイルが必要と公式Wikiにありました。このやり方に沿ってやるとビルドはうまく出来ます。やり方は後のコンパイルの章で記載しています。→【追加の修正】プリコンパイルすら不要でした。createdtsコマンド一発です。

続いて末尾に独自記述dtsiのincludeを追加します。ファイル名は任意です。

  • #include “zynq-myboard.dtsi”

編集後

5-2. pcw.dtsiの確認

VivadoのPSのIPで設定されている内容が反映されています。
ここで注意しておきたいのはあくまでZynqデバイス内蔵のペリフェラルのデバイス情報が載っているだけで、I/Fやバスの先に接続されているデバイスはここには含まれません。例えば

  • I2Cバス接続のRTC(リアルタイムクロック)
  • USB ulpi接続のPHY
  • RGMII接続のGigabitEtherPHY
  • HDMIのPHY
  • I2S接続のAudio DAC/ADC

これらは次の独自記述dtsiに記載していきます。

5-3. カスタム記述dtsi

system-top.dts末尾でincludeした個別のデバイスツリーを記述します。

記載内容は主に4点です。

  • model名:カーネルメッセージに表示される
  • Linux起動オプション
  • USB PHY
  • GigabitEtherPHY

記載の方法ですが、正解は正直よくわかりません。webで他のボードのデバイスツリーを読む、あるいは前記事のLinux構築で使用したxilinxのlinuxカーネルリポジトリのデバイスツリーファイル(linux-xlnx/arch/arm/boot/dts以下)を参考にしたりしています。zybo-z7用のdtsも見つけましたが、そのままコピペしてもビルドが通らなかったり、Linux起動してもEtherが認識しないなど、一筋縄では行きませんでした。泥臭い組込みあるあるですね。
【追記2023/2/19】Xilinx公式WikiでLinuxDriverのページにdevicetreeの記述方法は載っています。あくまでZynq PSの GEther IPです。USB-PHYやEtherPHYなら参考になるかも…
例:PSのGigabitEtherのmacbドライバ

5-4. カスタム記述dtsi(Linux起動オプション)

chosen{}で起動オプションを記述しています。

"console=ttyPS0,115200"
→ログインコンソールのシリアルポートと通信速度bpsの設定です。’,’の後にスペースを入れてはいけません。うっかり入れてuboot(115200bps)→Linuxカーネル(9600bps)に切り替わり、Linuxがクラッシュしたと勘違いしました。

"root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1"
→SDカード(MMC)の第2パーティションのext4ルートファイルシステムをマウントします。

5-5. カスタム記述dtsi(USB PHY)

compatible = "ulpi-phy";
→ulpi-phyデバドラを指定します。ちなみにこのデバドラはmainlineに無いxilinxの改造が入ったものらしい

#phy-cells = <0>;
→PHYの識別番号のようです。1つしか無いのでとりあえず0から割当てます。

reg = <0xe0002000 0x1000>;
→USB0のペリフェラルレジスタベースアドレスとアドレス範囲

view-port = <0x0170>;
→USB-PHYレジスタに間接アクセスするためのレジスタオフセットアドレス

drv-vbus;
→PHYの電源制御関係らしい。回路図ではTIのTPS2051ハイサイドロードスイッチがPHYから制御されていて、USBHostとUSBdeviceを切替時にVBUS電源の供給ON/OFFに使う機能かもしれない

5-6. カスタム記述dtsi(GigabitEtherPHY)

zybo z7ボードのGigabitEtherPHYにはRealtek(あの蟹チップです)のRTL8211Eが搭載されています。

phy-mode = "rgmii-id";
→RGMII接続

ethernet_phy: ethernet-phy@0 {}
→EtherPHY情報

reg = <0>;
PHYのレジスタアドレス.どう決定されるのかは不明です。

GigabitEtherに関してはcompatible="marvell,88e1116r";のようにPHYドライバを指定しなくてよいのか?と考えました。実際古いZyboボードのデバイスツリーでは”REALTEK,RTL8211E”を指定していました。

Kernel 5.15.xのドライバソースを調べると、905行目にRTL8211Eの設定項目がありました。どうやらPHY-IDなるものをPHYチップから読み出してから、判別していそうです。

RTL8211Eのデータシートを見てみます。<8.1. Register Mapping and Definitions>にoffset2,3アドレスにPHY-IDレジスタが配置されています。

PHY Identifier Register 1 (MSB) = 0b0000000000011100=h001c
PHY Identifier Register 2 (LSB) = 0b1100100100010101=hc915

ドライバソースの”0x001cc915″とIDが一致しました。PHY-IDを読んで自動判別するようになったようです。便利になっとる…

6.デバイスツリーコンパイル

デバイスツリーソースファイル(.dts)をコンパイルし、デバイスツリーblobファイル(.dtb)を作成します。system-top.dtsと同じフォルダ階層に移動しコンパイルします。

【修正2023/9】
デバイスツリーコンパイルの方法が間違っていたため、プリコンパイル工程を追記しました。←プリコンパイル不要になりました(下記参照)

【修正2023/12】
XSCTでcreatedtsコマンドを使うとソース生成、プリコンパイル、デバイスツリーコンパイルをバッチ処理してくれることを知りました。プリコンパイルはもはや不要です。詳しくは”5-2. デバイスツリーソース生成“へ。

まず、#inclue周りや、ヘッダファイル(.h)周りのプリコンパイルを公式Wikiに沿って行います。system-top.dts.tmpプリコンパイル済みファイルが出来ます。

ShellScript
#カレントディレクトリをsystem-top.dtsのファイルと同じ階層に移動しておく
$ gcc -I ./ -E -nostdinc -undef -D__DTS__ -x assembler-with-cpp -o ./system-top.dts.tmp ./system-top.dts

system-top.dts.tmpをDTCコンパイルします。

$ dtc -I dts -O dtb <プリコンパイル済みソースファイル名>.dts.tmp -o <blobファイル名>.dtb

Bash
$ dtc -I dts -O dtb system-top.dts.tmp -o devicetree.dtb

.dtbを.dtsに戻す(デコンパイル)場合は以下のようにします。

Bash
$ dtc -I dtb -O dts devicetree.dtb -o devicetree.dts

9.最後に

本記事はなひたふ氏の著書「ZYNQで実用的なシステムを構築するための本」を参考に実践した内容です。本記事では一部しか内容を取り上げていません。もっとディープな内容がほしい方は是非買ってみてください。

ABOUT ME
sh-goto
組込エンジニア. 最近の遊びはLinuxの低レイヤいじりとXilinxのZynqとFPGAを使った電子工作
関連記事