デバイスツリーの一般的な方法の分析

 

デバイスツリーの一般的な方法の分析

Linuxカーネルドライバーでのデバイスツリーの使用は、2011年3月17日のARMLinuxメーリングリストのLinusTorvaldsからの電子メールに端を発しています。彼は「このARM全体がお尻に苦痛を与えている」と宣言し、PowerPCの学習を提唱しました。他のアーキテクチャは、デバイスツリーテクノロジを成熟させています。それ以来、DeviceTreeはARMコミュニティの視野に正式に参入しました。

1.機能

デバイスツリーは、ハードウェアを記述するために使用されるデータ構造であり、OpenFirmware(OF)に由来するボードレベルの記述言語に似ています。現在広く使用されているLinuxカーネル2.6.xバージョンでは、さまざまなプラットフォームとさまざまなハードウェアに対して、これらのさまざまなプラットフォームとさまざまなハードウェアへの特別な適応のニーズを満たすために、多くの場合、移植性に欠けるさまざまなボードレベルの記述コードが多数あります。 。ただし、プラットフォームやハードウェアが多すぎると、そのようなコードがますます増え、最終的にLinuxの創設者であるLinusに不満が生じ、変更が強く求められました。デバイスツリーの導入は、ドライバーの適応に非常に便利です。デバイスツリーの完全なセットは、PCBを目の前に置くことができます。デバイスツリーはCPUを記述でき、クロック、割り込みコントローラー、IOコントローラー、SPIバスコントローラー、I2Cコントローラー、ストレージデバイスなどの既存のドライブユニットを記述できます。特定のデバイスについて、使用される割り込み、メモリマッピングスペースの量などを記述できます。

2.基本的なデータ形式

デバイスツリーは、ノードと属性で構成されています。属性はキーと値のペアであり、ノードにはさまざまな属性が含まれ、子ノードを含めることもできます。簡単なdtsファイルは次のとおりです。

 
  1. / {

  2. node1 {

  3. a-string-property = "A string";

  4. a-string-list-property = "first string", "second string";

  5. a-byte-data-property = [0x01 0x23 0x34 0x56];

  6. child-node1 {

  7. first-child-property;

  8. second-child-property = <1>;

  9. a-string-property = "Hello, world";

  10. };

  11. child-node2 {

  12. };

  13. };

  14. node2 {

  15. an-empty-property;

  16. a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */

  17. child-node1 {

  18. };

  19. };

  20. };

このファイルには実際には意味がありませんが、すべての基本的な要素が含まれています。

  • 1唯一のルートノード「/」
  • 2一部のノード:node1 node2
  • 3子ノードnode1の子ノードchild-node1およびchild-node2
  • 4散在する属性のグループ

属性は単純なキーと値のペアであり、値は空にすることも、任意のバイトストリームを含めることもできます。以下は、いくつかの属性の基本的なデータ構造です。

  • 1二重引用符で囲まれた文字情報

      string-property = "a string";
  • 2セルの単位情報は32ビットの符号なし整数データです

      cell-property = <0xFF01 412 0x12341283>;
  • 3バイナリデータストリーム

      binary-property = [0x01 0x02 0x03 0x04];
  • 4混合データをコンマで区切ります

      mixed-property = "a string", [0x01 0x02 0x03 0x04], <0xFF01 412 0x12341283>;
  • 5文字リスト

      string-list = "string test1", "string test2";

3.いくつかの基本的な概念

  • 完全な各dtsファイルにはルートノードが必要です
  • dtsiファイルは一般に一般的なファイル(C言語のヘッダーファイルと同様)であり、他のファイル
    インクルードの背後にある名前カバーできます。一致する場合は、このdtsに基づいて初期化および開始されます。
  • 親ノード名は、IC名ではなく、タイプ名である必要があります。ノード名の命名規則は通常[name] @ [address]であるか、@の後にコンテンツがない名前のみを持つことができますが、名前が同じであってはならないことを確認してください。@とアドレスを追加した場合、アドレスが異なる限り、名前は同じにすることができます。
  • 各デバイスノードには互換性のある属性が必要です
  • 互換性のあるコンテンツを使用してドライバーを照合します。構成方法は「[manufacturer]、[model]」です。重複を避けるためにベンダー名を追加しています。次のような名前が続く場合があります。

      compatible = "acme,coyotes-revenge", "acmd-board";

4.作業方法

a。住所

