組込みLinux Device Tree Usage @elinux.org 日本語

日本語自動変換されたら分かりにくいコード等の部分は、オリジナルで見れるようにしています。 私が英語だけでも日本語自動翻訳ではコードのキーワードも翻訳されてしまって読みづらかったので、文章は自動翻訳し、コードの部分はオリジナルのままにしました。

 a Creative Commons Attribution-ShareAlike 3.0 Unported License

引用元:elinux.org

著者: Tom Shanley / Don Anderson: PCI System Architecture. Mindshare Inc.

ccライセンスのAttribution-ShareAlikeなので商用でも自由に配布、改変配布できますが、著者名を明記する事と、同じcc-Attribution-ShareAlikeの継承が必要なので、最初に記しました。

Device Tree Usage

このページでは、新しいマシンのデバイス ツリーを作成する方法について説明します。デバイス ツリーの概念の概要と、それらを使用してマシンを説明する方法を説明することを目的としています。

デバイス ツリー データ形式の完全な技術的説明については、 ePAPR v1.1仕様を参照してください。ePAPR 仕様は、このページで説明されている基本的なトピックよりも多くの詳細をカバーしています。このページで説明されていないより高度な使用法については、ePAPR 仕様を参照してください。 ePAPR は現在、Devicetree Specification Documentation という新しい名前で更新されています。

基本データ形式

デバイス ツリーは、ノードとプロパティの単純なツリー構造です。プロパティはキーと値のペアであり、ノードにはプロパティと子ノードの両方が含まれる場合があります。たとえば、次は.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 {
        };
    };
};

このツリーは何も記述していないため明らかに役に立ちませんが、ノードとプロパティの構造を示しています。がある:

  • 単一のルート ノード: ” /
  • いくつかの子ノード: ” node1” と ” node2
  • ノード 1 の 2 つの子: ” child-node1” と ” child-node2
  • ツリー全体に散在する一連のプロパティ。

プロパティは単純なキーと値のペアで、値は空にするか、任意のバイト ストリームを含めることができます。データ型はデータ構造にエンコードされていませんが、デバイス ツリー ソース ファイルで表現できる基本的なデータ表現がいくつかあります。

  • テキスト文字列 (null で終了) は、二重引用符で表されます。
    • string-property = "a string";
  • 「セル」は、山括弧で区切られた 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 に基づいている) を考えてみましょう。

  • 1 つの 32 ビット ARM CPU
  • メモリ マップド シリアル ポートに接続されたプロセッサ ローカル バス、spi バス コントローラ、i2c コントローラ、割り込みコントローラ、および外部バス ブリッジ
  • 0 に基づく 256MB の SDRAM
  • 0x101F1000 および 0x101F2000 に基づく 2 つのシリアル ポート
  • 0x101F3000 に基づく GPIO コントローラー
  • 次のデバイスを備えた 0x10170000 に基づく SPI コントローラー
    • GPIO #1 に SS ピンが接続された MMC スロット
  • 以下のデバイスを備えた外部バスブリッジ
    • SMC SMC91111 0x10100000 に基づく外部バスに接続されたイーサネット デバイス
    • 次のデバイスを備えた 0x10160000 に基づく i2c コントローラー
      • マキシム DS1338 リアルタイムクロック。スレーブアドレス1101000(0x58)に応答
    • 0x30000000 に基づく 64MB の NOR フラッシュ

初期構造

最初のステップは、マシンのスケルトン構造を配置することです。これは、有効なデバイス ツリーに必要な最低限の構造です。この段階で、マシンを一意に識別したいと考えています。

/dts-v1/;

/ {
    compatible = "acme,coyotes-revenge";
};

compatibleシステムの名前を指定します。「<manufacturer>,<model>」の形式の文字列が含まれています。正確なデバイスを指定し、名前空間の競合を避けるためにメーカー名を含めることが重要です。オペレーティング システムはcompatible値を使用して、マシンで実行する場合、このプロパティに正しいデータを入力することが非常に重要です。

