MPSoC邏輯加速模塊數據通道快速設計


 

作者: 付漢傑 hankf@xilinx.com
版本: 1.0
時間: 2019-11-13

 

 

回到目錄前 ***** 回到目錄后

1. 概述

最近十幾年,整個芯片產業都感覺到了摩爾定律的放緩,甚至失效。根據A Domain-Specific Architecture for Deep Neural Networks,以后CPU每年的性能只能進步3%左右。要改進系統性能,只能定制架構(Domain-Specific Architecture)和芯片。

圖片來源於A Domain-Specific Architecture for Deep Neural Networks

而芯片設計的成本在不斷攀升。即使是成熟的28nm工藝,預估的芯片設計成本也超過8千萬美元。因此,定制架構和芯片不是普通中小企業能夠使用的辦法。


圖片來源於FINFET AND FD SOI: MARKET AND COST ANALYSIS

Xilinx SoC芯片,是設計定制架構(Domain-Specific Architecture)的最實惠最可行的辦法。這也是傳統的視頻應用和最前沿的機器學習應用,都大量用到Xilinx SoC芯片的原因。Xilinx SoC芯片,可以在PL(FPGA)中加速各種消耗CPU時間的算法。只要在PL里添加應用的加速算法,Xilinx SoC芯片就變成了Domain Specific Architecture,變成了ASIC(Application Specific Integrated Circuit)。

在PL(FPGA)里集成加速模塊,需要為加速模塊提供高速高效的數據通道。Xilinx為了方便客戶設計,在芯片、IP、驅動層面為數據通道提供了高效可靠的可重用模塊。

1.1. Xilinx SoC芯片對數據通道的支持

Xilinx SoC芯片里,在PS和PL之間,有多個高速數據通道。以MPSoC為例,PS(處理器子系統)和PL(FPGA)之間,PS作為主設備的通路有HPM0_FPD、HPM1_FPD、HPM0_LPD, 可以用於PS控制PL設備;PL作為主設備的通路有HP0、HP1、HP2、HP3、HPC0、HPC1、ACP、ACE, 可以用於PL訪問PS的DDR,使PS和PL通過共享內存交互數據。特別值得一提的是,HPC0、HPC1、ACP、ACE具有cache同步能力。因此后續的例子中,使用了HPC端口,從而在一個硬件設計上,既可以使用軟件管理cache同步,也可以使用硬件管理cache同步。

圖片來源於UG1085 Zynq UltraScale+ Device Technical Reference Manual v2.1 August 21, 2019

1.2. Xilinx IP對數據通道的支持

Xilinx提供了多個DMA IP, 比如AXI CDMA, AXI VDMA, AXI DMA。CDMA適合在內存之間搬移數據。 VDMA主要用於搬移圖像數據。AXI DMA的接口是AXI Stream接口,邏輯設計簡單,效率高,最適合作為加速模塊的數據通道。

1.3. Xilinx 驅動對數據通道的支持

Xilinx為AXI DMA提供成熟穩定的Linux驅動程序、standalone 驅動程序。AXI DMA Linux驅動程序,支持Linux DMA框架。如果在Linux內核使用AXI DMA,按Linux的DMA標准使用流程就行。更多信息,請參考 Xilinx SoftIP DMA'S Linux driver.

1.4. 應用程序對數據通道的支持

應用程序中對DMA的使用,與業務相關,千差萬別,Xilinx沒有提供一個標准應用程序。但是AXI DMA已經在業界得到了廣泛的應用,有多個開源軟件支持AXI DMA。
后續的設計中,使用Brandon Perez Xilinx AXI DMA Driver and Library

回到目錄前 ***** 回到目錄后

2. 測試環境

后續所有設計使用下面的主機、單板和工具進行。

2.1. 主機

Ubuntu 16.04

2.2. 單板及其軟件

  1. ZCU106
  2. U-Boot 2019.1
  3. Linux Kernel 4.19

2.3. 工具

  1. Vivado 2019.1
  2. SDK 2019.1
  3. PetaLinux 2019.1

回到目錄前 ***** 回到目錄后

3. 軟件同步Cache的數據通道設計

3.1. 軟件同步Cache的數據通道的硬件設計

 

大多數嵌入式系統的數據通道,CPU軟件負責管理cache同步。對於這種軟件管理Cache的數據通道,設計簡單,只需要把AXI DMA的管理端口S_AXI_LITE連接到PS的HPM0_FPD,使CPU能控制AXI DMA; 把各個M_AXI接口通過AXI Interconnect連接到HPC0_FPD端口,使AXI DMA能讀寫DDR;MM2S和S2MM通過AXIS_data_fifo連接到一起,實現數據傳輸;把中斷輸出通過IP Concat 連接到PS的中斷輸入。在實際應用中,以實際業務的模塊替換AXIS_data_fifo。
設計中有兩個注意事項。如果系統中有超過32-bit地址的DDR空間,建議讓AXI DMA支持40-bit地址。Xilinx MPSoC超過2GB的DDR的地址是0x800000000(32GB)。如果AXI DMA不支持超過32-bit的地址,就不能訪問在0x800000000的DDR,可能導致問題。AXI DMA的數據緩存比較小,如果數據量大,建議在數據通道上添加AXIS_data_fifo,避免數據溢出和丟失。
為了和后續設計保持一致,下面的設計使用了HPC端口。如果換成HP端口,也是可以工作的。

MPSoC AXI DMA連接圖

AXI DMA內部配置

 

 

MPSoC AXI DMA設計地址分配圖

回到目錄前 ***** 回到目錄后

3.2. 軟件同步Cache的數據通道的Linux驅動設計

3.2.1. Linux Kernel選項

 

為了在Linux中使用AXI DMA, 需要在Linux Kernel中為其增加驅動程序、測試代碼、以及一些輔助模塊。請在Linux Kernel中,為其增加下列模塊。配置后,也可以在Linux的配置文件.config可以找到下列項目。

1. CONFIG_DMADEVICES
2. CONFIG_XILINX_DMA
3. CONFIG_XILINX_DMATEST=m
4. CONFIG_ARM64_PTDUMP_CORE=y
5. CONFIG_ARM64_PTDUMP_DEBUGFS=y

3.2.2. Linux Devicetree

