Source code for pyfabil.plugins.tpm.pll

__author__ = 'lessju'

import pyfabil.boards.tpm_hw_definitions as tpm_hw_definitions
from pyfabil.plugins.firmwareblock import FirmwareBlock
from pyfabil.base.definitions import *
from pyfabil.base.utils import *
import logging
import time


[docs] class TpmPll(FirmwareBlock): """ FirmwareBlock tests class """ @compatibleboards(BoardMake.TpmBoard) @friendlyname('tpm_pll') @maxinstances(1) def __init__(self, board, **kwargs): """ TpmPll initialiser :param board: Pointer to board instance """ super(TpmPll, self).__init__(board) self._board_type = kwargs.get('board_type', 'XTPM') self._pll_out_config = [] fw_date_code = self.board["board.regfile.date_code"] self._fpga_firmware = None _use_jesd_refclk_only = False if self.board.is_programmed(0): self._fpga_firmware = self.board['fpga1.regfile.rev'] if self.board.hw_rev == tpm_hw_definitions.TPM_HW_REV_1_2: if self.board.has_register('fpga1.regfile.feature_extended.use_jesd_refclk_only'): _use_jesd_refclk_only = self.board['fpga1.regfile.feature_extended.use_jesd_refclk_only'] self._pps_invert = None self._jesd_refclk_only = None if self.board.hw_rev == tpm_hw_definitions.TPM_HW_REV_1_2: self._pps_invert = 1 if _use_jesd_refclk_only == 1: self._jesd_refclk_only = True logging.debug("Not using JESD global clock!") else: self._jesd_refclk_only = False if fw_date_code >= tpm_hw_definitions.CPLD_FW_VER_REQUIRED_FOR_I2C_CMD_ACK_TPM_V1_2: self._pll_status_enabled = True else: self._pll_status_enabled = False elif self.board.hw_rev >= tpm_hw_definitions.TPM_HW_REV_1_5: self._pps_invert = 0 self._jesd_refclk_only = True if fw_date_code > self.board.CPLD_FW_VER_LOCK_I2C_CHANGE: self._pll_status_enabled = True else: self._pll_status_enabled = False else: raise PluginError("TpmPll: Invalid hw_rev detected") # On TPM 1.6 check if we are using the special firmware supporting 800 MHz clock from PLL self._config_800MHz = False if self.board.hw_rev >= tpm_hw_definitions.TPM_HW_REV_1_5 and self._fpga_firmware is not None: if self._fpga_firmware == tpm_hw_definitions.FPGA_FW_800MHZ_EXCEPTION_TPM_V1_5: self._config_800MHz = True logging.info("FPGA FIRMWARE VERSION: %s" % hex(self._fpga_firmware)) logging.info("Using 800 MHz FPGA clock exception!") if self._board_type == "XTPM": if not self._config_800MHz: self._pll_out_config = [ "sysref", # 0 - SYSRF1 "clk", # 1 - CLKB1 "clk", # 2 - CLKB0 "unused", # 3 - PLL_CLK_TST "sysref", # 4 - SYSRF0 "unused", # 5 - NC "vcxo" if not self._jesd_refclk_only else "unused", # 6 - v1.6 PLL_CLK_FPGA0, v2.0 NC "unused", # 7 - 10M_FPGA0 "vcxo", # 8 - PLL_CLK_JESD_FPGA0 "sysref_pll1_retimed", # 9 - SYSREF_FPGA0 "sysref_pll1_retimed", # 10 - SYSREF_FPGA1 "unused", # 11 - 10M_FPGA1 "vcxo" if not self._jesd_refclk_only else "unused", # 12 - v1.6 PLL_CLK_FPGA1, v2.0 NC "vcxo" # 13 - PLL_CLK_JESD_FPGA1 ] else: logging.warning("FPGA FIRMWARE VERSION: %s"%hex(self._fpga_firmware)) logging.warning("PLL configure in 800MHz mode [experimental] [exception for fw %s only]"%hex(tpm_hw_definitions.FPGA_FW_800MHZ_EXCEPTION_TPM_V1_5)) self._pll_out_config = [ "sysref", # 0 - SYSRF1 "clk", # 1 - CLKB1 "clk", # 2 - CLKB0 "unused", # 3 - PLL_CLK_TST "sysref", # 4 - SYSRF0 "unused", # 5 - NC "unused", # 6 - NC "unused", # 7 - 10M_FPGA0 "clk", # 8 - PLL_CLK_JESD_FPGA0 "sysref_pll1_retimed",# 9 - SYSREF_FPGA0 "sysref_pll1_retimed",# 10 - SYSREF_FPGA1 "unused", # 11 - 10M_FPGA1 "unused", # 12 - NC "clk" # 13 - PLL_CLK_JESD_FPGA1 ] else: raise PluginError("TpmPll: Board type not supported") #######################################################################################
[docs] def pll_out_set(self, idx): """ Set PLL out :param idx: :return: """ type = self._pll_out_config[idx] if type == "clk": reg0 = 0x0 reg1 = 0x0 if not self._config_800MHz else 0x80 reg2 = 0x0 elif type == "clk_hstl": reg0 = 0x0 reg1 = 0x80 reg2 = 0x0 elif type == "clk_div_2": reg0 = 0x0 reg1 = 0x0 reg2 = 0x0 if not self._config_800MHz else 0x01 elif type == "clk_div_4": reg0 = 0x0 reg1 = 0x0 if not self._config_800MHz else 0x80 reg2 = 0x3 elif type == "vcxo": reg0 = 0x20 reg1 = 0x0 if not self._config_800MHz else 0x80 reg2 = 0x0 elif type == "vcxo_hstl": reg0 = 0x20 reg1 = 0x80 reg2 = 0x0 elif type == "inverted_vcxo": reg0 = 0xA0 reg1 = 0x0 if not self._config_800MHz else 0x80 reg2 = 0x0 elif type == "sysref": reg0 = 0x40 reg1 = 0x0 if not self._config_800MHz else 0x80 reg2 = 0x0 elif type == "sysref_lvds_boost": reg0 = 0x40 reg1 = 0x40 reg2 = 0x0 elif type == "sysref_pll1_retimed": reg0 = 0x60 reg1 = 0x0 if not self._config_800MHz else 0x80 reg2 = 0x0 elif type == "sysref_lvds": reg0 = 0x40 reg1 = 0x0 reg2 = 0x0 elif type == "sysref_hstl": reg0 = 0x40 reg1 = 0x80 reg2 = 0x0 else: reg0 = 0x0 reg1 = 0x0 reg2 = 0x0 return reg0, reg1, reg2
[docs] def pll_config(self, fsample): """ Configure the PLL :param fsample: """ doubler = 0x0 #0x0 0x10 if self._board_type == "XTPM": # PLL1 config self.board[('pll', 0x100)] = 0x1 self.board[('pll', 0x102)] = 0x1 self.board[('pll', 0x104)] = 10 if doubler == 0 else 20 # VCXO100MHz self.board[('pll', 0x106)] = 0x14 # VCXO100MHz ##mod self.board[('pll', 0x107)] = 0x13 # Not disable holdover # Check if it is a TPM 2.0 which requires differential input if self.board.hw_rev >= tpm_hw_definitions.TPM_HW_REV_2_0: logging.warn("TpmPLL: PLL VCXO input set to differential") self.board[('pll', 0x108)] = 0x29 # VCXO100MHz with differential input else: self.board[('pll', 0x108)] = 0x28 # VCXO100MHz self.board[('pll', 0x109)] = 0x0 # setting PLL1 feedback source as PLL2 divider output self.board[('pll', 0x10A)] = 0x2 # 10MHZ: 0x2 # PLL2 config self.board[('pll', 0x200)] = 0xE6 if fsample == 1000e6: self.board[('pll', 0x201)] = 0x0A self.board[('pll', 0x202)] = 0x13 self.board[('pll', 0x203)] = 0x00 self.board[('pll', 0x204)] = 0x4 # M1 self.board[('pll', 0x205)] = 0x7 self.board[('pll', 0x207)] = 0x2 # R1 self.board[('pll', 0x208)] = 0x9 # N2 elif fsample == 800e6: self.board[('pll', 0x201)] = 0x0A if doubler == 0 else 0x05 #0x05#0x0A self.board[('pll', 0x202)] = 0x13 if doubler == 0 else 0x23 #0x33#0x13 self.board[('pll', 0x203)] = doubler #0x10#0x00 self.board[('pll', 0x204)] = (0 << 5) | (0 << 4) | 0x5 # M1 self.board[('pll', 0x205)] = 0x7 self.board[('pll', 0x207)] = 0x1 #0x1#0x2 # R1 self.board[('pll', 0x208)] = 0x7 if doubler == 0 else 0x3 #0x3#0x7 # N2 elif fsample == 700e6: self.board[('pll', 0x201)] = 0xC8 self.board[('pll', 0x202)] = 0x13 self.board[('pll', 0x203)] = 0x00 self.board[('pll', 0x204)] = 0x5 # M1 self.board[('pll', 0x205)] = 0x7 self.board[('pll', 0x207)] = 0x0 # R1 self.board[('pll', 0x208)] = 0x6 # N2 else: raise PluginError("TpmPll: Frequency not supported") else: raise PluginError("TpmPll: Board type not supported") # Setting PLL Outputs for n in range(14): reg0, reg1, reg2 = self.pll_out_set(n) self.board[('pll', 0x300 + 3 * n + 0)] = reg0 self.board[('pll', 0x300 + 3 * n + 1)] = reg1 self.board[('pll', 0x300 + 3 * n + 2)] = reg2 # Setting SYSREF divider = 640 # sysref: divide by 640(*2) self.board[('pll', 0x400)] = divider & 0xFF self.board[('pll', 0x401)] = (divider >> 8) & 0xFF self.board[('pll', 0x402)] = 0x0 self.board[('pll', 0x403)] = 0x96 # Power down unused output self.board[('pll', 0x500)] = 0x10 pd = 0 for c in range(14): if self._pll_out_config[c] == "unused": pd |= 2 ** c self.board[('pll', 0x501)] = pd & 0xFF self.board[('pll', 0x502)] = (pd & 0xFF00) >> 8 self.board[('pll', 0x503)] = ~pd & 0xFF self.board[('pll', 0x504)] = (~pd & 0xFF00) >> 8 # enable STATUS outputs if self._pll_status_enabled: self.board[('pll', 0x505)] = 0x2 self.board[('pll', 0x506)] = 0x3 self.board[('pll', 0x507)] = 0xc # IO update command self.board[('pll', 0xF)] = 0x1 for i in range(10): if self.board[('pll', 0xF)] == 0: break if i == 9: raise PluginError("PLL timeout error - IO_UPDATE (0xF): 0x%x" % self.board[('pll', 0xF)]) time.sleep(0.1) # Enable sysref self.board[('pll', 0x403)] = 0x97 if do_until_eq(lambda: self.board[('pll', 0xF)], 0, ms_retry=100, s_timeout=10) is None: raise PluginError("PLL timeout error - IO_UPDATE (0xF): 0x%x"%self.board[('pll', 0xF)]) self.board[('pll', 0xF)] = 0x1 # SYNC command self.board[('pll', 0x32A)] = 0x1 if do_until_eq(lambda: self.board[('pll', 0xF)], 0, ms_retry=100, s_timeout=10) is None: raise PluginError("PLL timeout error - IO_UPDATE (0xF): 0x%x"%self.board[('pll', 0xF)]) self.board[('pll', 0xF)] = 0x1 # SYNC command self.board[('pll', 0x32A)] = 0x0 if do_until_eq(lambda: self.board[('pll', 0xF)], 0, ms_retry=100, s_timeout=10) is None: raise PluginError("PLL timeout error - IO_UPDATE (0xF): 0x%x"%self.board[('pll', 0xF)]) self.board[('pll', 0xF)] = 0x1 # PLL2 VCO calibration self.board[('pll', 0x203)] = doubler | 0x0 self.board[('pll', 0xF)] = 0x1 if do_until_eq(lambda: self.board[('pll', 0xF)], 0, ms_retry=100, s_timeout=10) is None: raise PluginError("PLL timeout error - IO_UPDATE (0xF): 0x%x"%self.board[('pll', 0xF)]) self.board[('pll', 0x203)] = doubler | 0x1 self.board[('pll', 0xF)] = 0x1 if do_until_eq(lambda: self.board[('pll', 0xF)], 0, ms_retry=100, s_timeout=10) is None: raise PluginError("PLL timeout error - IO_UPDATE (0xF): 0x%x"%self.board[('pll', 0xF)]) if do_until_eq(lambda: self.board[('pll', 0x509)] & 0x1, 0x0, ms_retry=100, s_timeout=10) is None: raise PluginError("PLL VCO calibration timeout - Status Readback 1 (0x509): 0x%x"%self.board[('pll', 0x509)]) if do_until_eq(lambda: self.board[('pll', 0x508)] in [0xF2, 0xE7], 0x1, ms_retry=100, s_timeout=10) is None: raise PluginError("PLL not locked - Status Readback 0 (0x508): 0x%x"%self.board[('pll', 0x508)]) if self._pll_status_enabled: self.reset_pll_loss_of_lock()
[docs] def get_pll_status(self): if not self._pll_status_enabled: return None locks = self.board["board.regfile.pll.status"] return locks
[docs] def get_pll_loss_of_lock(self): if not self._pll_status_enabled: return None return self.board["board.regfile.pll_lol"]
[docs] def reset_pll_loss_of_lock(self): if not self._pll_status_enabled: return # lol = self.board["board.regfile.pll_lol"] self.board["board.regfile.pll_lol"] = 0 #lol & (~lol & 0xff)
[docs] def pll_reset(self): """ Perform the PLL reset """ self.board['board.regfile.ctrl.ad9528_rst'] = 1 self.board['board.regfile.ctrl.ad9528_rst'] = 0 time.sleep(0.2) self.board['board.regfile.ctrl.ad9528_rst'] = 1 time.sleep(0.2)
[docs] def pll_start(self, fsample): """ Perform the PLL initialization procedure as implemented in ADI demo :param fsample: PLL output frequency in MHz. Supported frequency are 700, 800, 1000 MHz """ if fsample not in [1000e6, 800e6, 700e6]: logging.warn("TpmPLL: Frequency " + str(fsample / 1e6) + " MHz is not currently supported.") fsample = 800e6 self.pll_reset() self.board['fpga1.pps_manager.pps_in_invert'] = self._pps_invert self.board['fpga1.pps_manager.sync_tc'] = 0x07090404 self.board['fpga1.pps_manager.sync_prescale'] = 0x0 self.board['fpga1.pps_manager.sync_cnt_enable'] = 0x7 self.board['fpga2.pps_manager.pps_in_invert'] = self._pps_invert self.board['fpga2.pps_manager.sync_tc'] = 0x07090404 self.board['fpga2.pps_manager.sync_prescale'] = 0x0 self.board['fpga2.pps_manager.sync_cnt_enable'] = 0x7 if self._board_type == "XTPM": self.board[('pll', 0xF)] = 0x1 self.pll_config(fsample) self.pll_config(fsample) self.board['fpga1.pps_manager.sync_cnt_enable'] = 0 # disable sync self.board['fpga2.pps_manager.sync_cnt_enable'] = 0 # disable sync if self._pll_status_enabled: if self.get_pll_loss_of_lock() > 0: raise PluginError("PLL Loss of lock detected!") else: raise PluginError("TpmPll: Board type not supported")
##################### Superclass method implementations #################################
[docs] def initialise(self): """ Initialise TpmPll """ logging.info("TpmPll has been initialised") return True
[docs] def status_check(self): """ Perform status check :return: Status """ logging.info("TpmPll : Checking status") pll_reg_508 = self.board[('pll', 0x508)] if pll_reg_508 not in [0xF2, 0xE7]: logging.error('TpmPLL: PLL not not locked') return Status.BoardError if pll_reg_508 == 0xF2: logging.error('TpmPLL: PLL not not locked to reference clock') return Status.BoardError if self._pll_status_enabled: if self.get_pll_loss_of_lock() != 0: logging.error('TpmPLL: PLL Loss of Lock Detected') return Status.BoardError return Status.OK
[docs] def clean_up(self): """ Perform cleanup :return: Success """ logging.info("TpmPll : Cleaning up") return True