理論的には、互換性とは、OS がマシンを一意に識別するために必要なすべてのデータです。すべてのマシンの詳細がハードコードされている場合、OS は最上位のcompatibleプロパティで「acme,coyotes-revenge」を特に検索できます。

CPU

次のステップは、各 CPU について説明することです。「cpus」という名前のコンテナー ノードが、各 CPU の子ノードと共に追加されます。この場合、システムは ARM のデュアルコア Cortex A9 システムです。

/dts-v1/;

/ {
    compatible = "acme,coyotes-revenge";

    cpus {
        cpu@0 {
            compatible = "arm,cortex-a9";
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
        };
    };
};

各 cpu ノード<manufacturer>,<model>の互換性プロパティは、最上位レベルの互換性プロパティと同様に、正確な CPU モデルを の形式で指定する文字列です。

後でさらに多くのプロパティが cpu ノードに追加されますが、まず基本的な概念について詳しく説明する必要があります。

ノード名

命名規則について少し話しておく価値があります。すべてのノードには、] の形式の名前が必要<name>[@<unit-address>です。

<name>単純な ASCII 文字列で、長さは最大 31 文字です。一般に、ノードは、それが表すデバイスの種類に従って名前が付けられます。すなわち。3com イーサネット アダプタのノードは、ethernetではなくという名前を使用し3com509ます。

ノードがアドレス付きのデバイスを記述する場合、ユニットアドレスが含まれます。通常、ユニット アドレスはデバイスへのアクセスに使用されるプライマリ アドレスであり、ノードのregプロパティにリストされます。reg プロパティについては、このドキュメントの後半で説明します。

兄弟ノードには一意の名前を付ける必要がありますが、アドレスが異なる限り、複数のノードが同じ総称名を使用するのが普通です (つまり、serial@101f1000 & serial@101f2000)。

ノードの命名に関する詳細については、ePAPR 仕様のセクション 2.2.1 を参照してください。

デバイス

システム内のすべてのデバイスは、デバイス ツリー ノードによって表されます。次のステップは、ツリーに各デバイスのノードを追加することです。今のところ、アドレス範囲と irq の処理方法について説明できるようになるまで、新しいノードは空のままにします。

/dts-v1/;

/ {
    compatible = "acme,coyotes-revenge";

    cpus {
        cpu@0 {
            compatible = "arm,cortex-a9";
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
        };
    };

    serial@101F0000 {
        compatible = "arm,pl011";
    };

    serial@101F2000 {
        compatible = "arm,pl011";
    };

    gpio@101F3000 {
        compatible = "arm,pl061";
    };

    interrupt-controller@10140000 {
        compatible = "arm,pl190";
    };

    spi@10115000 {
        compatible = "arm,pl022";
    };

    external-bus {
        ethernet@0,0 {
            compatible = "smc,smc91c111";
        };

        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            rtc@58 {
                compatible = "maxim,ds1338";
            };
        };

        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
        };
    };
};

このツリーでは、システム内のデバイスごとにノードが追加されており、階層はデバイスがシステムに接続されている方法を反映しています。すなわち。外部バス上のデバイスは外部バス ノードの子であり、i2c デバイスは i2c バス コントローラー ノードの子です。一般に、階層は CPU の観点から見たシステムのビューを表します。

このツリーは現時点では有効ではありません。デバイス間の接続に関する情報が欠落しています。そのデータは後で追加されます。

このツリーで注目すべき点:

  • すべてのデバイス ノードにはcompatibleプロパティがあります。
  • フラッシュ ノードには、互換性のあるプロパティに 2 つの文字列があります。その理由については、次のセクションをお読みください。
  • 前述のように、ノード名は特定のモデルではなく、デバイスのタイプを反映しています。可能な限り使用すべき定義済みの汎用ノード名のリストについては、ePAPR 仕様のセクション 2.2.2 を参照してください。

compatibleプロパティを理解する

デバイスを表すツリー内のすべてのノードには、compatibleプロパティが必要です。 compatibleオペレーティング システムがデバイスにバインドするデバイス ドライバーを決定するために使用するキーです。

