Share on:

2 分鐘閱讀

前言

本篇內容主要介紹如果dtoverlay中沒有你的晶片型號或模組型號,該如何快速撰寫dts建立自己的設備樹。

前提準備

  • 一塊已經裝好RPi OS的樹梅派板子。
  • 下載好rpi linux kernel source code

確認你的設備晶片是否有dts可以直接使用

我們知道要開啟spi或是設定pin腳位功能或是使用了某些晶片元件,需要修改/boot/config.txt檔案~ 如果你還不知道怎麼開啟spi功能與設定pin腳位功能的話可以參考我這篇文章~這邊假設你已經啟用spi功能了。

假設我現在的RPi板子上接上一些額外的元件,我們要先查詢該元件的型號是什麼。假設型號是MCP251xFD的SPI to CAN Bus的晶片~我們在使用底下指令來查看是否有已經寫好的dts可以直接使用。

~$ dtoverlay -a |grep mcp251
  mcp2515
  mcp2515-can0
  mcp2515-can1
  mcp251xfd

經過查詢發現到mcp251xfd,再來我們要詳細看他的參數有哪些怎麼設定。請輸入底下指令。

~$ dtoverlay -h mcp251xfd
Name:   mcp251xfd

Info:   Configures the MCP251XFD CAN controller family
        For devices on spi1 or spi2, the interfaces should be enabled
        with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.

Usage:  dtoverlay=mcp251xfd,<param>=<val>

Params: spi<n>-<m>              Configure device at spi<n>, cs<m>
                                (boolean, required)

        oscillator              Clock frequency for the CAN controller (Hz)

        speed                   Maximum SPI frequence (Hz)

        interrupt               GPIO for interrupt signal

        rx_interrupt            GPIO for RX interrupt signal (nINT1) (optional)

        xceiver_enable          GPIO for CAN transceiver enable (optional)

        xceiver_active_high     specifiy if CAN transceiver enable pin is
                                active high (optional, default: active low)

再來就是依照參數說明做設定,如果還想要知道MCP251xFD這些參數怎麼設定的話可以參考我這篇文章

底下要直接說明如果dtoverlay查詢不到對應的晶片元件該如何自己建立dts!!

建立dts 自己寫晶片元件的dts

如果有人已經寫好的dts當然使用別人寫好的比較快速方便,但如果今天你要使用的晶片沒有人寫dts呢?如下我舉例現在要使用tpm-npct750。

~$ dtoverlay -a |grep tpm
  tpm-slb9670
  tpm-slb9673

從型號中可以發現沒有NPCT750的型號。

我們直接參考類似的晶片元件dts,如tpm-slb9670~ link

/*
 * Device Tree overlay for the Infineon SLB9670 Trusted Platform Module add-on
 * boards, which can be used as a secure key storage and hwrng.
 * available as "Iridium SLB9670" by Infineon and "LetsTrust TPM" by pi3g.
 */

/dts-v1/;
/plugin/;

/ {
	compatible = "brcm,bcm2835";

	fragment@0 {
		target = <&spi0>;
		__overlay__ {
			status = "okay";
		};
	};

	fragment@1 {
		target = <&spidev1>;
		__overlay__ {
			status = "disabled";
		};
	};

	fragment@2 {
		target = <&spi0>;
		__overlay__ {
			/* needed to avoid dtc warning */
			#address-cells = <1>;
			#size-cells = <0>;
			slb9670: slb9670@1 {
				compatible = "infineon,slb9670";
				reg = <1>;	/* CE1 */
				#address-cells = <1>;
				#size-cells = <0>;
				spi-max-frequency = <32000000>;
				status = "okay";
			};

		};
	};
};

依照電路圖我可以得知我的TPM SPI是接到RPi的SPI1、Chip Select 1。 所以我把上面的dts中的

target = <&spi0>改成target = <&spi1>因為是接到SPI1

