• FPGA NVME SSD


    一,环境搭建

    1,安装Petalinux插件:将所需的依赖库都先安装(参考UG1144文档要求)

    sudo apt-get install tofrodos iproute2 gawk

    sudo apt-get install gcc git make

    sudo apt-get install xvfb

    sudo apt-get install net-tools libncurses5-dev tftpd

    sudo apt-get install zlib1g-dev zlib1g-dev:i386 libssl-dev flex bison libselinux1

    sudo apt-get install gnupg wget diffstat chrpath socat xterm

    sudo apt-get install autoconf libtool tar unzip texinfo zlib1g-dev gcc-multilib build-essential libsdl1.2-dev libglib2.0-dev

    sudo apt-get install screen pax gzip tar

    sudo apt-get install openssl

    2,Ubuntu系统默认的/bin/sh是dash,而PetaLinux要求的是bash在终端中,执行:sudo dpkg-reconfigure bash

    3,进入.run文件的目录,修改其执行属性:chmod +x petalinux-v2017.4-final-installer.run

    4,安装PetaLinux

    因为安装PetaLinux时不能用root权限,所以先在非root目录下创建一个文件夹,并且修改权限为:755

    mkdir -p /home/alinx/linux-xlnx-xilinx-v2017.4

    chmod 755 /home/alinx/linux-xlnx-xilinx-v2017.4

    在/home目录下创建petalinux文件夹,并且修改权限为755.

    进入.run文件所在的目录,执行安装命令。

    ./petalinux-v2017.4-final-installer.run /home/alinx/linux-xlnx-xilinx-v2017.4

    等待一段时间.run安装包的校验、提取,然后出现许可文件的阅读,按Enter回车键阅读,按Q键退出,按Y键接受许可,需要操作3次,然后等待PetaLinux安装结束。

    INFO: Checking installer checksum...

    INFO: Extracting PetaLinux installer...

    LICENSE AGREEMENTS

    PetaLinux SDK contains software from a number of sources.  Please review

    the following licenses and indicate your acceptance of each to continue.

    You do not have to accept the licenses, however if you do not then you may

    not use PetaLinux SDK.

    Use PgUp/PgDn to navigate the license viewer, and press 'q' to close

    Press Enter to display the license agreements

    Do you accept Xilinx End User License Agreement? [y/N] > y

    Do you accept Webtalk Terms and Conditions? [y/N] > y

    Do you accept Third Party End User License Agreement? [y/N] > y

    5,验证PetaLinux安装成功

    (1)先设置环境变量

    source /opt/Xilinx/Vivado/2017.4/settings64.sh  

    source /opt/pkg/petalinux/settings.sh

    (2)验证环境变量设置成功

    echo $PETALINUX

    如果出现安装路径,则表示成功。

    /home/alinx/linux-xlnx-xilinx-v2017.4

    二,vivado搭建过程:

    PCIE采用了全双工的传输设计,即允许在同一时刻,同时进行发送和接收数据。如下图所示,设备A和设备B之间通过双向的Link相连接,每个Link支持1到32个通道(Lane)。由于是串行总线,因此所有的数据(包括配置信息等)都是以数据包为单位进行发送的。

    vivado中有三种方式实现PCIE数据传输:Programmed I/O(PIO),Peer-to-Peer和DMA。

    调用7 Series Integrated Block for PCI Express IP核,这是最基础的PCIE IP核,比较复杂。

     PCIE IP核所做的工作主要有两点,一个是将TLP包转换成AXI协议;另一个是支持DMA操作。

     

     

    调用AXI Memory Mapped To PCI Express IP核,对7 Series Integrated Block for PCI Express进一步封装,使用Example Design直接运行,但需要添加DMA IP核实现DMA数据传输。

     1,PCIE basics

     2,PCIE link config

     3,PCIE ID

      4,PCIE BARS

    5,PCIE misc

      6,AXI BARS

      7,AXI system

    8,将vivado PCIE_NVME工程FILE->EXPORT->EXPORT HARDWARE,导入生成PCIE_NVME.hdf文件,最终会复制到复制到 zynq_pcie_nvme中的hdf_location.sdk文件夹里面

    顶层文件:

    `timescale 1 ps / 1 ps
     
    module zc706_pcie_wrapper
       (DDR_addr,
        DDR_ba,
        DDR_cas_n,
        DDR_ck_n,
        DDR_ck_p,
        DDR_cke,
        DDR_cs_n,
        DDR_dm,
        DDR_dq,
        DDR_dqs_n,
        DDR_dqs_p,
        DDR_odt,
        DDR_ras_n,
        DDR_reset_n,
        DDR_we_n,
        FIXED_IO_ddr_vrn,
        FIXED_IO_ddr_vrp,
        FIXED_IO_mio,
        FIXED_IO_ps_clk,
        FIXED_IO_ps_porb,
        FIXED_IO_ps_srstb,
        mmcm_lock,
        pcie_7x_mgt_rxn,
        pcie_7x_mgt_rxp,
        pcie_7x_mgt_txn,
        pcie_7x_mgt_txp,
        perst_n,
        ref_clk_clk_n,
        ref_clk_clk_p);
      inout [14:0]DDR_addr;
      inout [2:0]DDR_ba;
      inout DDR_cas_n;
      inout DDR_ck_n;
      inout DDR_ck_p;
      inout DDR_cke;
      inout DDR_cs_n;
      inout [3:0]DDR_dm;
      inout [31:0]DDR_dq;
      inout [3:0]DDR_dqs_n;
      inout [3:0]DDR_dqs_p;
      inout DDR_odt;
      inout DDR_ras_n;
      inout DDR_reset_n;
      inout DDR_we_n;
      inout FIXED_IO_ddr_vrn;
      inout FIXED_IO_ddr_vrp;
      inout [53:0]FIXED_IO_mio;
      inout FIXED_IO_ps_clk;
      inout FIXED_IO_ps_porb;
      inout FIXED_IO_ps_srstb;
      output mmcm_lock;
      input [3:0]pcie_7x_mgt_rxn;
      input [3:0]pcie_7x_mgt_rxp;
      output [3:0]pcie_7x_mgt_txn;
      output [3:0]pcie_7x_mgt_txp;
      input perst_n;
      input [0:0]ref_clk_clk_n;
      input [0:0]ref_clk_clk_p;
     
      wire [14:0]DDR_addr;
      wire [2:0]DDR_ba;
      wire DDR_cas_n;
      wire DDR_ck_n;
      wire DDR_ck_p;
      wire DDR_cke;
      wire DDR_cs_n;
      wire [3:0]DDR_dm;
      wire [31:0]DDR_dq;
      wire [3:0]DDR_dqs_n;
      wire [3:0]DDR_dqs_p;
      wire DDR_odt;
      wire DDR_ras_n;
      wire DDR_reset_n;
      wire DDR_we_n;
      wire FIXED_IO_ddr_vrn;
      wire FIXED_IO_ddr_vrp;
      wire [53:0]FIXED_IO_mio;
      wire FIXED_IO_ps_clk;
      wire FIXED_IO_ps_porb;
      wire FIXED_IO_ps_srstb;
      wire mmcm_lock;
      wire [3:0]pcie_7x_mgt_rxn;
      wire [3:0]pcie_7x_mgt_rxp;
      wire [3:0]pcie_7x_mgt_txn;
      wire [3:0]pcie_7x_mgt_txp;
      wire perst_n;
      wire [0:0]ref_clk_clk_n;
      wire [0:0]ref_clk_clk_p;
     
      zc706_pcie zc706_pcie_i
           (.DDR_addr(DDR_addr),
            .DDR_ba(DDR_ba),
            .DDR_cas_n(DDR_cas_n),
            .DDR_ck_n(DDR_ck_n),
            .DDR_ck_p(DDR_ck_p),
            .DDR_cke(DDR_cke),
            .DDR_cs_n(DDR_cs_n),
            .DDR_dm(DDR_dm),
            .DDR_dq(DDR_dq),
            .DDR_dqs_n(DDR_dqs_n),
            .DDR_dqs_p(DDR_dqs_p),
            .DDR_odt(DDR_odt),
            .DDR_ras_n(DDR_ras_n),
            .DDR_reset_n(DDR_reset_n),
            .DDR_we_n(DDR_we_n),
            .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
            .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
            .FIXED_IO_mio(FIXED_IO_mio),
            .FIXED_IO_ps_clk(FIXED_IO_ps_clk),
            .FIXED_IO_ps_porb(FIXED_IO_ps_porb),
            .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
            .mmcm_lock(mmcm_lock),
            .pcie_7x_mgt_rxn(pcie_7x_mgt_rxn),
            .pcie_7x_mgt_rxp(pcie_7x_mgt_rxp),
            .pcie_7x_mgt_txn(pcie_7x_mgt_txn),
            .pcie_7x_mgt_txp(pcie_7x_mgt_txp),
            .perst_n(perst_n),
            .ref_clk_clk_n(ref_clk_clk_n),
            .ref_clk_clk_p(ref_clk_clk_p));
    endmodule

    10、约束文件:

    #GPIO LEDs
    set_property PACKAGE_PIN A17 [get_ports mmcm_lock]
    set_property IOSTANDARD LVCMOS18 [get_ports mmcm_lock]
     
    # PCI Express reset (perst)
    set_property PACKAGE_PIN AK23 [get_ports perst_n]
    set_property IOSTANDARD LVCMOS18 [get_ports perst_n]
     
    # PCI Express reference clock 100MHz
    set_property PACKAGE_PIN N8 [get_ports {ref_clk_clk_p[0]}]
    set_property PACKAGE_PIN N7 [get_ports {ref_clk_clk_n[0]}]
    create_clock -period 10.000 -name ref_clk_clk_p -waveform {0.000 5.000} [get_ports ref_clk_clk_p]
     
    # MGT locations
    set_property PACKAGE_PIN P5 [get_ports {pcie_7x_mgt_rxn[0]}]
    set_property PACKAGE_PIN P6 [get_ports {pcie_7x_mgt_rxp[0]}]
    set_property PACKAGE_PIN N3 [get_ports {pcie_7x_mgt_txn[0]}]
    set_property PACKAGE_PIN N4 [get_ports {pcie_7x_mgt_txp[0]}]
     
    set_property PACKAGE_PIN T5 [get_ports {pcie_7x_mgt_rxn[1]}]
    set_property PACKAGE_PIN T6 [get_ports {pcie_7x_mgt_rxp[1]}]
    set_property PACKAGE_PIN P1 [get_ports {pcie_7x_mgt_txn[1]}]
    set_property PACKAGE_PIN P2 [get_ports {pcie_7x_mgt_txp[1]}]
     
    set_property PACKAGE_PIN U3 [get_ports {pcie_7x_mgt_rxn[2]}]
    set_property PACKAGE_PIN U4 [get_ports {pcie_7x_mgt_rxp[2]}]
    set_property PACKAGE_PIN R3 [get_ports {pcie_7x_mgt_txn[2]}]
    set_property PACKAGE_PIN R4 [get_ports {pcie_7x_mgt_txp[2]}]
     
    set_property PACKAGE_PIN V5 [get_ports {pcie_7x_mgt_rxn[3]}]
    set_property PACKAGE_PIN V6 [get_ports {pcie_7x_mgt_rxp[3]}]
    set_property PACKAGE_PIN T1 [get_ports {pcie_7x_mgt_txn[3]}]
    set_property PACKAGE_PIN T2 [get_ports {pcie_7x_mgt_txp[3]}]

    PCIE 发送和接收:

     

     

    TLP FPGA 接收端:

     

     

     

    四,在SDK裸机阶段可以先自行测试,就像axi_ethernet PL扩展网口类似。

    1,新建fsbl文件,测试文件添加pcie_gen2_enumerate.c,platform_config.h,platform.c,platform.h

     2,下载验证:接上PS串口根据这些打印信息,判断PCIE有没有初始化或测试成功

    SDK代码:main.c/pcie_gen2_enumerate.c

    #include "xparameters.h"    /* Defines for XPAR constants */
    #include "xaxipcie.h"        /* XAxiPcie level 1 interface */
    #include "stdio.h"
    #include "xil_printf.h"
    /************************** Constant Definitions ****************************/
    #define AXIPCIE_DEVICE_ID     XPAR_AXIPCIE_0_DEVICE_ID
    /*
     * Command register offsets
     */
    #define PCIE_CFG_CMD_IO_EN    0x00000001 /* I/O access enable */
    #define PCIE_CFG_CMD_MEM_EN    0x00000002 /* Memory access enable */
    #define PCIE_CFG_CMD_BUSM_EN    0x00000004 /* Bus master enable */
    #define PCIE_CFG_CMD_PARITY    0x00000040 /* parity errors response */
    #define PCIE_CFG_CMD_SERR_EN    0x00000100 /* SERR report enable */
    /*
     * PCIe Configuration registers offsets
     */
    #define PCIE_CFG_ID_REG            0x0000 /* Vendor ID/Device ID offset */
    #define PCIE_CFG_CMD_STATUS_REG        0x0001 /*
                            * Command/Status Register
                                 * Offset
                            */
    #define PCIE_CFG_PRI_SEC_BUS_REG    0x0006 /*
                            * Primary/Sec.Bus Register
                            * Offset
                            */
    #define PCIE_CFG_CAH_LAT_HD_REG        0x0003 /*
                             * Cache Line/Latency Timer/
                             * Header Type/
                             * BIST Register Offset
                             */
    #define PCIE_CFG_BAR_0_REG        0x0004 /* PCIe Base Addr 0 */
    #define PCIE_CFG_FUN_NOT_IMP_MASK    0xFFFF
    #define PCIE_CFG_HEADER_TYPE_MASK    0x00EF0000
    #define PCIE_CFG_MUL_FUN_DEV_MASK    0x00800000
    #define PCIE_CFG_MAX_NUM_OF_BUS        256
    #define PCIE_CFG_MAX_NUM_OF_DEV        1
    #define PCIE_CFG_MAX_NUM_OF_FUN        8
    #define PCIE_CFG_PRIM_SEC_BUS        0x00070100
    #define PCIE_CFG_HEADER_O_TYPE        0x0000
    #define PCIE_CFG_BAR_0_ADDR        0x00001111
    #define     XAxiPcie_IsGen3(InstancePtr)     \
        (XAxiPcie_ReadReg((InstancePtr)->Config.BaseAddress,     \
        XAXIPCIE_PHYSC_OFFSET) & 0x00001000) ? 1 : 0
    #define     XAxiPcie_IsGen2(InstancePtr)     \
        (XAxiPcie_ReadReg((InstancePtr)->Config.BaseAddress,     \
        XAXIPCIE_PHYSC_OFFSET) & 0x00000001) ? 1 : 0
    #define     XAxiPcie_LinkWidth(InstancePtr)     \
        ((XAxiPcie_ReadReg((InstancePtr)->Config.BaseAddress,     \
        XAXIPCIE_PHYSC_OFFSET) & XAXIPCIE_PHYSC_LINK_WIDTH_MASK) >> 1)
    /**************************** Type Definitions ******************************/
    /*****************Macros (Inline Functions) Definitions ********************/
    /************************** Function Prototypes *****************************/
    int PcieInitRootComplex(XAxiPcie *AxiPciePtr, u16 DeviceId);
    void PCIeEnumerateFabric(XAxiPcie *AxiPciePtr);
    static void __attribute__ ((noinline)) UtilDelay(unsigned int Seconds);
    /************************** Variable Definitions ****************************/
    /* Allocate PCIe Root Complex IP Instance */
    XAxiPcie AxiPcieInstance;
    /****************************************************************************/
    * This function is the entry point for PCIe Root Complex Enumeration Example
    *****************************************************************************/
    int main(void)
    {
        int Status;
        // Allow time for link-up
        UtilDelay(1);
        xil_printf("=============================\r\n");
        xil_printf("PCIe Gen2 Enumeration Example\r\n");
        xil_printf("=============================\r\n");
        /* Initialize Root Complex */
        Status = PcieInitRootComplex(&AxiPcieInstance, AXIPCIE_DEVICE_ID);
        if (Status != XST_SUCCESS)
        {
            xil_printf("Failed to initialize AXI PCIe Root port\r\n");
            return XST_FAILURE;
        }
        /* Scan PCIe Fabric */
        PCIeEnumerateFabric(&AxiPcieInstance);
        return XST_SUCCESS;
    }
     
    /****************************************************************************/
    * This function returns the negotiated PCIe link speed once link-up is achieved
    ******************************************************************************/
    int get_pcie_link_speed(XAxiPcie *AxiPciePtr)
    {
        int is_gen2;
        int is_gen3;
        is_gen2 = XAxiPcie_IsGen2(AxiPciePtr);
        is_gen3 = XAxiPcie_IsGen3(AxiPciePtr);
        if((is_gen2 == 0) && (is_gen3 == 1))
            return(3);
        if((is_gen2 == 1) && (is_gen3 == 0))
            return(2);
        if((is_gen2 == 0) && (is_gen3 == 0))
            return(1);
        return(0);
    }
    /****************************************************************************/
    /**
    * This function returns the negotiated PCIe link width once link-up is achieved
    *
    * @param    AxiPciePtr is a pointer to an instance of XAxiPcie data
    *        structure represents a root complex IP.
    * @return    - link width (1,2,4 or 8)
    ******************************************************************************/
    int get_pcie_link_width(XAxiPcie *AxiPciePtr)
    {
        int i;
        int link_width;
        int result;
        
        link_width = XAxiPcie_LinkWidth(AxiPciePtr);
        result = 1;
        for(i = 0; i < link_width; i++)
            result = result * 2;
        return(result);
    }
    /****************************************************************************/
    /**
    * This function initializes a AXI PCIe IP built as a root complex
    *
    * @param    AxiPciePtr is a pointer to an instance of XAxiPcie data
    *        structure represents a root complex IP.
    * @param     DeviceId is AXI PCIe IP unique ID
    *
    * @return    - XST_SUCCESS if successful.
    *        - XST_FAILURE if unsuccessful.
    *
    * @note     None.
    *
    *
    ******************************************************************************/
    int PcieInitRootComplex(XAxiPcie *AxiPciePtr, u16 DeviceId)
    {
        int Status;
        u32 HeaderData;
        u32 InterruptMask;
        u8  BusNumber;
        u8  DeviceNumber;
        u8  FunNumber;
        u8  PortNumber;
        XAxiPcie_Config *ConfigPtr;
        ConfigPtr = XAxiPcie_LookupConfig(DeviceId);
        Status = XAxiPcie_CfgInitialize(AxiPciePtr, ConfigPtr,ConfigPtr->BaseAddress);
        if (Status != XST_SUCCESS) 
      {
            xil_printf("Failed to initialize PCIe Root Complex" "IP Instance\r\n");
            return XST_FAILURE;
        }
        if(!AxiPciePtr->Config.IncludeRootComplex) 
      {
            xil_printf("Failed to initialize...AXI PCIE is configured""as endpoint\r\n");
            return XST_FAILURE;
        }
        /* Make sure link is up. */
        Status = XAxiPcie_IsLinkUp(AxiPciePtr);
        if (Status != TRUE ) 
      {
            xil_printf("Link:\r\n  - LINK NOT UP!\r\n");
            return XST_FAILURE;
        }
        xil_printf("Link:\r\n  - LINK UP, Gen%d x%d lanes\r\n",
            get_pcie_link_speed(AxiPciePtr),get_pcie_link_width(AxiPciePtr));
        xil_printf("Interrupts:\r\n");
        /* See what interrupts are currently enabled */
        XAxiPcie_GetEnabledInterrupts(AxiPciePtr, &InterruptMask);
        xil_printf("  - currently enabled: %8X\r\n", InterruptMask);
        /* Make sure all interrupts disabled. */
        XAxiPcie_DisableInterrupts(AxiPciePtr, XAXIPCIE_IM_ENABLE_ALL_MASK);
        /* See what interrupts are currently pending */
        XAxiPcie_GetPendingInterrupts(AxiPciePtr, &InterruptMask);
        xil_printf("  - currently pending: %8X\r\n", InterruptMask);
        /* Just if there is any pending interrupt then clear it.*/
        XAxiPcie_ClearPendingInterrupts(AxiPciePtr,XAXIPCIE_ID_CLEAR_ALL_MASK);
        /*Read enabled interrupts and pending interrupts
         * to verify the previous two operations and also
         * to test those two API functions*/
         xil_printf("Cleared pending interrupts:\r\n");
          XAxiPcie_GetEnabledInterrupts(AxiPciePtr, &InterruptMask);
        xil_printf("  - currently enabled: %8X\r\n", InterruptMask);
        XAxiPcie_GetPendingInterrupts(AxiPciePtr, &InterruptMask);
        xil_printf("  - currently pending: %8X\r\n", InterruptMask);
        // Read back requester ID.
        XAxiPcie_GetRequesterId(AxiPciePtr, &BusNumber,
                    &DeviceNumber, &FunNumber, &PortNumber);
        xil_printf("Requester ID:\r\n");
        xil_printf("  - Bus Number: %02X\r\n"
                "  - Device Number: %02X\r\n"
                     "  - Function Number: %02X\r\n"
                         "  - Port Number: %02X\r\n",
                 BusNumber, DeviceNumber, FunNumber, PortNumber);
        /* Set up the PCIe header of this Root Complex */
        XAxiPcie_ReadLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_CMD_STATUS_REG, &HeaderData);
        HeaderData |= (PCIE_CFG_CMD_BUSM_EN | PCIE_CFG_CMD_MEM_EN |
                    PCIE_CFG_CMD_IO_EN | PCIE_CFG_CMD_PARITY |
                                PCIE_CFG_CMD_SERR_EN);
        XAxiPcie_WriteLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_CMD_STATUS_REG, HeaderData);
        /*
         * Read back local config reg.
         * to verify the write.
         */
        xil_printf("PCIe Local Config Space:\r\n");
        XAxiPcie_ReadLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_CMD_STATUS_REG, &HeaderData);
        xil_printf("  - %8X at register CommandStatus\r\n", HeaderData);
        /*
         * Set up Bus number
         */
        HeaderData = PCIE_CFG_PRIM_SEC_BUS;
        XAxiPcie_WriteLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_PRI_SEC_BUS_REG, HeaderData);
        /*
         * Read back local config reg.
         * to verify the write.
         */
        XAxiPcie_ReadLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_PRI_SEC_BUS_REG, &HeaderData);
        xil_printf("  - %8X at register Prim Sec. Bus\r\n", HeaderData);
         /* Now it is ready to function */
        return XST_SUCCESS;
    }
    /*****************************************************************************/
    /**
    * This function enumerates its PCIe system and figures out the nature of each
    * component there like end points,bridges,...
    ******************************************************************************/
    void PCIeEnumerateFabric(XAxiPcie *AxiPciePtr)
    {
        u32 ConfigData;
        u32 PCIeHeaderType;
        u32 PCIeMultiFun;
        u32 PCIeBusNum;
        u32 PCIeDevNum;
        u32 PCIeFunNum;
        u16 PCIeVendorID;
        u32 RegVal;
        xil_printf("Enumeration of PCIe Fabric:\r\n");
        /* Scan PCIe Fabric */
        for (PCIeBusNum = 0; PCIeBusNum < PCIE_CFG_MAX_NUM_OF_BUS;PCIeBusNum++) 
      {
            for (PCIeDevNum = 0; PCIeDevNum < PCIE_CFG_MAX_NUM_OF_DEV;PCIeDevNum++) 
        {
                for (PCIeFunNum = 0;PCIeFunNum < PCIE_CFG_MAX_NUM_OF_FUN;PCIeFunNum++) 
           {
                    /* Vendor ID */
                    XAxiPcie_ReadRemoteConfigSpace(
                        AxiPciePtr,PCIeBusNum,
                        PCIeDevNum, PCIeFunNum,
                        PCIE_CFG_ID_REG, &ConfigData);
                    PCIeVendorID = (u16) (ConfigData & 0xFFFF);
                    if (PCIeVendorID ==PCIE_CFG_FUN_NOT_IMP_MASK)
                    {
                        if (PCIeFunNum == 0)
                        /*
                         * We don't need to look any further on this device.
                         */
                        break;
                    }
                    else
                    {
                        xil_printf("PCIeBus %02X:\r\n"
                            "  - PCIeDev: %02X\r\n"
                            "  - PCIeFunc: %02X\r\n",
                            PCIeBusNum, PCIeDevNum,PCIeFunNum);
                        xil_printf("  - Vendor ID: %04X \r\n",PCIeVendorID);
                        /* Header Type */
                        XAxiPcie_ReadRemoteConfigSpace(
                            AxiPciePtr, PCIeBusNum,
                            PCIeDevNum, PCIeFunNum,
                            PCIE_CFG_CAH_LAT_HD_REG,
                            &ConfigData);
                        PCIeHeaderType = ConfigData & PCIE_CFG_HEADER_TYPE_MASK;
                        PCIeMultiFun = ConfigData &
                            PCIE_CFG_MUL_FUN_DEV_MASK;
                        if (PCIeHeaderType==PCIE_CFG_HEADER_O_TYPE)
                        {
                            /* This is an End Point */
                            xil_printf("  - End Point\r\n");
                            /*
                             * Initialize this end point
                             * and return.
                             */
                            XAxiPcie_ReadRemoteConfigSpace(
                                AxiPciePtr,
                                PCIeBusNum, PCIeDevNum,
                                PCIeFunNum,
                            PCIE_CFG_CMD_STATUS_REG,
                                    &ConfigData);
                            ConfigData|=(PCIE_CFG_CMD_BUSM_EN | PCIE_CFG_CMD_MEM_EN);
                             XAxiPcie_WriteRemoteConfigSpace
                                (AxiPciePtr,
                                PCIeBusNum, PCIeDevNum,
                                PCIeFunNum,
                         PCIE_CFG_CMD_STATUS_REG,ConfigData);
                            /*
                             * Write Address to
                             * PCIe BAR0
                             */
                            ConfigData =
                            (PCIE_CFG_BAR_0_ADDR |
                                PCIeBusNum |
                                PCIeDevNum |
                                PCIeFunNum);
                            XAxiPcie_WriteRemoteConfigSpace
                            (AxiPciePtr,
                            PCIeBusNum, PCIeDevNum,
                            PCIeFunNum, PCIE_CFG_BAR_0_REG,ConfigData);
                            xil_printf("  - End Point has been"
                                " enabled\r\n");
                        }
                        else
               {
                            /* This is a bridge */
                              xil_printf("  - Bridge\r\n");
                        }
                    }
                    if ((!PCIeFunNum) && (!PCIeMultiFun))
             {
        /* If it is function 0 and it is not a multi function device, we don't need
       to look any further on this devie */
                        break;
                    }
                }  /* Functions in one device */
            }  /* Devices on the same bus */
        }  /* Buses in the same system */
        xil_printf("End of Enumeration\r\n");
        /* Bridge enable */
        XAxiPcie_GetRootPortStatusCtrl(AxiPciePtr, &RegVal);
        RegVal |= XAXIPCIE_RPSC_BRIDGE_ENABLE_MASK;
        XAxiPcie_SetRootPortStatusCtrl(AxiPciePtr, RegVal);
        return;
    }
    static void __attribute__ ((noinline)) UtilDelay(unsigned int Seconds)
    {
    #if defined (__MICROBLAZE__) || defined(__PPC__)
        static int WarningFlag = 0;
        /* If MB caches are disabled or do not exist, this delay loop could
         * take minutes instead of seconds (e.g., 30x longer).  Print a warning
         * message for the user (once).  If only MB had a built-in timer!
         */
        if (((mfmsr() & 0x20) == 0) && (!WarningFlag)) {
            WarningFlag = 1;
        }
    #define ITERS_PER_SEC   (XPAR_CPU_CORE_CLOCK_FREQ_HZ / 6)
        asm volatile ("\n"
                "1:               \n\t"
                "addik r7, r0, %0 \n\t"
                "2:               \n\t"
                "addik r7, r7, -1 \n\t"
                "bneid  r7, 2b    \n\t"
                "or  r0, r0, r0   \n\t"
                "bneid %1, 1b     \n\t"
                "addik %1, %1, -1 \n\t"
                :: "i"(ITERS_PER_SEC), "d" (Seconds));
    #else
        sleep(Seconds);
    #endif
    }

     

    三,带系统的编译:

    1,导入硬件:将*.hdf复制到虚拟机里面

     

     

     

     2,导入hdf硬件:petalinux-config --get-hw-description ../linux_base.sdk 

     

     

     

     

    3,启动方式配置

    4,命令配置Linux内核: petalinux-config -c kernel

        我们使用内核配置菜单来启用PCI支持并为NVMExpress设备启用驱动程序:

    (1)启用:总线选项-> PCI支持

             启用:总线选项-> PCI支持->消息信号中断(MSI和MSI-X)

             启用:总线选项-> PCI支持->启用PCI资源重新分配检测 

     

     (2)启用:总线选项-> PCI支持-> PCI主机控制器驱动程序-> Xilinx AXI PCIe主机桥支持

     

     3)启用:设备驱动程序->块设备-> NVM Express块设备

     

     

     5,要配置Linux根文件系统,请运行以下命令: petalinux-config -c rootfs
       (1)配置根文件系统以包括一些实用程序,我们将需要设置NVMe PCIe SSD:
    · 启用PCI utils(用于lspci):文件系统包->控制台/ utils-> pciutils-> pciutils

     

     

     

     

     

    (2)为lsblk,fdisk,mkfs,blkid启用必需的软件包:
    · 文件系统软件包-> base-> util-linux-> util-linux
    · 文件系统软件包->base-> util-linux-> util-linux-blkid
    · 文件系统软件包-> base-> util-linux-> util-linux-fdisk

    · 文件系统软件包->base-> util-linux-> util-linux-mkfs
    · 文件系统软件包->base-> util-linux-> util-linux-mount
     

     

     

     

     

    (3)配置根文件 e2fsprogs

      文件系统软件包->base-> e2fsprogs-> e2fsprogs
    · 文件系统软件包->base-> e2fsprogs-> e2fsprogs-mke2fs

     

     

     

    6,使用命令构建PetaLinux: petalinux-build

       (方法1)生成启动文件:petalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga --u-boot --force 

       (方法2)我们先加载比特流,然后加载内核:

      · petalinux-boot --jtag --fpga --bitstream ../impl_1/design_1_wrapper.bit

    ·   petalinux-boot --jtag --kernel

      通过JTAG传输内核将需要几分钟。等待命令行返回,然后可能还要花10到20秒钟,可以在Putty终端上看到系统启动打印

     

    五,系统启动验证

     1,在PetaLinux中设置NVME SSD

      使用命令检查SSD是否已被识别为块设备:lsblk

     

     使用命令在新分区上创建文件系统mkfs -t ext2 /dev/nvme0n1p1

     

     附SDK测试代码:

    #include "xparameters.h"    /* Defines for XPAR constants */
    #include "xaxipcie.h"        /* XAxiPcie level 1 interface */
    #include "stdio.h"
    #include "xil_printf.h"
    /************************** Constant Definitions ****************************/
    #define AXIPCIE_DEVICE_ID     XPAR_AXIPCIE_0_DEVICE_ID
    #define PCIE_CFG_CMD_IO_EN    0x00000001 /* I/O access enable */
    #define PCIE_CFG_CMD_MEM_EN    0x00000002 /* Memory access enable */
    #define PCIE_CFG_CMD_BUSM_EN    0x00000004 /* Bus master enable */
    #define PCIE_CFG_CMD_PARITY    0x00000040 /* parity errors response */
    #define PCIE_CFG_CMD_SERR_EN    0x00000100 /* SERR report enable */
    //PCIe Configuration registers offsets
    #define PCIE_CFG_ID_REG            0x0000 /* Vendor ID/Device ID offset */
    #define PCIE_CFG_CMD_STATUS_REG        0x0001 /*
                            * Command/Status Register
                            * Offset
                            */
    #define PCIE_CFG_PRI_SEC_BUS_REG    0x0006 /*
                            * Primary/Sec.Bus Register
                            * Offset
                            */
    #define PCIE_CFG_CAH_LAT_HD_REG        0x0003 /*
                             * Cache Line/Latency Timer/
                             * Header Type/
                             * BIST Register Offset
                             */
    #define PCIE_CFG_BAR_0_REG        0x0004 /* PCIe Base Addr 0 */
    #define PCIE_CFG_FUN_NOT_IMP_MASK    0xFFFF
    #define PCIE_CFG_HEADER_TYPE_MASK    0x00EF0000
    #define PCIE_CFG_MUL_FUN_DEV_MASK    0x00800000
    #define PCIE_CFG_MAX_NUM_OF_BUS        256
    #define PCIE_CFG_MAX_NUM_OF_DEV        1
    #define PCIE_CFG_MAX_NUM_OF_FUN        8
    #define PCIE_CFG_PRIM_SEC_BUS        0x00070100
    #define PCIE_CFG_HEADER_O_TYPE        0x0000
    #define PCIE_CFG_BAR_0_ADDR        0x00001111
    // Macros for reading link speed and width from the core
    #define     XAxiPcie_IsGen3(InstancePtr)     \
        (XAxiPcie_ReadReg((InstancePtr)->Config.BaseAddress,     \
        XAXIPCIE_PHYSC_OFFSET) & 0x00001000) ? 1 : 0
    #define     XAxiPcie_IsGen2(InstancePtr)     \
        (XAxiPcie_ReadReg((InstancePtr)->Config.BaseAddress,     \
        XAXIPCIE_PHYSC_OFFSET) & 0x00000001) ? 1 : 0
    #define     XAxiPcie_LinkWidth(InstancePtr)     \
        ((XAxiPcie_ReadReg((InstancePtr)->Config.BaseAddress,     \
        XAXIPCIE_PHYSC_OFFSET) & XAXIPCIE_PHYSC_LINK_WIDTH_MASK) >> 1)
    /**************************** Type Definitions ******************************/
    /***************** Macros (Inline Functions) Definitions ********************/
    /************************** Function Prototypes *****************************/
    int PcieInitRootComplex(XAxiPcie *AxiPciePtr, u16 DeviceId);
    void PCIeEnumerateFabric(XAxiPcie *AxiPciePtr);
    static void __attribute__ ((noinline)) UtilDelay(unsigned int Seconds);
    /************************** Variable Definitions ****************************/
    /* Allocate PCIe Root Complex IP Instance */
    XAxiPcie AxiPcieInstance;
    /****************************************************************************/
    /**
    * This function is the entry point for PCIe Root Complex Enumeration Example
    * @return     - XST_SUCCESS if successful
    *        - XST_FAILURE if unsuccessful.
    *
    * @note     None.
    *
    *****************************************************************************/
    int main(void)
    {
        int Status;
        // Allow time for link-up
        UtilDelay(1);
        xil_printf("=============================\r\n");
        xil_printf("PCIe Gen2 Enumeration Example\r\n");
        xil_printf("=============================\r\n");
        /* Initialize Root Complex */
        Status = PcieInitRootComplex(&AxiPcieInstance, AXIPCIE_DEVICE_ID);
        if (Status != XST_SUCCESS)
       {
            xil_printf("Failed to initialize AXI PCIe Root port\r\n");
            return XST_FAILURE;
        }
        /* Scan PCIe Fabric */
        PCIeEnumerateFabric(&AxiPcieInstance);
        return XST_SUCCESS;
    }
    /****************************************************************************/
    /**
    * This function returns the negotiated PCIe link speed once link-up is achieved
    * @param    AxiPciePtr is a pointer to an instance of XAxiPcie data
    *        structure represents a root complex IP.
    * @return    - 1 if Gen1
    *           - 2 if Gen2
    *           - 3 if Gen3
    *        - 0 if unsuccessful.
    *
    * @note     None.
    ******************************************************************************/
    int get_pcie_link_speed(XAxiPcie *AxiPciePtr)
    {
        int is_gen2;
        int is_gen3;
        is_gen2 = XAxiPcie_IsGen2(AxiPciePtr);
        is_gen3 = XAxiPcie_IsGen3(AxiPciePtr);
        if((is_gen2 == 0) && (is_gen3 == 1))
            return(3);
        if((is_gen2 == 1) && (is_gen3 == 0))
            return(2);
        if((is_gen2 == 0) && (is_gen3 == 0))
            return(1);
        return(0);
    }
    /****************************************************************************/
    /**
    * This function returns the negotiated PCIe link width once link-up is achieved
    * @param    AxiPciePtr is a pointer to an instance of XAxiPcie data
    *        structure represents a root complex IP.
    * @return    - link width (1,2,4 or 8)
    * @note     None.
    ******************************************************************************/
    int get_pcie_link_width(XAxiPcie *AxiPciePtr)
    {
        int i;
        int link_width;
        int result;
        link_width = XAxiPcie_LinkWidth(AxiPciePtr);
        result = 1;
        for(i = 0; i < link_width; i++)
            result = result * 2;
        return(result);
    }
    /****************************************************************************/
    /**
    * This function initializes a AXI PCIe IP built as a root complex
    * @param    AxiPciePtr is a pointer to an instance of XAxiPcie data
    *        structure represents a root complex IP.
    * @param     DeviceId is AXI PCIe IP unique ID
    * @return    - XST_SUCCESS if successful.
    *        - XST_FAILURE if unsuccessful.
    * @note     None.
    ******************************************************************************/
    int PcieInitRootComplex(XAxiPcie *AxiPciePtr, u16 DeviceId)
    {
        int Status;
        u32 HeaderData;
        u32 InterruptMask;
        u8  BusNumber;
          u8  DeviceNumber;
        u8  FunNumber;
        u8  PortNumber;
        XAxiPcie_Config *ConfigPtr;
        ConfigPtr = XAxiPcie_LookupConfig(DeviceId);
        Status = XAxiPcie_CfgInitialize(AxiPciePtr, ConfigPtr,ConfigPtr->BaseAddress);
        if (Status != XST_SUCCESS) 
        {
            xil_printf("Failed to initialize PCIe Root Complex""IP Instance\r\n");
            return XST_FAILURE;
        }
        if(!AxiPciePtr->Config.IncludeRootComplex) 
       {
            xil_printf("Failed to initialize...AXI PCIE is configured"" as endpoint\r\n");
            return XST_FAILURE;
        }
        /* Make sure link is up. */
        Status = XAxiPcie_IsLinkUp(AxiPciePtr);
        if (Status != TRUE ) 
       {
            xil_printf("Link:\r\n  - LINK NOT UP!\r\n");
            return XST_FAILURE;
        }
        xil_printf("Link:\r\n  - LINK UP, Gen%d x%d lanes\r\n",
            get_pcie_link_speed(AxiPciePtr),get_pcie_link_width(AxiPciePtr));
        xil_printf("Interrupts:\r\n");
        /* See what interrupts are currently enabled */
        XAxiPcie_GetEnabledInterrupts(AxiPciePtr, &InterruptMask);
        xil_printf("  - currently enabled: %8X\r\n", InterruptMask);
        /* Make sure all interrupts disabled. */
        XAxiPcie_DisableInterrupts(AxiPciePtr, XAXIPCIE_IM_ENABLE_ALL_MASK);
        /* See what interrupts are currently pending */
        XAxiPcie_GetPendingInterrupts(AxiPciePtr, &InterruptMask);
        xil_printf("  - currently pending: %8X\r\n", InterruptMask);
        /* Just if there is any pending interrupt then clear it.*/
        XAxiPcie_ClearPendingInterrupts(AxiPciePtr,
                            XAXIPCIE_ID_CLEAR_ALL_MASK);
        / * Read enabled interrupts and pending interrupts
         * to verify the previous two operations and also
         * to test those two API functions
         */
        xil_printf("Cleared pending interrupts:\r\n");
        XAxiPcie_GetEnabledInterrupts(AxiPciePtr, &InterruptMask);
        xil_printf("  - currently enabled: %8X\r\n", InterruptMask);
        XAxiPcie_GetPendingInterrupts(AxiPciePtr, &InterruptMask);
        xil_printf("  - currently pending: %8X\r\n", InterruptMask);
        /*
         * Read back requester ID.
         */
        XAxiPcie_GetRequesterId(AxiPciePtr, &BusNumber,
                    &DeviceNumber, &FunNumber, &PortNumber);
        xil_printf("Requester ID:\r\n");
        xil_printf("  - Bus Number: %02X\r\n"
                "  - Device Number: %02X\r\n"
                     "  - Function Number: %02X\r\n"
                         "  - Port Number: %02X\r\n",
                 BusNumber, DeviceNumber, FunNumber, PortNumber);
        /* Set up the PCIe header of this Root Complex */
        XAxiPcie_ReadLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_CMD_STATUS_REG, &HeaderData);
        HeaderData |= (PCIE_CFG_CMD_BUSM_EN | PCIE_CFG_CMD_MEM_EN |
                    PCIE_CFG_CMD_IO_EN | PCIE_CFG_CMD_PARITY |
                                PCIE_CFG_CMD_SERR_EN);
        XAxiPcie_WriteLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_CMD_STATUS_REG, HeaderData);
        /*
         * Read back local config reg.
         * to verify the write.
         */
        xil_printf("PCIe Local Config Space:\r\n");
        XAxiPcie_ReadLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_CMD_STATUS_REG, &HeaderData);
        xil_printf("  - %8X at register CommandStatus\r\n", HeaderData);
        /*
         * Set up Bus number
         */
        HeaderData = PCIE_CFG_PRIM_SEC_BUS;
        XAxiPcie_WriteLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_PRI_SEC_BUS_REG, HeaderData);
        /*
         * Read back local config reg.
         * to verify the write.
         */
        XAxiPcie_ReadLocalConfigSpace(AxiPciePtr,
                        PCIE_CFG_PRI_SEC_BUS_REG, &HeaderData);
        xil_printf("  - %8X at register Prim Sec. Bus\r\n", HeaderData);
        /* Now it is ready to function */
        return XST_SUCCESS;
    }
    /*****************************************************************************/
    /**
    * This function enumerates its PCIe system and figures out the nature of each
    * component there like end points,bridges,...
    *
    * @param     AxiPciePtr is a pointer to an instance of XAxiPcie
    *        data structure represents a root complex IP.
    *
    * @return     None.
    *
    * @note     None.
    *
    ******************************************************************************/
    void PCIeEnumerateFabric(XAxiPcie *AxiPciePtr)
    {
        u32 ConfigData;
        u32 PCIeHeaderType;
        u32 PCIeMultiFun;
        u32 PCIeBusNum;
        u32 PCIeDevNum;
        u32 PCIeFunNum;
        u16 PCIeVendorID;
        u32 RegVal;
        xil_printf("Enumeration of PCIe Fabric:\r\n");
        /* Scan PCIe Fabric */
        for (PCIeBusNum = 0; PCIeBusNum < PCIE_CFG_MAX_NUM_OF_BUS;
                                    PCIeBusNum++) {
            for (PCIeDevNum = 0; PCIeDevNum < PCIE_CFG_MAX_NUM_OF_DEV;
                                    PCIeDevNum++) {
                for (PCIeFunNum = 0;
                    PCIeFunNum < PCIE_CFG_MAX_NUM_OF_FUN;
                                    PCIeFunNum++) {
                    /* Vendor ID */
                    XAxiPcie_ReadRemoteConfigSpace(
                        AxiPciePtr,PCIeBusNum,
                        PCIeDevNum, PCIeFunNum,
                        PCIE_CFG_ID_REG, &ConfigData);
                    PCIeVendorID = (u16) (ConfigData & 0xFFFF);
                    if (PCIeVendorID ==
                            PCIE_CFG_FUN_NOT_IMP_MASK) {
                        if (PCIeFunNum == 0)
                        /*
                         * We don't need to look
                         * any further on this device.
                         */
                        break;
                    }
                    else {
                        xil_printf("PCIeBus %02X:\r\n"
                            "  - PCIeDev: %02X\r\n"
                            "  - PCIeFunc: %02X\r\n",
                            PCIeBusNum, PCIeDevNum,
                                    PCIeFunNum);
                        xil_printf("  - Vendor ID: %04X \r\n",
                                    PCIeVendorID);
                        /* Header Type */
                        XAxiPcie_ReadRemoteConfigSpace(
                            AxiPciePtr, PCIeBusNum,
                            PCIeDevNum, PCIeFunNum,
                            PCIE_CFG_CAH_LAT_HD_REG,
                            &ConfigData);
                        PCIeHeaderType = ConfigData &
                            PCIE_CFG_HEADER_TYPE_MASK;
                        PCIeMultiFun = ConfigData &
                            PCIE_CFG_MUL_FUN_DEV_MASK;
                        if (PCIeHeaderType ==
                            PCIE_CFG_HEADER_O_TYPE) {
                            /* This is an End Point */
                            xil_printf("  - End Point\r\n");
                            /*
                             * Initialize this end point
                             * and return.
                             */
                            XAxiPcie_ReadRemoteConfigSpace(
                                AxiPciePtr,
                                PCIeBusNum, PCIeDevNum,
                                PCIeFunNum,
                            PCIE_CFG_CMD_STATUS_REG,
                                    &ConfigData);
                            ConfigData |=
                            (PCIE_CFG_CMD_BUSM_EN |
                                PCIE_CFG_CMD_MEM_EN);
                            XAxiPcie_WriteRemoteConfigSpace
                                (AxiPciePtr,
                                PCIeBusNum, PCIeDevNum,
                                PCIeFunNum,
                            PCIE_CFG_CMD_STATUS_REG,
                                    ConfigData);
                            /*
                             * Write Address to
                             * PCIe BAR0
                             */
                            ConfigData =
                            (PCIE_CFG_BAR_0_ADDR |
                                PCIeBusNum |
                                PCIeDevNum |
                                PCIeFunNum);
                            XAxiPcie_WriteRemoteConfigSpace
                            (AxiPciePtr,
                            PCIeBusNum, PCIeDevNum,
                            PCIeFunNum, PCIE_CFG_BAR_0_REG,
                            ConfigData);
                            xil_printf("  - End Point has been"
                                " enabled\r\n");
                        }
                        else {
                            /* This is a bridge */
                            xil_printf("  - Bridge\r\n");
                        }
                    }
                    if ((!PCIeFunNum) && (!PCIeMultiFun)) {
                        /*
                         * If it is function 0 and it is not a
                         * multi function device, we don't need
                         * to look any further on this devie
                         */
                        break;
                    }
                }  /* Functions in one device */
            }  /* Devices on the same bus */
        }  /* Buses in the same system */
        xil_printf("End of Enumeration\r\n");
        /* Bridge enable */
        XAxiPcie_GetRootPortStatusCtrl(AxiPciePtr, &RegVal);
        RegVal |= XAXIPCIE_RPSC_BRIDGE_ENABLE_MASK;
        XAxiPcie_SetRootPortStatusCtrl(AxiPciePtr, RegVal);
        return;
    }
    static void __attribute__ ((noinline)) UtilDelay(unsigned int Seconds)
    {
    #if defined (__MICROBLAZE__) || defined(__PPC__)
        static int WarningFlag = 0;
        if (((mfmsr() & 0x20) == 0) && (!WarningFlag)) 
        {
            WarningFlag = 1;
        }
    #define ITERS_PER_SEC   (XPAR_CPU_CORE_CLOCK_FREQ_HZ / 6)
        asm volatile ("\n"
                "1:               \n\t"
                "addik r7, r0, %0 \n\t"
                "2:               \n\t"
                "addik r7, r7, -1 \n\t"
                "bneid  r7, 2b    \n\t"
                "or  r0, r0, r0   \n\t"
                "bneid %1, 1b     \n\t"
                "addik %1, %1, -1 \n\t"
                :: "i"(ITERS_PER_SEC), "d" (Seconds));
    #else
        sleep(Seconds);
    #endif
    }

     

     

     

  • 相关阅读:
    Notepad++ 和正则表达式 只保留自己想要的内容
    【Java基础】Java基础知识
    Go语言的100个错误使用场景(30-40)|数据类型与字符串使用
    【实例分享】银河麒麟高级服务器操作系统环境资源占用异常-情况分析及处理方法
    java计算机毕业设计扶贫平台MyBatis+系统+LW文档+源码+调试部署
    【Python抢票神器】火车票枪票软件到底靠谱吗?实测—终极攻略。
    TCP协议之《自动阻塞CORK控制》
    STM32单片机蓝牙APP智能急救手表跌倒报警心率报警MAX30102
    web前端期末大作业:云南旅游网页主题网站设计——云南城市旅游5页HTML+CSS+JavaScript
    SpringBoot电商项目实战Day10 希尔排序
  • 原文地址:https://blog.csdn.net/hailangdeyingzi/article/details/127828094