compatible文字列のリストです。リストの最初の文字列は、ノードが形式で表す正確なデバイスを指定します"<manufacturer>,<model>"。次の文字列は、デバイスが互換性のある他のデバイスを表します。

たとえば、Freescale MPC8349 System on Chip (SoC) には、National Semiconductor ns16550 レジスタ インターフェイスを実装するシリアル デバイスがあります。したがって、MPC8349 シリアル デバイスの互換プロパティは次のようになりますcompatible = "fsl,mpc8349-uart", "ns16550"。この場合、fsl,mpc8349-uart正確なデバイスを指定ns16550し、National Semiconductor 16550 UART とレジスタレベルで互換性があることを示します。

注:ns16550単に歴史的な理由から、製造元のプレフィックスはありません。新しい互換性のある値はすべて、製造元の接頭辞を使用する必要があります。

このプラクティスにより、正確なハードウェアを一意に識別しながら、既存のデバイス ドライバーを新しいデバイスにバインドできます。

警告: “fsl,mpc83xx-uart” などのワイルドカード互換の値を使用しないでください。シリコン ベンダーは、変更するには手遅れになると、ワイルドカードの仮定を破る変更を必ず行います。代わりに、特定のシリコン実装を選択し、後続のすべてのシリコンと互換性を持たせてください。

アドレッシングのしくみ

アドレス可能なデバイスは、次のプロパティを使用してアドレス情報をデバイス ツリーにエンコードします。

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

アドレス指定可能な各デバイスはreg、形式のタプルのリストである を取得しreg = <address1 length1 [address2 length2] [address3 length3] ... >ます。各タプルは、デバイスが使用するアドレス範囲を表します。各アドレス値は、セルと呼ばれる 1 つ以上の 32 ビット整数のリストです。同様に、長さの値は、セルのリストまたは空にすることができます。

アドレス フィールドと長さフィールドは両方とも可変サイズの変数であるため、親ノードの#address-cellsおよび#size-cellsプロパティを使用して、各フィールドに含まれるセルの数を示します。つまり、reg プロパティを正しく解釈するには、親ノードの #address-cells と #size-cells の値が必要です。このすべてがどのように機能するかを確認するために、CPU から始めて、アドレス指定プロパティをサンプル デバイス ツリーに追加してみましょう。

CPU アドレッシング

CPU ノードは、アドレス指定について話すときの最も単純なケースを表しています。各 CPU には 1 つの一意の ID が割り当てられ、CPU ID に関連付けられたサイズはありません。

    cpus {
        #address-cells = <1>;
        #size-cells = <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 が割り当てられます。 #size-cells各 CPU には 1 つのアドレスしか割り当てられないため、CPU ノードの場合は 0 です。

regまた、値がノード名の値と一致することもわかります。慣例により、ノードにregプロパティがある場合、ノード名にはプロパティの最初のアドレス値である unit-address を含める必要がありregます。

メモリ マップド デバイス

CPUノードに見られるような単一のアドレス値の代わりに、メモリマップされたデバイスには、応答するアドレスの範囲が割り当てられます。 #size-cells各子regタプルの長さフィールドの大きさを示すために使用されます。次の例では、各アドレス値は 1 セル (32 ビット) であり、各長さ値も 1 セルであり、これは 32 ビット システムでは一般的です。64 ビット マシンでは、#address-cells と #size-cells に 2 の値を使用して、デバイス ツリーで 64 ビット アドレス指定を取得できます。

/dts-v1/;

/ {
    #address-cells = <1>;
    #size-cells = <1>;

    ...

    serial@101f0000 {
        compatible = "arm,pl011";
        reg = <0x101f0000 0x1000 >;
    };

    serial@101f2000 {
        compatible = "arm,pl011";
        reg = <0x101f2000 0x1000 >;
    };

    gpio@101f3000 {
        compatible = "arm,pl061";
        reg = <0x101f3000 0x1000
              0x101f4000 0x0010>;
    };

    interrupt-controller@10140000 {
        compatible = "arm,pl190";
        reg = <0x10140000 0x1000 >;
    };

    spi@10115000 {
        compatible = "arm,pl022";
        reg = <0x10115000 0x1000 >;
    };

    ...

};

各デバイスにはベース アドレスが割り当てられ、領域のサイズが割り当てられます。この例の GPIO デバイス アドレスには、2 つのアドレス範囲が割り当てられています。0x101f3000…0x101f3fff および 0x101f4000..0x101f400f。

一部のデバイスは、異なるアドレッシング方式のバス上にあります。たとえば、デバイスは個別のチップ選択ラインを使用して外部バスに接続できます。各親ノードはその子のアドレス指定ドメインを定義するため、システムを最もよく表すアドレス マッピングを選択できます。以下のコードは、チップセレクト番号がアドレスにエンコードされた外部バスに接続されたデバイスのアドレス割り当てを示しています。

    external-bus {
        #address-cells = <2>;
        
#size-cells = <1>;

        ethernet@0,0 {
            compatible = "smc,smc91c111";
            reg = <0 0 0x1000>;
        };

        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            reg = <1 0 0x1000>;
            rtc@58 {
                compatible = "maxim,ds1338";
            };
        };

        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
            reg = <2 0 0x4000000>;
        };
    };

