Raspberry Pi 3 のDevice Tree Sourceを読む

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とする。
* ４３ を 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 ３では、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