Sep 20, 2018 原创文章

  C6678 PCIE(0)-- PDK_c667x_2_0_9 测试例程

C6678 PCIE 开发调试记录

分享到: 0

请保证您的浏览器支持MathJax插件,以免数学公式无法显示

在DSP和FPGA的PCIe通信中,DSP常被做End Point 端使用。

使用命令行导入例程

C6678的Processor SDK,其中提供了相关例程的源代码、RTSC配置文件(.cfg)和一个CCS工程的创建脚本,但没有直接提供CCS工程。需要使用CCS命令行创建。

eclipsec -noSplash -data “F:/workspace_v7” -application com.ti.ccstudio.apps.projectCreate -ccs.name pcie_demo -ccs.outputType executable -ccs.device TMS320C66XX.TMS320C6678 -ccs.definePathVariable PDK_INSTALL_PATH C:/ti/pdk_c667x_2_0_9/packages @scope project -rtsc.target ti.targets.elf.C66 -rtsc.platform ti.platforms.evm6678 -rtsc.buildProfile release -ccs.args C:/ti/pdk_c667x_2_0_9/packages/ti/drv/pcie/example/sample/c6678/c66/bios/PCIE_evmc6678_wSoCLib_C66BiosExampleProject.txt

参考使用:https://e2echina.ti.com/question_answer/dsp_arm/c6000_multicore/f/53/t/10178

代码说明

任务函数初始化

在main函数中定义任务函数,并启动BIOS。


 Task_Params params;  
 Task_Params_init (&params);  
 params.stackSize = 36864; //32768;  
 Task_create((Task_FuncPtr) pcie, &params, NULL);  
 BIOS_start();

模式定义

将模式定义为EP模式


 pcieMode_e PcieModeGbl = pcie_EP_MODE;

任务函数内容

EDMA初始化


 EDMA3_DRV_Handle hEdma = NULL;  
 hEdma = edmaInit(hEdma);  
 if (hEdma==NULL) PCIE_logPrintf("ERROR: EDMA handle not initialized!\n");

获取PCIE LLD版本


 PCIE_logPrintf ("Version #: 0x%08x; string %s\n\n", (unsigned)Pcie_getVersion(), Pcie_getVersionStr());

PCIE初始化


 /* Pass device config to LLD */  
 if ((retVal = Pcie_init (&pcieInitCfg)) != pcie_RET_OK)  
 {  
  PCIE_logPrintf ("LLD device configuration failed\n");  
  exit(1);  
 }

初始化缓存


  /* Initialize application buffers */
  pcieInitAppBuf();
  

启动PCIe模块


  if ((retVal = pciePowerCfg()) != pcie_RET_OK) {
    PCIE_logPrintf ("PCIe Power Up failed (%d)\n", (int)retVal);
    exit(1);
  }
  

创建/启动一个PCIe实例

使用Pcie_open()函数创建一个句柄handle。创建的过程中,PCIe设备并没有发生变化。对于同一个设备可以拥有多个句柄。


Pcie_Handle handle = NULL;


  if ((retVal = Pcie_open(0, &handle)) != pcie_RET_OK)
  {
    PCIE_logPrintf ("Open failed (%d)\n", (int)retVal);
    exit(1);
  }
  

配置 SERDES


  /* Configure SERDES*/
  if ((retVal = pcieSerdesCfg()) != pcie_RET_OK) {
    PCIE_logPrintf ("PCIe Serdes config failed (%d)\n", (int)retVal);
    exit(1);
  }

设置PCIe模式


pcieMode_e PcieModeGbl = pcie_EP_MODE; 


  /* Set the PCIe mode*/
  if ((retVal = Pcie_setInterfaceMode(handle, PcieModeGbl)) != pcie_RET_OK) {
    PCIE_logPrintf ("Set PCIe Mode failed (%d)\n", (int)retVal);
    exit(1);
  }