external-busアドレス値に 2 つのセルを使用します。1 つはチップ セレクト番号用で、もう 1 つはチップ セレクトのベースからのオフセット用です。アドレスのオフセット部分のみが範囲を持つ必要があるため、長さフィールドは 1 つのセルのままです。したがって、この例では、各regエントリに 3 つのセルが含まれています。チップセレクト番号、オフセット、および長さ。

アドレス ドメインはノードとその子ノードに含まれているため、親ノードは、バスにとって意味のあるアドレッシング スキームを自由に定義できます。直接の親ノードと子ノードの外側にあるノードは、通常、ローカル アドレス指定ドメインを気にする必要はなく、あるドメインから別のドメインに取得するためにアドレスをマップする必要があります。

非メモリ マップ デバイス

他のデバイスは、プロセッサ バスにマップされたメモリではありません。アドレス範囲を持つことはできますが、CPU から直接アクセスすることはできません。代わりに、親デバイスのドライバーが CPU に代わって間接アクセスを実行します。

i2c デバイスの例を挙げると、各デバイスにはアドレスが割り当てられますが、それに関連付けられた長さや範囲はありません。これは、CPU アドレスの割り当てとほとんど同じように見えます。

        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <1 0 0x1000>;
            rtc@58 {
                compatible = "maxim,ds1338";
                reg = <58>;
            };
        };

範囲 (アドレス変換)

アドレスをデバイスに割り当てる方法について説明しましたが、この時点では、これらのアドレスはデバイス ノードに対してローカルにあるだけです。これらのアドレスから CPU が使用できるアドレスにマップする方法はまだ説明されていません。

ルート ノードは常に、アドレス空間の CPU のビューを記述します。ルートの子ノードはすでに CPU のアドレス ドメインを使用しているため、明示的なマッピングは必要ありません。たとえば、serial@101f0000 デバイスにはアドレス 0x101f0000 が直接割り当てられます。

ルートの直接の子ではないノードは、CPU のアドレス ドメインを使用しません。メモリ マップド アドレスを取得するために、デバイス ツリーはアドレスをあるドメインから別のドメインに変換する方法を指定する必要があります。プロパティはこのranges目的で使用されます。

次に、ranges プロパティが追加されたサンプル デバイス ツリーを示します。

/dts-v1/;

/ {
    compatible = "acme,coyotes-revenge";
    #address-cells = <1>;
    #size-cells = <1>;
    ...
    external-bus {
        #address-cells = <2>;
        #size-cells = <1>;
        ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet
                  1 0  0x10160000   0x10000     // Chipselect 2, i2c controller
                  2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash

        ethernet@0,0 {
            compatible = "smc,smc91c111";
            reg = <0 0 0x1000>;
        };

        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <1 0 0x1000>;
            rtc@58 {
                compatible = "maxim,ds1338";
                reg = <58>;
            };
        };

        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
            reg = <2 0 0x4000000>;
        };
    };
};

