Sep 20, 2018 原创文章
C6678 PCIE(0)-- PDK_c667x_2_0_9 测试例程
在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 (¶ms);
params.stackSize = 36864; //32768;
Task_create((Task_FuncPtr) pcie, ¶ms, 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);