デバイスのアドレス特性は、次の属性に従って制御されます。

  • reg
  • #address-cells
  • #size-cells

regは地域を意味します。形式は次のとおりです。

reg = <address1 length1 [address2 length2] [address3 length3]>;

親クラスのアドレスセルとサイズセルは、サブクラスの関連属性に含まれるセルの数を決定します。子ノードに特別なニーズがある場合は、親ノードの制御を取り除くことができるように、子ノードを自分で定義できます。 。
Address-cellsは、アドレス1/2/3に含まれるセルの数を決定し、size-cellsは、長さ1/2/3に含まれるセルの数を決定します。次のようなローカルモジュール:

 
  1. spi@10115000 {

  2. compatible = "arm,pl022";

  3. reg = <0x10115000 0x1000 >;

  4. };

0x10115000にあるSPIデバイスがアドレス空間に適用されます。開始アドレスは0x10115000、長さは0x1000です。つまり、このSPIデバイスのアドレス範囲は0x10115000〜0x10116000です。

実際のアプリケーションでは、外部チップチップの選択によってモジュールをアクティブ化するという別の状況があります。たとえば、外部バスにマウントされたときにチップセレクトラインを介して動作する必要がある一部のモジュール:

 
  1. external-bus {

  2. #address-cells = <2>

  3. #size-cells = <1>;

  4.  
  5. ethernet@0,0 {

  6. compatible = "smc,smc91c111";

  7. reg = <0 0 0x1000>;

  8. };

  9.  
  10. i2c@1,0 {

  11. compatible = "acme,a1234-i2c-bus";

  12. #address-cells = <1>;

  13. #size-cells = <0>;

  14. reg = <1 0 0x1000>;

  15. rtc@58 {

  16. compatible = "maxim,ds1338";

  17. reg = <58>;

  18. };

  19. };

  20.  
  21. flash@2,0 {

  22. compatible = "samsung,k8f1315ebm", "cfi-flash";

  23. reg = <2 0 0x4000000>;

  24. };

  25. };

外部バスは2つのセルを使用してアドレスを記述します。1つはチップセレクトシーケンス番号で、もう1つはチップセレクトシーケンス番号のオフセットです。アドレス空間の長さは、セルによって記述されます。したがって、上記のサブデバイスはすべて、アドレス空間の属性(チップセレクト、オフセット、アドレス長)を記述するために3つのセルを必要とします。前の例では、i2cコントローラーモジュールの下にあるrtcモジュールという例外があります。I2Cデバイスは1つのアドレスにのみ割り当てられ、他のスペースを必要としないため、完全に記述できるアドレスセルは1つだけであり、サイズセルは必要ありません。

記述対象のデバイスがローカルデバイスでない場合は、デバイスアドレス空間からCPUアドレス空間へのマッピング関係を記述し、ここでranges属性を使用する必要がありますまたは、上記の外部バスの例:

 
  1. #address-cells = <1>;

  2. #size-cells = <1>;

  3. ...

  4. external-bus {

  5. #address-cells = <2>

  6. #size-cells = <1>;

  7. ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet

  8. 1 0 0x10160000 0x10000 // Chipselect 2, i2c controller

  9. 2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash

  10. };

ranges属性は、アドレス変換テーブルです。表の各行には、子アドレス、親アドレス、および自己アドレス空間の領域サイズが含まれています。それらのサイズ(含まれるセル)は、子ノードのアドレスセルの値、親ノードのアドレスセルの値、および子ノードのサイズセルによって決定されます。例として最初の行を取り上げます。

  • 00子ノード外部バスのaddress-cells = <2>によって決定される2つのセル。
  • 0x10100000親ノードのaddress-cells = <1>によって決定されるセル。
  • 0x10000子ノード外部バスのsize-cells = <1>によって決定されるセル。
    最後に、最初の行の説明の意味は次のとおりです。チップセレクト0、オフセット0(ネットワークカードが選択されている)。これはCPUアドレス空間の0x10100000〜0x10110000にマップされ、アドレス長は0x10000です。

b。割り込み

割り込み接続を説明するには、次の4つの属性が必要
です。1。interrupt-controllerこのノードが割り込み信号を受信することを宣言するために空の属性が使用されます
。2。#interrupt-cellsこれは、識別に使用される割り込みコントローラーノードの属性です。コントローラに必要なユニット数割り込み記述子を作成します
。3。interrupt-parentは、デバイスノードが属する割り込みコントローラを識別します。この属性が設定されていない場合、自動的に親ノードに接続されます
。4.interruptsは割り込みのリストです。各割り込み出力信号を示す識別子。