rangesアドレス変換のリストです。範囲テーブルの各エントリは、子アドレス、親アドレス、および子アドレス空間内の領域のサイズを含むタプルです。各フィールドのサイズは、子の#address-cells値、親の#address-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 マッピングを使用する必要があるかどうかは、オペレーティング システムが必要とする情報とハードウェア設計に大きく依存します。

rangesi2c@1,0 ノードにはプロパティがないことにも注意してください。これは、外部バスとは異なり、i2c バス上のデバイスは CPU のアドレス ドメインにメモリ マップされていないためです。代わりに、CPU は i2c@1,0 デバイスを介して間接的に rtc@58 デバイスにアクセスします。プロパティがないrangesということは、デバイスがその親以外のデバイスから直接アクセスできないことを意味します。

割り込みのしくみ

ツリーの自然な構造に従うアドレス範囲変換とは異なり、割り込み信号は、マシン内の任意のデバイスから発信および終了できます。デバイスツリーで自然に表現されるデバイスアドレッシングとは異なり、割り込み信号はツリーとは独立したノード間のリンクとして表現されます。割り込み接続を記述するために、4 つのプロパティが使用されます。

  • interrupt-controller– 割り込み信号を受信するデバイスとしてノードを宣言する空のプロパティ
  • #interrupt-cells– これは、割り込みコントローラ ノードのプロパティです。この割り込みコントローラの割り込み指定子に含まれるセルの数を示します (#address-cellsおよび と同様#size-cells)。
  • interrupt-parent– 接続されている割り込みコントローラーへのphandleを含むデバイス ノードのプロパティ。interrupt-parent プロパティを持たないノードは、親ノードからプロパティを継承することもできます。
  • interrupts– デバイスの割り込み出力信号ごとに 1 つずつ、割り込み指定子のリストを含むデバイス ノードのプロパティ。

割り込み指定子は、デバイスが接続されている割り込み入力を指定する1 つまたは複数のデータ セル (#interrupt-cells で指定) です。以下の例に示すように、ほとんどのデバイスには 1 つの割り込み出力しかありませんが、1 つのデバイスに複数の割り込み出力を持つことができます。割り込み指定子の意味は、割り込みコントローラー デバイスのバインディングに完全に依存します。各割り込みコントローラは、割り込み入力を一意に定義するために必要なセルの数を決定できます。

次のコードは、Coyote’s Revenge のサンプル マシンに割り込み接続を追加します。

/dts-v1/;

/ {
    compatible = "acme,coyotes-revenge";
    #address-cells = <1>;
    #size-cells = <1>;
    interrupt-parent = <&intc>;

    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu@0 {
            compatible = "arm,cortex-a9";
            reg = <0>;
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
            reg = <1>;
        };
    };

    serial@101f0000 {
        compatible = "arm,pl011";
        reg = <0x101f0000 0x1000 >;
        interrupts = < 1 0 >;
    };

    serial@101f2000 {
        compatible = "arm,pl011";
        reg = <0x101f2000 0x1000 >;
        interrupts = < 2 0 >;
    };

    gpio@101f3000 {
        compatible = "arm,pl061";
        reg = <0x101f3000 0x1000
               0x101f4000 0x0010>;
        interrupts = < 3 0 >;
    };

    intc: interrupt-controller@10140000 {
        compatible = "arm,pl190";
        reg = <0x10140000 0x1000 >;
        interrupt-controller;
        #interrupt-cells = <2>;
    };

    spi@10115000 {
        compatible = "arm,pl022";
        reg = <0x10115000 0x1000 >;
        interrupts = < 4 0 >;
    };

    external-bus {
        #address-cells = <2>;
        #size-cells = <1>;
        ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet
                  1 0  0x10160000   0x10000     // Chipselect 2, i2c controller
                  2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash

        ethernet@0,0 {
            compatible = "smc,smc91c111";
            reg = <0 0 0x1000>;
            interrupts = < 5 2 >;
        };

        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <1 0 0x1000>;
            interrupts = < 6 2 >;
            rtc@58 {
                compatible = "maxim,ds1338";
                reg = <58>;
                interrupts = < 7 3 >;
            };
        };

        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
            reg = <2 0 0x4000000>;
        };
    };
};

