Raspberry Piのdtoverlay・dtparam、dtbそしてブートプロセスのメモ

 はじめに

この記事はRaspberry Pi 3B+の実際の挙動と公式のドキュメントから大体こんな感じだろうというところで書いてるので正確さは期待しないでください。

下図のような構成でLinux kernel(Raspberry Pi向けのカーネルじゃなくて、mainlineとかstable treeのカーネル)を使うときにdtoverlay・dtparamを使う方法を調べたメモです。なので、自分でビルドしたカーネルを使う必要がなければRaspberry Pi OSとかmeta-raspberrypiを使うのが良いかと思います。

-> Raspberry Piのブートローダー  
  -> u-boot 
    -> Linux kernel

Linux kernel source とdtbファイル

mainlineのカーネルにはbcm2837-rpi-3-b-plus.dts等のdtsファイルがあるのでこれをビルドして使えばmainlineのカーネルでもRaspberry Piで動きます。だがしかし、config.txtでdtoverlay・dtparamを使うのはできませんでした。なんでかというと、Raspberry Piカーネルとmainlineのカーネルにあるdtsファイルを見比べるとRaspberry Piカーネルのほうにはoverridesがあって設定をoverrideできるようになってるんですね。例えばarm/boot/dts/bcm2710-rpi-3-b-plus.dtsだとこんな感じで設定があります。

/ {
    __overrides__ {
        act_led_gpio = <&act_led>,"gpios:4";
        act_led_activelow = <&act_led>,"gpios:8";
        act_led_trigger = <&act_led>,"linux,default-trigger";

        pwr_led_gpio = <&pwr_led>,"gpios:4";
        pwr_led_activelow = <&pwr_led>,"gpios:8";
        pwr_led_trigger = <&pwr_led>,"linux,default-trigger";

        eee = <&eth_phy>,"microchip,eee-enabled?";
        tx_lpi_timer = <&eth_phy>,"microchip,tx-lpi-timer:0";
        eth_led0 = <&eth_phy>,"microchip,led-modes:0";
        eth_led1 = <&eth_phy>,"microchip,led-modes:4";
        eth_downshift_after = <&eth_phy>,"microchip,downshift-after:0";
        eth_max_speed = <&eth_phy>,"max-speed:0";
    };
};

上記のブロックはmainlineのほうにはありません。そんなわけでdtoverlay・dtparamを手軽に使うならdtbファイルはブートローダーなんかと一緒に配布されてるdtbファイル(firmwareのリポジトリ)を使いましょうという感じです。

dtoverlay・dtparamはどのように処理されてるか

Raspberry Piブートローダーが自身のデバイスに合う適切なdtbファイルを読んでくれます(公式ドキュメントのどこかにそんなことが書いてありました)。そして、config.txtに記載されてるdtoverlay・dtparamの記述に沿ってメモリ上に読み込まれてるdtbファイルのデータを更新します。そしてそのメモリ上で更新したdtbファイルを使うという流れです。

u-bootをブートローダーとして使いたい場合

Raspberry Piブートローダーはすでにdtbファイルを読み込んでdtoverlay・dtparamの設定もメモリ上で反映させてます。そのため、u-bootがfatloadとかして自分でdtbファイルを読んじゃうと意味がありません。なので、config.txtでdtbファイルを読み込むアドレスを指定し、u-bootのほうはそのアドレスからdtbファイルを読む感じにします。例えばconfig.txtで下記のように読み込むアドレスを指定しておきます。

device_tree_address=0x02600000

u-bootのほうはこんな感じでfdtコマンドを使ってconfig.txtで指定したメモリアドレスを利用します。

setenv fdt_addr_r 0x02600000
fdt addr ${fdt_addr_r}

こんな感じにすればRaspberry Piブートローダーが設定したdtbファイルをu-bootから読めて、それを更にカーネルの起動に利用することができます。