Skip to content
Snippets Groups Projects
main_pcie40_regconfig.cpp 12.9 KiB
Newer Older
qzhou's avatar
qzhou committed
/*-------------------------------------------------------------------------------*\
  regconfig: From PCIe40 board to access register of FEE through belle2link

qzhou's avatar
qzhou committed
  Qi-Dong Zhou, KEK 
qzhou's avatar
qzhou committed

  2020.03.06  0.01 first version based on reghs.c

\*--------------------------------------------------------------------------------*/
qzhou's avatar
qzhou committed
#define VERSION 01
#define MOD_DATE 20201102
qzhou's avatar
qzhou committed

qzhou's avatar
qzhou committed
#include "pcie40_b2slc.h"
#include "pcie40_reg.h"
#include "pcie40_b2config.h"
qzhou's avatar
qzhou committed
#include "pcie40_ecs.h"
qzhou's avatar
qzhou committed
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <vector>

qzhou's avatar
qzhou committed
//#define PCIE_DEV     0
#define MAX_NUM_CH   48
qzhou's avatar
qzhou committed
#define MAX_NUM_BANK 8 
qzhou's avatar
qzhou committed
#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;
qzhou's avatar
qzhou committed
int bank             = -1;
qzhou's avatar
qzhou committed
unsigned int addr    = 0;
unsigned int data    = 0;
qzhou's avatar
qzhou committed
char *filename;
char *operation;
qzhou's avatar
qzhou committed

//Flag for switch slc access method
bool PCIE40_REG      = false;
qzhou's avatar
qzhou committed
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;
qzhou's avatar
qzhou committed

/* 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
qzhou's avatar
qzhou committed
#define PCIE40_SETUNMASK       0x113
#define PCIE40_SET_BANKMASK    0x114
#define PCIE40_SET_BANKUNMASK  0x115
qzhou's avatar
qzhou committed

/* 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
qzhou's avatar
qzhou committed

/* 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) {
Patrick Robbe's avatar
Patrick Robbe committed
  size_t first = 0;
  size_t last = str.find_first_of(del);
qzhou's avatar
qzhou committed
  std::vector<std::string> result;
qzhou's avatar
qzhou committed
  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) {
Patrick Robbe's avatar
Patrick Robbe committed
      last = str.size();
qzhou's avatar
qzhou committed
    }
  }
  return result;
}

void argument(int argc, char **argv){
qzhou's avatar
qzhou committed
  char *ARGV0 = argv[0]; 	
qzhou's avatar
qzhou committed
  for(int i=1;i<argc;i++){
qzhou's avatar
qzhou committed
    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;
    } 
qzhou's avatar
qzhou committed
    if(ss=="--ch"){
      ch = atoi(argv[++i]);
      if( ch<0 || ch >= MAX_NUM_CH){
qzhou's avatar
qzhou committed
	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);
qzhou's avatar
qzhou committed
      }
    }
    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;
      }
Patrick Robbe's avatar
Patrick Robbe committed
      //std::cout << path.back() << std::endl;      
qzhou's avatar
qzhou committed
    } 
    if(ss=="--op"){
      OP_FLAG = true;
      operation = argv[++i];
    }
    if(ss=="-h" || ss=="-help"){
qzhou's avatar
qzhou committed
      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"
qzhou's avatar
qzhou committed
                       "       --dev   xx              #device slot number which installed PCIe40\n" 
                       "       --pcie40                #access the register of pcie40\n" 
qzhou's avatar
qzhou committed
                       "       --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"
qzhou's avatar
qzhou committed
	               "       %s --bank 0 --op setbankmask\n"
                       "       --op operation name writen in check hsreg()\n\n"
qzhou's avatar
qzhou committed
	               "       %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);
qzhou's avatar
qzhou committed
      return;
    }
  }
}

/* ---------------------------------------------------------------------- *\
   hsreg
\* ---------------------------------------------------------------------- */
int
hsreg(const char *name)
{
  static struct { const char *name; int adrs; } regs[] = {
qzhou's avatar
qzhou committed
    { "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 },
qzhou's avatar
qzhou committed
    { "trghold",        PCIE40_TRGOFF },
    { "trigger",        PCIE40_TRGON },
    { "realtrg",        PCIE40_TTTRG },
    { "simtrg",         PCIE40_DUMTRG },
    { "simple",         PCIE40_SUPMODE },
    { "verbose",        PCIE40_RAWMODE },
qzhou's avatar
qzhou committed
    { "supmode",        PCIE40_SUPMODE },
    { "rawmode",        PCIE40_RAWMODE },
qzhou's avatar
qzhou committed
    { "pdstl",          PCIE40_PDSTL },
    { "pdstlall",       PCIE40_PDSTLALL },
    { "adcth",          PCIE40_ADCTH },
    { "tdcth",          PCIE40_TDCTH },
    { "delay",          PCIE40_DELAY },
    { "window",         PCIE40_WINDOW },
qzhou's avatar
qzhou committed
    { "stat",           PCIE40REGL_STAT },
qzhou's avatar
qzhou committed
  };
qzhou's avatar
qzhou committed

  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;
}

qzhou's avatar
qzhou committed
/* ---------------------------------------------------------------------- *\
   pcie40_op
\* ---------------------------------------------------------------------- */
int
pcie40_op(int dev, int ch, int op_addr, int addr, int data, pcie40reg_t pcie40)
qzhou's avatar
qzhou committed
{
  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) {
qzhou's avatar
qzhou committed
    if (!pcie40_b2l_status(dev_slot, ch)) {
      printf("Failed: b2l is down\n");
qzhou's avatar
qzhou committed
      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");
qzhou's avatar
qzhou committed
    } else {
      printf("%s serial %d version %d\n",
    	     feename(pcie->feehw, pcie->feefw), pcie->feeser, pcie->feever);
qzhou's avatar
qzhou committed
    }
  } 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);
