Raspberry Pi 3 のdevice treeの設定がカーネル内のどこで処理されるのかを調べてみました。
とりあえず、分かったところの分だけを公開。
Raspberry Pi3 の device tree の設定
- カーネルソースコードの下記の場所にdevice treeの設定ファイルがあります。
- https://github.com/raspberrypi/linux/blob/rpi-4.4.y/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
- 調べたかったのは、 Raspberry Pi 3のWi-Fi/BTコンボチップ との接続部分なので、その部分だけを見ていきます。
ヘッダ部分
- /dts-v1/; はdeviece treeのバージョンを示す。
- bcm2708.dtsiをインクルードしてデフォルト設定を読み込む。この行以降はデフォルト設定から変更を行うための記述となる。
- / { ... } はルートノードです。
/dts-v1/;
#include "bcm2710.dtsi"
/ {
compatible = "brcm,bcm2710","brcm,bcm2709";
model = "Raspberry Pi 3 Model B";
};
&gpio
- &gpioのノードでmultiplexされた端子の設定を行います。
&gpio {
sdio_pins: sdio_pins {
brcm,pins = <34 35 36 37 38 39>;
brcm,function = <7>; // alt3 = SD1
brcm,pull = <0 2 2 2 2 2>;
};
bt_pins: bt_pins {
brcm,pins = <43>;
brcm,function = <4>; /* alt0:GPCLK2 */
brcm,pull = <0>;
};
uart0_pins: uart0_pins {
brcm,pins = <32 33>;
brcm,function = <7>; /* alt3=UART0 */
brcm,pull = <0 2>;
};
- 34 35 36 37 38 39の番号の を sdio_pinsとして使う。 34はpull無し、36 37 28 29をpull upとする。
- 43 を bt用のクロックとして使う。 43はpull無し。
- 32 33 を BT用のuartとして使う。 32はpull無し、33をpull upとする。
&gpioを処理する部分
- brcm,pinsとprcm,functions,とbrcm,pullはdrivers/pinctrl/bcm/pinctrl-bcm2835.c の bcm2835_pctl_dt_node_to_map()で処理します。
- propetry構造体のポインタ pins と funcs と pulls を of_find_property()で取得
- 要素数 num_pins と num_funcs と num_pullsを取得
- pinctrl_map 構造体をアロケート
- 各ピンに対して
- of_property_read_u32_index()でpin番号を取得
- of_property_read_u32_index()でfunc番号を取得して、bcm2835_pctl_dt_node_to_map_func()でpinにfuncを設定する。
- of_property_read_u32_index()でpull プルアップ/プルダウン設定を取得して、bcm2835_pctl_dt_node_to_map_pull()でpinにプルアップ/プルダウン設定をおこなう。
static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **map, unsigned *num_maps)
{
struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
struct property *pins, *funcs, *pulls;
int num_pins, num_funcs, num_pulls, maps_per_pin;
struct pinctrl_map *maps, *cur_map;
int i, err;
u32 pin, func, pull;
pins = of_find_property(np, "brcm,pins", NULL);
if (!pins) {
dev_err(pc->dev, "%s: missing brcm,pins property\n",
of_node_full_name(np));
return -EINVAL;
}
funcs = of_find_property(np, "brcm,function", NULL);
pulls = of_find_property(np, "brcm,pull", NULL);
if (!funcs && !pulls) {
dev_err(pc->dev,
"%s: neither brcm,function nor brcm,pull specified\n",
of_node_full_name(np));
return -EINVAL;
}
num_pins = pins->length / 4;
num_funcs = funcs ? (funcs->length / 4) : 0;
num_pulls = pulls ? (pulls->length / 4) : 0;
if (num_funcs > 1 && num_funcs != num_pins) {
dev_err(pc->dev,
"%s: brcm,function must have 1 or %d entries\n",
of_node_full_name(np), num_pins);
return -EINVAL;
}
if (num_pulls > 1 && num_pulls != num_pins) {
dev_err(pc->dev,
"%s: brcm,pull must have 1 or %d entries\n",
of_node_full_name(np), num_pins);
return -EINVAL;
}
maps_per_pin = 0;
if (num_funcs)
maps_per_pin++;
if (num_pulls)
maps_per_pin++;
cur_map = maps = kzalloc(num_pins * maps_per_pin * sizeof(*maps),
GFP_KERNEL);
if (!maps)
return -ENOMEM;
for (i = 0; i < num_pins; i++) {
err = of_property_read_u32_index(np, "brcm,pins", i, &pin);
if (err)
goto out;
if (pin >= ARRAY_SIZE(bcm2835_gpio_pins)) {
dev_err(pc->dev, "%s: invalid brcm,pins value %d\n",
of_node_full_name(np), pin);
err = -EINVAL;
goto out;
}
if (num_funcs) {
err = of_property_read_u32_index(np, "brcm,function",
(num_funcs > 1) ? i : 0, &func);
if (err)
goto out;
err = bcm2835_pctl_dt_node_to_map_func(pc, np, pin,
func, &cur_map);
if (err)
goto out;
}
if (num_pulls) {
err = of_property_read_u32_index(np, "brcm,pull",
(num_pulls > 1) ? i : 0, &pull);
if (err)
goto out;
err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin,
pull, &cur_map);
if (err)
goto out;
}
}
*map = maps;
*num_maps = num_pins * maps_per_pin;
return 0;
out:
kfree(maps);
return err;
}
&mmc
- &mmcではmmcドライバの設定を行います。
- Raspberry Pi 3では、SDメモリスロットのつながっているホスト側をsdhostドライバ、Wi-FI/BTチップが繋がっているホスト側をmmcドライバとしています。
&mmc {
pinctrl-names = "default";
pinctrl-0 = <&sdio_pins>;
non-removable;
bus-width = <4>;
status = "okay";
brcm,overclock-50 = <0>;
};
- 端子 sdio_poins
- 取り外ししないデバイスを接続
- バス幅 4bit
- status はデフォルト(cm2708_common.dtsi)だとdisabledになっているのをokayにして有効にする。
- SDCLK 50MHZにする機能:0 (多分無効という意味?)
&mmcを処理する部分
- pinctrl-names と pinctrl-0 がどこで処理されるか不明。 driver/pinctlのどこか
- non-removblable と bus-wideはdrivers/mmc/core/host.c の mmc_of_parse()で処理する。
- status どこで処理しているか不明
- brcm,overclock-50はdrivers/mmc/host/bcm2835-mmc.c の bcm2835_mmc_probe()で処理する。
&uart0
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins &bt_pins>;
status = "okay";
};
- uart0 の部分でUART0の設定をおこなう
- 端子 uart0_pins bt_pins
- status はデフォルト(cm2708_common.dtsi)だとdisabledになっているのをokayにして有効にする。
参考
- https://www.raspberrypi.org/documentation/configuration/device-tree.md
- Linux Kernel の Documentation/devicetree 以下のドキュメント
- pinctrl-bindings.txt