デバイスツリーの使用法
このページでは、新しいマシン用のデバイスツリーの書き方について説明します。 デバイスツリーの概念の概要と、それらを使用してマシンを説明する方法を説明します。
デバイスツリーのデータフォーマットの技術的な詳細は、 ePAPR v1.1仕様を参照してください。 ePAPRの仕様は、このページで取り上げている基本的なトピックよりもはるかに多くの詳細を網羅しています。このページでは取り上げていない、より高度な使い方についてはそれを参照してください。 ePAPRは現在 、新しい名前のDevicetree Specification Documentationで更新されています。
内容 [ 隠す ]
1 基本データフォーマット
2つの 基本概念 2.1 サンプル機
2.2 初期構造
2.3 CPU
2.4 ノード名
2.5 デバイス
2.6 互換プロパティを理解する
3 アドレス指定のしくみ 3.1 CPUアドレッシング
3.2 メモリマップドデバイス
3.3 非メモリマップデバイス
3.4 範囲(アドレス変換)
4 割り込みのしくみ
5 機器固有のデータ
6つの 特別なノード 6.1 エイリアスノード
6.2 選ばれたノード
7 高度なトピック 7.1 高度なサンプルマシン
7.2 PCIホストブリッジ 7.2.1 PCIバスの番号付け
7.2.2 PCIアドレス変換
7.2.3 PCI DMAアドレス変換
7.3 高度な割り込みマッピング
8 リアクション
基本データフォーマット
デバイスツリーは、ノードとプロパティの単純なツリー構造です。 プロパティはキーと値のペアであり、ノードはプロパティと子ノードの両方を含むことができます。 たとえば、次は.dts形式の単純なツリーです。
/dts-v1/;
/ {
node1 {
a-string-property = "A string";
a-string-list-property = "first string", "second string";
// hex is implied in byte arrays. no '0x' prefix is required
a-byte-data-property = [01 23 34 56];
child-node1 {
first-child-property;
second-child-property = <1>;
a-string-property = "Hello, world";
};
child-node2 {
};
};
node2 {
an-empty-property;
a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */
child-node1 {
};
};
};
このツリーは何も記述していないので明らかに役に立ちませんが、ノードとプロパティの構造を示しています。以下に示す
・単一のルートノード: " / "
・2つの子ノード: " node1 "と " node2 "
・node1の2 child-node1 : " child-node1 "と " child-node2 "
・treeの至るところに散在するプロパティの束
プロパティは、値が空または任意のバイトストリームを含むことができる単純なキーと値のペアです。 データ型はデータ構造にエンコードされていませんが、デバイスツリーのソースファイルで表現できる基本的なデータ表現がいくつかあります。
テキスト文字列(nullで終わる)は二重引用符で表されます。 string-property = "a string";
'Cells'はダッシュで区切られた32ビットの符号なし整数です。 cell-property = <0xbeef 123 0xabcd1234>;
バイナリデータは大括弧で区切られます。 binary-property = [0x01 0x23 0x45 0x67];
異なる表現のデータは、コンマを使用して連結することができます。 mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;
コンマは、文字列のリストを作成するためにも使用されます。 string-list = "red fish", "blue fish";
基本概念
デバイスツリーがどのように使用されるかを理解するために、簡単なマシンから始めて、それを段階的に説明するためにデバイスツリーを構築します。
サンプル機
「Acme」(という架空のメーカ)によって製造され、「Coyote's Revenge」という名前の、次の仮想マシン(ARM Versatileを大まかにベースにしたもの)を考えてみます。
32ビットARM CPU×1
メモリマップドシリアルポートに接続されたプロセッサローカルバス、SPIバスコントローラ、i2cコントローラ、割り込みコントローラ、および外部バスブリッジ
0に基づく256MBのSDRAM
0x101F1000と0x101F2000に基づく2つのシリアルポート
0x101F3000に基づくGPIOコントローラ
以下のデバイスを使用する0x10170000ベースのSPIコントローラ SSピンがGPIO#1に接続されたMMCスロット
以下の装置を備えた外部バスブリッジ SMC SMC91111イーサネットデバイスは、外部バスに接続されています(0x10100000)。
以下のデバイスを使用する0x10160000に基づくi2cコントローラ マキシムDS1338リアルタイムクロック。 スレーブアドレス1101000(0x58)に応答
0x30000000に基づく64MBのNORフラッシュ
初期構造
第一歩は機械のための骨組構造を置くことである。 これは有効なデバイスツリーに最低限必要な構造です。 この段階では、マシンを一意に識別します。
/ dts-v1 /;
/ {
compatible = "acme、coyotes-revenge";
;
compatibleはシステムの名前を指定します。 "、"という形式の文字列が含まれます。正確なデバイスを指定し、名前空間の衝突を避けるために製造元名を含めることが重要です。オペレーティングシステムはcompatible値を使用して決定します。マシン上で実行するには、このプロパティに正しいデータを入れることが非常に重要です。
理論的には、互換性は、OSがマシンを一意に識別するために必要なすべてのデータです。 すべてのマシンの詳細がハードコードされている場合、OSはcompatible性のあるトップレベルプロパティで "acme、coyotes-revenge"を特に探すことができます。
CPU
次のステップは、各CPUについて説明することです。 「cpus」という名前のコンテナノードが、各CPUの子ノードとともに追加されます。 この場合、システムはARMのデュアルコアCortex A9システムです。
/ dts-v1 /;
/ {
compatible = "acme、coyotes-revenge";
CPU {
CPU @ 0 {
compatible = "arm、cortex-a9";
;
cpu @ 1 {
compatible = "arm、cortex-a9";
;
;
;
各cpuノードのcompatibleプロパティは、最上位レベルのcompatibleプロパティと同じように、 ,形式で正確なcpuモデルを指定する文字列です。
後でもっと多くのプロパティがcpuノードに追加されるでしょう、しかし最初にもっと基本的な概念について話す必要があります。
ノード名
命名規則について話すことは少し時間がかかることです。 すべてのノードは、 [@ ]の形式の名前を持つ必要があります。
は単純なASCII文字列で、長さは最大31文字です。 一般に、ノードはそれがどのような種類のデバイスを表すかに従って命名されます。 すなわち。 3comイーサネットアダプタのノードは3com509ではなくethernetという名前を使用しethernet 。
ノードがアドレスでデバイスを記述している場合、unit-addressが含まれます。 一般に、ユニットアドレスはデバイスへのアクセスに使用されるプライマリアドレスであり、ノードのregプロパティにリストされています。 この文書の後半でregプロパティについて説明します。
兄弟ノードには一意の名前を付ける必要がありますが、アドレスが異なる限り、複数のノードが同じ一般名を使用するのが普通です(すなわち、serial @ 101f1000&serial @ 101f2000)。
ノード命名の詳細については、ePAPR仕様のセクション2.2.1を参照してください。
デバイス
システム内のすべてのデバイスは、デバイスツリーノードによって表されます。 次のステップは、各デバイスのノードをツリーに追加することです。 今のところ、アドレス範囲とirqがどのように扱われるかについて話ができるまで新しいノードは空のままにされるでしょう。
/ dts-v1 /;
/ {
compatible = "acme、coyotes-revenge";
CPU {
CPU @ 0 {
compatible = "arm、cortex-a9";
;
cpu @ 1 {
compatible = "arm、cortex-a9";
;
;
シリアル@ 101F0000 {
compatible = "arm、pl011";
;
シリアル@ 101F2000 {
compatible = "arm、pl011";
;
gpio @ 101F3000 {
compatible = "arm、pl061";
;
割り込みコントローラ@ 10140000 {
compatible = "arm、pl190";
;
spi @ 10115000 {
compatible = "arm、pl022";
;
外部バス{
イーサネット@ 0,0 {
compatible = "smc、smc91c111";
;
i2c @ 1,0 {
compatible = "acme、a1234-i2c-bus";
rtc @ 58 {
compatible = "マキシム、ds1338";
;
;
フラッシュ@ 2,0 {
compatible = "samsung、k8f1315ebm"、 "cfi-flash";
;
;
;
このツリーでは、システム内の各デバイスにノードが追加されており、階層はデバイスがシステムにどのように接続されているかを反映しています。 すなわち。 外部バス上のデバイスは外部バスノードの子であり、i2cデバイスはi2cバスコントローラノードの子です。 一般に、階層はCPUから見たシステムのビューを表します。
この木は現時点では無効です。 デバイス間の接続に関する情報が不足しています。 そのデータは後で追加されます。
このツリーで注意すべきことがいくつかあります。
すべてのデバイスノードにはcompatibleプロパティがcompatibleます。
フラッシュノードのcompatibleプロパティには2つの文字列があります。 その理由については、次のセクションを読んでください。
前述のように、ノード名は特定のモデルではなくデバイスのタイプを反映しています。 可能な限り使用されるべき定義済みの一般的なノード名のリストについては、ePAPR仕様のセクション2.2.2を参照してください。
compatibleプロパティを理解する
デバイスを表すツリー内のすべてのノードには、 compatibleプロパティが必要です。 compatibleは、どのデバイスドライバをデバイスにバインドするかを決定するためにオペレーティングシステムが使用するキーです。
compatibleは文字列のリストです。 リストの最初の文字列は、ノードが表す","正確なデバイス","の形式で指定します。 次の文字列は、そのデバイスと互換性がある他のデバイスを表します。
たとえば、FreescaleのMPC8349システムオンチップ(SoC)には、National Semiconductorのns16550レジスタインタフェースを実装するシリアルデバイスがあります。 したがって、MPC8349シリアルデバイスのcompatibleプロパティは、 compatible = "fsl,mpc8349-uart", "ns16550"ます。 この場合、 fsl,mpc8349-uartは正確なデバイスを指定し、 ns16550はNational Semiconductor 16550 UARTとレジスタレベルの互換性があると述べています。
注: ns16550は歴史的な理由から製造元プレフィックスがありません。 互換性のある新しい値はすべて製造元プレフィックスを使用する必要があります。
この方法により、既存のデバイスドライバを新しいデバイスにバインドしながら、正確なハードウェアを一意に識別することができます。
警告: "fsl、mpc83xx-uart"などのようなワイルドカード互換の値を使用しないでください。 シリコンベンダは常に、ワイルドカードの想定を破るような変更を加えるでしょう。 代わりに、特定のシリコンの実装を選択し、それ以降のすべてのシリコンに互換性を持たせてください。
アドレス指定のしくみ
アドレス指定可能なデバイスは、アドレス情報をデバイスツリーにエンコードするために次のプロパティを使用します。
reg
#address-cells
#size-cells
各アドレス指定可能デバイスは、 reg reg = という形式のタプルのリストであるregを取得しreg = 。 各タプルは、デバイスによって使用されるアドレス範囲を表します。 各アドレス値は、 セルと呼ばれる1つ以上の32ビット整数のリストです。 同様に、長さの値はセルのリストか空のどちらかです。
addressフィールドとlengthフィールドはどちらも可変サイズであるため、親ノードの#address-cells #size-cellsプロパティと#size-cellsプロパティを使用して、各フィールドに含まれるセルの数を指定します。 または言い換えれば、regプロパティを正しく解釈するには、親ノードの#address-cellsおよび#size-cellsの値が必要です。 これらすべてがどのように機能するかを見るために、CPUから始めて、サンプルデバイスツリーにアドレス指定プロパティを追加しましょう。
CPUアドレス指定
アドレッシングについて話すとき、CPUノードは最も単純なケースを表します。 各CPUには一意のIDが1つ割り当てられ、CPU IDに関連付けられたサイズはありません。
CPU {
#address-cells = <1>;
#サイズセル= 0。
CPU @ 0 {
compatible = "arm、cortex-a9";
reg = 0;
;
cpu @ 1 {
compatible = "arm、cortex-a9";
reg = <1>;
;
;
cpusノードでは、 #address-cellsは1に設定され、 #size-cellsは0に設定されます。つまり、子reg値は、サイズフィールドのないアドレスを表す単一のuint32です。 この場合、2つのCPUにアドレス0と1が割り当てられます。各CPUには1つのアドレスしか割り当てられていないため、 #size-cellsはCPUノードでは0です。
また、 reg値がノード名の値と一致することにも気付くでしょう。 慣例により、ノードにregプロパティがある場合、ノード名にはreg propertyの最初のアドレス値であるunit-addressを含める必要があります。
メモリマップドデバイス
CPUノードで見られるような単一アドレス値の代わりに、メモリマップドデバイスはそれが応答するアドレスの範囲を割り当てられます。 #size-cellsは、各子regタプルの長さフィールドの#size-cellsために使用されます。 次の例では、各アドレス値は1セル(32ビット)で、各長さ値も1セルです。これは32ビットシステムでは一般的です。 64ビットマシンは、#address-cellsと#size-cellsに2の値を使用して、デバイスツリーで64ビットアドレッシングを行うことができます。
/ dts-v1 /;
/ {
#address-cells = <1>;
#size-cells = <1>;
...
シリアル@ 101f0000 {
compatible = "arm、pl011";
reg = <0x101f0000 0x1000>;
;
シリアル@ 101f2000 {
compatible = "arm、pl011";
reg = <0x101f2000 0x1000>;
;
gpio @ 101f3000 {
compatible = "arm、pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
;
割り込みコントローラ@ 10140000 {
compatible = "arm、pl190";
reg = <0x10140000 0x1000>;
;
spi @ 10115000 {
compatible = "arm、pl022";
reg = <0x10115000 0x1000>;
;
...
;
各デバイスには、ベースアドレスと、割り当てられている領域のサイズが割り当てられています。 この例のGPIOデバイスアドレスには、2つのアドレス範囲が割り当てられています。 0x101f3000 ... 0x101f3fffおよび0x101f4000..0x101f400f。
一部のデバイスは、異なるアドレス指定方式でバス上にあります。 例えば、装置は個別のチップ選択線を用いて外部バスに取り付けることができる。 各親ノードはその子に対するアドレッシングドメインを定義するので、アドレスマッピングはシステムを最もよく表すように選択することができる。 以下のコードは、チップセレクト番号をアドレスにエンコードした、外部バスに接続されたデバイスのアドレス割り当てを示しています。
外部バス{
#address-cells = <2>;
#size-cells = <1>;
イーサネット@ 0,0 {
compatible = "smc、smc91c111";
reg = <0 0 0x1000>;
;
i2c @ 1,0 {
compatible = "acme、a1234-i2c-bus";
reg = <1 0 0x1000>;
rtc @ 58 {
compatible = "マキシム、ds1338";
;
;
フラッシュ@ 2,0 {
compatible = "samsung、k8f1315ebm"、 "cfi-flash";
reg = <2 0 0x4000000>;
;
;
external-busはアドレス値に2つのセルを使用します。 1つはチップセレクト番号用、もう1つはチップセレクトのベースからのオフセット用です。 アドレスのオフセット部分だけが範囲を持つ必要があるので、長さフィールドは単一セルのままです。 したがって、この例では、各regエントリに3つのセルが含まれています。 チップ選択番号、オフセット、および長さ
アドレスドメインはノードとその子に含まれるので、親ノードはバスにとって意味のあるアドレス指定方式を自由に定義できます。 直接の親ノードと子ノードの外側にあるノードは、通常、ローカルアドレスドメインを気にする必要はなく、アドレスはあるドメインから別のドメインに移動するためにマッピングされる必要があります。
非メモリマップデバイス
他のデバイスはプロセッサバス上でメモリマップされていません。 それらはアドレス範囲を持つことができますが、CPUから直接アクセスすることはできません。 代わりに、親デバイスのドライバがCPUに代わって間接アクセスを実行します。
i2cデバイスの例を挙げると、各デバイスにはアドレスが割り当てられていますが、それに関連する長さや範囲はありません。 これは、CPUアドレスの割り当てとほとんど同じです。
i2c @ 1,0 {
compatible = "acme、a1234-i2c-bus";
#address-cells = <1>;
#サイズセル= 0。
reg = <1 0 0x1000>;
rtc @ 58 {
compatible = "マキシム、ds1338";
reg = <58>;
;
;
範囲(アドレス変換)
デバイスにアドレスを割り当てる方法については説明しましたが、現時点ではこれらのアドレスはデバイスノードに対してローカルです。 それらのアドレスからCPUが使用できるアドレスへのマッピング方法についてはまだ説明していません。
ルートノードは常にアドレス空間に対するCPUの見方を記述します。 ルートの子ノードはすでにCPUのアドレスドメインを使用しているため、明示的なマッピングは不要です。 たとえば、シリアル@ 101f0000デバイスにはアドレス0x101f0000が直接割り当てられます。
ルートの直接の子ではないノードは、CPUのアドレスドメインを使用しません。 メモリマップアドレスを取得するには、デバイスツリーでドメイン間でアドレスを変換する方法を指定する必要があります。 rangesプロパティはこの目的に使用されます。
これは、rangeプロパティが追加されたサンプルデバイスツリーです。
/ dts-v1 /;
/ {
compatible = "acme、coyotes-revenge";
#address-cells = <1>;
#size-cells = <1>;
...
外部バス{
#address-cells = <2>
#size-cells = <1>;
範囲= <0 0 0x10100000 0x10000 // Chipselect 1、イーサネット
1 0 0x10160000 0x10000 // Chipselect 2、i2cコントローラー
2 0 0x30000000 0x1000000>; // Chipselect 3、NORフラッシュ
イーサネット@ 0,0 {
compatible = "smc、smc91c111";
reg = <0 0 0x1000>;
;
i2c @ 1,0 {
compatible = "acme、a1234-i2c-bus";
#address-cells = <1>;
#サイズセル= 0。
reg = <1 0 0x1000>;
rtc @ 58 {
compatible = "マキシム、ds1338";
reg = <58>;
;
;
フラッシュ@ 2,0 {
compatible = "samsung、k8f1315ebm"、 "cfi-flash";
reg = <2 0 0x4000000>;
;
;
;
rangesはアドレス変換のリストです。 範囲テーブルの各エントリは、子アドレス、親アドレス、および子アドレススペース内の領域のサイズを含むタプルです。 各フィールドのサイズは、子の#address-cells値、親の#address-cells値、および子の#size-cells値を#size-cellsます。 この例の外部バスの場合、子アドレスは2セル、親アドレスは1セル、サイズも1セルです。 3つの範囲が翻訳されています:
チップセレクト0からのオフセット0は、アドレス範囲0x10100000..0x1010ffffにマッピングされます。
チップセレクト1からのオフセット0は、アドレス範囲0x10160000..0x1016ffffにマッピングされます。
チップセレクト2からのオフセット0はアドレス範囲0x30000000..0x30ffffffにマッピングされます
あるいは、親アドレス空間と子アドレス空間が同一の場合、ノードは代わりに空のrangesプロパティを追加できます。 空の範囲プロパティが存在するということは、子アドレス空間内のアドレスが1:1で親アドレス空間にマッピングされることを意味します。
1:1マッピングですべてのアドレス変換を記述できるのに、なぜアドレス変換がまったく使用されないのかを尋ねることができます。 一部のバス(PCIなど)は完全に異なるアドレス空間を持ち、その詳細はオペレーティングシステムに公開する必要があります。 他のものはバスの本当のアドレスを知る必要があるDMAエンジンを持っています。 すべてのデバイスが同じソフトウェアプログラマブル物理アドレスマッピングを共有しているため、デバイスをまとめてグループ化する必要がある場合があります。 1:1マッピングを使用するかどうかは、オペレーティングシステムが必要とする情報とハードウェア設計によって大きく異なります。
また、i2c @ 1,0ノードにはrangeプロパティはありません。 その理由は、外部バスとは異なり、i2cバス上のデバイスはCPUのアドレスドメインにメモリマップされていないためです。 代わりに、CPUはi2c @ 1,0デバイスを介してrtc @ 58デバイスに間接的にアクセスします。 rangesプロパティがないということは、親デバイス以外のデバイスからデバイスに直接アクセスできないということです。
割り込みのしくみ
ツリーの自然な構造に従うアドレス範囲変換とは異なり、割り込み信号はマシン内の任意のデバイスから発信され、そこで終了します。 デバイスツリーで自然に表現されるデバイスアドレス指定とは異なり、割り込み信号はツリーから独立したノード間のリンクとして表現されます。 割り込み接続を記述するために4つのプロパティが使用されます。
interrupt-controller - 割り込み信号を受信するデバイスとしてノードを宣言する空のプロパティ
#interrupt-cells - これは割り込みコントローラノードのプロパティです。 この割り込みコントローラの割り込み指定子に含まれるセルの数を示します ( #address-cellsおよび#size-cellsと同様)。
interrupt-parent - 接続されている割り込みコントローラへのファンドルを含むデバイスノードのプロパティ。 interrupt-parentプロパティを持たないノードも、その親ノードからプロパティを継承できます。
interrupts - デバイス上の各割り込み出力信号ごとに1つの、 割り込み指定子のリストを含むデバイスノードのプロパティ。
割り込み指定子は、(#interrupt-cellsで指定された)データの1つ以上のセルで、デバイスがどの割り込み入力に接続されているかを指定します。 以下の例に示すように、ほとんどのデバイスは単一の割り込み出力しか持ちませんが、1つのデバイスに複数の割り込み出力を持つことが可能です。 割り込み指定子の意味は、割り込みコントローラデバイスのバインディングに完全に依存します。 各割り込みコントローラは、割り込み入力を一意に定義するために必要なセル数を決定できます。
次のコードは、CoyoteのRevengeサンプルマシンに割り込み接続を追加します。
/ dts-v1 /;
/ {
compatible = "acme、coyotes-revenge";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
CPU {
#address-cells = <1>;
#サイズセル= 0。
CPU @ 0 {
compatible = "arm、cortex-a9";
reg = 0;
;
cpu @ 1 {
compatible = "arm、cortex-a9";
reg = <1>;
;
;
シリアル@ 101f0000 {
compatible = "arm、pl011";
reg = <0x101f0000 0x1000>;
割り込み= <1 0>。
;
シリアル@ 101f2000 {
compatible = "arm、pl011";
reg = <0x101f2000 0x1000>;
割り込み= <2 0>。
;
gpio @ 101f3000 {
compatible = "arm、pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
割り込み= <3 0>。
;
intc: interrupt-controller @ 10140000 {
compatible = "arm、pl190";
reg = <0x10140000 0x1000>;
割り込みコントローラ
#interrupt-cells = <2>;
;
spi @ 10115000 {
compatible = "arm、pl022";
reg = <0x10115000 0x1000>;
割り込み= <4 0>。
;
外部バス{
#address-cells = <2>
#size-cells = <1>;
範囲= <0 0 0x10100000 0x10000 // Chipselect 1、イーサネット
1 0 0x10160000 0x10000 // Chipselect 2、i2cコントローラー
2 0 0x30000000 0x1000000>; // Chipselect 3、NORフラッシュ
イーサネット@ 0,0 {
compatible = "smc、smc91c111";
reg = <0 0 0x1000>;
割り込み= <5 2>。
;
i2c @ 1,0 {
compatible = "acme、a1234-i2c-bus";
#address-cells = <1>;
#サイズセル= 0。
reg = <1 0 0x1000>;
割り込み= <6 2>。
rtc @ 58 {
compatible = "マキシム、ds1338";
reg = <58>;
割り込み= <7 3>。
;
;
フラッシュ@ 2,0 {
compatible = "samsung、k8f1315ebm"、 "cfi-flash";
reg = <2 0 0x4000000>;
;
;
;
注意すべき点がいくつかあります。
このマシンには、割り込みコントローラ@ 10140000という単一の割り込みコントローラがあります。
ラベル 'intc:'が割り込みコントローラノードに追加され、ラベルはルートノードのinterrupt-parentプロパティにファンドルを割り当てるために使用されました。 明示的にオーバーライドされない限り、すべての子ノードがそれを継承するため、このinterrupt-parent値はシステムのデフォルトになります。
各デバイスは割り込みプロパティを使用して、異なる割り込み入力ラインを指定します。
#interrupt-cellsは2なので、各割り込み指定子には2つのセルがあります。 この例では、最初のセルを使用して割り込みライン番号をエンコードし、2番目のセルを使用してアクティブハイとアクティブロー、またはエッジとレベルセンシティブなどのフラグをエンコードするという一般的なパターンを使用します。 特定の割り込みコントローラについては、コントローラのバインディングのドキュメントを参照して、指定子のエンコード方法を確認してください。
装置固有のデータ
共通のプロパティ以外に、任意のプロパティと子ノードをノードに追加できます。 いくつかの規則に従う限り、オペレーティングシステムに必要なデータはすべて追加できます。
まず、新しいデバイス固有のプロパティ名は、既存の標準プロパティ名と競合しないように製造プレフィックスを使用する必要があります。
次に、デバイスドライバの作成者がデータの解釈方法を認識できるように、プロパティと子ノードの意味をバインディングに文書化する必要があります。 バインディングは、特定の互換性のある値が何を意味するのか、それが持つべきプロパティ、持つべき子ノード、そしてそれが表すデバイスを文書化します。 それぞれのユニークなcompatible値はそれ自身の束縛を持つべきです(または他の互換性のある値との互換性を主張する)。 新しいデバイスのためのバインディングはこのWikiに文書化されています。 文書形式とレビュープロセスの説明については、 メインページを参照してください。
3つ目は、devicetree-discuss @ lists.ozlabs.orgメーリングリストにレビュー用の新しいバインディングを投稿してください。 新しいバインディングを確認すると、将来問題を引き起こす可能性がある多くの一般的な間違いが見つかります。
特別なノード
aliasesノード
特定のノードは通常、 /external-bus/ethernet@0,0ようにフルパスで参照されますが、ユーザーが本当に知りたいのは「どのデバイスがeth0ですか?」という場合、これは面倒です。 aliasesノードを使用して、短いエイリアスをフルデバイスパスに割り当てることができます。 例えば:
エイリアス{
ethernet0 =&eth0;
serial0 =&serial0;
;
オペレーティングシステムは、デバイスに識別子を割り当てるときにエイリアスを使用することを歓迎します。
ここで使用されている新しい構文に気付くでしょう。 property = & label ; 構文は、ラベルによって参照されるフルノードパスを文字列プロパティとして割り当てます。 これはphandle = < & label >;とは異なりphandle = < & label >; セルにphandle値を挿入する、以前に使用された形式。
chosenノード
chosenノードは実際のデバイスを表すものではありませんが、ブート引数のようにファームウェアとオペレーティングシステムの間でデータをやり取りするための場所として機能します。 選択したノードのデータはハードウェアを表していません。 通常、選択されたノードは.dtsソースファイルでは空のままにされ、起動時に読み込まれます。
この例のシステムでは、ファームウェアは選択されたノードに次のものを追加します。
選ばれた{
; bootargs = "root = / dev / nfs rw nfsroot = 192.168.1.1 console = ttyS0,115200";
;
高度なトピック
高度なサンプル機
基本が定義されたので、サンプルマシンにハードウェアを追加して、より複雑なユースケースについて説明しましょう。
アドバンストサンプルマシンでは、0x10180000にマッピングされたメモリと、アドレス0x80000000を超えて開始するようにプログラムされた制御レジスタを持つPCIホストブリッジを追加しています。
デバイスツリーについてすでに知っていることを考えると、PCIホストブリッジを説明するために次のノードを追加することから始めることができます。
pci @ 10180000 {
compatible = "arm、versatile-pci-hostbridge"、 "pci";
reg = <0x10180000 0x1000>;
割り込み= <8 0>。
;
PCIホストブリッジ
このセクションでは、ホスト/ PCIブリッジノードについて説明します。
このセクションでは、PCIに関する基本的な知識がいくつか想定されています。 これはPCIに関するチュートリアルではありません。さらに詳しい情報が必要な場合は、 [1]を読んでください。 ePAPR v1.1またはOpen FirmwareへのPCI Bus Bindingのいずれかを参照することもできます。 Freescale MPC5200の完全な実用例はここにあります 。
PCIバス番号
各PCIバスセグメントには一意の番号が付けられ、バスの番号は2つのセルを含むbus-rangesプロパティを使用してpciノードに表示されます。 最初のセルはこのノードに割り当てられているバス番号を示し、2番目のセルは下位のPCIバスのうちのいずれかの最大バス番号を示します。
サンプルマシンは単一のpciバスを持っているので、両方のセルは0です。
pci @ 0x10180000 {
compatible = "arm、versatile-pci-hostbridge"、 "pci";
reg = <0x10180000 0x1000>;
割り込み= <8 0>。
バス範囲= <0 0>。
;
PCIアドレス変換
前述のローカルバスと同様に、PCIアドレス空間はCPUアドレス空間とは完全に分離されているため、PCIアドレスからCPUアドレスへの変換にはアドレス変換が必要です。 いつものように、これはrange 、 #address-cells 、 #size-cellsプロパティを使って行われます。
pci @ 0x10180000 {
compatible = "arm、versatile-pci-hostbridge"、 "pci";
reg = <0x10180000 0x1000>;
割り込み= <8 0>。
バス範囲= <0 0>。
#address-cells = <3>
#size-cells = <2>;
範囲= < 0x42000000 0 0x80000000 0x80000000 0 0x20000000
0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
0x01000000 0 0x00000000 0xb0000000 0 0x01000000 >;
;
ご覧のとおり、 子アドレス (PCIアドレス)は3つのセルを使用し、PCI範囲は2つのセルにエンコードされています。 最初の質問は、PCIアドレスを指定するのになぜ3つの32ビットセルが必要なのかということです。 3つのセルにはphys.hi、phys.mid、phys.lowというラベルが付いています[2] 。
phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr
phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
phys.low cell: llllllll llllllll llllllll llllllll
PCIアドレスは64ビット幅で、phys.midとphys.lowにエンコードされています。 しかし、本当に興味深いことはphys.highにあります。これは少しフィールドです。
n :リロケータブル領域フラグ(ここでは役割を果たしていません)
p :プリフェッチ可能(キャッシュ可能)リージョンフラグ
t :エイリアスアドレスフラグ(ここでは役割を果たしていません)
ss :スペースコード 00:設定スペース
01:入出力スペース
10:32ビットメモリ空間
11:64ビットメモリ空間
bbbbbbbb :PCIバス番号 PCIは階層的に構成することができる。 そのため、サブバスを定義するPCI / PCIブリッジがあるかもしれません。
ddddd :通常IDSEL信号接続に関連付けられているデバイス番号。
fff :機能番号です。 多機能PCIデバイスに使用されます。
rrrrrrrr :レジスタ番号。 構成サイクルに使用されます。
PCIアドレス変換の目的上、重要なフィールドはpとssです。 phys.hiのpとssの値によって、どのPCIアドレス空間にアクセスするかが決まります。 それで私たちの範囲プロパティを見て、私たちは3つの領域があります:
ホストCPUのアドレス0x80000000にマッピングされる512 MBのサイズのPCIアドレス0x80000000から始まる32ビットのプリフェッチ可能なメモリ領域。
ホストCPU上のアドレス0xa0000000にマップされる256 MBサイズのPCIアドレス0xa0000000から始まる32ビットのプリフェッチ不可メモリ領域。
ホストCPU上のアドレス0xb0000000にマップされる、16 MBサイズのPCIアドレス0x00000000から始まるI / O領域。
作業にレンチを投げるために、phys.hiビットフィールドの存在は、オペレーティングシステムが、変換の目的で無関係なフィールドを無視できるように、ノードがPCIブリッジを表していることを知る必要があることを意味します。 OSは、PCIバスノード内の文字列「pci」を探して、余分なフィールドをマスクする必要があるかどうかを判断する。
PCI DMAアドレス変換
上記の範囲は、CPUがPCIメモリをどのように認識するかを定義し、CPUが正しいメモリウィンドウを設定し、さまざまなPCIデバイスレジスタに正しいパラメータを書き込むのに役立ちます。 これはアウトバウンドメモリとも呼ばれます 。
アドレス変換の特別な場合は、PCIホストハードウェアがシステムのコアメモリをどのように認識するかに関するものです。 これは、PCIホストコントローラがマスターとして機能し、システムのコアメモリに個別にアクセスするときに発生します。 これは多くの場合CPUのビューとは異なるビューであるため(メモリラインの配線方法による)、初期化時にこれをPCIホストコントローラにプログラムする必要があるかもしれません。 これは、PCIバスが独立して直接メモリアクセスを実行するため、一種のDMAと見なされ 、このためマッピングはdma-rangeと呼ばれます 。 このタイプのメモリマッピングは、 インバウンドメモリとも呼ばれ、PCIデバイスツリー仕様の一部ではありません。
場合によっては、ブート時にROM(BIOS)などでこれらのレジスタを設定しますが、他の場合では、PCIコントローラは完全に初期化されていないため、これらの変換はデバイスツリーから設定する必要があります。 PCIホストドライバは、通常、dma-rangeプロパティを解析し、それに応じてホストコントローラ内のいくつかのレジスタを設定します。
上記の例を拡張します。
pci @ 0x10180000 {
compatible = "arm、versatile-pci-hostbridge"、 "pci";
reg = <0x10180000 0x1000>;
割り込み= <8 0>。
バス範囲= <0 0>。
#address-cells = <3>
#size-cells = <2>;
範囲= <0x42000000 0 0x80000000 0x80000000 0 0x20000000
0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
0x01000000 0 0x00000000 0xb0000000 0 0x01000000
dma-range = < 0x02000000 0 0x00000000 0x80000000 0 0x20000000 >;
;
このdma-rangeエントリは、PCIホストコントローラの観点からは、PCIアドレス0x00000000の 512 MBがメインコアメモリのアドレス0x80000000に表示されることを示しています。 ご覧のとおり、 ssアドレスタイプを0x02に設定すると、32ビットメモリになります。
高度な割り込みマッピング
それでは、最も興味深い部分、PCI割り込みマッピングについて説明します。 PCIデバイスは、#INTA、#INTB、#INTC、および#INTDワイヤを使用して割り込みをトリガできます。 単機能デバイスは、割り込みに#INTAを使用する必要があります。 多機能デバイスは、1つの割り込みピンを使用する場合は#INTAを使用し、2つの割り込みピンを使用する場合は#INTAおよび#INTBなどを使用する必要があります。 、そして#INTD。 #INTAから#INTDまでの4つのIRQラインに負荷を分散するには、すべての#INTAクライアントが同じ着信割り込みラインに接続されないように、通常、各PCIスロットまたはデバイスを割り込みコントローラの異なる入力に回転方式で配線します。 。 この手順は割り込みのスウィズルと呼ばれます。 そのため、デバイスツリーには、各PCI割り込み信号を割り込みコントローラの入力にマッピングする方法が必要です。 #interrupt-cells 、 interrupt-map 、およびinterrupt-map-maskプロパティは、割り込みマッピングを記述するために使用されます。
実際には、ここで説明する割り込みマッピングはPCIバスに限定されず、どのノードでも複雑な割り込みマップを指定できますが、PCIの場合が最も一般的です。
pci @ 0x10180000 {
compatible = "arm、versatile-pci-hostbridge"、 "pci";
reg = <0x10180000 0x1000>;
割り込み= <8 0>。
バス範囲= <0 0>。
#address-cells = <3>
#size-cells = <2>;
範囲= <0x42000000 0 0x80000000 0x80000000 0 0x20000000
0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = < 0xc000 0 0 1 &intc 9 3 // 1番目のスロット
0xc000 0 0 2 &intc 10 3
0xc000 0 0 3 &intc 11 3
0xc000 0 0 4 &intc 12 3
0xc800 0 0 1 &intc 10 3 // 2番目のスロット
0xc800 0 0 2 &intc 11 3
0xc800 0 0 3 &intc 12 3
0xc800 0 0 4 &intc 9 3 >;
;
まず、2つのセルを使用するシステム割り込みコントローラとは異なり、PCI割り込み番号は1つのセルしか使用しないことに気付くでしょう。1つはirq番号用、もう1つはflags用です。PCI割り込みは常にレベルローセンシティブになるように指定されているため、PCIは割り込み用に1セルしか必要としません。
この例のボードでは、それぞれ4つの割り込みラインを持つ2つのPCIスロットがあるので、8つの割り込みラインを割り込みコントローラにマップする必要があります。これはinterrupt-mapプロパティを使って行われます。割り込みマッピングの正確な手順は[3]に記載されています。
割り込み番号(#INTAなど)は単一のPCIバス上の複数のPCIデバイスを区別するのに十分ではないため、どのPCIデバイスが割り込みラインをトリガーしたかを示す必要があります。幸いなことに、すべてのPCIデバイスには固有のデバイス番号があります。いくつかのPCIデバイスの割り込みを区別するために、PCIデバイス番号とPCI割り込み番号からなるタプルが必要です。より一般的に言えば、4つのセルを持つユニット割り込み指定子を構築します。
phys.hi、phys.mid、phys.low、およびからなる3つの#アドレスセル
1つの#interrupt-cell(#INTA、#INTB、#INTC、#INTD)。
PCIアドレスのデバイス番号部分だけが必要なので、interrupt-map-maskプロパティが有効になります。interrupt-map-maskも、ユニット割り込み指定子のように4タプルです。マスクの1は、ユニット割り込み指定子のどの部分を考慮に入れるかを示します。この例では、phys.hiのデバイス番号部分のみが必要で、4つの割り込みラインを区別するために3ビットが必要であることがわかります(PCI割り込みラインのカウントは0ではなく1から始まります)。
これで、割り込みマッププロパティを構築できます。このプロパティはテーブルで、このテーブルの各エントリは、子(PCIバス)ユニットの割り込み指定子、親ハンドル(割り込み処理を担当する割り込みコントローラ)、および親ユニットの割り込み指定子で構成されています。したがって、最初の行で、PCI割り込み#INTAがIRQ 9にマッピングされていることがわかります。これは、割り込みコントローラの影響を受けにくいレベルです。 [4] 。
今のところ欠けているのは、PCIバスユニットの割り込み指定子にある奇妙な数字だけです。ユニット割り込み指定子の重要な部分はphys.hiビットフィールドのデバイス番号です。デバイス番号はボード固有であり、各PCIホストコントローラが各デバイスのIDSELピンをどのようにアクティブにするかによって異なります。この例では、PCIスロット1にデバイスID 24(0x18)が割り当てられ、PCIスロット2にデバイスID 25(0x19)が割り当てられています。各スロットのphys.hiの値は、次のようにデバイス番号をビットフィールドのdddddセクションに11ビットだけシフトアップすることによって決定されます。
スロット1のphys.hiは0xC000です。
スロット2のphys.hiは0xC800です。
それをまとめてinterrupt-mapプロパティにまとめます。
スロット1の#INTAはIRQ9で、プライマリー割り込みコントローラーでレベルローセンシティブ
スロット1の#INTBはIRQ10で、プライマリー割り込みコントローラーでは低感度です。
スロット1の#INTCはIRQ11で、プライマリー割り込みコントローラーでは低感度です。
スロット1の#INTDはIRQ12で、プライマリー割り込みコントローラーでレベルローセンシティブ
そして
スロット2の#INTAはIRQ10で、プライマリー割り込みコントローラーでは低感度です。
スロット2の#INTBはIRQ11で、プライマリー割り込みコントローラーでは低感度です。
スロット2の#INTCはIRQ12で、プライマリー割り込みコントローラーでは低感度です。
スロット2の#INTDはIRQ9で、プライマリー割り込みコントローラーでレベルローセンシティブ
このinterrupts = <8 0>;プロパティは、ホスト/ PCIブリッジコントローラ自体が引き起こす可能性のある割り込みを表します。これらの割り込みをPCIデバイスが引き起こす可能性のある割り込みと混同しないでください(INTA、INTBなどを使用)。
最後に注意することが1つあります。interrupt-parentプロパティと同様に、ノードにinterrupt-mapプロパティが存在すると、すべての子ノードと孫ノードのデフォルトの割り込みコントローラが変更されます。このPCIの例では、PCIホストブリッジがデフォルトの割り込みコントローラになります。PCIバス経由で接続されているデバイスが別の割り込みコントローラに直接接続されている場合は、独自のinterrupt-parentプロパティも指定する必要があります。