PetaLinux自動為AXI DMA在plnx_workspace\device-tree\device-tree\pl.dtsi創建了Devicetree節點。
注意,AXI DMA的Devicetree節點的標簽(label)被定義成axi_dma_0,它在后面會被反復引用。

 

    axi_dma_0: dma@a0001000 {
        #dma-cells = <1>;
        clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";
        clocks = <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>;
        compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";
        interrupt-names = "mm2s_introut", "s2mm_introut";
        interrupt-parent = <&gic>;
        interrupts = <0 89 4 0 90 4>;
        reg = <0x0 0xa0001000 0x0 0x1000>;
        xlnx,addrwidth = <0x28>;
        xlnx,include-sg ;
        xlnx,sg-length-width = <0x1a>;
        dma-channel@a0001000 {
            compatible = "xlnx,axi-dma-mm2s-channel";
            dma-channels = <0x1>;
            interrupts = <0 89 4>;
            xlnx,datawidth = <0x40>;
            xlnx,device-id = <0x0>;
            xlnx,include-dre ;
        };
        dma-channel@a0001030 {
            compatible = "xlnx,axi-dma-s2mm-channel";
            dma-channels = <0x1>;
            interrupts = <0 90 4>;
            xlnx,datawidth = <0x40>;
            xlnx,device-id = <0x0>;
            xlnx,include-dre ;
        };
    };

工程師需要使能AXI DMA的Devicetree節點,請在meta-user\recipes-bsp\device-tree\files\system-user.dtsi中為它添加屬性status = "okay"。

&axi_dma_0 {
               status = "okay";
    };

有了上述Devicetree節點,AXI DMA的驅動程序能自動從系統得到自己的運行信息,比如地址、中斷號等。

回到目錄前 ***** 回到目錄后

3.3. 軟件同步Cache的數據通道的Linux內核測試

3.3.1. Linux內核測試模塊

在內核測試AXI DMA,需要在內核配置中選擇CONFIG_XILINX_DMATEST。前面的
Linux Kernel選項 已經以模塊形式選擇CONFIG_XILINX_DMATEST。

編譯后,單板的文件系統中會有測試模塊的文件axidmatest.ko。

# ls /lib/modules/4.19.0-xilinx-v2019.1/kernel/drivers/dma/xilinx/ -l
total 20
-rw-r--r--    1 root     root         19760 Nov  1 08:01 axidmatest.ko

3.3.2. Linux內核測試的Devicetree

在內核測試AXI DMA,要在Devicetree中指定測試模塊使用的AXI DMA的模塊名和通道號。下面的devicetree, 測試模塊使用"dmas = <&axi_dma_0 0 &axi_dma_0 1>"指定了設備的標簽axi_dma_0,表示測試模塊使用Linux Devicetree中定義的在地址a0001000的AXI DMA設備。
如果硬件設計中有多個AXI DMA,可以指定不同AXI DMA的label,測試不同的AXI DMA。注意,axidmatest.c的函數xilinx_axidmatest_probe()調用dma_request_slave_channel()時,使用了dma-names之后的字符串axidma0和axidma1,因此在Devicetree文件也必須使用字符串axidma0和axidma1,不能使用其它的名稱。其中axidma0在axidmatest.c的被作為mm2s的DMA通道,axidma1被作為s2mm的DMA通道。

/ {
    axidmatest_1: axidmatest@1 {
        compatible ="xlnx,axi-dma-test-1.00.a";
       dmas = <&axi_dma_0 0
               &axi_dma_0 1>;
        dma-names = "axidma0", "axidma1";
               } ;
};

內核測試模塊axidmatest.c中使用字符串axidma0和axidma1的代碼如下:

static int xilinx_axidmatest_probe(struct platform_device *pdev)
{
    struct dma_chan *chan, *rx_chan;
    int err;

    chan = dma_request_slave_channel(&pdev->dev, "axidma0");
    if (IS_ERR(chan)) {
        pr_err("xilinx_dmatest: No Tx channel\n");
        return PTR_ERR(chan);
    }

    rx_chan = dma_request_slave_channel(&pdev->dev, "axidma1");
    if (IS_ERR(rx_chan)) {
        err = PTR_ERR(rx_chan);
        pr_err("xilinx_dmatest: No Rx channel\n");
        goto free_tx;
    }

    err = dmatest_add_slave_channels(chan, rx_chan);
    if (err) {
        pr_err("xilinx_dmatest: Unable to add channels\n");
        goto free_rx;
    }

    return 0;

free_rx:
    dma_release_channel(rx_chan);
free_tx:
    dma_release_channel(chan);

    return err;
}

3.3.3. Linux內核測試

 

加載內核測試模塊的文件axidmatest.ko,會啟動測試,利用AXI DMA的mm2s通道把數據從DDR搬移到AXI Stream接口,再利用AXI DMA的s2mm DMA通道把數據搬移到DDR。測試次的記錄如下:

# insmod axidmatest.ko
[  210.871166] dmatest: Started 1 threads using dma1chan0 dma1chan1
[  212.937889] dma1chan0-dma1c: terminating after 5 tests, 0 failures (status 0)

內核測試模塊axidmatest.ko還支持參數,test_buf_size指定測試內存塊的字節數,缺省是16384字節;iterations指定測試次數,缺省是5次。測試100次的記錄如下:

# insmod axidmatest.ko test_buf_size=65536 iterations=100
[  210.871166] dmatest: Started 1 threads using dma1chan0 dma1chan1
[  212.937889] dma1chan0-dma1c: terminating after 100 tests, 0 failures (status 0)

回到目錄前 ***** 回到目錄后

3.4. 軟件同步Cache的數據通道的應用程序測試

 

3.4.1. 應用程序

為了方便,使用Brandon Perez在Github上開源的驅動和應用程序 Xilinx AXI DMA Driver and Library測試。
測試代碼包含一個DMA上層驅動,給DMA創建設備節點;數個應用程序,其中axidma_benchmark可以測試AXI DMA性能。

3.4.2. 應用程序的Devicetree

 