2つある場合、1つ目は割り込み番号で、2つ目は高レベル、低レベル、エッジトリガー、その他のトリガー特性などの割り込みタイプです。特定の割り込みコントローラーについて、関連するドキュメントを注意深く読んで、割り込みフラグの解析方法を決定する必要があります。

c。その他

上記のルールに加えて、いくつかのカスタム属性とサブノードを自分で追加することもできますが、次のルールに従う必要があります。

  1. 新しいデバイス属性は、それらと現在の標準属性との間の名前の競合を避けるために、製造元の名前のプレフィックスを付ける必要があります。
  2. デバイスドライバーの開発者がこれらのデータを解釈する方法を理解できるように、新しく追加された属性と子ノードの特定の意味を文書化する必要があります。説明ドキュメントでは、互換性の値の意味、持つべき属性、持つことができる子ノード、およびそれが表すデバイスを具体的に指定する必要があります。それぞれの独立した互換性は別々に説明されるべきです。
  3. これらの新しく追加されたものは、レビューのために[email protected]メーリングリストに送信し、それが将来他の問題を引き起こすかどうかを確認する必要があります。

5.高度な例

 
  1. pci@0x10180000 {

  2. compatible = "arm,versatile-pci-hostbridge", "pci";

  3. reg = <0x10180000 0x1000>;

  4. interrupts = <8 0>;

  5. bus-ranges = <0 0>;

  6.  
  7. #address-cells = <3>

  8. #size-cells = <2>;

  9. ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000

  10. 0x02000000 0 0xa0000000 0xa0000000 0 0x10000000

  11. 0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;

  12. };

前述のローカルバスと同様に、PCIアドレス空間とCPUアドレス空間は完全に分離されているため、ここではアドレス変換の範囲属性を定義する必要があります。
#address-cellsは、PCIが3つのセルを使用することを定義し、PCIのアドレス範囲は2つの単位で解釈できます。したがって、最初の質問は、PCIアドレスを記述するために3つの32ビットセルが必要な理由です。

これらの3つのセルは、物理アドレスの上位ビット、中間ビット、および下位ビットを表します

  • 1 phys.highセル:npt000ss bbbbbbbb dddddfff rrrrrrrr
  • 2 phys.midセル:hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
  • 3 phys.lowセル:llllllll llllllll llllllll llllllll

PCIアドレスは64ビット幅で、phys.midとphys.lowにエンコードされています。本当に重要なことは、phys.highスペースにあります。

n:再適用スペースフラグ(ここでは使用されません)を
表しますp:先読みスペース(キャッシュ)フラグを表し
ますt:エイリアスアドレスフラグ(ここでは使用されません)
ss:スペースコード
00:設定スペース
01:IOスペース10:
32ビットストレージスペース
11:64ビットストレージスペース

bbbbbbbb:PCIバス番号。PCIは階層アーキテクチャである可能性があるため、
サブバスddddd:デバイス番号を区別する必要がある場合があります。これは通常、最初のデバイス選択信号IDSELが接続されているときに適用されます。
fff:機能のシリアル番号。一部の多機能PCIデバイスで使用される場合があります。
rrrrrrrr:設定サイクルで使用される登録番号。

 
  1. ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000

  2. 0x02000000 0 0xa0000000 0xa0000000 0 0x10000000

  3. 0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;

この範囲のサブテーブルが表すものを振り返ってください。親ノードのアドレスセルは1、子ノードのアドレスセルは3、子ノードのサイズセルは2です。次に、最初の行を次のように分割できます。

0x42000000 0 0x80000000 子节点地址| 0x80000000 父节点地址| 0 0x20000000 地址空间长度|

0x42000000はphys.high、最初の桁は01000010、pは1、ssは10です。つまり、32ビットのストレージスペースがキャッシュスペースとして要求されます。phys.midは0、phys.lowは0x80000000です。これらは一緒にPCIアドレスを形成します。つまり、アドレス0x80000000のPCIバスからキャッシュとして32ビットのストレージスペースが要求されます。次のセル0x8000000000 x20000000は、CPUスペースの後のパラメーターを表します。適用されたアドレスはCPUスペースのアドレス0x80000000にマップされ、合計サイズは0x20000000(512MB)です。

おすすめ

転載: blog.csdn.net/wlf_go/article/details/81938901