qzhou's avatar
qzhou committed
  } else if (op_addr == PCIE40_SET_BANKMASK) {
qzhou's avatar
qzhou committed
    pcie40_b2l_set_bankmask(dev_slot, bank, true);
qzhou's avatar
qzhou committed
  } else if (op_addr == PCIE40_SET_BANKUNMASK) {
qzhou's avatar
qzhou committed
    pcie40_b2l_set_bankmask(dev_slot, bank, false);
qzhou's avatar
qzhou committed
  } else if (cmd) {
qzhou's avatar
qzhou committed
    pcie40_writefee8(dev, ch, PCIE40REG_FEECONT, cmd);
qzhou's avatar
qzhou committed
    
  } else if (cmd_cdc) {
qzhou's avatar
qzhou committed
    pcie40_writefee8(dev, ch, PCIE40REG_CDCCONT, cmd_cdc);
qzhou's avatar
qzhou committed
  }else if (op_addr == PCIE40_PDSTL) {
    if (addr <= 0 || addr > 48) {
      printf("pedestal channel %d out of range [1,48]\n", addr);
      return -1;
    }
qzhou's avatar
qzhou committed
    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);
qzhou's avatar
qzhou committed
  } else if (op_addr == PCIE40_PDSTLALL) {
    for (i=1; i<=48; i++) {
qzhou's avatar
qzhou committed
      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);
qzhou's avatar
qzhou committed
    }
qzhou's avatar
qzhou committed
  } else if (op_addr == PCIE40_ADCTH || op_addr == PCIE40_TDCTH) {
qzhou's avatar
qzhou committed
    int adr = (op_addr == PCIE40_ADCTH) ? PCIE40REG_ADCTH : PCIE40REG_TDCTH;
qzhou's avatar
qzhou committed
    
    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) {
qzhou's avatar
qzhou committed
    int adr = (op_addr == PCIE40_WINDOW) ? PCIE40REG_WINDOW : PCIE40REG_DELAY;
qzhou's avatar
qzhou committed
    
    if (addr != -1) {
      pcie40_writefee8(dev, ch, adr, addr & 0xff);
    } else {
      printf("reg%02x = %02x\n", adr, pcie40_readfee8(dev, ch, adr));
    }
    
qzhou's avatar
qzhou committed
  } else {
qzhou's avatar
qzhou committed

    printf("undefined action %x\n", op_addr);
    return -1;
qzhou's avatar
qzhou committed
  }
qzhou's avatar
qzhou committed
  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;
qzhou's avatar
qzhou committed
  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){
qzhou's avatar
qzhou committed
	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);
qzhou's avatar
qzhou committed
  }
  //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);
  }
qzhou's avatar
qzhou committed
  // close pcie40 device driver for current process
  ecs_close( dev_slot , SLC_BAR) ;

  return 0 ;
}