linux 系统中描述硬件的方法为 device tree和 device tree overlay。overlay技术为考虑硬体变更之后需要重新编译新的device tree 文件锁带来的麻烦。device tree 适用于描述系统上的固定硬件资源,,如系统时钟,DMA。而device tree overlay则可以用于系统中需要变更的资源,比如引脚复用。SoCFPGA中的FPGA由于经常需要被动态配置或者部分配置。使用overlay技术来管理配置之后的硬件资是一种便捷方法。
Intel SoCFPGA从2016年开始就加入了overlay的支持,方法是通过configFS来调用fpga manager动态配置FPGA,同时使用 overlay 方法管理硬件资源。
device tree overlay的描述方法依然为节点加属性构成。只是会固定一些结构
/dts-v1/ /plugin/;
/ {
fragment@0 {
target-path = "/soc/base-fpga-region";
#address-cells = <2>;
#size-cells = <1>;
__overlay__ {
}
}
在 __overlay__
添加需要动态描述的信息。
当前,使用SoCEDS中的sopc2dts工具产生的device tree 还不能很好的支持overlay,而内核中带的device tree文件也需要经过修改才能使用。
修改部分需要把 socfpga.dtsi中的base_fpga_region 节点去掉,然后改动板子的dts文件。
soc {
clkmgr@ffd04000 {
clocks {
#clock-cells = <0>;
clk_0: clk_0 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <50000000>;
clock-output-names = "clk_0-clk";
};
fft_sub_clk_0: fft_sub_clk_0 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <50000000>;
clock-output-names = "fft_sub_clk_0-clk";
};
};
};
base_fpga_region: base-fpga-region {
compatible = "fpga-region";
fpga-mgr = <&fpga_mgr>;
fpga-bridges = <&fpga_bridge0>, <&fpga_bridge1>,
<&fpga_bridge2>, <&fpga_bridge3>;
#address-cells = <0x2>;
#size-cells = <0x1>;
ranges = <0x00000000 0x00000000 0xc0000000 0x20000000>,
<0x00000001 0x00000000 0xff200000 0x00200000>;
};
};
其中clock 描述供 overlay的 dts 引用,也许可以不要。这里是参考Altera WorkShop的写法。
而overlay device tree来描述FPGA 的资源,具体如下
/dts-v1/ /plugin/;
/ {
fragment@0 {
target-path = "/soc/base-fpga-region";
#address-cells = <2>;
#size-cells = <1>;
__overlay__ {
#address-cells = <2>;
#size-cells = <1>;
firmware-name = "socfpga.rbf";
sysid_qsys: sysid@0x100001000 {
compatible = "altr,sysid-16.0", "altr,sysid-1.0";
reg = <0x00000001 0x00001000 0x00000008>;
clocks = <&clk_0>;
id = <2899645442>;
timestamp = <1460474164>;
};
validator_subsys_0: validator@0x100010000 {
compatible = "demo,validator-1.0", "demo,validator-1.0";
reg = <0x00000001 0x00010000 0x00000400>;
clocks = <&clk_0>;
};
demo_driver_subsys_0: driver@0x100030000 {
compatible = "demo,driver-1.0", "demo,driver-1.0";
reg = <0x00000001 0x00030000 0x00001000>;
interrupts = <0 48 4>;
clocks = <&clk_0>;
};
fft_sub_sgdma_from_fft: msgdma@0x1000a0000 {
compatible = "altr,msgdma-16.0", "altr,msgdma-1.0";
reg = <0x00000001 0x000a0000 0x00000020>,
<0x00000001 0x000b0000 0x00000010>;
reg-names = "csr", "descriptor_slave";
interrupts = <0 43 4>;
clocks = <&fft_sub_clk_0>;
};
fft_sub_sgdma_to_fft: msgdma@0x100080000 {
compatible = "altr,msgdma-16.0", "altr,msgdma-1.0";
reg = <0x00000001 0x00080000 0x00000020>,
<0x00000001 0x00090000 0x00000010>;
reg-names = "csr", "descriptor_slave";
interrupts = <0 44 4>;
clocks = <&fft_sub_clk_0>;
};
fft_sub_FFT_STadapter_0: fft_stadapter@0x1000d0000 {
compatible = "altr,fft_stadapter-1.1", "altr,fft_stadapter";
reg = <0x00000001 0x000d0000 0x00000010>;
clocks = <&fft_sub_clk_0>;
};
memcpy_msgdma: msgdma@0x100020000 {
compatible = "demo,memcpy_msgdma";
reg = <0x00000001 0x00020000 0x00000020>,
<0x00000001 0x00020020 0x00000010>;
reg-names = "csr", "descriptor_slave";
interrupts = <0 47 4>;
clocks = <&clk_0>;
};
fifo_0: fifo@0x100040020 {
compatible = "ALTR,fifo-16.0", "ALTR,fifo-1.0";
reg = <0x00000001 0x00040020 0x00000004>,
<0x00000001 0x00040030 0x00000004>,
<0x00000001 0x00040000 0x00000020>;
reg-names = "in", "out", "in_csr";
clocks = <&clk_0>;
};
fifo_1: fifo@0x100044020 {
compatible = "ALTR,fifo-16.0", "ALTR,fifo-1.0";
reg = <0x00000001 0x00044020 0x00000004>,
<0x00000001 0x00044030 0x00000004>,
<0x00000001 0x00044000 0x00000020>;
reg-names = "in", "out", "in_csr";
clocks = <&clk_0>;
};
fifo_2: fifo@0x100048020 {
compatible = "ALTR,fifo-16.0", "ALTR,fifo-1.0";
reg = <0x00000001 0x00048020 0x00000004>,
<0x00000001 0x00048030 0x00000004>,
<0x00000001 0x00048000 0x00000020>;
reg-names = "in", "out", "in_csr";
clocks = <&clk_0>;
};
};
};
};
可以看到overlay device tree 中引用到了clk_0 和fft_sub_clk_0。同时这里指定了firmware-name,内核在解析dtbo 文件的时候,会读取这个 rbf 文件配置FPGA,具体工作由内核驱动提供。
编译这个dts 文件产生 dtbo 文件,命令为
dtc -O dtb -o socfpga.dtbo -b 0 -@ socfpga.dts
把dtbo 文件和socfpga.rbf 放到文件系统的 /lib/firmware目录中。
当系统启动之后,需要手动控制overlay文件生效。
mkdir /config
mount -t configfs configfs /config
mkdir /config/device-tree/overlays/test
echo socfpga.dtbo > /config/device-tree/overlays/test/path
执行成功后,FPGA会被正常配置,overlay 部分的device tree 也会生效。
参考资源:
1. https://rocketboards.org/foswiki/view/Documentation/WS2LinuxKernelIntroductionForAlteraSoCDevicesLab4SoCFPGALinuxKernel
2. https://learn.adafruit.com/introduction-to-the-beaglebone-black-device-tree/device-tree-overlays