測試之前,通過Devicetree指定DMA上層驅動測試時使用的AXI DMA設備。對於下面的devicetree,DMA上層驅動使用"dmas = <&axi_dma_0 0 &axi_dma_0 1>"指定了設備的標簽axi_dma_0,表示DMA上層驅動使用地址a0001000的AXI DMA設備。
測試中,AXI DMA設備有兩個通道,一個是mm2s,一個是s2mm。Xilinx PetaLinux生成的設備樹中,兩個通道的device-id都是0。而Brandon Perez的DMA上層驅動要求每個通道的device-id不同。因此在devicetree中,使用delete-node刪除了自動生成的設備節點axi_dma_0,並復制原來的內容,把其中的device-id分別改為了1和2。

/delete-node/ &axi_dma_0;

/ {
    axi_dma_0: dma@a0001000 {
        #dma-cells = <1>;
        clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";
        clocks = <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>;
        compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";
        interrupt-names = "mm2s_introut", "s2mm_introut";
        interrupt-parent = <&gic>;
        interrupts = <0 89 4 0 90 4>;
        reg = <0x0 0xa0001000 0x0 0x1000>;
        xlnx,addrwidth = <0x28>;
        xlnx,include-sg ;
        xlnx,sg-length-width = <0x1a>;
        dma-channel@a0001000 {
            compatible = "xlnx,axi-dma-mm2s-channel";
            dma-channels = <0x1>;
            interrupts = <0 89 4>;
            xlnx,datawidth = <0x40>;
            xlnx,device-id = <0x1>;
            xlnx,include-dre ;
        };
        dma-channel@a0001030 {
            compatible = "xlnx,axi-dma-s2mm-channel";
            dma-channels = <0x1>;
            interrupts = <0 90 4>;
            xlnx,datawidth = <0x40>;
            xlnx,device-id = <0x2>;
            xlnx,include-dre ;
        };
    };

    axidma_chrdev: axidma_chrdev@0 { 
        compatible = "xlnx,axidma-chrdev"; 
        dmas = <&axi_dma_0 0 &axi_dma_0 1>; 
        dma-names = "tx_channel", "rx_channel"; 
    }; 
};

3.4.3. 應用程序的修改

 

由於Linux Kernel版本變化,需要修改部分代碼。

在driver\axidma_dma.c里,需要增加頭文件of_dma.h。否則,會為axidma_compatible_of_ids[] 報告錯誤“field name not in record or union initializer”。

#include <linux/of_dma.h>

在driver\axidma_chrdev.c的函數axidma_mmap()里,需要為of_dma_configure增加一個參數。否則,會為of_dma_configure()報告錯誤“error: too few arguments to function of_dma_configure”。

    // Configure the DMA device
    //of_dma_configure(dev->device, NULL);
    of_dma_configure(dev->device, NULL, true);

回到目錄前 ***** 回到目錄后

3.4.4. 應用程序編譯

 

在X86的機器上編譯MPSoC A53的代碼,需要通過CROSS_COMPILE設置交叉編譯器。編譯驅動代碼,需要通過ARCH設置CPU架構,並且知道Linux Kernel的源代碼。編譯完成后,在目錄outputs下,有DMA上層驅動文件axidma.ko,和測試應用程序axidma_benchmark。

編譯命令:

$ export ARCH=arm64
$ export CROSS_COMPILE=aarch64-linux-gnu-
$ make KBUILD_DIR=../source/linux-kernel/ clean
$ make KBUILD_DIR=../source/linux-kernel/

3.4.4.1. 應用程序編譯的完整日志:

編譯的完整日志

回到目錄前 ***** 回到目錄后

3.4.5. 應用程序測試

 

將目錄outputs下的所有文件,復制到單板上,增加可執行權限,再安裝DMA上層驅動文件axidma.ko,最后執行測試應用程序axidma_benchmark。

root@xilinx-zcu106-2019_1:~# insmod axidma.ko
[  133.465535] axidma: axidma_dma.c: axidma_dma_init: 729: DMA: Found 1 transmit channels and 1 receive channels.
[  133.475533] axidma: axidma_dma.c: axidma_dma_init: 731: VDMA: Found 0 transmit channels and 0 receive channels.

root@xilinx-zcu106-2019_1:~# ./axidma_benchmark
AXI DMA Benchmark Parameters:
        Transmit Buffer Size: 7.91 MiB
        R[  218.929479] axidma axidma: DMA mask not set
eceive Buffer Size: 7.91 MiB
        Number of DMA Transfers: 1000 transfers
Using transmit channel 1 and receive channel 2.
Single transfer test successfully completed!
Beginning performance analysis of the DMA engine.

DMA Timing Statistics:
        Elapsed Time: 10.41 s
        Transmit Throughput: 760.01 MiB/s
        Receive Throughput: 760.01 MiB/s
        Total Throughput: 1520.03 MiB/s

可以看到,AXI DMA能為發送和接收雙方向都提供760MiBps的性能。

3.4.5.1. 應用程序測試的完整記錄

回到目錄前 ***** 回到目錄后

3.4.6. 雙功能的Linux Devicetree

 

Devicetree只是提供一些參數。我們不會同時運行內核測試和應用程序測試。因此可以內核測試和應用程序測試的參數同時放在一個Devicetree里,是一個內核文件既支持內核測試,又支持應用程序測試。
為了便於讀者測試,下面提供統一的Linux Devicetree。它在應用程序的Devicetree基礎上,增加了內核測試模塊的參數。

/delete-node/ &axi_dma_0;

/ {
    chosen {
              bootargs = "cpuidle.off=1";
       };

    axi_dma_0: dma@a0001000 {
        #dma-cells = <1>;
        clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";
        clocks = <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>;
        compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";
        interrupt-names = "mm2s_introut", "s2mm_introut";
        interrupt-parent = <&gic>;
        interrupts = <0 89 4 0 90 4>;
        reg = <0x0 0xa0001000 0x0 0x1000>;
        xlnx,addrwidth = <0x28>;
        xlnx,include-sg ;
        xlnx,sg-length-width = <0x1a>;
        status = "okay";
    
        dma-channel@a0001000 {
            compatible = "xlnx,axi-dma-mm2s-channel";
            dma-channels = <0x1>;
            interrupts = <0 89 4>;
            xlnx,datawidth = <0x40>;
            xlnx,device-id = <0x1>;
            xlnx,include-dre ;
        };
        dma-channel@a0001030 {
            compatible = "xlnx,axi-dma-s2mm-channel";
            dma-channels = <0x1>;
            interrupts = <0 90 4>;
            xlnx,datawidth = <0x40>;
            xlnx,device-id = <0x2>;
            xlnx,include-dre ;
        };
    };

    axidmatest_1: axidmatest@1 {
            compatible ="xlnx,axi-dma-test-1.00.a";
               dmas = <&axi_dma_0 0
                        &axi_dma_0 1>;
            dma-names = "axidma0", "axidma1";
    } ;
    
    axidma_chrdev: axidma_chrdev@0 { 
        compatible = "xlnx,axidma-chrdev"; 
        dmas = <&axi_dma_0 0 &axi_dma_0 1>; 
        dma-names = "tx_channel", "rx_channel"; 
    }; 
};

