⚙️

DTSバインディングについて(Zephyr OS)

2025/01/18に公開

DTSバインディングについて

はじめに

以下のzephyrドキュメントに書かれていることをベースに書き起こしたのみです。
(詳細はそちらを直に確認された方が早いかもしれません。。。)

https://docs.zephyrproject.org/latest/build/dts/bindings-intro.html

また、本記事は正確性に配慮して記述したつもりではありますが、私の知識不足で誤りが含まれている可能性もある旨、ご了承いただけましたら幸いです。

そもそもdtsとは

Device Tree Sourceの略称で、基板別に設定値を指定できるもの。
主にLinuxカーネルで利用されている。

このファイルは、CPUや基本理念は同じであるものの、一部の動作やMMIOが異なるような場面で活用できる。
例として、Raspberry PI3と4Bを例に挙げると、この二つは共通のCPUアーキテクチャ(aarch64)を用いて、ほぼ同じコードを動かすことができるが、一部アドレス(VideoCoreへのMBOXアドレス値など)が微妙に異なっていたりする。

このアドレスの差異を直に制御したい場合、通常は以下のようにコードへ直書きすることになる。

#ifdef RPI3
#define MBOX_ADDR xxx //rpi3のアドレス
#else if defined(RPI4B)
#define MBOX_ADDR xxx //rpi4のアドレス
#endif

// または以下のようにする(mbox_address.hは、ボード別に独立して用意しておきつつ、-Iの指定で切り替える)
#include "include/mbox_address.h" 

ボードの種類が少ないうちはこれで良いが、サポート対象が増えると手に負えない状態になっていく。(大半がPC/AT互換のx86系ならさほど問題にはならないのかもしれないが、組み込み系はとにかくバリエーションも組み合わせも多すぎる)
その対策として導入されたのがdtsという仕組みで、設定ファイル(dts)にボード別の設定値を書いておくだけで、各バリエーション毎に設定を気軽に切り替えられるようになった。
(より詳しくは、以下の記事様の方が何百倍も参考になる。)
https://www.silex.jp/library/blog/20240529-2

dtsバインディングとは

dtsを利用することで、デバイス別に設定値を定義することはできる。
一方で、dtsは単に値を設定するだけなので、値が絶対に必要なのか、あるいはオプションなのか、値の型はどうすれば良いのか等がわからない。

そこで登場するのがdtsバインディングという仕組みである。
これはyamlで記述するもので、あるデバイスのdts定義に必要な値、型を提供する。
(加えて、C/C++ソースから利用するためのマクロ生成も、このバインディングを用いて行われる。)

例えば、ある機能でnum-foosという値が必要だとする。
これをhoge-boardで実装する場合、以下のようにdtsを書くことになる。

/* Node in a DTS file */
bar-device {
    compatible = "foo-company,bar-device";
    num-foos = <3>;
};

これに対応するdtsバインディングは以下になる。

# A YAML binding matching the node

compatible: "foo-company,bar-device"

properties:
  num-foos:
    type: int
    required: true

yamlファイル(dtsバインディング)の中で、foo-company,bar-deviceを利用するためにはnum-foosをint型で定義する必要があることを規定しておくことで、dts側の型違いや定義もれを防げるようになる。
ちなみに、このチェックはZephyrのビルドフロー中で行われる。

最後に

概要としては上記の通りですが、実際にはyamlファイルのinclude等を組み合わせて、ややテクニカルに実現されている気がします。
私もまだ理解しきれていないですが、詳しくはzephyr以下dts/bindingフォルダーを見るのが参考になるかもしれません。

Discussion