/*-------------------------------------------------------------------------------*\ regconfig: From PCIe40 board to access register of FEE through belle2link Qi-Dong Zhou, KEK 2020.03.06 0.01 first version based on reghs.c \*--------------------------------------------------------------------------------*/ #define VERSION 01 #define MOD_DATE 20201102 #include "pcie40_b2slc.h" #include "pcie40_reg.h" #include "pcie40_b2config.h" #include "pcie40_ecs.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <vector> //#define PCIE_DEV 0 #define MAX_NUM_CH 48 #define MAX_NUM_BANK 8 #define MAX_SLOT 3 #define SLC_BAR 2 // parse int dev_slot = 0; // default device slot number, If use multiple PCIe40 on a server, change it with --dev xx option int ch = -1; int bank = -1; unsigned int addr = 0; unsigned int data = 0; char *filename; char *operation; //Flag for switch slc access method bool PCIE40_REG = false; bool USE_FEE8 = false; bool USE_FEE32 = false; bool READ_ONLY = false; bool WRITE = false; bool STREAM = false; bool STREAM_ARICH = false; bool OP_FLAG = false; /* 0 parameter */ #define PCIE40_NOP 0x100 #define PCIE40_LINK 0x101 #define PCIE40_CHECKFEE 0x102 #define PCIE40_TRGOFF 0x104 #define PCIE40_TRGON 0x105 #define PCIE40_RESETB2L 0x110 #define PCIE40_CONFPLL 0x111 #define PCIE40_SETMASK 0x112 #define PCIE40_SETUNMASK 0x113 #define PCIE40_SET_BANKMASK 0x114 #define PCIE40_SET_BANKUNMASK 0x115 /* 0 parameter (obsolete, unused) */ #define PCIE40_TTTRG 0x106 #define PCIE40_DUMTRG 0x107 /* 0 parameter (CDC special) */ #define PCIE40_SUPMODE 0x108 #define PCIE40_RAWMODE 0x109 /* 1 parameter */ #define PCIE40_STREAM 0x200 /* 1 parameter (CDC special) */ #define PCIE40_PDSTLALL 0x201 #define PCIE40_ADCTH 0x202 #define PCIE40_TDCTH 0x203 #define PCIE40_DELAY 0x204 #define PCIE40_WINDOW 0x205 /* 2 parameters */ #define PCIE40_FEE8 0x300 #define PCIE40_FEE32 0x301 /* 2 parameters (CDC special) */ #define PCIE40_PDSTL 0x302 /* defined address */ #define REG_FEEHWTYPE 0x0 #define REG_FEESERIAL 0x0 #define REG_FEEFWTYPE 0x0 #define REG_FEEFWVER 0x0 std::vector<std::string> splitpath(const std::string str, const char del) { size_t first = 0; size_t last = str.find_first_of(del); std::vector<std::string> result; while (first < str.size()) { std::string subStr(str, first, last - first); result.push_back(subStr); first = last + 1; last = str.find_first_of(del, first); if (last == std::string::npos) { last = str.size(); } } return result; } void argument(int argc, char **argv){ char *ARGV0 = argv[0]; for(int i=1;i<argc;i++){ std::string ss = argv[i]; if(ss=="--dev"){ dev_slot = atoi(argv[++i]); if( dev_slot<0 || dev_slot >= MAX_SLOT){ fprintf(stderr, "Invalid device slot %d, Valid slot [0, %d]\n", dev_slot, MAX_SLOT); } } if(ss=="--pcie40"){ PCIE40_REG = true; } if(ss=="--ch"){ ch = atoi(argv[++i]); if( ch<0 || ch >= MAX_NUM_CH){ fprintf(stderr, "Invalid channel ID %d, Valid ID [0, %d]\n", ch, MAX_NUM_CH-1); } } if(ss=="--bank"){ bank = atoi(argv[++i]); if( bank<0 || bank >= MAX_NUM_BANK){ fprintf(stderr, "Invalid bank ID %d, Valid ID [0, %d]\n", ch, MAX_NUM_BANK-1); } } if(ss=="--fee8"){ USE_FEE8 = true; } if(ss=="--fee32"){ USE_FEE32 = true; } if(ss=="-r" || ss=="--read"){ READ_ONLY = true; addr = strtoul(argv[++i], 0, 16); } if(ss=="-w" || ss=="--write"){ WRITE = true; addr = strtoul(argv[++i], 0, 16); data = strtoul(argv[++i], 0, 16); //printf("add = %02x data = %08x\n", addr, data); } if(ss=="--stream"){ STREAM = true; filename = argv[++i]; std::string file_str = filename; char delims = '.'; std::vector<std::string> path = splitpath(file_str, delims); if(path.back() == "bin" || path.back() == "bit"){ STREAM_ARICH = true; } //std::cout << path.back() << std::endl; } if(ss=="--op"){ OP_FLAG = true; operation = argv[++i]; } if(ss=="-h" || ss=="-help"){ fprintf(stderr, "%s version %d.%02d date %d\n" , ARGV0, VERSION/100, VERSION%100, MOD_DATE); fprintf(stderr, "usage: %s --pcie40 -r 0x00050010\n", ARGV0); fprintf(stderr, " %s --ch 0 --fee32 -w 0x12 0x0\n" " --dev xx #device slot number which installed PCIe40\n" " --pcie40 #access the register of pcie40\n" " --ch xx #link channel number\n" " --fee8 or --fee32 #use A7D8 or A16D32 for access register\n" " -r xx or -w xx xx #read or write register with address xx[hex] or data xx[hex]\n\n" " %s --ch 0 --op checkfee\n" " %s --bank 0 --op setbankmask\n" " --op operation name writen in check hsreg()\n\n" " %s --ch 0 --stream /path/firmware.bit\n" " --stream /path/filename #streaming a file by using stream file method\n\n" , ARGV0, ARGV0, ARGV0, ARGV0); return; } } } /* ---------------------------------------------------------------------- *\ hsreg \* ---------------------------------------------------------------------- */ int hsreg(const char *name) { static struct { const char *name; int adrs; } regs[] = { { "link", PCIE40_LINK } , { "checkfee", PCIE40_CHECKFEE }, { "resetb2l", PCIE40_RESETB2L }, { "confpll", PCIE40_CONFPLL }, { "setmask", PCIE40_SETMASK }, { "setunmask", PCIE40_SETUNMASK }, { "setbankmask", PCIE40_SET_BANKMASK }, { "setbankunmask", PCIE40_SET_BANKUNMASK }, { "trghold", PCIE40_TRGOFF }, { "trigger", PCIE40_TRGON }, { "realtrg", PCIE40_TTTRG }, { "simtrg", PCIE40_DUMTRG }, { "simple", PCIE40_SUPMODE }, { "verbose", PCIE40_RAWMODE }, { "supmode", PCIE40_SUPMODE }, { "rawmode", PCIE40_RAWMODE }, { "pdstl", PCIE40_PDSTL }, { "pdstlall", PCIE40_PDSTLALL }, { "adcth", PCIE40_ADCTH }, { "tdcth", PCIE40_TDCTH }, { "delay", PCIE40_DELAY }, { "window", PCIE40_WINDOW }, { "stat", PCIE40REGL_STAT }, }; unsigned int i; if (isdigit(name[0])) { return strtoul(name, 0, 16); } for (i = 0; i<sizeof(regs)/sizeof(regs[0]); i++) { if (strcmp(regs[i].name, name) == 0) { return regs[i].adrs; } } i = strtoul(name, 0, 16); return (i > 0 && i < 0x100) ? i : -1; } //---------------------------------------------------------------------- // getfee // ---------------------------------------------------------------------- int getfee(pcie40reg_t *pcie40) { int hwtype; int serial; int fwtype; int fwver; hwtype = pcie40_readfee8(dev_slot, ch, PCIE40REG_FEEHWTYPE); serial = pcie40_readfee8(dev_slot, ch, PCIE40REG_FEESERIAL); fwtype = pcie40_readfee8(dev_slot, ch, PCIE40REG_FEEFWTYPE); fwver = pcie40_readfee8(dev_slot, ch, PCIE40REG_FEEFWVER); pcie40->feeser = (serial | (hwtype << 8)) & 0xfff; pcie40->feever = (fwver | (fwtype << 8)) & 0xfff; pcie40->feehw = (hwtype >> 4) & 0x0f; pcie40->feefw = (fwtype >> 4) & 0x0f; pcie40->feecrce = pcie40_readfee8(dev_slot, ch, PCIE40REG_CRCERR); return 0; } /* ---------------------------------------------------------------------- *\ pcie40_op \* ---------------------------------------------------------------------- */ int pcie40_op(int dev, int ch, int op_addr, int addr, int data, pcie40reg_t pcie40) { int i; int cmd = 0; int cmd_cdc = 0; switch (op_addr) { case PCIE40_LINK: cmd = 0x01; break; case PCIE40_TRGOFF: cmd = 0x03; break; case PCIE40_TRGON: cmd = 0x04; break; case PCIE40_SUPMODE: cmd_cdc = 0x07; break; /* suppress mode */ case PCIE40_RAWMODE: cmd_cdc = 0x08; break; /* raw mode */ } if (op_addr == PCIE40_CHECKFEE) { if (!pcie40_b2l_status(dev_slot, ch)) { printf("Failed: b2l is down\n"); return -1; } pcie40reg_t *pcie = &pcie40; memset(pcie, 0, sizeof(*pcie)); pcie->feeser = 0xffff; pcie->feever = 0xffff; getfee(pcie); if (pcie->feeser & 0x8000) { printf("fee info is not available\n"); } else { printf("%s serial %d version %d\n", feename(pcie->feehw, pcie->feefw), pcie->feeser, pcie->feever); } } else if (op_addr == PCIE40_RESETB2L) { pcie40_resetMinipodLink(dev, ch); printf("B2LINK-%02d is %s\n",ch, pcie40_b2l_status(dev_slot, ch)?"UP":"DOWN or NOT READY"); } else if (op_addr == PCIE40_CONFPLL) { pcie40_configurePLLs(dev); } else if (op_addr == PCIE40_SETMASK) { pcie40_b2l_set_mask(dev_slot, ch, true); } else if (op_addr == PCIE40_SETUNMASK) { pcie40_b2l_set_mask(dev_slot, ch, false); } else if (op_addr == PCIE40_SET_BANKMASK) { pcie40_b2l_set_bankmask(dev_slot, bank, true); } else if (op_addr == PCIE40_SET_BANKUNMASK) { pcie40_b2l_set_bankmask(dev_slot, bank, false); } else if (cmd) { pcie40_writefee8(dev, ch, PCIE40REG_FEECONT, cmd); } else if (cmd_cdc) { pcie40_writefee8(dev, ch, PCIE40REG_CDCCONT, cmd_cdc); }else if (op_addr == PCIE40_PDSTL) { if (addr <= 0 || addr > 48) { printf("pedestal channel %d out of range [1,48]\n", addr); return -1; } pcie40_writefee8(dev, ch, PCIE40REG_PDSTLMIN + (addr-1)*2+0, (data>>0) & 0xff); pcie40_writefee8(dev, ch, PCIE40REG_PDSTLMIN + (addr-1)*2+1, (data>>8) & 0xff); } else if (op_addr == PCIE40_PDSTLALL) { for (i=1; i<=48; i++) { pcie40_writefee8(dev, ch, PCIE40REG_PDSTLMIN + (i-1)*2+0, (addr>>0) & 0xff); pcie40_writefee8(dev, ch, PCIE40REG_PDSTLMIN + (i-1)*2+1, (addr>>8) & 0xff); } } else if (op_addr == PCIE40_ADCTH || op_addr == PCIE40_TDCTH) { int adr = (op_addr == PCIE40_ADCTH) ? PCIE40REG_ADCTH : PCIE40REG_TDCTH; if (addr != -1) { pcie40_writefee8(dev, ch, adr + 0, (addr>>0) & 0xff); pcie40_writefee8(dev, ch, adr + 1, (addr>>8) & 0xff); } else { printf("reg%02x = %02x%02x\n", adr, pcie40_readfee8(dev, ch, adr + 1) & 0xff, pcie40_readfee8(dev, ch, adr + 0) & 0xff); } }else if (op_addr == PCIE40_WINDOW || op_addr == PCIE40_DELAY) { int adr = (op_addr == PCIE40_WINDOW) ? PCIE40REG_WINDOW : PCIE40REG_DELAY; if (addr != -1) { pcie40_writefee8(dev, ch, adr, addr & 0xff); } else { printf("reg%02x = %02x\n", adr, pcie40_readfee8(dev, ch, adr)); } } else { printf("undefined action %x\n", op_addr); return -1; } return 0; } int main(int argc, char** argv){ // parse arguments argument(argc, argv); // open pcie40 device driver for current process ecs_open( dev_slot , SLC_BAR ); int result = -1; pcie40reg_t pcie40; if(PCIE40_REG && READ_ONLY){ result = ecs_read( dev_slot , SLC_BAR , addr); printf("reg%08x = %08x\n", addr, result); } //register access via b2l if(USE_FEE8 || USE_FEE32 || STREAM){ if(pcie40_b2l_status(dev_slot, ch)){ if(USE_FEE8 && READ_ONLY){ result = pcie40_readfee8( dev_slot , ch , addr ); printf("reg%04x = %08x\n", addr, result); }else if(USE_FEE8 && WRITE){ result = pcie40_writefee8( dev_slot , ch , addr, data ); if(result == 0) printf("Write 0x%04x to register 0x%04x\n", data, addr); else printf("ERROR: Failed to write 0x%04x to register 0x%04x\n", data, addr); }else if(USE_FEE32 && READ_ONLY){ result = pcie40_readfee32( dev_slot , ch , addr ); printf("reg%04x = %08x\n", addr, result); }else if(USE_FEE32 && WRITE){ result = pcie40_writefee32( dev_slot , ch , addr, data ); if(result == 0) printf("Write 0x%08x to register 0x%04x\n", data, addr); else printf("ERROR: Failed to write 0x%08x to register %04x\n", data, addr); }else if(STREAM){ if(STREAM_ARICH){ const char* detector = "ARICH"; result = pcie40_writestream( dev_slot , ch , filename, detector) ; }else{ const char* detector = "KLM"; result = pcie40_writestream( dev_slot , ch , filename, detector) ; } if(result == 0) std::cerr<<"Succeed streaming file: " << filename << std::endl; else std::cerr<<"ERROR: Failed streaming file: " << filename << std::endl; } }else{ printf("ERROR: b2link-%02d is down or not ready\n", ch); } } //This is frame for register operation //Expert usage: specify the addr and data with "-r" or "-w" if needed if(OP_FLAG){ unsigned int op_addr = hsreg( operation ); pcie40_op(dev_slot, ch, op_addr, addr, data, pcie40); } // close pcie40 device driver for current process ecs_close( dev_slot , SLC_BAR) ; return 0 ; }