注意すべき点:

  • マシンには、1 つの割り込みコントローラー、interrupt-controller@10140000 があります。
  • ラベル ‘intc:’ が割り込みコントローラー ノードに追加され、このラベルを使用して、ルート ノードの interrupt-parent プロパティに phandle が割り当てられました。この割り込み親の値は、明示的にオーバーライドされない限り、すべての子ノードが継承するため、システムのデフォルトになります。
  • 各デバイスは、割り込みプロパティを使用して、異なる割り込み入力ラインを指定します。
  • #interrupt-cells は 2 なので、各割り込み指定子には 2 つのセルがあります。この例では、最初のセルを使用して割り込みライン番号をエンコードし、2 番目のセルを使用してアクティブ ハイ対アクティブ ロー、またはエッジ対レベル センシティブなどのフラグをエンコードする一般的なパターンを使用します。特定の割り込みコントローラーについては、コントローラーのバインディング ドキュメントを参照して、指定子がどのようにエンコードされているかを確認してください。

デバイス固有のデータ

共通のプロパティ以外に、任意のプロパティと子ノードをノードに追加できます。オペレーティング システムが必要とするデータは、いくつかの規則に従っていれば追加できます。

まず、新しいデバイス固有のプロパティ名は、既存の標準プロパティ名と競合しないように、製造プレフィックスを使用する必要があります。

次に、デバイス ドライバーの作成者がデータの解釈方法を理解できるように、プロパティと子ノードの意味をバインディングで文書化する必要があります。バインディングは、特定の互換性のある値が何を意味するか、それが持つべきプロパティ、持つ可能性のある子ノード、およびそれが表すデバイスを文書化します。一意の各compatible値には、独自のバインディングが必要です (または、別の互換性のある値との互換性を主張する必要があります)。新しいデバイスのバインディングは、この wiki に記載されています。ドキュメントの形式とレビュー プロセスの説明については 、メイン ページを参照してください。

3 番目に、devicetree-discuss@lists.ozlabs.org メーリング リストにレビュー用の新しいバインディングを投稿します。新しいバインディングを確認すると、将来的に問題を引き起こす可能性のある多くの一般的な間違いが見つかります。

特別なノード

aliasesノード

通常、特定のノードは のようにフル パスで参照されますが/external-bus/ethernet@0,0、ユーザーが本当に知りたいのが「どのデバイスが eth0 か?」という場合は面倒です。このノードを使用して、完全なデバイス パスにaliases短いエイリアスを割り当てることができます。例えば:

    aliases {
        ethernet0 = &eth0;
        serial0 = &serial0;
    };

オペレーティング システムは、識別子をデバイスに割り当てるときにエイリアスを使用できます。

ここで使用されている新しい構文に気付くでしょう。この構文は、ラベルによって参照される完全なノード パスを文字列プロパティとして割り当てます。これは、phandle 値をセルに挿入する前に使用した形式とは異なります。 property = &label;phandle = < &label >;

chosenノード

ノードは実際のchosenデバイスを表しているわけではありませんが、ブート引数など、ファームウェアとオペレーティング システムの間でデータを渡す場所として機能します。選択したノードのデータはハードウェアを表していません。通常、選択されたノードは .dts ソース ファイルで空のままにされ、起動時に読み込まれます。

この例のシステムでは、ファームウェアは選択されたノードに以下を追加する場合があります。

    chosen {
        bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
    };

高度なトピック

高度なサンプル マシン

基本が定義されたので、サンプル マシンにいくつかのハードウェアを追加して、より複雑なユース ケースのいくつかについて説明しましょう。

