DTSバインディングについて(Zephyr OS)
DTSバインディングについて
はじめに
以下のzephyrドキュメントに書かれていることをベースに書き起こしたのみです。
(詳細はそちらを直に確認された方が早いかもしれません。。。)
また、本記事は正確性に配慮して記述したつもりではありますが、私の知識不足で誤りが含まれている可能性もある旨、ご了承いただけましたら幸いです。
そもそも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)にボード別の設定値を書いておくだけで、各バリエーション毎に設定を気軽に切り替えられるようになった。
(より詳しくは、以下の記事様の方が何百倍も参考になる。)
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