回到目錄前 ***** 回到目錄后

3.4.7. 單板上的實際Devicetree

開發人員調試時,經常有多個不同屬性的版本。Cache同步的設置,影響實際功能運行。如果不放心,建議在單板上檢查,是否為DMA設置了硬件同步Cache功能。
在Linux單板上,Devicetree在單板的目錄/sys/firmware/devicetree/base/下。
在下面的記錄中,使用命令ls /sys/firmware/devicetree/base/dma@a0001000/查看DMA設備的信息。可以看到,地址a0001000為dma含有dma-coherent屬性,支持硬件同步Cache功能。查看信息時,使用grep以關鍵詞coherent過濾,可以排除其它信息。

root@xilinx-zcu106-2019_1:~# ls /proc/device-tree -l
lrwxrwxrwx    1 root     root            29 Nov 13 03:12 /proc/device-tree -> /sys/firmware/devicetree/base

root@xilinx-zcu106-2019_1:~# ls /sys/firmware/devicetree/base/
#address-cells   aux_ref_clk      cpus             fclk1            gt_crx_ref_clk   pcap             smmu@fd800000
#size-cells      axidma_chrdev@0  dcc              fclk2            leds             pmu              timer
aliases          axidmatest@1     dma@a0001000     fclk3            memory           psci             video_clk
amba             chosen           dp_aclk          firmware         model            pss_alt_ref_clk  zynqmp_aes
amba_apu@0       compatible       edac             fpga-full        name             pss_ref_clk      zynqmp_ipi
amba_pl@0        cpu_opp_table    fclk0            gpio-keys        nvmem_firmware   sha384           zynqmp_rsa

root@xilinx-zcu106-2019_1:~# ls /sys/firmware/devicetree/base/dma\@a0001000/ -l
total 0
-r--r--r--    1 root     root             4 Nov 13 03:13 #dma-cells
-r--r--r--    1 root     root            62 Nov 13 03:13 clock-names
-r--r--r--    1 root     root            32 Nov 13 03:13 clocks
-r--r--r--    1 root     root            37 Nov 13 03:13 compatible
drwxr-xr-x    2 root     root             0 Nov 13 03:13 dma-channel@a0001000
drwxr-xr-x    2 root     root             0 Nov 13 03:13 dma-channel@a0001030
-r--r--r--    1 root     root             0 Nov 13 03:13 dma-coherent
-r--r--r--    1 root     root            26 Nov 13 03:13 interrupt-names
-r--r--r--    1 root     root             4 Nov 13 03:13 interrupt-parent
-r--r--r--    1 root     root            24 Nov 13 03:13 interrupts
-r--r--r--    1 root     root             4 Nov 13 03:13 name
-r--r--r--    1 root     root             4 Nov 13 03:13 phandle
-r--r--r--    1 root     root            16 Nov 13 03:13 reg
-r--r--r--    1 root     root             5 Nov 13 03:13 status
-r--r--r--    1 root     root             4 Nov 13 03:13 xlnx,addrwidth
-r--r--r--    1 root     root             0 Nov 13 03:13 xlnx,include-sg
-r--r--r--    1 root     root             4 Nov 13 03:13 xlnx,sg-length-width

root@xilinx-zcu106-2019_1:~# ls /sys/firmware/devicetree/base/dma\@a0001000/ -l | grep coherent
-r--r--r--    1 root     root             0 Nov 13 06:36 dma-coherent

回到目錄前 ***** 回到目錄后

4. 硬件同步Cache的數據通道設計

MPSoC PL與PS之間的HPC0、HPC1、ACP、ACE端口,具有硬件同步cache能力。如果使用硬件管理cache同步,可以降低軟件負擔,提升系統能力。
現在使用HPC端口,建立硬件同步cache的數據通道。

4.1. AXI 信號

HPC端口也是AXI端口,含有所有AXI端口的信號。AXI主設備驅動的AxCACHE和AxPROT信號, 要滿足相關的協議要求。具體情況請參考AMBA AXI and ACE Protocol Specification, ARM IHI 0022E

4.1.1. AxCACHE

AXI上的AxCACHE,也就是ARCACHE[3:0]和AWCACHE[3:0],描述AXI傳輸中的內存屬性和cache控制屬性。
需要把AXI上的ARCACHE[3:0]和AWCACHE[3:0],設置成1111, 表示Write-back Read and Write-allocate。

4.1.2. AxPROT

AXI上的AxPROT,也就是ARPROT[2:0]和AWPROT[2:0],表示AXI傳輸中的訪問權限屬性。如果CPU軟件處於EL3,比如裸核(Standalone, bare metal)程序, 執行的是安全訪問(secure access), AxPROT[1] 要設置成0。如果CPU軟件處於EL1和EL0,比如Linux內核驅動和應用程序, 執行的是非安全訪問(non-secure access), AxPROT[1] 要設置成1。

4.2. Cache監聽(Snooping)

4.2.1. Broadcasting Inner Shareable

內存的cache屬性包括non-shareable, inner shareable,outer shareable。inner shareable范圍只包含A53 和L2 cache。缺省情況下,Inner Shareable的內存傳輸不會被廣播給CCI。Linux缺省設置cacheable memory為Inner Shareable,導致CCI看不到所有cacheable memory的傳輸。為了使能硬件同步cache,必須使Inner Shareable的內存傳輸也被廣播給CCI。
寄存器lpd_apu(0xFF41A040)的最低兩位有這個功能,bit 0表示Enable broadcasting of Outer Shareable trasnactions;bit 1表示Enable broadcasting of Inner Shareable transactions。
注意,必須在A53處於復位態時設置寄存器lpd_apu。用啟動文件boot.bin里的寄存器初始化功能設置寄存器lpd_apu,使BootROM在加載時設置寄存器lpd_apu,可以達到上述要求。