配置EP模式的PCIe


    /* Configure application registers for End Point*/
    if ((retVal = pcieCfgEP(handle)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("Failed to configure PCIe in EP mode (%d)\n", (int)retVal);
      exit(1);
    }


/*****************************************************************************
 * Function: Configure PCIe in End Point Mode
 ****************************************************************************/

pcieRet_e pcieCfgEP(Pcie_Handle handle)
{
    pcieRet_e retVal;

    pcieObSizeReg_t        obSize;  //Specification of the Outbound Size Register
    pcieGen2Reg_t          gen2;
    pcieType0Bar32bitIdx_t type0Bar32bitIdx;
    pcieStatusCmdReg_t     statusCmd;
    pcieDevStatCtrlReg_t   devStatCtrl;
    pcieAccrReg_t          accr;
                  
    pcieRegisters_t        setRegs;
    pcieRegisters_t        getRegs;

    memset (&obSize,           0, sizeof(obSize));
    memset (&gen2,             0, sizeof(gen2));
    memset (&type0Bar32bitIdx, 0, sizeof(type0Bar32bitIdx));
    memset (&statusCmd,        0, sizeof(statusCmd));
    memset (&devStatCtrl,      0, sizeof(devStatCtrl));
    memset (&accr,             0, sizeof(accr));

    /*Disable link training*/
    if ((retVal = pcieLtssmCtrl(handle, FALSE)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("Failed to disable Link Training!\n");
      return retVal;
    }

    /* Configure the size of the translation regions */   
    memset (&setRegs, 0, sizeof(setRegs));
    memset (&getRegs, 0, sizeof(getRegs));

  #ifdef PCIE_REV0_HW
    /* Only required for rev 0 */
    obSize.size = pcie_OB_SIZE_8MB; //将 PCIe Outbound translation regions 设置为8MB
    setRegs.obSize = &obSize;
    
    if ((retVal = Pcie_writeRegs (handle, pcie_LOCATION_LOCAL, &setRegs)) != pcie_RET_OK) 
    {
      // pcie_LOCATION_LOCAL        < Access the local PCIe peripheral
      // pcie_LOCATION_REMOTE     < Access the remote PCIe peripheral 
      PCIE_logPrintf ("SET OB_SIZE register failed!\n");
      return retVal;
    }
  #endif
      /* Set gen2/link cap */
    if ((retVal = pcieSetGen2(handle)) != pcie_RET_OK)
    {
      PCIE_logPrintf ("pcieSetGen2 failed!\n");
      return retVal;
    }
  
    /* 配置 BAR 掩码 Configure BAR Masks */   
    /* First need to enable writing on BAR mask registers */
    if ((retVal = pcieCfgDbi (handle, 1)) != pcie_RET_OK)
    {
      return retVal;
    }

    /* 配置掩码 Configure Masks*/
    memset (&getRegs, 0, sizeof(getRegs));
    memset (&setRegs, 0, sizeof(setRegs));
    type0Bar32bitIdx.reg.reg32 = PCIE_BAR_MASK; //  PCIE_BAR_MASK --> 0x0FFFFFFF
    setRegs.type0BarMask32bitIdx = &type0Bar32bitIdx;

    /* BAR 0 */
    type0Bar32bitIdx.idx = 0; /* 配置 BAR 0  configure BAR 0*/
    if ((retVal = Pcie_writeRegs (handle, pcie_LOCATION_LOCAL, &setRegs)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("SET BAR MASK register failed!\n");
      return retVal;
    }
  
    /* BAR 1 */
    type0Bar32bitIdx.idx = 1; /* 配置 BAR 1 configure BAR 1*/
    if ((retVal = Pcie_writeRegs (handle, pcie_LOCATION_LOCAL, &setRegs)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("SET BAR MASK register failed!\n");
      return retVal;
    }
  
    /* Disable DBI writes */
    if ((retVal = pcieCfgDbi (handle, 0)) != pcie_RET_OK)
    {
      return retVal;
    }
  
    /* Enable memory access and mastership of the bus */
    memset (&setRegs, 0, sizeof(setRegs));
    memset (&getRegs, 0, sizeof(getRegs));

    getRegs.statusCmd = &statusCmd;
    if ((retVal = Pcie_readRegs (handle, pcie_LOCATION_LOCAL, &getRegs)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("Read Status Comand register failed!\n");
      return retVal;
    }

    //enables device to respond to memory access
    statusCmd.memSp  = 1;  
    //enables mastership of the bus
    statusCmd.busMs  = 1; 
    //device responds to detected parity errors
    statusCmd.resp   = 1;      
    //[rw] serr enenables
    //generation of the appropriate PCI Express error messages to the Root Complex.
    statusCmd.serrEn = 1;

    setRegs.statusCmd = &statusCmd;   
  
    if ((retVal = Pcie_writeRegs (handle, pcie_LOCATION_LOCAL, &setRegs)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("SET Status Command register failed!\n");
      return retVal;
    }

    /* Enable Error Reporting */
    memset (&setRegs, 0, sizeof(setRegs));
    memset (&getRegs, 0, sizeof(getRegs));

    getRegs.devStatCtrl = &devStatCtrl;
    if ((retVal = Pcie_readRegs (handle, pcie_LOCATION_LOCAL, &getRegs)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("Regad Device Status Control register failed!\n");
      return retVal;
    }

    //Enable Unsupported Request Reporting
    devStatCtrl.reqRp = 1;
    //Fatal Error Reporting Enable
    devStatCtrl.fatalErRp = 1;
    //Non-fatal Error Reporting Enable
    devStatCtrl.nFatalErRp = 1;
    //Correctable Error Reporting Enable
    devStatCtrl.corErRp = 1;

    setRegs.devStatCtrl = &devStatCtrl;   
    
    if ((retVal = Pcie_writeRegs (handle, pcie_LOCATION_LOCAL, &setRegs)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("SET Device Status Control register failed!\n");
      return retVal;
    }
 
  #ifdef PCIE_REV0_HW
    /* Enable ECRC */
    memset (&setRegs, 0, sizeof(setRegs));
    
    //ECRC Check Enable
    accr.chkEn=1;
    //ECRC Check Capable
    accr.chkCap=1;
    //ECRC Generation Enable
    accr.genEn=1;
    //ECRC Generation Capability
    accr.genCap=1;

    setRegs.accr = &accr;

    if ((retVal = Pcie_writeRegs (handle, pcie_LOCATION_LOCAL, &setRegs)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("SET ACCR register failed!\n");
      return retVal;
    }
  #endif

    return pcie_RET_OK;
}


配置地址转换

孪生网络

1、Outbound Address Translation(OAT)

存储器域访问PCI域,把设备内部地址映射到PCIE总线上。

2、Inbound Address Translation(IAT)

PCI域访问存储器域、把PCIE总线地址映射到设备内部上。

RC访问EP: RC存储器域->outbound->RC PCI域->EP PCI域->inbound->EP存储器域

EP访问RC:EP存储器域->outbound->EP PCI域->RC PCI域->inbound->RC存储器域

Out即出去,发起访问的一侧,须要进行outbound,去访问对端

In即进来,被访问的一侧,须要进行inbound,使得对端能够访问

EP访问RC演示样例(蓝色箭头)

(1)首先,EP须要配置outbound,RC须要inbound(一般RC端不用配),这样就建立了EP端0x20000000到RC端0x50000000的映射

(2)在RC端改动0x50000000的内容,EP端能够看到对应的变化。从EP端读/写0x20000000和从RC端读/写0x50000000,结果是一样的

RC访问EP演示样例(黑色箭头)

(1)首先,RC端须要配置outbound(一般内核中配好),EP端须要inbound(0x5b000000 inbound到BAR2),这样就建立了RC端0x20100000(BAR2)到EP端0x5b000000的映射。

(2)在EP端改动0x5b000000内存的内容,在RC端0x20100000能够看到对应的变化,从RC端读/写0x20100000和从EP端读/写0x5b000000,结果是一样的。


pcieIbTransCfg_t ibCfg;       
// Specification of pcieBarCfg --> Pcie_cfgBar is used to configure a 32bits BAR Register
pcieBarCfg_t     barCfg;       
// Specification of pcieIbTransCfg --> Configure and enable Inbound Address Translation for rev 0


  /* 配置地址转换 Configure Address Translation */
  
  barCfg.location = pcie_LOCATION_LOCAL; // Local or remote peripheral -->  local PCIe peripheral
  barCfg.mode     = pcie_EP_MODE;              // PCIe mode --> setting the PCIe Mode to End Point
  barCfg.base     = PCIE_IB_LO_ADDR_EP;      // Base Address (32bits) --> Inbound  Base Address for PCIe EP --> 0x70000000
  barCfg.prefetch = pcie_BAR_NON_PREF;     // Prefetch --> Non Prefetchable Region
  barCfg.type     = pcie_BAR_TYPE32;             // Type --> 32 bits BAR
  barCfg.memSpace = pcie_BAR_MEM_MEM; // Memory Space --> Memory BAR 
  barCfg.idx      = PCIE_BAR_IDX_EP;               // BAR Index PCie 1
  
  if ((retVal = Pcie_cfgBar(handle, &barCfg)) != pcie_RET_OK) 
  {
    PCIE_logPrintf ("Failed to configure BAR!\n");
    exit(1);
  }

  ibCfg.ibBar         = PCIE_BAR_IDX_EP;                       // Inbound Translation BAR match --> 1
  ibCfg.ibStartAddrLo = PCIE_IB_LO_ADDR_EP;           // Low Inbound Start address (32bits) --> 0x70000000
  ibCfg.ibStartAddrHi = PCIE_IB_HI_ADDR_EP;            // High Inbound Start address (32bits) --> 0
  ibCfg.ibOffsetAddr  = (uint32_t)pcieConvert_CoreLocal2GlobalAddr ((uint32_t)dstBuf.buf);
                                                                              // Inbound Translation Address Offset(32bits)
  ibCfg.region        = PCIE_IB_REGION_EP;                  // Identifies the translation region (0-3) --> 0

  if ((retVal = pcieIbTransCfg(handle, &ibCfg)) != pcie_RET_OK) 
  {
    PCIE_logPrintf ("Failed to configure Inbound Translation (%d)!\n", (int)retVal);
    exit(1);
  }
  else
  {
    PCIE_logPrintf ("Successfully configured Inbound Translation!\n");
  }


  /*****************************************************************************
  * Function: Configure and enable Inbound Address Translation for rev 0
  ****************************************************************************/
  pcieRet_e pcieIbTransCfg(Pcie_Handle handle, pcieIbTransCfg_t *ibCfg)
  {
    pcieRet_e retVal;

    pcieRegisters_t      setRegs;
    pcieRegisters_t      getRegs;

    pcieCmdStatusReg_t   cmdStatus;

    memset (&setRegs,   0, sizeof(setRegs));
    memset (&getRegs,   0, sizeof(getRegs));
    memset (&cmdStatus, 0, sizeof(cmdStatus));

    /* Set outbound offset registers */
    if ((retVal = Pcie_cfgIbTrans(handle, ibCfg)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("Failed to configure Inbound Translation registers!\n");
      return retVal;
    }

    /*enable Inbound address translation*/
    memset (&setRegs,    0, sizeof(setRegs));
    memset (&getRegs,    0, sizeof(getRegs));

    getRegs.cmdStatus = &cmdStatus;
    if ((retVal = Pcie_readRegs (handle, pcie_LOCATION_LOCAL, &getRegs)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("Read CMD STATUS register failed!\n");
      return retVal;
    }
    cmdStatus.ibXltEn = 1;
    setRegs.cmdStatus = &cmdStatus;   
    
    if ((retVal = Pcie_writeRegs (handle, pcie_LOCATION_LOCAL, &setRegs)) != pcie_RET_OK) 
    {
      PCIE_logPrintf ("SET CMD STATUS register failed!\n");
      return retVal;
    }

    return pcie_RET_OK;
  }


  if ((retVal = pcieObTransCfg (handle, PCIE_OB_LO_ADDR_EP, PCIE_OB_HI_ADDR_EP, PCIE_OB_REGION_EP)) != pcie_RET_OK) 
  {
    PCIE_logPrintf ("Failed to configure Outbound Address Translation(%d)!\n", (int)retVal);
    exit(1);
  }
  else
  {
    PCIE_logPrintf ("Successfully configured Outbound Translation!\n");
  }


  PCIE_logPrintf ("Starting link training...\n");

  /*Enable link training*/
  if ((retVal = pcieLtssmCtrl(handle, TRUE)) != pcie_RET_OK) 
  {
    PCIE_logPrintf ("Failed to Enable Link Training! (%d)\n", (int)retVal);
    exit(1);
  }

  /* Wait for link to be up */
  pcieWaitLinkUp(handle);

  PCIE_logPrintf ("Link is up.\n");
  if ((retVal = pcieCheckLinkParams(handle)) != pcie_RET_OK)
  {
    PCIE_logPrintf ("Link width/speed verification FAILed: %d\n", retVal);
    /* This exit() can be removed if this example is being used as
     * template with non TI card that supports slower or narrower connections
     */
    exit(1);
  }

  if ((retVal = Pcie_getMemSpaceRange (handle, &pcieBase, NULL)) != pcie_RET_OK) {
    PCIE_logPrintf ("getMemSpaceRange failed (%d)\n", (int)retVal);
    exit(1);
  }
  

dstBuf_t        *pciedstBufBase;
pciedstBufBase = (dstBuf_t *)pcieBase; 

EP端读写数据


/* Size of application buffers */
#define PCIE_BUFSIZE_APP 40 

/* Does not need to be aligned (even for cache) since it is only accessed locally */
uint32_t srcBuf[PCIE_BUFSIZE_APP];



    /**********************************************************************/
    /* Wait for a single message from the RC then echo it back            */
    /**********************************************************************/

    /* EP waits for the data received from RC */
    /* EP 端等待从 RC 端接收数据 */

    do {
      cache_invalidate ((void *)dstBuf.buf, PCIE_EXAMPLE_DSTBUF_BYTES);
    } while(dstBuf.buf[PCIE_BUFSIZE_APP] != PCIE_EXAMPLE_BUF_FULL);

    PCIE_logPrintf ("End Point received data.\n");

  

    /* Loopback to RC what was written in the DST buffer.
       Write from EP to RC */
    for (i=0; i<PCIE_BUFSIZE_APP; i++)
    {
      pciedstBufBase->buf[i] = dstBuf.buf[i];
    }
    
    /* Mark that the buffer is full, so RC can process it */
    pciedstBufBase->buf[PCIE_BUFSIZE_APP] = PCIE_EXAMPLE_BUF_FULL;

    /* Note on cache coherence: Write back is not necessary because pcieBase is in
       peripheral address space instead of physical memory*/

    PCIE_logPrintf ("End Point sent data to Root Complex, completing the loopback.\n");

        PCIE_logPrintf ("End of Test.\n");

#ifdef PCIE_EXAMPLE_DMA_EP
    if (PcieExampleEdmaEP(pciedstBufBase, 0xbabeface, 100000,
                          (EDMA3_DRV_Handle)hEdma)) 
    {
      PCIE_logPrintf ("Failed to pass token \n");
      exit(1);
    }
    PCIE_logPrintf ("End Point sent data to Root Complex, DMA completing the loopback.\n");
    PCIE_logPrintf ("End of DMA Test.\n");
#endif

#ifdef PCIE_EXAMPLE_DMA_EP
    if (PcieExampleEdmaEP(pciedstBufBase, 0xbabeface, 100000,
                          (EDMA3_DRV_Handle)hEdma)) 
    {
      PCIE_logPrintf ("Failed to pass token \n");
      exit(1);
    }
    PCIE_logPrintf ("End Point sent data to Root Complex, DMA completing the loopback.\n");
    PCIE_logPrintf ("End of DMA Test.\n");
#endif


#ifdef EDMA
  edmaDeinit(hEdma);
#endif
  PCIE_logPrintf ("Test passed.\n");
  BIOS_exit(0);
  

打赏


感谢您的支持,我会继续努力的!

扫码支持

长按识别二维码或打开支付宝扫一扫 完成打赏
或 使用<支付宝链接>打赏


关闭

分享到: 0