[Linux][kernel] Device Tree についてのまとめ

# はじめに
仕事で Device Tree を触る機会があったので情報をまとめる。
Web上で日本語情報はほぼなかったため後から見返す用。随時追記予定。
少なくともLinux kernel 2.6.38以降導入のため、現状のオライリーの書籍にも記載はなかった。
おそらくいろいろと間違っている可能性が高いですので、以下のリンク先等を正としてください。

2016/6/1 追記: devicetree.org がリニューアルしていたので、リンクを修正しました。

[Specifications – Devicetree](http://www.devicetree.org/specifications/)
 => Device Tree Specification Release X.X のリンク先のPDFを参照
[Device Tree - eLinux.org](http://elinux.org/Device_Tree)
[Device Tree Usage - eLinux.org](http://elinux.org/Device_Tree_Usage)
[Device Tree Reference - eLinux.org](http://elinux.org/Device_Tree_Reference)
[linux/Documentation/devicetree at master · torvalds/linux](https://github.com/torvalds/linux/tree/master/Documentation/devicetree)
["Device Tree for Dummies", ELC 2014 by Thomas Petazzoni (PDF)](http://elinux.org/images/f/f9/Petazzoni-device-tree-dummies_0.pdf)

# Device Tree とは
ARM Linux 向けにで使用されているプロパティ情報を記述した設定ファイルのこと。
Device Treeの仕組み自体は1994年に標準化されたOpen Firmwareというものを元にしている。
デバイスのベースアドレスや、クロック、割り込み番号といった、ハードウェア固有のプロパティをカーネルから分離しデバイスドライバの再利用性を高めることが目的の機能らしい。

Device Tree Souce に記載したプロパティをデバイスドライバから読み込んで使用する。
Device Treeの仕組みは、Linux カーネルのソースのかなりの割合を占めるデバイスドライバの肥大化を防ぐために導入された。
2.6.38 以前のLinuxカーネルにはARMのプラットフォームの依存性を記述する統一的な決まりがなかったため、各プラットフォームごとにそれぞれ独自フォーマットで実装されていた。

Linux コミュニティとしては Device Tree 非対応のデバイスドライバのパッチ受け付けはしない決まりになった模様。
そのため、ARM Linuxを使用する開発者は避けては通れないものになっている。

# Linux での Device Tree 標準化の経緯
kernel 2.6.38の時に、Linus氏が肥大するARMコードに激怒したのが発端とのこと。

```
From: Linus Torvalds <torvalds <at> linux-foundation.org>
Subject: Re: [GIT PULL] omap changes for v2.6.39 merge window
Newsgroups: gmane.linux.kernel, gmane.linux.ports.arm.kernel, gmane.linux.ports.arm.omap
Date: 2011-03-30 19:21:32 GMT (4 years, 31 weeks, 2 days, 17 hours and 24 minutes ago)

(中略)

THAT is an example of something that is totally and utterly screwed
up. Those kinds of random board-level detail files abound in the ARM
tree. They should either be in a per-board file, or (much better) the
ARM people should have standardized this ten f*cking years ago, and
put it in a bootloader or something that just initializes the crap so
that the kernel doesn't have to have random tables like that at all.

ARM right now i a nightmare, and most of it is because ARM hardware
manufacturers are morons. But the way the ARM tree is then laid out
has made that even more painful, and the decision to put all the crazy
board details in the kernel tables instead of trying to have a
per-board boot loader that fills in the details is just crazy.

Look at the dirstat for arch/ in just the current merge window
(cut-off at 5% just to not get too much):

[torvalds <at> i5 linux]$ git diff -C --dirstat=5 --cumulative v2.6.38.. arch
  14.0% arch/arm/mach-omap2/
   5.8% arch/arm/plat-mxc/include/mach/
   6.3% arch/arm/plat-mxc/
  57.1% arch/arm/
   5.4% arch/m68k/
   9.6% arch/unicore32/
   6.9% arch/x86/
 100.0% arch/

almost *SIXTY* percent of all arch updates were to ARM code. And
that's despite the fact that one of those architectures (unicore32) is
a totally new architecture, and despite m68k having gone through a
first-level unification of nommu and mmu code!

And was this just a fluke? No. Doing the same for 2.3.37..38 gives
58.3% for arch/arm (and in that release we had a blackfin unification
effort, otherwise arm would have been an even bigger percentage).

That's ridiculous. It's entirely due to the whole f*cked-up arm ecosystem.

(後略)
```
 引用: ~~http://article.gmane.org/gmane.linux.kernel/1120436~~
 引用: [LKML: Linus Torvalds: Re: [GIT PULL] omap changes for v2.6.39 merge window](https://lkml.org/lkml/2011/3/30/379)

上記の議論の流れは以下のスレッド参照。
~~http://thread.gmane.org/gmane.linux.kernel/1114495/focus=112007~~
=> 2016/12/20追記: `thread.gmane.org/gmane.linux.kernel` のarchiveがなぜか消えてて見つかりませんでした・・・。

# 用語
## DTS : Device Tree Source
Device Treeのソースファイル。専用の形式で書かれている。
拡張子は `*.dts` と `*.dtsi` の2種類

`*.dts` はボード固有の定義が記述されている。
`*.dtsi`は通常SoC(System on Chip)固有の情報が含まれており、`*.dts/*.dtsi`からCプリプロセッサによりincludeされる。

## DTB : Device Tree Blob
Device Tree Sourceをコンパイルしたバイナリファイル。

## DTC : Device Tree Compiler
Device Tree Sourceをビルドするためのコンパイラ。
機能として、*.dtb -> *.dtsへの逆アセンブルもサポートしている。

# dts の配置場所
## `linux-4.2.5` の場合

[The Linux Kernel Archives](https://www.kernel.org/) からカーネルのソースを取得
※展開後は691MB程度あるので注意

```
wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.2.5.tar.xz
tar Jxvf linux-4.2.5.tar.xz
```

Device Tree Source(.dts/.dtsi)のほとんどは以下に配置されている。

```
/arch/arm/boot/dts/
```

# Device Tree Source の文法について
文法については以下を参照してください。

[Specifications – Devicetree](http://www.devicetree.org/specifications/)
 => Device Tree Specification Release X.X のリンク先のPDFを参照

# dtbを実際に使用する場合の注意

dtb の読み出しはブートローダが行う。zImageとは別に配置する必要がある。
ファイルの入れ替えで良いか、`dd`コマンドで書き込む必要があるかはブートローダに依存する。

# カーネルドライバ内からDeviceTreeのプロパティへのアクセス方法
## `module_platform_driver` マクロを使用

使用例

```c:linux-4.2.5/drivers/media/platform/fsl-viu.c#L1664-1693
/*
 * Initialization and module stuff
 */
static const struct of_device_id mpc512x_viu_of_match[] = { 
    { 
        .compatible = "fsl,mpc5121-viu", // ※compatibleを指定
    },
    {},
};
MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
                                                                                                                                                                                                             
static struct platform_driver viu_of_platform_driver = { 
    .probe = viu_of_probe,
    .remove = viu_of_remove,
#ifdef CONFIG_PM
    .suspend = viu_suspend,
    .resume = viu_resume,
#endif
    .driver = { 
        .name = DRV_NAME,
        .of_match_table = mpc512x_viu_of_match, // ※of_match_table に格納
    },
};

module_platform_driver(viu_of_platform_driver);

MODULE_DESCRIPTION("Freescale Video-In(VIU)");
MODULE_AUTHOR("Hongjun Chen");
MODULE_LICENSE("GPL");
MODULE_VERSION(VIU_VERSION);
```

この後のprobeに設定した関数にてDeviceTreeのnodeを取得できる

```c:linux-4.2.5/drivers/media/platform/fsl-viu.c#L1483-1497
static int viu_of_probe(struct platform_device *op)
{
    struct viu_dev *viu_dev;
    struct video_device *vdev;
    struct resource r;
    struct viu_reg __iomem *viu_regs;
    struct i2c_adapter *ad;
    int ret, viu_irq;
    struct clk *clk;

    ret = of_address_to_resource(op->dev.of_node, 0, &r); // ※op->dev.of_nodeで struct device_node を取得
    if (ret) { 
        dev_err(&op->dev, "Can't parse device node resource\n");
        return -ENODEV;
    } 
...
```

## `of_find_compatible_node()` を使用

`of_find_compatible_node()`を使用してもnodeが取得できる。

# デバッグ方法
## `/proc/device-tree` を参照する
ARM Linuxの場合は、オプションで有効化されている場合は `/proc` 以下でDeviceTreeの情報を取得できる。

```
/proc/device-tree
```

値は`hexdump`で確認できる

```
# hexdump -C '/proc/device-tree/#size-cells'
00000000  00 00 00 01                                       |....|
00000004
# hexdump -C '/proc/device-tree/axi@0/compatible'
00000000  78 6c 6e 78 2c 70 73 37  2d 61 78 69 2d 69 6e 74  |xlnx,ps7-axi-int|
00000010  65 72 63 6f 6e 6e 65 63  74 2d 31 2e 30 30 2e 61  |erconnect-1.00.a|
00000020  00 73 69 6d 70 6c 65 2d  62 75 73 00              |.simple-bus.|
0000002c
```

## カーネルでどのデバイスツリーが使用中かを判別する
`/proc/device-tree/compatible` を確認すれば `compatible` の記載文字列が確認できるため、dtsの推測はできる。

```bash:/proc/device-tree/compatibleを確認する
$ strings /proc/device-tree/compatible
fsl,imx6dl-sabreauto
fsl,imx6dl
```
## `.dtb` を `.dts` に戻す

Ubuntuの場合は以下でパッケージを取得できる。

```bash
apt-get install device-tree-compiler
```

逆アセンブルする場合は以下のコマンドで可能。

```bash
dtc -I dtb -O dts -o ${hoge}.dts ${hoge}.dtb
```

# エディタ関連
## VimのSyntax対応
v7.3.684 (6 Oct 2012) 以降で `dts.vim` に対応済み
https://github.com/vim/vim/commit/0c5fa7d740bafefbf0b2ea48a2a660901d7d4f10

# 参考書籍
Interface2014年10月号、11月号に特集されている。ただし概要程度。

Linux 3.2 に対応したO'Reillyの書籍が出るらしい（延期して2017年11月予定）から解説が乗る可能性はあります。
[Linux Device Drivers, 4th Edition - O'Reilly Media](http://shop.oreilly.com/product/0636920030867.do)
=> 2016/10/13追記: 何故か商品ページが削除されている・・・

# 参考
## Wiki
[elinux.org - Device_Tree](http://elinux.org/Device_Tree)
[Specifications – Devicetree](http://www.devicetree.org/specifications/)
[Device Tree presentations papers articles](http://elinux.org/Device_Tree_presentations_papers_articles)

## 発表資料
["Device Tree for Dummies", ELC 2014 by Thomas Petazzoni (PDF)](http://elinux.org/images/f/f9/Petazzoni-device-tree-dummies_0.pdf)
[elinux.org - Solving Device Tree Issues (PDF)](http://events.linuxfoundation.org/sites/events/files/slides/dt_debugging.pdf)
[Experiences_With_Device_Tree_Support_Development_For_ARM-Based_SOC (PDF)](http://elinux.org/images/4/48/Experiences_With_Device_Tree_Support_Development_For_ARM-Based_SOC%27s.pdf)

## 記事（ブログ, Qiita, StackOverFlow等）
[とあるエンジニアの備忘log - Device Tree 入門](http://masahir0y.blogspot.jp/2014/05/device-tree.html)
[とあるエンジニアの備忘log - Device Tree アクセス関数まとめ (Linux Kernel) ](http://masahir0y.blogspot.jp/2014/05/device-tree_28.html)
[Qiita - メモ：Device tree blob (.dtb)をDevice tree source (.dts)に戻す](http://qiita.com/spicemanjp/items/5054e536442248aad87c)
[A Tutorial on the Device Tree (Zynq) -- Part I | xillybus.com](http://xillybus.com/tutorials/device-tree-zynq-1)
[linux - how to program device tree file(.dts)? - Stack Overflow](http://stackoverflow.com/questions/17488320/how-to-program-device-tree-file-dts)