4.2.1.1. 寄存器初始化文件

准備寄存器初始化文件,置寄存器lpd_apu最低兩位都為1。

.set. 0xFF41A040 = 0x3;

4.2.1.2. 修改啟動文件boot.bin的配置信息

在啟動文件boot.bin的配置信息中,以關鍵字"[init]"添加寄存器初始化文件,以創建含有寄存器初始化文件的啟動文件。

//arch = zynqmp; split = false; format = BIN
the_ROM_image:
{
   ...
   [init]<path>\regs.init
}

完整的boot.bin的配置信息,bootgen.bif

/* bootgen -arch zynqmp -image bootgen.bif -o BOOT.BIN -w on */

the_ROM_image:
{
    [bootloader, destination_cpu=a53-0] ./zcu106_fsbl.elf
    [pmufw_image] ./images/linux/pmufw.elf 
    [destination_device=pl] ./images/linux/system.bit
    [destination_cpu=a53-0, exception_level=el-3, trustzone] ./images/linux/bl31.elf
    [destination_cpu=a53-0, exception_level=el-2] ./images/linux/u-boot.elf
    [init]./regs.init
}

4.2.1.3. 創建啟動文件boot.bin

SDK和PetaLinux都含有工具bootgen。
通過工具bootgen創建啟動文件boot.bin的命令執行記錄:

$ source /opt/Xilinx/peta/2019.1/settings.sh
$ which bootgen
/xilinxtool/peta/2019.1/tools/xsct/bin/bootgen
$ bootgen -arch zynqmp -image bootgen.bif -o BOOT.BIN -w on 

********Xilinx Bootgen v2019.1
  ******Build date : May 24 2019-14:54:05
    ** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.

4.2.2. FSBL使能CCI監聽APU

缺省情況下,MPSoC CCI (Cache Coherent Interconnect)不監聽傳輸。為了利用CCI cache同步功能,需要使能CCI監聽傳輸功能。

設置寄存器Snoop_Control_Register_S3(0xFD6E4000)的最低位,使CCI監聽APU cluster。寄存器Snoop_Control_Register_S3最低位的含義是Enable issuing of snoop requests from slave interface S3。
在FSBL的xfsbl_main.c的main()里添加下列修改Snoop_Control_Register_S3的部分代碼:

    case XFSBL_STAGE4:
    {

        XFsbl_Printf(DEBUG_INFO,
                "================= In Stage 4 ============ \n\r");

        {
            /* Modify Register Snoop_Control_Register_S3 for HPC Cache Cohenercy */
            unsigned int ui_snoop_control=0;
            XFsbl_Printf(DEBUG_PRINT_ALWAYS,"Check snoop control register at 0xfd6e4000.\n\r");
            ui_snoop_control = XFsbl_In32(0xfd6e4000);
            XFsbl_Printf(DEBUG_PRINT_ALWAYS,"Snoop control register at 0xfd6e4000 original value: 0x%08x.\n\r", ui_snoop_control );
            XFsbl_Out32(0xfd6e4000, ui_snoop_control|0x1);

            ui_snoop_control = XFsbl_In32(0xfd6e4000);
            XFsbl_Printf(DEBUG_PRINT_ALWAYS,"Snoop control register at 0xfd6e4000 new value: 0x%08x.\n\r", ui_snoop_control );
        }
                   
        /**
         * Handoff to the applications
         * Handoff address
         * xip
         * ps7 post config
         */
        FsblStatus = XFsbl_Handoff(&FsblInstance, PartitionNum, EarlyHandoff);

        //... ...        
    }

曾經嘗試讓寄存器初始化文件設置寄存器Snoop_Control_Register_S3,也就是下面的寄存器初始化文件,導致系統不能啟動。

.set. 0xFF41A040 = 0x3;
.set. 0xFD6E4000 = 0xC0000001;

回到目錄前 ***** 回到目錄后

4.3. 硬件同步Cache的數據通道的硬件設計

在前面的軟件管理Cache的數據通道的硬件設計的基礎上,引出GPIO的EMIO管腳,通過Slice IP分配,再控制Cache相關的AXI信號。S_AXI_HPC0_FPD的AWCACHE[3:0]連接到了EMIO[3:0], AWPROT[2:0]連接到了EMIO[7:5],、ARCACHE[3:0]連接到了EMIO[11:8],ARPROT[2:0]信號連接到了EMIO[15:13]。
AXI DMA的內部配置,地址分配等,都保持不變。

支持cache同步的MPSoC AXI DMA連接圖

4.4. 硬件同步Cache的數據通道的Linux驅動設計

4.4.1. Linux Kernel選項

在cache同步的工程里,需要使用GPIO的EMIO管腳,Linux內核需要指出GPIO,請選擇“GPIO_ZYNQ”。不過Xilinx Linux的缺省配置,都包含這個配置項。可以在Linux的配置文件.config搜索CONFIG_GPIO_ZYNQ,確認Linux內核包含“GPIO_ZYNQ”。

CONFIG_GPIO_ZYNQ=y

4.4.2. Linux Devicetree

現在硬件管理Cache同步,因此在Devicetree里給DMA增加Cache同步屬性“dma-coherent”,使Linux跳過Cache刷新操作,節省CPU時間。

&axi_dma_0 {
    status = "okay";
    dma-coherent;
    };

4.4.2.1. 統一的Linux Devicetree

為了便於使用,在雙功能的Linux Devicetree的基礎上增加Cache同步屬性“dma-coherent”,從而同時支持內核測試和應用程序測試。

/include/ "system-conf.dtsi"

/delete-node/ &axi_dma_0;