高度なサンプル マシンは、制御レジスタ メモリが 0x10180000 にマップされた PCI ホスト ブリッジと、アドレス 0x80000000 より上で開始するようにプログラムされた BAR を追加します。

デバイス ツリーについて既にわかっていることを踏まえて、まず次のノードを追加して PCI ホスト ブリッジを記述します。

        pci@10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            割り込み = <8 0>;
        };

PCI ホスト ブリッジ

このセクションでは、ホスト/PCI ブリッジ ノードについて説明します。

このセクションでは、PCI の基本的な知識があることを前提としています。これは PCI に関するチュートリアルではありません。さらに詳細な情報が必要な場合は、[1]をお読みください。また、 ePAPR v1.1 またはPCI Bus Binding to Open Firmwareも参照できます 。Freescale MPC5200 の完全な動作例は、ここにあります。

PCI バスの番号付け

各 PCI バス セグメントには一意の番号が付けられ、バスの番号付けは、bus-range2 つのセルを含むプロパティを使用して pci ノードで公開されます。最初のセルはこのノードに割り当てられたバス番号を示し、2 番目のセルは下位の PCI バスの最大バス番号を示します。

サンプル マシンには単一の PCI バスがあるため、両方のセルは 0 です。

        pci@0x10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            interrupts = <8 0>;
            bus-range = <0 0>;
        };

PCI アドレス変換

前述のローカル バスと同様に、PCI アドレス空間は CPU アドレス空間から完全に分離されているため、PCI アドレスから CPU アドレスに変換するにはアドレス変換が必要です。いつものように、これは、、、およびプロパティを使用して行わrange#address-cellsます#size-cells


        pci@0x10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            interrupts = <8 0>;
            bus-range = <0 0>;

            #address-cells = <3>
            #size-cells = <2>;
            ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
                      0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
                      0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
        };

ご覧のとおり、子アドレス(PCI アドレス) は 3 つのセルを使用し、PCI 範囲は 2 つのセルにエンコードされています。最初の疑問は、PCI アドレスを指定するのになぜ 32 ビット セルが 3 つ必要なのかということです。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: I/O空間
    • 10: 32 ビットのメモリ空間
    • 11: 64 ビットのメモリ空間
  • bbbbbbbb: PCI バス番号。PCI は階層構造になっている場合があります。そのため、サブバスを定義する PCI/PCI ブリッジがあるかもしれません。
  • ddddd: デバイス番号。通常、IDSEL 信号接続に関連付けられています。
  • fff: 機能番号。多機能 PCI デバイスに使用されます。
  • rrrrrrrr: 登録番号; 構成サイクルに使用されます。

PCI アドレス変換の目的で、重要なフィールドはpssです。phys.hi の p と ss の値によって、どの PCI アドレス空間がアクセスされているかが決まります。range プロパティを見ると、次の 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-rangesと名付けられています。このタイプのメモリ マッピングは、インバウンド メモリと呼ばれることがあり、PCI デバイス ツリー仕様の一部ではありません。

場合によっては、ROM (BIOS) などによってブート時にこれらのレジスタが設定されますが、PCI コントローラが完全に初期化されておらず、これらの変換をデバイス ツリーから設定する必要がある場合もあります。次に、PCI ホスト ドライバーは通常、dma-ranges プロパティを解析し、それに応じてホスト コントローラーのいくつかのレジスターを設定します。

上記の例を拡張すると、次のようになります。

        pci@0x10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            interrupts = <8 0>;
            bus-range = <0 0>;

            #address-cells = <3>
            #size-cells = <2>;
            ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
                      0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
                      0x01000000 0 0x00000000 0xb0000000 0 0x01000000
            dma-ranges = <0x02000000 0 0x00000000 0x80000000 0 0x20000000>;
        };

このdma-rangesエントリは、PCI ホスト コントローラーの観点から、PCI アドレス0x00000000512 MBがアドレス0x80000000のメイン コア メモリに表示されることを示します。ご覧のとおり、ssアドレス タイプを 0x02 に設定しただけで、これは 32 ビット メモリであることを示しています。