target = <&spidev1>改成target-path = “spi1/spidev@1” 這段是要關閉spi dev讓她不會再user space 底下長出/dev/spi設備樹出來,該SPI1 CS1已經被NPCT750佔用了所以必須關閉,前者target = <&spidev1>是spi0的spi dev CS1,後者target-path = “spi1/spidev@1”是spi1的spi dev CS1,如果這裡沒有把他disabled的話,會有錯誤訊息說spi dev is in use無法建立/dev/spi1.1。

再來npct750: npct750@1 :前面是label,:後面是node-name 皆為自訂義的名稱,當然我們會寫晶片的型號好讓別人容易理解,@後面是unit-addess,代表節點位置,而且必須要跟reg<>裡面的第一個數值一致,這邊因為我們是Chip Select 1所以數值就是1,你要問我怎麼知道這些規範,請參考device tree spec 第2.2.1節

而compatible的格式是”manufacturer,model”,前者是晶片製造商,後者是晶片driver型號。 這邊我們通常會去找tpm driver source code的.compatible定義~

//tpm_tis_spi_main.c
static const struct of_device_id of_tis_spi_match[] __maybe_unused = {
	{ .compatible = "st,st33htpm-spi", .data = tpm_tis_spi_probe },
	{ .compatible = "infineon,slb9670", .data = tpm_tis_spi_probe },
	{ .compatible = "tcg,tpm_tis-spi", .data = tpm_tis_spi_probe },
	{ .compatible = "google,cr50", .data = cr50_spi_probe },
	{}
};

從driver source code 我們知道有四個選項,而且我們發現前三個都是呼叫同一個function call tpm_tis_spi_probe,所以其實寫哪三個都一樣,但是為了命名原則我們還是會選用TCG specification 這個標準通用型的。網路上也查到此敘述。

Chip: Nuvoton NPCT750, compliant with TCG specification Family “2.0” Rev1.38

最後就是spi-max-frequency這個要去看你晶片的datasheet,頻率不能超過晶片支援的最大頻率。

/dts-v1/;
/plugin/;

/ {
	compatible = "brcm,bcm2835";

	fragment@0 {
		target = <&spi1>;
		__overlay__ {
			status = "okay";
		};
	};

	fragment@1 {
		target-path = "spi1/spidev@1";
		__overlay__ {
			status = "disabled";
		};
	};

	fragment@2 {
		target = <&spi1>;
		__overlay__ {
			/* needed to avoid dtc warning */
			#address-cells = <1>;
			#size-cells = <0>;
			npct750: npct750@1 {
				compatible = "tcg,tpm_tis-spi";
				reg = <1>;	/* CE1 */
				#address-cells = <1>;
				#size-cells = <0>;
				spi-max-frequency = <1000000>;
				status = "okay";
			};

		};
	};
};

編譯dts成dtbo

把剛剛改好的檔案命名好正確的檔名放到/home/caspar/linux/arch/arm64/boot/dts/overlays底下。

~$ cp tpm-npct750-overlay.dts ~/linux/arch/arm64/boot/dts/overlays

進到~/linux/arch/arm64/boot/dts/overlays修改Makefile

$ cd ~/linux/arch/arm64/boot/dts/overlays
$ vim Makefile

移到最下面新增底下程式tpm-npct750.dtbo

        waveshare-can-fd-hat-mode-a.dtbo \
        waveshare-can-fd-hat-mode-b.dtbo \
        wittypi.dtbo \
        wm8960-soundcard.dtbo \
        tpm-npct750.dtbo

targets += dtbs dtbs_install
targets += $(dtbo-y)

開始編譯

$ cd ~/linux
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
  DTCO    arch/arm64/boot/dts/overlays/tpm-npct750.dtbo

最後把編譯出來的tpm-npct750.dtbo放到板子內的/boot/overlays/內

並且修改/boot/config.txt加上這行

# Enable TPM2.0
dtoverlay=tpm-npct750

結語

學會新增dts之後開發其他板子會更容易上手~

留言