/ {
    chosen {
              bootargs = "cpuidle.off=1";
       };

    axi_dma_0: dma@a0001000 {
        #dma-cells = <1>;
        clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";
        clocks = <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>;
        compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";
        interrupt-names = "mm2s_introut", "s2mm_introut";
        interrupt-parent = <&gic>;
        interrupts = <0 89 4 0 90 4>;
        reg = <0x0 0xa0001000 0x0 0x1000>;
        xlnx,addrwidth = <0x28>;
        xlnx,include-sg ;
        xlnx,sg-length-width = <0x1a>;
        dma-coherent;
        status = "okay";
    
        dma-channel@a0001000 {
            compatible = "xlnx,axi-dma-mm2s-channel";
            dma-channels = <0x1>;
            interrupts = <0 89 4>;
            xlnx,datawidth = <0x40>;
            xlnx,device-id = <0x1>;
            xlnx,include-dre ;
        };
        dma-channel@a0001030 {
            compatible = "xlnx,axi-dma-s2mm-channel";
            dma-channels = <0x1>;
            interrupts = <0 90 4>;
            xlnx,datawidth = <0x40>;
            xlnx,device-id = <0x2>;
            xlnx,include-dre ;
        };
    };

    axidmatest_1: axidmatest@1 {
            compatible ="xlnx,axi-dma-test-1.00.a";
               dmas = <&axi_dma_0 0
                        &axi_dma_0 1>;
            dma-names = "axidma0", "axidma1";
    } ;
    
    axidma_chrdev: axidma_chrdev@0 { 
        compatible = "xlnx,axidma-chrdev"; 
        dmas = <&axi_dma_0 0 &axi_dma_0 1>; 
        dma-names = "tx_channel", "rx_channel"; 
    }; 
};

4.5. 使用GPIO設置AXI信號

測試中,使用GPIO EMIO管腳來設置AxCACHE[3:0]和AxPROT[1]。
對於GPIO的使用,具體情況請參考Linux GPIO Driver, GPIO User Space App

4.5.1. 系統GPIO信息

Linux系統啟動后,在/sys/class/gpio/創建了相關節點。在ZCU106單板上,MPSoC PS的GPIO號從338開始,其中有78個是GPIO MIO管腳,因此GPIO EMIO管腳從416開始。

root@xilinx-zcu106-2019_1:~# ls /sys/class/gpio/
export       gpiochip306  gpiochip322  gpiochip338  unexport
root@xilinx-zcu106-2019_1:~# ls /sys/class/gpio/ -l
export
gpiochip306 -> ../../devices/platform/amba/ff020000.i2c/i2c-0/0-0021/gpio/gpiochip306
gpiochip322 -> ../../devices/platform/amba/ff020000.i2c/i2c-0/0-0020/gpio/gpiochip322
gpiochip338 -> ../../devices/platform/amba/ff0a0000.gpio/gpio/gpiochip338
unexport
root@xilinx-zcu106-2019_1:~# ls /sys/class/gpio/gpiochip338/
base       device     label      ngpio      power      subsystem  uevent
root@xilinx-zcu106-2019_1:~# cat /sys/class/gpio/gpiochip338/base
338
root@xilinx-zcu106-2019_1:~# cat /sys/class/gpio/gpiochip338/label
zynqmp_gpio
root@xilinx-zcu106-2019_1:~# cat /sys/class/gpio/gpiochip338/ngpio
174

4.5.2. GPIO設置腳本

GPIO操作有點復雜,因此寫了一個腳本,完成設置Cache相關的AXI信號的工作。

#/bin/bash

function gpio_output_func()
{
    # MPSoC EMIO GPIO number.
    gpio_num=$[338+78+$1]
    
    echo "Set GPIO number: $gpio_num to value: $2"

    if [ ! -f /sys/class/gpio/gpio$gpio_num/direction ]; then 
        #  Export a GPIO pin
        echo $gpio_num > /sys/class/gpio/export
    fi
    
    #  Read the direction and value from the GPIO pin */    
    gpio_direction=`cat /sys/class/gpio/gpio$gpio_num/direction`
    gpio_value=`cat /sys/class/gpio/gpio$gpio_num/value`
    echo "GPIO number: $gpio_num previous direction: $gpio_direction, previous value: $gpio_value"
      
    #  Set the direction to an output and write a value 1 to GPIO pin */
    echo out > /sys/class/gpio/gpio$gpio_num/direction
    echo $2 > /sys/class/gpio/gpio$gpio_num/value
    
    gpio_direction=`cat /sys/class/gpio/gpio$gpio_num/direction`
    gpio_value=`cat /sys/class/gpio/gpio$gpio_num/value`
    echo "GPIO number: $gpio_num current direction: $gpio_direction, current value: $gpio_value"

}

# Check GPIO chip
gpio_chip=`cat /sys/class/gpio/gpiochip338/label`
gpio_base=`cat /sys/class/gpio/gpiochip338/base`
gpio_number=`cat /sys/class/gpio/gpiochip338/ngpio`
echo "MPSoC GPIO information: chip: $gpio_chip, base: $gpio_base, number: $gpio_number."

# https://www.xilinx.com/support/answers/69446.html
# awcache, emio[3:0], 1111, Write-back Read and Write-allocate
gpio_output_func 0 1 
gpio_output_func 1 1
gpio_output_func 2 1
gpio_output_func 3 1

# awprot, emio[7:5]
# AxPROT[1] needs to match the security setting and processor exception level for the memory region.
# Bare metal application, EL3, secure memory accesses. AxPROT[1] : 0
# Linux kernel/application, EL1/EL0, non-secure memory accesses. AxPROT[1] : 1
gpio_output_func 5 0
gpio_output_func 6 1
gpio_output_func 7 0

# arcache, emio[11:8], 1111, Write-back Read and Write-allocate
gpio_output_func 8 1
gpio_output_func 9 1
gpio_output_func 10 1
gpio_output_func 11 1

# arprot, emio[15:13]
# Linux kernel/application, EL1/EL0, non-secure memory accesses. AxPROT[1] : 1
gpio_output_func 13 0
gpio_output_func 14 1
gpio_output_func 15 0

4.5.3. GPIO設置記錄

使用前述腳本,設置GPIO很方便。GPIO設置記錄如下:

root@xilinx-zcu106-2019_1:~# ls -l
total 896
-rwxr-x---    1 root     root           944 Nov  1 09:06 axi_dma_test_top.sh
-rwxr-x---    1 root     root           173 Nov  1 09:06 cp_dma_modules.sh
-rwxr-x---    1 root     root          2705 Nov  1 09:06 gpio_set_hpc_cache.sh
-rwxr-x---    1 root     root          1991 Nov  1 09:06 gpio_single_output.sh