高度な割り込みマッピング

ここで、最も興味深い部分である PCI 割り込みマッピングに進みます。PCI デバイスは、ワイヤー #INTA、#INTB、#INTC、および #INTD を使用して割り込みをトリガーできます。割り込み名の前の # ハッシュ記号は、それがアクティブ LOW であることを意味します。これは一般的な規則であり、PCI 割り込みラインは常にアクティブ LOW です。単機能デバイスは、割り込みに #INTA を使用する義務があります。多機能デバイスは、1 つの割り込みピンを使用する場合は #INTA、2 つの割り込みピンを使用する場合は #INTA と #INTB などを使用する必要があります。これらの規則により、通常、#INTA は #INTB、#INTC よりも多くの機能で使用されます。 、および #INTD。#INTA から #INTD までの 4 つの IRQ ラインに負荷を分散するために、通常、各 PCI スロットまたはデバイスは、すべての #INTA クライアントが同じ着信割り込みラインに接続されるのを避けるために、割り込みコントローラーの異なる入力に順番に配線されます。 .割り込みをスウィズルします。そのため、デバイス ツリーには、各 PCI 割り込み信号を割り込みコントローラーの入力にマッピングする方法が必要です。、およびプロパティは#interrupt-cells、割り込みマッピングを記述するために使用されます。 interrupt-mapinterrupt-map-mask

実際、ここで説明する割り込みマッピングは PCI バスに限定されたものではありません。どのノードでも複雑な割り込みマップを指定できますが、PCI のケースが最も一般的です。

        pci@0x10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            interrupts = <8 0>;
            bus-range = <0 0>;

            #address-cells = <3>
            #size-cells = <2>;
            ranges = <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 // 1st slot
                                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 // 2nd slot
                                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 つはフラグ用です。PCI 割り込みは常にレベル LOW センシティブになるように指定されているため、PCI は割り込み用に 1 つのセルしか必要としません。

この例のボードには、それぞれ 4 つの割り込みラインを持つ 2 つの PCI スロットがあるため、8 つの割り込みラインを割り込みコントローラーにマップする必要があります。これは、interrupt-map プロパティを使用して行われます。割り込みマッピングの正確な手順は[3]で説明されています。

割り込み番号 (#INTA など) は、単一の PCI バス上の複数の PCI デバイスを区別するのに十分ではないため、どの PCI デバイスが割り込みラインをトリガーしたかを示す必要もあります。幸いなことに、すべての PCI デバイスには、使用できる固有のデバイス番号があります。複数の PCI デバイスの割り込みを区別するには、PCI デバイス番号と PCI 割り込み番号からなるタプルが必要です。より一般的に言えば、4 つのセルを持つ ユニット割り込み指定子を作成します。

  • phys.hi、phys.mid、phys.low、および phys.hi で構成される3 つの#address-cells
  • 1 つの #interrupt-cell (#INTA、#INTB、#INTC、#INTD)。

PCI アドレスのデバイス番号部分のみが必要なため、interrupt-map-mask プロパティが機能します。interrupt-map-mask もユニット割り込み指定子と同様に 4 タプルです。マスク内の 1 は、ユニット割り込み指定子のどの部分を考慮する必要があるかを示します。この例では、phys.hi のデバイス番号部分のみが必要であり、4 つの割り込みラインを区別するために 3 ビットが必要であることがわかります (PCI 割り込みラインのカウントは 0 ではなく 1 から始まります!)。

これで、interrupt-map プロパティを構築できます。このプロパティはテーブルであり、このテーブルの各エントリは、子 (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 プロパティも指定する必要があります。

ノート

  1.  Tom Shanley / Don Anderson: PCI システム アーキテクチャ。株式会社マインドシェア
  2. Open Firmware への PCI バスのバインド。
  3. Open Firmware 推奨プラクティス: 割り込みマッピング
  4.  PCI 割り込みは常にレベル低センシティブです。

コメント