This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DS90UB953-Q1: unable to enter BIST mode from ub960

Part Number: DS90UB953-Q1
Other Parts Discussed in Thread: ALP

Hi,

Our system has two ub960s, each with four ub953s connected to it. Each ub953 is connected to a camera. The whole system works fine, and we are able to stream images from the cameras. I'm attempting to write a program to evaluate the link quality between the ub960s and ub953s by using the BIST functionality. However, when I set the BIST Control Register (0xB3) on a ub960 to 0x1 none of the attached ub953s enter BIST mode. This is confirmed by checking the SER_BIST_ACT bit in the PORT_DEBUG Register (0xD0) for each RX port on the ub960. I also check the REMOTE_PAR_CAP1 Register (0x35) on the ub953 and BIST_EN bit is 0. Is there any reason the ub953 wouldn't enter BIST mode after enabling it on the ub960? Also, since register 0xB3 is not RX port specific, will it enable BIST on all connected ub953s? Thanks

  • Hello Kevin,

    Could you please run the example code, attached below, provided with the ALP software with four UB953s connected to one UB960? Hopefully running the provided example code will get you into a working BIST mode on all UB953s.  

     

    ## BIST_953_960_WithForcedError.py
    ##
    ## revision 1.1 June 26, 2018
    ##
    ########
    ######################
    ##
    ## This script file is used to check the link between the 953 and 960
    ##
    ## The Built In Self Test (BIST) generates a puesdo random sequence
    ## and checks for CRC errors between transmitted and received sequence.
    ##
    ## Rev. 1.1
    ## Added Parity Errors, restructured code
    ##
    ##
    ######################
    
    import time
    
    UB960 = 0x7A
    
    #	Port selection, Passthrough, and aliasing
    board.WriteI2C(UB960, 0x4C, 0x01)
    board.WriteI2C(UB960, 0x58, 0x5E)
    board.WriteI2C(UB960, 0x5C, 0x18)											#953a aliasing
    
    board.WriteI2C(UB960, 0x4C, 0x12)
    board.WriteI2C(UB960, 0x58, 0x5E)
    board.WriteI2C(UB960, 0x5C, 0x20)											#953b aliasing
    
    board.WriteI2C(UB960, 0x4C, 0x24)
    board.WriteI2C(UB960, 0x58, 0x5E)
    board.WriteI2C(UB960, 0x5C, 0x22)											#953c aliasing
    
    board.WriteI2C(UB960, 0x4C, 0x38)
    board.WriteI2C(UB960, 0x58, 0x5E)
    board.WriteI2C(UB960, 0x5C, 0x24)											#953d aliasing
    
    board.WriteI2C(UB960, 0x4C, 0x01)
    
    for x in range (0, 4):
    
    	#print ("x = ", x)
    
    	if x == 0:
    		UB953 = 0x18
    		board.WriteI2C(UB960, 0x4C, 0x01)		#0x4C is FPD3_PORT_SEL. RX0 R/W Enabled				
    		print ("\t\tRX0")
    	elif x == 1:
    		UB953 = 0x20
    		board.WriteI2C(UB960, 0x4C, 0x12)		#0x4C is FPD3_PORT_SEL. RX1 R/W Enabled
    		print ("\t\tRX1")
    	elif x == 2:
    		UB953 = 0x22
    		board.WriteI2C(UB960, 0x4C, 0x24)		#0x4C is FPD3_PORT_SEL. RX2 R/W Enabled
    		print ("\t\tRX2")
    	else:
    		UB953 = 0x24
    		board.WriteI2C(UB960, 0x4C, 0x38)		#0x4C is FPD3_PORT_SEL. RX3 R/W Enabled
    		print ("\t\tRX3")
    
    
    	#	Digital Reset except for registers
    	board.WriteI2C(UB953, 0x01, 0x01)											#Resets 953a
    	time.sleep(0.5)
    	board.WriteI2C(UB960, 0x01, 0x01)											#Resets 960
    	time.sleep(0.5)
    
    	print ("Devices Reset")
    
    
    	#	Confirm Devices can communicate with each other
    	print ("960 Device ID (0x00):", hex(board.ReadI2C(UB960, 0x00, 1)))			#960 Device ID, should be 0x7A, check 0x00 for confirmation
    	time.sleep(0.5)
    	print ("953 Device ID (0x00):", hex(board.ReadI2C(UB953, 0x00, 1)))			#953 Device ID, should be 0x30, check 0x5B for confirmation
    
    
    	print ("------------------------------------------------------------------")
    	time.sleep(0.5)
    
    
    	#	Read Reciever Lock Status
    	print ("Reciever Lock Status (0x4D):", hex(board.ReadI2C(UB960, 0x4D, 1)))						#0x04 is DEVICE_STS of 960
    	print ("Bit [1:0] should be high. i.e. 0x13")
    
    	print ("------------------------------------------------------------------")
    
    	#time.sleep(1)
    
    
    
    	#	Enable write for Port0 of FPD3_PORT_SEL. Note this is done earlier in script 
    	#board.WriteI2C(UB960, 0x4C, 0x01)											#0x4C is FPD3_PORT_SEL
    
    
    
    	#	Clear Errors and Error Count
    	board.WriteI2C(UB953, 0x49, 0x28)											#0x49 is BC_CTRL. 0x28 selects BIST_CRC ERR CLR and CRC ERR CLR
    
    	print ("Read BCC Error Status (0x79):", hex(board.ReadI2C(UB953, 0x79, 1)))	#Clear possible BCC_Error by Reading BCC Error Status
    	print ("Consult Register 0x79 on the SER for more information")
    
    	print ("------------------------------------------------------------------")
    
    	print ("Pre-Error Link Status of 953 (0x52):", hex(board.ReadI2C(UB953, 0x52,1)))					#0x52 is GENERAL_STS of 953
    	print ("Should read 0x45 = RX Lock Detect, HS PLL Lock, Link Detect")
    
    	print ("------------------------------------------------------------------")
    
    	print ("BIST CRC Error count (0x54) on 953 before BIST.", hex(board.ReadI2C(UB953, 0x54, 1)))#0x54 is BIST ERR CNT
    
    	print ("------------------------------------------------------------------")
    
    
    
    
    
    	#	Enabling BIST, Error, and Lock-Change Status
    	print ("Read BIST CTL register (0xB3) Before BIST ENABlED", hex(board.ReadI2C(UB960, 0xB3, 1)))		#0xB3 is BIST_CTL, bit 1 controls if enabled or not
    	print ("Should read 0x00 or 0x08\n")
    
    	board.WriteI2C(UB960, 0xB3, 0x01)											#Enable BIST using BIST_CTL
    
    	print ("Read BIST CTL (0xB3) register After BIST ENABLED", hex(board.ReadI2C(UB960, 0xB3, 1)))		#0xB3 is BIST_CTL
    	print ("Should read 0x01")
    
    	time.sleep(0.25)
    	print ("------------------------------------------------------------------")
    	print ("Read BIST Lock Status Change of 960 RIGHT AFTER BIST enabled (0x4D):", hex(board.ReadI2C(UB960, 0x4D,1)))		#0x4D is RX_PORT_STS1 of 960
    	print ("Read to clear BIST enable Lock Status Change.")
    
    	board.WriteI2C(UB960, 0xD0, 0x01)											#Force 1 Error, 0xD0 is PORT_DEBUG register
    
    	#board.WriteI2C(UB960, 0xD0, 0x02)											#Force Continious errors, 0xD0 is PORT_DEBUG register
    	time.sleep(3)																#Can run BIST for as long as needed
    	#board.WriteI2C(UB960, 0xD0, 0x00)											#If forced continious errors, stop forcing errors
    
    	print ("Read Post-BIST Lock Status Change of 960 RIGHT BEFORE BIST disabled (0x4D):", hex(board.ReadI2C(UB960, 0x4D,1)))		#0x4D is RX_PORT_STS1 of 960
    	print ("bits [1:0] should be high i.e. 0x3, If lock status changed during BIST, bit [4] will be high")
    
    
    
    	#	Disable BIST and Port0
    	board.WriteI2C(UB960, 0xB3, 0x00)											#Disable BIST, using BIST_CTL
    	#board.WriteI2C(UB960, 0x4C, 0x00)											#0x4C is FPD3_PORT_SEL
    	print ("------------------------------------------------------------------")
    
    
    	#	Check if Error(s) occured
    	print ("Reciever Lock Status (0x4D):", hex(board.ReadI2C(UB960, 0x4D, 1)))						#0x4D is PORT_STS1 of 960
    	print ("Bits [1:0] should be high. i.e. 0x13")
    	print ("------------------------------------------------------------------")
    
    
    	print ("Pre-Error Link Status of 953 (0x52):", hex(board.ReadI2C(UB953, 0x52,1)))					#0x52 is GENERAL_STS of 953
    	print ("Should read 0x4D = RX Lock Detect, HS PLL Lock, Link Detect, and BIST CRC Error")
    	print ("------------------------------------------------------------------")
    
    
    	print ("BIST CRC Error count (0x54) on 953 after BIST.", hex(board.ReadI2C(UB953, 0x54, 1))) #0x54 is BIST ERR CNT
    	print ("Parity Error count MSB (0x56) on 960.", hex(board.ReadI2C(UB960, 0x56, 1))) #0x56 is number of Parity error 8 most significant bits
    	print ("Parity Error count LSB (0x55) on 960.", hex(board.ReadI2C(UB960, 0x55, 1))) #0x55 is number of Parity error 8 least significant bits	
    	print ("------------------------------------------------------------------")
    
    	
    	#	Clear BIST Errors on 953
    	board.WriteI2C(UB953, 0x49, 0x28)											#0x49 is BC_CTRL. 0x28 selects BIST_CRC ERR CLR and CRC ERR CLR
    
    	print ("#################################################################") 			#New line Printed
    
    print ("\n\n")


    Due to the register 0xB3 being a shared register it will attempt to enable BIST on all the UB953s. For BIST to become active on a UB953, the UB953 and back channel must have been setup properly beforehand, you can see how to setup a UB953 and the back channel in the provided example code. 

    Do note that, as in the example code, you must first configure the back channel before you can enable BIST.

    If you do not have the ALP software you can download ALP here.

    Regards,

    Joshua 

  • I've compared my code to that script, and don't see any major differences except that I check the SER_BIST_ACT bit to verify the ub953 is in BIST mode. All the checks the script does (RX_LOCK_DETECT, HS_PLL_LOCK, LINK_DET on the serializer, LOCK_STS on the deserializer, etc...) also pass for my code. The back channel is definitely setup and working because the REMOTE_PAR_CAP1 Register (0x35) on the serializers has the correct values for the MPORT and PORT_NUM fields filled in.

    Unfortunately, I can't use the ALP software to test as it seems to be a windows gui program, and these systems run linux and I only have ssh access. Is there a version of that script that doesn't require the ALP software to run?

  • Hi Kevin,

    Could I ask you to send me your script?

    Unfortunately there is no version of ALP or the script that we have that can be run on Linux, but it should be a simple process for you to convert the read and write functions within the script into a form that can be used in the Linux environment. 

    Thank you,

    Joshua

  • #include <stdio.h>
    #include <fstream>
    #include <fcntl.h>
    #include <unistd.h>
    #include <linux/i2c.h>
    #include <linux/i2c-dev.h>
    #include <errno.h>
    #include <sys/ioctl.h>
    #include <cstring>
    
    int i2c_bus = 2;
    
    const int num_des = 2;
    const int num_des_ports = 4;
    const int des_add[num_des] = { 0x30, 0x3d };
    
    const int num_ser = 8;
    const int ser_add[num_des][num_des_ports] = { { 0x43, 0x42, 0x41, 0x40 },
                                                  { 0x47, 0x46, 0x45, 0x44 } };
    
    int get_serializer_address(int sidx)
    {
      return ser_add[sidx / num_des_ports][sidx % num_des_ports];
    }
    
    const int num_cam = 8;
    const int cam_add[num_des][num_des_ports] = { { 0x63, 0x62, 0x61, 0x60 },
                                                  { 0x67, 0x66, 0x65, 0x64 } };
    
    int get_camera_address(int cidx)
    {
      return cam_add[cidx / num_des_ports][cidx % num_des_ports];
    }
    
    class I2CGetSet
    {
    public:
      I2CGetSet() : file(0), prev_chip_address(-255)
      {
        char buf[512];
        snprintf(buf, 511, "/dev/i2c-%d", i2c_bus);
        file = open(buf, O_RDWR);
      }
    
      ~I2CGetSet()
      {
        cleanup();
      }
    
      void cleanup()
      {
        if (file > 0)
          close(file);
        file = 0;
      }
    
      // Return codes:
      //  -1 -> popen failed
      //  -2 -> pclose didn't return 0
      //  -3 -> i2cget output couldn't be converted to u8
      //  -4 -> open failed
      //  -5 -> ioctl(I2C_SLAVE_FORCE) failed
      //  -6 -> ioctl(I2C_SMBUS) failed
      //   _ -> value
      int get(int chip_address, int data_address)
      {
        if (file <= 0)
          return -4;
        if (chip_address != prev_chip_address)
        {
          if (ioctl(file, I2C_SLAVE_FORCE, chip_address) < 0)
          {
            prev_chip_address = -255;
            return -5;
          }
          prev_chip_address = chip_address;
        }
        // below is equivalent to i2c_smbus_read_byte_data()
        i2c_smbus_data data;
        i2c_smbus_ioctl_data args;
        args.read_write = I2C_SMBUS_READ;
        args.command = data_address;
        args.size = I2C_SMBUS_BYTE_DATA;
        args.data = &data;
        int err = ioctl(file, I2C_SMBUS, &args);
        if (err < 0)
          printf("I2C_SMBUS-read fail: %s %d\n", strerror(errno), err);
        return err < 0 ? -6 : (data.byte & 0x0FF);
      }
    
      // Return codes:
      //   0 -> success
      //  -1 -> popen failed
      //  -2 -> pclose didn't return 0
      //  -3 -> open failed
      //  -4 -> reading current value failed
      //  -5 -> ioctl(I2C_SLAVE_FORCE) failed
      //  -6 -> ioctl(I2C_SMBUS) failed
      int set(int chip_address, int data_address, int mask, int value)
      {
        if (file <= 0)
          return -3;
        int oldvalue =
            mask < 0 ? 0 : get(chip_address, data_address);  // read current value
        if (oldvalue < 0)
        {
          printf("i2cset: failed to read old value %d\n", oldvalue);
          return -4;
        }
        if (chip_address != prev_chip_address)
        {
          if (ioctl(file, I2C_SLAVE_FORCE, chip_address) < 0)
          {
            prev_chip_address = -255;
            return -5;
          }
          prev_chip_address = chip_address;
        }
        if (mask >= 0)
          value = (value & mask) | (oldvalue & ~mask);  // apply mask
        // below is equivalent to i2c_smbus_write_byte_data()
        i2c_smbus_data data;
        data.byte = value;
        i2c_smbus_ioctl_data args;
        args.read_write = I2C_SMBUS_WRITE;
        args.command = data_address;
        args.size = I2C_SMBUS_BYTE_DATA;
        args.data = &data;
        int err = ioctl(file, I2C_SMBUS, &args);
        if (err < 0)
          printf("I2C_SMBUS-write fail: %s %d\n", strerror(errno), err);
        return err < 0 ? -6 : 0;
      }
    
    private:
      int file, prev_chip_address;
    };
    
    int is_busy(int file, int chip_address)
    {
      int ret = ioctl(file, I2C_SLAVE, chip_address);
      if (ret < 0 && errno == EBUSY)  // bound to driver?
        return 1;
      return 0;
    }
    
    int check_devices()
    {
      printf("\nChecking for devices...\n");
    
      char buf[512];
      snprintf(buf, 511, "/dev/i2c-%d", i2c_bus);
      int file = open(buf, O_RDWR);
      if (file <= 0)
      {
        printf("failed to open i2c bus %d!\n", i2c_bus);
        return 1;
      }
    
      // deserializers
      for (int d = 0; d < num_des; ++d)
      {
        if (!is_busy(file, des_add[d]))
        {
          printf("des %#x not detected!\n", des_add[d]);
          close(file);
          return 2;
        }
      }
      printf("Deserializers detected.\n");
    
      // serializers
      for (int s = 0; s < num_ser; ++s)
      {
        int sadd = get_serializer_address(s);
        if (!is_busy(file, sadd))
        {
          printf("ser %#x not detected!\n", sadd);
          close(file);
          return 3;
        }
      }
      printf("Serializers detected.\n");
    
      // cameras
      for (int c = 0; c < num_cam; ++c)
      {
        int cadd = get_camera_address(c);
        if (!is_busy(file, cadd))
        {
          printf("cam %#x not detected!\n", cadd);
          close(file);
          return 4;
        }
      }
      printf("Cameras detected.\n");
    
      printf("All devices detected successfully.\n");
    
      return 0;
    }
    
    int reset_ser_and_des(I2CGetSet& i2c)
    {
      printf("\nResetting serializers and deserializers...\n");
    
      for (int s = 0; s < num_ser; ++s)
      {
        int sadd = get_serializer_address(s);
        int ret = i2c.set(sadd, 0x1, -1, 0x1);
        if (ret != 0)
        {
          printf("failed to set reg 0x1 on ser %#x %d!\n", sadd, ret);
          return 1;
        }
      }
    
      usleep(500000);
    
      for (int d = 0; d < num_des; ++d)
      {
        int ret = i2c.set(des_add[d], 0x1, -1, 0x1);
        if (ret != 0)
        {
          printf("failed to set reg 0x1 on des %#x %d!\n", des_add[d], ret);
          return 2;
        }
      }
    
      usleep(500000);
    
      printf("Reset complete.\n");
    
      return 0;
    }
    
    int verify_device_ids(I2CGetSet& i2c)
    {
      printf("\nVerifying device ids...\n");
    
      for (int d = 0; d < num_des; ++d)
      {
        int des_id = i2c.get(des_add[d], 0x0) >> 1;
        if (des_id != des_add[d])
        {
          printf("des %#x id mismatch (%#x)!\n", des_add[d], des_id);
          return 1;
        }
      }
    
      for (int s = 0; s < num_ser; ++s)
      {
        int sadd = get_serializer_address(s);
        int ser_id = i2c.get(sadd, 0x0) >> 1;
        // serializer id from deserializer
        int didx = s / num_des_ports;
        int dadd = des_add[didx];
        int dport = s % num_des_ports;
        if (i2c.set(dadd, 0x4C, 0x30, dport << 4) != 0)  // read port select
        {
          printf("failed to select port on des %#x-%d\n", dadd, dport);
          return 2;
        }
        int des_ser_id = i2c.get(dadd, 0x5b) >> 1;
        // deserializer id from serializer
        int ser_des_id = i2c.get(sadd, 0x37) >> 1;
        if (ser_id != 0x18 || ser_id != des_ser_id || ser_des_id != dadd)
        {
          printf("ser %#x id mismatch (%#x %#x %#x)!\n", sadd, ser_id, des_ser_id,
                 ser_des_id);
          return 3;
        }
        // check REMOTE_PAR_CAP1 on serializer
        int remote_par_cap1 = i2c.get(sadd, 0x35);
        if (remote_par_cap1 != (0x10 | dport))
        {
          printf("ser %#x REMOTE_PAR_CAP1 error (%#x %#x)!\n", sadd,
                 remote_par_cap1);
          return 4;
        }
      }
    
      printf("ID checks passed.\n");
    
      return 0;
    }
    
    int verify_lock_status(I2CGetSet& i2c)
    {
      printf("\nVerifying lock status...\n");
    
      for (int d = 0; d < num_des; ++d)
      {
        for (int p = 0; p < num_des_ports; ++p)
        {
          if (i2c.set(des_add[d], 0x4C, 0x30, p << 4) != 0)  // read port select
          {
            printf("failed to select port on des %#x-%d\n", des_add[d], p);
            return 1;
          }
          int sts1 = i2c.get(des_add[d], 0x4d);
          int sts2 = i2c.get(des_add[d], 0x4e);
          if (sts1 < 0 || sts2 < 0)
          {
            printf("failed to read status regs of des %#x-%d!\n", des_add[d], p);
            return 2;
          }
          int port_num = sts1 >> 6;
          int lock_sts = sts1 & 0x1;
          int freq_stable = sts2 & 0x4;
          int no_fpd3_clk = sts2 & 0x2;
          if (port_num != p || !lock_sts || !freq_stable || no_fpd3_clk)
          {
            printf("des %#x-%d not locked (%#x %#x)!\n", des_add[d], p, sts1, sts2);
            return 3;
          }
        }
      }
      printf("All deserializer ports indicate lock.\n");
    
      for (int s = 0; s < num_ser; ++s)
      {
        int sadd = get_serializer_address(s);
        int sts = i2c.get(sadd, 0x52);
        if (sts < 0)
        {
          printf("failed to read status reg of ser %#x!\n", sadd);
          return 4;
        }
        int rx_lock_detect = sts & 0x40;
        int hs_pll_lock = sts & 0x4;
        int link_det = sts & 0x1;
        if (!rx_lock_detect || !hs_pll_lock || !link_det)
        {
          printf("ser %#x not locked (%#x)!\n", sadd, sts);
          return 5;
        }
      }
      printf("All serializers indicate lock.\n");
    
      printf("Lock status verified.\n");
    
      return 0;
    }
    
    int run_bist(I2CGetSet& i2c, int bist_len, int didx, int dport)
    {
      int dadd = des_add[didx];
      int sadd = ser_add[didx][dport];
    
      printf("\nRunning BIST for [%#x-%d <-> %#x]...\n", dadd, dport, sadd);
    
      // read and write port select
      if (i2c.set(dadd, 0x4C, 0x30 | 0xF, (dport << 4) | (1 << dport)) != 0)
      {
        printf("failed to select port on des %#x-%d\n", dadd, dport);
        return 1;
      }
    
      printf("Clearing error counts prior to BIST...\n");
    
      {
        if (i2c.set(sadd, 0x49, 0x28, 0x28) != 0)
        {
          printf("failed to clear err cnts on ser %#x!\n", sadd);
          return 2;
        }
        if (i2c.get(sadd, 0x52) < 0)
        {
          printf("failed to read reg 0x52 on ser %#x!\n", sadd);
          return 3;
        }
        if (i2c.get(sadd, 0x54) < 0)
        {
          printf("failed to read reg 0x54 on ser %#x!\n", sadd);
          return 4;
        }
      }
    
      printf("Enabling BIST mode and verifying lock after...\n");
    
      {
        int bist_ctrl_before = i2c.get(dadd, 0xB3);
        if (bist_ctrl_before < 0)
        {
          printf("failed to read reg 0xB3 on des %#x\n", dadd);
          return 5;
        }
        printf(" BIST_CTRL before = %#x\n", bist_ctrl_before);
        if (i2c.set(dadd, 0xB3, -1, 0x1) != 0)
        {
          printf("failed to set BIST_EN on des %#x\n", dadd);
          return 6;
        }
        usleep(250000);
        int bist_ctrl_after = i2c.get(dadd, 0xB3);
        if (bist_ctrl_after < 0)
        {
          printf("failed to read reg 0xB3 on des %#x\n", dadd);
          return 7;
        }
        printf(" BIST_CTRL after  = %#x\n", bist_ctrl_after);
        if (bist_ctrl_after != 0x1)
        {
          printf("failed to enable BIST on des %#x\n", dadd);
          return 8;
        }
        int sts1 = i2c.get(dadd, 0x4D);
        if (sts1 < 0 || (sts1 >> 6) != dport)
        {
          printf("failed to read reg 0x4D on des %#x-%d\n", dadd, dport);
          return 9;
        }
        if (!(sts1 & 0x1))
        {
          printf("no lock on des %#x-%d after setting BIST_CTRL\n", dadd, dport);
          return 10;
        }
      }
    
      printf("Running BIST for %d seconds...\n", bist_len);
    
      bool ser_was_in_bist_mode = true;
    
      for (int t = 0; t < bist_len; t += 5)
      {
        int sleep_secs = std::min(bist_len - t, 5);
        usleep(sleep_secs * 1000000);
        printf("... %d of %d\n", t + sleep_secs, bist_len);
    
        // verify BIST is enabled on the serializer
        int port_debug = i2c.get(dadd, 0xD0);
        if (port_debug != 0x20)
        {
          printf("  BIST is not enabled on ser %#x (%#x)!\n", sadd, port_debug);
          printf("    ser = %#x %#x %#x %#x %#x %#x %#x %#x %#x\n",
                 i2c.get(sadd, 0x3), i2c.get(sadd, 0x9), i2c.get(sadd, 0x13),
                 i2c.get(sadd, 0x14), i2c.get(sadd, 0x32), i2c.get(sadd, 0x35),
                 i2c.get(sadd, 0x52), i2c.get(sadd, 0x5D), i2c.get(sadd, 0x5C),
                 (i2c.get(sadd, 0x56) << 8) | i2c.get(sadd, 0x55));
          printf("    des = %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x\n",
                 i2c.get(dadd, 0xB3), i2c.get(dadd, 0x47), i2c.get(dadd, 0x4d),
                 i2c.get(dadd, 0x4e),
                 (i2c.get(dadd, 0x4f) << 8) | i2c.get(dadd, 0x50),
                 i2c.get(dadd, 0x51), i2c.get(dadd, 0x54),
                 (i2c.get(dadd, 0x55) << 8) | i2c.get(dadd, 0x56),
                 i2c.get(dadd, 0x7a), i2c.get(dadd, 0x7b));
          ser_was_in_bist_mode = false;
        }
      }
    
      printf("Disabling BIST mode...\n");
    
      {
        int bist_ctrl_before = i2c.get(dadd, 0xB3);
        if (bist_ctrl_before < 0)
        {
          printf("failed to read reg 0xB3 on des %#x\n", dadd);
          return 11;
        }
        printf(" BIST_CTRL before = %#x\n", bist_ctrl_before);
        if (i2c.set(dadd, 0xB3, -1, 0x0) != 0)
        {
          printf("failed to set BIST_EN on des %#x\n", dadd);
          return 12;
        }
        usleep(250000);
        int bist_ctrl_after = i2c.get(dadd, 0xB3);
        if (bist_ctrl_after < 0)
        {
          printf("failed to read reg 0xB3 on des %#x\n", dadd);
          return 13;
        }
        printf(" BIST_CTRL after  = %#x\n", bist_ctrl_after);
        if (bist_ctrl_after != 0x0)
        {
          printf("failed to disable BIST on des %#x\n", dadd);
          return 14;
        }
        int port_debug = i2c.get(dadd, 0xD0);
        if (port_debug != 0x0)
        {
          printf("BIST is still enabled on ser %#x (%#x)\n", sadd, port_debug);
          return 15;
        }
        if (!ser_was_in_bist_mode)
        {
          printf("BIST was not enabled on ser %#x!\n", sadd);
          return 16;
        }
      }
    
      printf("Gathering results...\n");
    
      int ser_err_cnt = 0, des_err_cnt = 0;
      bool ser_lock_lost = false, des_lock_lost = false;
    
      {
        int sts = i2c.get(dadd, 0x4D);
        if (sts < 0 || (sts >> 6) != dport)
        {
          printf("failed to read reg 0x4D on des %#x-%d\n", dadd, dport);
          return 17;
        }
        int bist_err_cnt = i2c.get(dadd, 0x57);
        if (bist_err_cnt < 0)
        {
          printf("failed to read reg 0x57 on des %#x-%d\n", dadd, dport);
          return 18;
        }
        des_lock_lost = !(sts & 0x1) || (sts & 0x10);
        des_err_cnt = bist_err_cnt;
      }
    
      {
        int sts = i2c.get(sadd, 0x52);
        if (sts < 0)
        {
          printf("failed to read reg 0x52 on ser %#x\n", sadd);
          return 19;
        }
        int bist_err_cnt = i2c.get(sadd, 0x54);
        if (bist_err_cnt < 0)
        {
          printf("failed to read reg 0x54 on ser %#x\n", sadd);
          return 20;
        }
        ser_lock_lost =
            !(sts & 0x40) || (sts & 0x10) || !(sts & 0x4) || !(sts & 0x1);
        ser_err_cnt = bist_err_cnt;
      }
    
      if (des_lock_lost || des_err_cnt > 0 || ser_lock_lost || ser_err_cnt > 0)
      {
        printf("Link [%#x-%d <-> %#x] errors detected.\n", dadd, dport, sadd);
        printf("   ll = (%d,%d)  cnts = (%d,%d)\n", des_lock_lost, ser_lock_lost,
               des_err_cnt, ser_err_cnt);
        return -1;
      }
      else
      {
        printf("Link [%#x-%d <-> %#x] passed without errors.\n", dadd, dport, sadd);
        return 0;
      }
    }
    
    int main(int argc, char* argv[])
    {
      if (argc != 2)
      {
        printf("invalid syntax:  cam_diag bist_run_len_seconds\n");
        return 1;
      }
    
      int bist_len = atoi(argv[1]);
      if (bist_len < 10 || bist_len > 3600)
      {
        printf("invalid bist_len: [10, 3600]\n");
        return 2;
      }
    
      if (check_devices())
      {
        printf("check_devices failed!\n");
        return 3;
      }
    
      I2CGetSet i2c;
    
      if (reset_ser_and_des(i2c))
      {
        printf("reset_ser_and_des failed!\n");
        return 4;
      }
    
      if (verify_device_ids(i2c))
      {
        printf("verify_device_ids failed!\n");
        return 5;
      }
    
      if (verify_lock_status(i2c))
      {
        printf("verify_lock_status failed!\n");
        return 6;
      }
    
      for (int d = 0; d < num_des; ++d)
      {
        for (int p = 0; p < num_des_ports; ++p)
        {
          int ret = run_bist(i2c, bist_len, d, p);
          if (ret > 0)
            printf("BIST failed to run!\n");
          else if (ret == 0)
            printf("BIST completed successfully. No link errors detected.\n");
          else
            printf("BIST completed successfully. Link errors were detected.\n");
        }
      }
    
      usleep(250000);
    
      reset_ser_and_des(i2c);
    
      return 0;
    }

    That's the code for my program. Below is a log from running it. Everything is fine except that SER_BIST_ACT is never asserted. I have found that if I manually enable BIST mode on a ub953 by setting LOCAL_BIST_EN in register 0x14 that SER_BIST_ACT is asserted on the deserializer. However, after setting LOCAL_BIST_EN I'm unable to communicate with the ub953 over i2c until the system is power cycled.

    Checking for devices...
    Deserializers detected.
    Serializers detected.
    Cameras detected.
    All devices detected successfully.
    
    Resetting serializers and deserializers...
    Reset complete.
    
    Verifying device ids...
    ID checks passed.
    
    Verifying lock status...
    All deserializer ports indicate lock.
    All serializers indicate lock.
    Lock status verified.
    
    Running BIST for [0x30-0 <-> 0x43]...
    Clearing error counts prior to BIST...
    Enabling BIST mode and verifying lock after...
     BIST_CTRL before = 0
     BIST_CTRL after  = 0x1
    Running BIST for 10 seconds...
    ... 5 of 10
      BIST is not enabled on ser 0x43 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x10 0x45 0 0
        des = 0x1 0 0x3 0xc 0x6400 0 0 0 0x2 0x1
    ... 10 of 10
      BIST is not enabled on ser 0x43 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x10 0x45 0 0
        des = 0x1 0 0x3 0x4 0x6400 0 0 0 0 0
    Disabling BIST mode...
     BIST_CTRL before = 0x1
     BIST_CTRL after  = 0
    BIST was not enabled on ser 0x43!
    BIST failed to run!
    
    Running BIST for [0x30-1 <-> 0x42]...
    Clearing error counts prior to BIST...
    Enabling BIST mode and verifying lock after...
     BIST_CTRL before = 0
     BIST_CTRL after  = 0x1
    Running BIST for 10 seconds...
    ... 5 of 10
      BIST is not enabled on ser 0x42 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x11 0x45 0 0
        des = 0x1 0 0x43 0xc 0x6400 0 0 0 0x2 0x1
    ... 10 of 10
      BIST is not enabled on ser 0x42 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x11 0x45 0 0
        des = 0x1 0 0x43 0x4 0x6400 0 0 0 0 0
    Disabling BIST mode...
     BIST_CTRL before = 0x1
     BIST_CTRL after  = 0
    BIST was not enabled on ser 0x42!
    BIST failed to run!
    
    Running BIST for [0x30-2 <-> 0x41]...
    Clearing error counts prior to BIST...
    Enabling BIST mode and verifying lock after...
     BIST_CTRL before = 0
     BIST_CTRL after  = 0x1
    Running BIST for 10 seconds...
    ... 5 of 10
      BIST is not enabled on ser 0x41 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x12 0x45 0 0
        des = 0x1 0 0x83 0x4 0x6400 0 0 0 0 0
    ... 10 of 10
      BIST is not enabled on ser 0x41 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x12 0x45 0 0
        des = 0x1 0 0x83 0x4 0x6400 0 0 0 0 0
    Disabling BIST mode...
     BIST_CTRL before = 0x1
     BIST_CTRL after  = 0
    BIST was not enabled on ser 0x41!
    BIST failed to run!
    
    Running BIST for [0x30-3 <-> 0x40]...
    Clearing error counts prior to BIST...
    Enabling BIST mode and verifying lock after...
     BIST_CTRL before = 0
     BIST_CTRL after  = 0x1
    Running BIST for 10 seconds...
    ... 5 of 10
      BIST is not enabled on ser 0x40 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x13 0x45 0 0
        des = 0x1 0 0xc3 0xc 0x6400 0 0 0 0x2 0x1
    ... 10 of 10
      BIST is not enabled on ser 0x40 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x13 0x45 0 0
        des = 0x1 0 0xc3 0x4 0x6400 0 0 0 0 0
    Disabling BIST mode...
     BIST_CTRL before = 0x1
     BIST_CTRL after  = 0
    BIST was not enabled on ser 0x40!
    BIST failed to run!
    
    Running BIST for [0x3d-0 <-> 0x47]...
    Clearing error counts prior to BIST...
    Enabling BIST mode and verifying lock after...
     BIST_CTRL before = 0
     BIST_CTRL after  = 0x1
    Running BIST for 10 seconds...
    ... 5 of 10
      BIST is not enabled on ser 0x47 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x10 0x45 0 0x4
        des = 0x1 0 0x3 0xc 0x6400 0 0x3 0 0x2 0x2
    ... 10 of 10
      BIST is not enabled on ser 0x47 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x10 0x45 0 0
        des = 0x1 0 0x3 0x4 0x6400 0 0x3 0 0 0
    Disabling BIST mode...
     BIST_CTRL before = 0x1
     BIST_CTRL after  = 0
    BIST was not enabled on ser 0x47!
    BIST failed to run!
    
    Running BIST for [0x3d-1 <-> 0x46]...
    Clearing error counts prior to BIST...
    Enabling BIST mode and verifying lock after...
     BIST_CTRL before = 0
     BIST_CTRL after  = 0x1
    Running BIST for 10 seconds...
    ... 5 of 10
      BIST is not enabled on ser 0x46 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x11 0x45 0 0
        des = 0x1 0 0x43 0x4 0x6400 0 0x7 0 0 0
    ... 10 of 10
      BIST is not enabled on ser 0x46 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x11 0x45 0 0
        des = 0x1 0 0x43 0x4 0x6400 0 0x7 0 0 0
    Disabling BIST mode...
     BIST_CTRL before = 0x1
     BIST_CTRL after  = 0
    BIST was not enabled on ser 0x46!
    BIST failed to run!
    
    Running BIST for [0x3d-2 <-> 0x45]...
    Clearing error counts prior to BIST...
    Enabling BIST mode and verifying lock after...
     BIST_CTRL before = 0
     BIST_CTRL after  = 0x1
    Running BIST for 10 seconds...
    ... 5 of 10
      BIST is not enabled on ser 0x45 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x12 0x45 0 0
        des = 0x1 0 0x83 0xc 0x6400 0 0x1 0 0x2 0x2
    ... 10 of 10
      BIST is not enabled on ser 0x45 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x12 0x45 0 0
        des = 0x1 0 0x83 0x4 0x6400 0 0x1 0 0 0
    Disabling BIST mode...
     BIST_CTRL before = 0x1
     BIST_CTRL after  = 0
    BIST was not enabled on ser 0x45!
    BIST failed to run!
    
    Running BIST for [0x3d-3 <-> 0x44]...
    Clearing error counts prior to BIST...
    Enabling BIST mode and verifying lock after...
     BIST_CTRL before = 0
     BIST_CTRL after  = 0x1
    Running BIST for 10 seconds...
    ... 5 of 10
      BIST is not enabled on ser 0x44 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x13 0x45 0 0
        des = 0x1 0 0xc3 0xc 0x6400 0 0 0 0x2 0x1
    ... 10 of 10
      BIST is not enabled on ser 0x44 (0)!
        ser = 0x48 0x1e 0 0 0x9 0x13 0x45 0 0
        des = 0x1 0 0xc3 0x4 0x6400 0 0 0 0 0
    Disabling BIST mode...
     BIST_CTRL before = 0x1
     BIST_CTRL after  = 0
    BIST was not enabled on ser 0x44!
    BIST failed to run!
    
    Resetting serializers and deserializers...
    Reset complete.

  • Hello Kevin,

    Can you please give me a register dump during the BIST operation on the 960?

    Thank you,

    Joshua

  •      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
    00: 60 00 1e 40 d0 01 00 fe 1c 10 7a 7a 0f 00 ff ff    `.?@??.???zz?...
    10: 00 00 00 00 00 00 00 00 80 61 a8 e3 dd 00 04 04    ........?a???.??
    20: 00 03 00 0f 00 00 00 00 00 00 00 00 00 00 00 00    .?.?............
    30: 00 00 01 43 00 00 00 00 00 00 00 00 00 00 00 00    ..?C............
    40: 00 a9 71 01 00 00 20 00 00 00 00 12 01 03 0c 64    .?q?.. ....????d
    50: 00 00 00 03 00 00 00 00 5e 00 00 30 00 30 60 00    ...?....^..0.0`.
    60: 00 00 00 00 00 86 c6 00 00 00 00 00 00 7c 8a a8    .....??......|??
    70: 2b 2c 00 00 00 00 00 c5 00 01 02 01 00 00 00 00    +,.....?.???....
    80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    a0: 00 00 00 00 00 1d 00 00 00 00 00 00 00 00 00 00    .....?..........
    b0: 1c 13 1f 01 25 00 18 00 8c 33 83 74 80 00 00 00    ????%.?.?3?t?...
    c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    d0: 00 43 94 02 60 f2 00 02 00 01 00 00 00 00 00 00    .C??`?.?.?......
    e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    f0: 5f 55 42 39 36 30 00 00 00 00 00 00 00 00 00 00    _UB960..........

         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
    00: 30 00 72 48 00 03 41 28 fe 1e 10 7f 7f 83 b4 00
    10: 00 00 00 00 00 20 18 3c 80 62 62 62 00 00 00 00
    20: 00 00 00 00 00 02 00 00 67 33 01 00 00 00 00 00    .....?..g3?.....
    30: 00 20 09 04 00 10 00 60 00 00 00 00 00 00 00 00    . ??.?.`........
    40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    50: 20 c0 45 00 00 00 00 00 07 07 07 00 00 00 00 00     ?E.....???.....
    60: 00 00 00 00 00 88 00 00 00 00 00 00 00 00 00 00    .....?..........
    70: 00 00 25 00 00 00 00 00 00 00 e4 00 00 00 00 00    ..%.......?.....
    80: 00 00 00 00 00 00 90 00 00 00 00 00 04 00 00 00    ......?.....?...
    90: 32 e3 64 01 00 00 00 00 00 00 08 00 00 00 23 0f    2?d?......?...#?
    a0: 00 0f 0f 0d 0d 10 42 10 10 10 03 01 00 00 00 00    .?????B?????....
    b0: 04 08 07 00 00 00 00 00 00 00 00 00 00 00 00 00    ???.............
    c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    f0: 5f 55 42 39 35 33 00 00 00 00 00 00 00 00 00 00    _UB953.........

    This is the i2cdump output for ub960 and ub953 when BIST should be enabled.

  • Hello Kevin,

    When in BIST mode the forward and back channels are constantly being overwritten with BIST related data, this will prevent communication between the deserializer and serializer. 

    Within your script please comment out any read and writes to the UB953s from the UB960 while BIST is active. Writing to the UB953 through the UB960 while BIST is active puts the UB960 into a held state until a power reset is done. If you want to read and write to the UB953s while BIST is active, communicate locally with the UB953 and not thought the UB960.

    Thank you,

    Joshua Horlander-Cruz  

  • Hi Joshua,

    My program doesn't do any reading or writing to the ub953s once BIST is enabled unless the port debug register SER_BIST_ACT bit indicates that BIST is not enabled on the serializer.

    I'm also curious why the script you posted doesn't check the SER_BIST_ACT bit to verify the serializer is in BIST mode? Without checking that, there's no way to know that it's actually in BIST mode unless I'm missing something.

  • Hi Kevin,

    When running the script I sent you, with a UB960 and a single UB530, I am experiencing no problem with asserting the SER_DES_ACT bit, even when I switch ports and modified the code appropriately the SER_DES_ACT functioned correctly as did BIST mode. 

    As we do not support Linux, could you please convert the script I sent you into a form that you can use and then report the results to me, in case there is a minor difference between your script and the one I sent that is causing the issue?

    The reason that the script I sent does not check SER_BIST_ACT is because it forces BIST errors, these errors will be recorded in register 0x54 on the serializer if BIST was activated correctly, essentially validating that BIST enabled and was functioning correctly. 

    Regards,

    Joshua

  • The program is the script translated into a form I can use. I don't know how to translate it any more accurately.

    I tried using bit 0 of the port debug register on the ub960 to trigger back channel errors when BIST mode should be active (0xB3 set to 0x1 on the ub960). The errors are detected by the ub953. However, they show up in the ub953 as CRC errors (registers 0x55 and 0x56) and not BIST errors (register 0x54).

    To me the primary question is: if register 0xB3 on the ub960 is set to 0x1 what are the possible reasons that SER_BIST_ACT would not be asserted? The datasheets don't provide any hints on this. I can provide more register dumps if it would be useful.

  • Hi Kevin,

    To my knowledge the only reason the SER_BIST_ACT bit will not become asserted if there is a problem with the communication between the UB953 and UB960. 

    I noticed that in your script there are no writes to 0x5C on the UB960 to set up alias IDs for the UB953s, yet the UB953s all have different addresses, are these addresses set up somewhere else?

    Can you run the new script provided below and see if the output you get matches the output that I provided, image of my output provided below?  In this new script most of the checks are eliminated and BIST validation is more streamlined making for an easier read and a much shorter script. As we don't support Linux, can you convert the attached script below into a form that you can use?

    The provided script only uses one UB953 connected to RX0 on a UB960 with default settings on the UB960s EVM (J7 is open) and UB953s EVM, please make sure to use this hardware setup when running the script. 

    import time
    
    UB960 = 0x60
    UB953 = 0x18
    
    #Hard reset 953 and 960
    board.WriteI2C(UB953, 0x02, 0x01)
    board.WriteI2C(UB960, 0x02, 0x01)
    
    #set up port and SER alias ID
    board.WriteI2C(UB960, 0x4C, 0x01)
    board.WriteI2C(UB960, 0x58, 0x5E)
    board.WriteI2C(UB960, 0x5C, 0x18)
    
    print ("\t\tRX0")
    print ("960 Device ID (0x00):", hex(board.ReadI2C(UB960, 0x00, 1)))
    print ("953 Device ID (0x00):", hex(board.ReadI2C(UB953, 0x00, 1)))
    print ("Reciever Lock Status (0x4D), Bit [1:0] should be high:", hex(board.ReadI2C(UB960, 0x4D, 1)))
    print("------------------------------------------------------------------")
    print("Read BCC Error Status (0x79):", hex(board.ReadI2C(UB953, 0x79, 1)))
    board.WriteI2C(UB960, 0xB3, 0x01)	#Enable BIST using BIST_CTL
    print ("Read BIST CTL (0xB3) register After BIST ENABLED", hex(board.ReadI2C(UB960, 0xB3, 1)))
    time.sleep(0.25)
    print ("Read BIST Lock Status Change of 960 RIGHT AFTER BIST enabled (0x4D):", hex(board.ReadI2C(UB960, 0x4D,1)))
    
    for x in range(7):
        board.WriteI2C(UB960, 0xD0, 0x01)										#Force 1 Error, 0xD0 is PORT_DEBUG register
        time.sleep(0.1)
    print("SER_BIST_ACT (0xD0) VALUE, BIST is Enabled",hex(board.ReadI2C(UB960, 0xD0, 1)))
    board.WriteI2C(UB960, 0xB3, 0x00) #Disable BIST
    print ("Read BIST CTL (0xB3) register After BIST DISABLED", hex(board.ReadI2C(UB960, 0xB3, 1)))
    print ("BIST CRC Error count (0x54) on 953 after BIST.", hex(board.ReadI2C(UB953, 0x54, 1))) #0x54 is BIST ERR CNT
    print("SER_BIST_ACT (0xD0) VALUE, BIST disabled",hex(board.ReadI2C(UB960, 0xD0, 1)))
    print ("#################################################################")
    print ("\n\n")

     

    Regards,

    Joshua Horlander-Cruz