root@xilinx-zcu106-2019_1:~# ./gpio_set_hpc_cache.sh
MPSoC GPIO information: chip: zynqmp_gpio, base: 338, number: 174.
Set GPIO number: 416 to value: 1
GPIO number: 416 previous direction: in, previous value: 0
GPIO number: 416 current direction: out, current value: 1
Set GPIO number: 417 to value: 1
GPIO number: 417 previous direction: in, previous value: 0
GPIO number: 417 current direction: out, current value: 1
Set GPIO number: 418 to value: 1
GPIO number: 418 previous direction: in, previous value: 0
GPIO number: 418 current direction: out, current value: 1
Set GPIO number: 419 to value: 1
GPIO number: 419 previous direction: in, previous value: 0
GPIO number: 419 current direction: out, current value: 1
Set GPIO number: 421 to value: 0
GPIO number: 421 previous direction: in, previous value: 0
GPIO number: 421 current direction: out, current value: 0
Set GPIO number: 422 to value: 1
GPIO number: 422 previous direction: in, previous value: 0
GPIO number: 422 current direction: out, current value: 1
Set GPIO number: 423 to value: 0
GPIO number: 423 previous direction: in, previous value: 0
GPIO number: 423 current direction: out, current value: 0
Set GPIO number: 424 to value: 1
GPIO number: 424 previous direction: in, previous value: 0
GPIO number: 424 current direction: out, current value: 1
Set GPIO number: 425 to value: 1
GPIO number: 425 previous direction: in, previous value: 0
GPIO number: 425 current direction: out, current value: 1
Set GPIO number: 426 to value: 1
GPIO number: 426 previous direction: in, previous value: 0
GPIO number: 426 current direction: out, current value: 1
Set GPIO number: 427 to value: 1
GPIO number: 427 previous direction: in, previous value: 0
GPIO number: 427 current direction: out, current value: 1
Set GPIO number: 429 to value: 0
GPIO number: 429 previous direction: in, previous value: 0
GPIO number: 429 current direction: out, current value: 0
Set GPIO number: 430 to value: 1
GPIO number: 430 previous direction: in, previous value: 0
GPIO number: 430 current direction: out, current value: 1
Set GPIO number: 431 to value: 0
GPIO number: 431 previous direction: in, previous value: 0
GPIO number: 431 current direction: out, current value: 0

4.6. 硬件同步Cache的數據通道的Linux內核測試

如果不正確設置cache相關的AXI信號,運行AXI DMA內核模塊測試,會出現發送超時錯誤,錯誤代碼10。

root@xilinx-zcu106-2019_1:~# insmod axidmatest.ko
[  111.124426] dmatest: Started 1 threads using dma1chan0 dma1chan1
[  112.125900] xilinx-vdma a0001000.dma: Cannot start channel (____ptrval____): 10009
[  112.133478] xilinx-vdma a0001000.dma: Channel (____ptrval____) has errors 10, cdr 15aa0000 tdr 15aa0500

[  142.315600] dma1chan0-dma1c: #0: tx test timed out
[  143.321632] xilinx-vdma a0001000.dma: Cannot start channel (____ptrval____): 20009
[  143.329210] xilinx-vdma a0001000.dma: Channel (____ptrval____) has errors 10, cdr 15aa0580 tdr 15aa0a80

[  175.083600] dma1chan0-dma1c: #1: tx test timed out
[  176.089632] xilinx-vdma a0001000.dma: Cannot start channel (____ptrval____): 30009
[  176.097208] xilinx-vdma a0001000.dma: Channel (____ptrval____) has errors 10, cdr 15aa0b00 tdr 15aa1000

[  207.851608] dma1chan0-dma1c: #2: tx test timed out
[  208.857699] xilinx-vdma a0001000.dma: Cannot start channel (____ptrval____): 40009
[  208.865271] xilinx-vdma a0001000.dma: Channel (____ptrval____) has errors 10, cdr 15aa1080 tdr 15aa1580

[  240.619602] dma1chan0-dma1c: #3: tx test timed out
[  241.625660] xilinx-vdma a0001000.dma: Cannot start channel (____ptrval____): 50009
[  241.633238] xilinx-vdma a0001000.dma: Channel (____ptrval____) has errors 10, cdr 15aa1600 tdr 15aa1b00

[  273.387603] dma1chan0-dma1c: #4: tx test timed out
[  273.392400] dma1chan0-dma1c: terminating after 5 tests, 5 failures (status 0)

如果出現上述錯誤,請檢查FSBL修改了寄存器Snoop_Control_Register_S3(0xFD6E4000),有相關打印;Boot.bin含義初始化寄存器lpd_apu(0xFF41A040)的內容;通過GPIO設置了cache相關的AXI信號。能在Linux下讀到寄存器lpd_apu(0xFF41A040)的內容,但是不能讀寄存器Snoop_Control_Register_S3,會收到Bus error。

root@xilinx-zcu106-2019_1:~# devmem 0xFF41A040
0x00000003
root@xilinx-zcu106-2019_1:~# devmem 0xFD6E4000
Bus error

注意,出現測試失敗的情況后,需要重啟動單板。在測試中發現,如果不重啟動單板,即使設置了cache相關的AXI信號,后續測試還是會失敗。

如果所有設置正確,運行AXI DMA內核模塊測試,沒有任何錯誤信息,和傳統數據通路的Linux內核測試的輸出信息一樣。

回到目錄前 ***** 回到目錄后

4.7. 硬件同步Cache的數據通道的應用程序測試

如果不正確設置cache相關的AXI信號,運行AXI DMA內核模塊測試,會出現錯誤。

root@xilinx-zcu106-2019_1:~# ./axidma_benchmark
AXI DMA Benchmark Parameters:
        Transmit Buffer Size: 7.91 MiB
        Receive Buffer Size: 7.91 MiB
        Number of DMA Transfers: 1000 transfers

[  140.621473] axidma axidma: DMA mask not set

Using transmit channel 1 and receive channel 2.

[  140.716763] xilinx-vdma a0001000.dma: Channel (____ptrval____) has errors 10, cdr 15aa0000 tdr 15aa0000
[  141.716756] xilinx-vdma a0001000.dma: Cannot start channel (____ptrval____): 10009
[  151.783898] axidma: axidma_dma.c: axidma_start_transfer: 301: DMA receive transaction timed out.

Failed to perform the AXI DMA read-write transfer: Timer expired

注意,出現測試失敗后,也需要重啟動單板。

如果正確設置cache相關的AXI信號,運行AXI DMA內核模塊測試,沒有任何錯誤信息,和
傳統數據通路的應用程序測試的輸出信息一樣。

回到目錄前 ***** 回到目錄后

5. 數據通道的改進

5.1. 增加AXI Firewall的硬件設計

在設計和調試過程中,可能出現意料之外的錯誤。如果CPU訪問的AXI通道出現問題,會導致系統死機。
為了幫助調試,Xilinx提供了輔助的IP,包括AXI Firewall,AXI protocol checker。AXI Firewall在AXI 波形異常時,主動結束AXI傳輸,保護系統不死機,同時給出出錯信號。建議把AXI Firewall加在PS的輸入和輸出端口,用GPIO EMIO的輸入端口連接AXI Firewall的錯誤指示信號。

增加AXI Firewall的硬件設計連接圖

AXI Firewall的參數配置

增加AXI Firewall的硬件地址分配

5.2. AXI stream設備示例代碼

Vivado提供AXI的示例代碼。在Vivado的菜單“Tools”下,選擇“Create and Package New IP...”, 即可定制AXI stream設備示例代碼。

AXI stream設備示例圖,步驟1

AXI stream設備示例圖,步驟2

AXI stream設備示例圖,步驟3

AXI stream設備示例圖,步驟4

AXI stream設備示例圖,步驟5

使用AXI stream設備示例的硬件設計連接圖

使用AXI stream設備示例的硬件地址分配圖

上述例子,也能正常運行AXI DMA的內核測試和應用程序測試。

5.3. AXI DMA 性能

5.3.1. 提升頻率

上述測試工程,AXI DMA的運行頻率是100MHz。提升頻率到250Mhz,發現性能和之前一樣。

5.3.2. 增加AXI端口

上述測試工程,只使用了一個PS的AXI端口。更改設計,提升頻率到250Mhz,使mm2s和s2mm各用一個AXI端口,發現性能和之前一樣。

回到目錄前 ***** 回到目錄后

6. 設計文件

為了便於客戶移植,把所有設計相關文件打包,封裝在文件zcu106-2019.1-bsp-accel-1113-1730-axi-dma-firewall-hw-coherent.bsp里。

6.1. 硬件工程

PetaLinux BSP文件里,提供了HDF文件project-spec\hw-descriptionsystem.hdf,PetaLinux工程的配置,devicetree文件等。
HDF文件project-spec\hw-description\system.hdf,是一個壓縮文件,得到tcl文件design_1_bd.tcl,可以在Vivado里執行,恢復硬件工程。
為了便於版本管理,只提供了硬件同步Cache、帶AXI Firewall的硬件工程。如果不需要這些特性,可以刪除設置AXI 信號的GPIO信號,AXI Firewall。

6.2. Linux 映象

目錄pre-built\linux\images下含有BOOT.BIN,image.ub,可以直接運行測試。

6.3. 啟動文件

目錄pre-built\linux\images下還有xfsbl_main.c,regs.init,bootgen.bif,用於恢復FSBL,BOOT.BIN。

6.4. 應用層測試程序

目錄re-built\linux\bperez77_xilinx_axidma-master含有應用層測試程序的代碼。
目錄pre-built\linux\bperez77_xilinx_axidma-master\outputs 含有已經編譯好的應用層測試的驅動和程序。

6.5. 測試輔助腳本

目錄/pre-built/linux/scripts下含有幾個測試腳本,用於簡化測試操作。其中axi_dma_test_prep.sh可以把所有文件從SD卡,拷貝到當前目錄。axi_dma_test_run_kernel_one.sh運行一次內核態的測試。axi_dma_test_run_user_benchmark.sh運行一次用戶態的測試。

1. gpio_set_hpc_cache.sh
2. gpio_single_output.sh
3. axi_dma_test_prep.sh
4. axi_dma_test_run_kernel_big.sh
5. axi_dma_test_run_kernel_one.sh
6. axi_dma_test_run_user_benchmark.sh
7. cp_dma_modules.sh
8. gpio_set_hpc_cache.sh
9. gpio_single_output.sh

6.6. 測試運行記錄

為了方便理解,在目錄pre-built\linux\images下提供了完整的Linux運行記錄, linux-axi-dma-test-log.txt。

回到目錄前 ***** 回到目錄后

7. 參考文檔

  1. UG1085 Zynq UltraScale+ Device Technical Reference Manual v2.1 August 21, 2019
  2. UG1228 Zynq UltraScale+ MPSoC Embedded Design Methodology Guide v1.0 March 31, 2017
  3. UG1137 Zynq UltraScale+ MPSoC Software Developer Guide v10.0 June 26, 2019
  4. UG1209 Zynq UltraScale+ MPSoC: Embedded Design Tutorial v2018.2 July 31, 2018
  5. UG1037 AXI Reference Guide v4.0 July 15, 2017
  6. PG021 AXI DMA v7.1 LogiCORE IP Product Guide v7.1 June 14, 2019
  7. PB042 LogiCORE IP Slice Product Brief v1.0 April 6, 2016
  8. PG081 AXI4-Stream Accelerator Adapter v2.1 November 18, 2015
  9. ZCU106 Evaluation Board User Guide UG1244 v1.0 March 28, 2018
  10. AMBA AXI and ACE Protocol Specification, ARM IHI 0022E
  11. Zynq UltraScale MPSoC Cache Coherency
  12. AR# 69446 Zynq UltraScale+ MPSoC Example Design - Use AXI HPC port to perform coherent transfers
  13. Xilinx SoftIP DMA'S Linux driver.
  14. Linux GPIO Driver
  15. GPIO User Space App
  16. Connecting XSDB to Linux CPU idle
  17. Brandon Perez Xilinx AXI DMA Driver and Library
  18. Kawazome Ichiro User space mappable DMA Buffer
  19. Linux DMA From User Space
  20. A Domain-Specific Architecture for Deep Neural Networks
  21. Devicetree Specification Release v0.2 Devicetree.org 20 December 2017
  22. FINFET AND FD SOI: MARKET AND COST ANALYSIS
  23. Device Tree(二):基本概念

回到目錄前 ***** 回到目錄后


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM