aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm/dboard_manager/magnesium.py
diff options
context:
space:
mode:
Diffstat (limited to 'mpm/python/usrp_mpm/dboard_manager/magnesium.py')
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/magnesium.py514
1 files changed, 15 insertions, 499 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
index f81e07f43..6bbdd808f 100644
--- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py
+++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
@@ -1,5 +1,5 @@
#
-# Copyright 2017 Ettus Research, a National Instruments Company
+# Copyright 2017-2018 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
@@ -9,62 +9,20 @@ Magnesium dboard implementation module
from __future__ import print_function
import os
-import time
import threading
-import math
-import re
from six import iterkeys, iteritems
from usrp_mpm import lib # Pulls in everything from C++-land
from usrp_mpm.dboard_manager import DboardManagerBase
-from usrp_mpm.dboard_manager.lmk_mg import LMK04828Mg
from usrp_mpm.dboard_manager.mg_periphs import TCA6408, MgCPLD
-from usrp_mpm.dboard_manager.mg_periphs import DboardClockControl
-from usrp_mpm.cores import nijesdcore
+from usrp_mpm.dboard_manager.mg_init import MagnesiumInitManager
from usrp_mpm.mpmlog import get_logger
-from usrp_mpm.mpmutils import async_exec
from usrp_mpm.sys_utils.uio import open_uio
from usrp_mpm.sys_utils.udev import get_eeprom_paths
-from usrp_mpm.cores import ClockSynchronizer
from usrp_mpm.bfrfs import BufferFS
-INIT_CALIBRATION_TABLE = {"TX_BB_FILTER" : 0x0001,
- "ADC_TUNER" : 0x0002,
- "TIA_3DB_CORNER" : 0x0004,
- "DC_OFFSET" : 0x0008,
- "TX_ATTENUATION_DELAY" : 0x0010,
- "RX_GAIN_DELAY" : 0x0020,
- "FLASH_CAL" : 0x0040,
- "PATH_DELAY" : 0x0080,
- "TX_LO_LEAKAGE_INTERNAL" : 0x0100,
- "TX_LO_LEAKAGE_EXTERNAL" : 0x0200,
- "TX_QEC_INIT" : 0x0400,
- "LOOPBACK_RX_LO_DELAY" : 0x0800,
- "LOOPBACK_RX_RX_QEC_INIT" : 0x1000,
- "RX_LO_DELAY" : 0x2000,
- "RX_QEC_INIT" : 0x4000,
- "BASIC" : 0x4F,
- "OFF" : 0x00,
- "DEFAULT" : 0x4DFF,
- "ALL" : 0x7DFF,
- }
-
-TRACKING_CALIBRATION_TABLE = {"TRACK_RX1_QEC" : 0x01,
- "TRACK_RX2_QEC" : 0x02,
- "TRACK_ORX1_QEC" : 0x04,
- "TRACK_ORX2_QEC" : 0x08,
- "TRACK_TX1_LOL" : 0x10,
- "TRACK_TX2_LOL" : 0x20,
- "TRACK_TX1_QEC" : 0x40,
- "TRACK_TX2_QEC" : 0x80,
- "OFF" : 0x00,
- "RX_QEC" : 0x03,
- "TX_QEC" : 0xC0,
- "TX_LOL" : 0x30,
- "DEFAULT" : 0xC3,
- "ALL" : 0xF3,
- }
-
-
+###############################################################################
+# SPI Helpers
+###############################################################################
def create_spidev_iface_lmk(dev_node):
"""
Create a regs iface from a spidev node
@@ -108,9 +66,6 @@ def create_spidev_iface_phasedac(dev_node):
)
###############################################################################
-# Peripherals
-###############################################################################
-###############################################################################
# Main dboard control class
###############################################################################
class Magnesium(DboardManagerBase):
@@ -155,16 +110,6 @@ class Magnesium(DboardManagerBase):
'alignment': 1024,
},
}
- # DAC is initialized to midscale automatically on power-on: 16-bit DAC, so midpoint
- # is at 2^15 = 32768. However, the linearity of the DAC is best just below that
- # point, so we set it to the (carefully calculated) alternate value instead.
- INIT_PHASE_DAC_WORD = 31000 # Intentionally decimal
- PHASE_DAC_SPI_ADDR = 0x0
- # External PPS pipeline delay from the PPS captured at the FPGA to TDC input,
- # in reference clock ticks
- EXT_PPS_DELAY = 5
- # Variable PPS delay before the RP/SP pulsers begin. Fixed value for the N3xx devices.
- N3XX_INT_PPS_DELAY = 4
default_master_clock_rate = 125e6
default_time_source = 'internal'
default_current_jesd_rate = 2500e6
@@ -189,9 +134,6 @@ class Magnesium(DboardManagerBase):
self.eeprom_fs = None
self.eeprom_path = None
self.cpld = None
- self._init_cals_mask = 0
- self._tracking_cals_mask = 0
- self._init_cals_timeout = 0
# Now initialize all peripherals. If that doesn't work, put this class
# into a non-functional state (but don't crash, or we can't talk to it
# any more):
@@ -332,70 +274,6 @@ class Magnesium(DboardManagerBase):
"""
Execute necessary init dance to bring up dboard
"""
- def _init_lmk(lmk_spi, ref_clk_freq, master_clk_rate,
- pdac_spi, init_phase_dac_word, phase_dac_spi_addr):
- """
- Sets the phase DAC to initial value, and then brings up the LMK
- according to the selected ref clock frequency.
- Will throw if something fails.
- """
- self.log.trace("Initializing Phase DAC to d{}.".format(
- init_phase_dac_word
- ))
- pdac_spi.poke16(phase_dac_spi_addr, init_phase_dac_word)
- return LMK04828Mg(
- lmk_spi,
- self.spi_lock,
- ref_clk_freq,
- master_clk_rate,
- self.log
- )
- def _sync_db_clock():
- " Synchronizes the DB clock to the common reference "
- reg_offset = 0x200
- ref_clk_freq = self.ref_clock_freq
- ext_pps_delay = self.EXT_PPS_DELAY
- if args.get('time_source', self.default_time_source) == 'sfp0':
- reg_offset = 0x400
- ref_clk_freq = 62.5e6
- ext_pps_delay = 1 # only 1 flop between the WR core output and the TDC input
- synchronizer = ClockSynchronizer(
- dboard_ctrl_regs,
- self.lmk,
- self._spi_ifaces['phase_dac'],
- reg_offset,
- self.master_clock_rate,
- ref_clk_freq,
- 860E-15, # fine phase shift. TODO don't hardcode. This should live in the EEPROM
- self.INIT_PHASE_DAC_WORD,
- self.PHASE_DAC_SPI_ADDR,
- ext_pps_delay,
- self.N3XX_INT_PPS_DELAY,
- self.slot_idx)
- # The radio clock traces on the motherboard are 69 ps longer for Daughterboard B
- # than Daughterboard A. We want both of these clocks to align at the converters
- # on each board, so adjust the target value for DB B. This is an N3xx series
- # peculiarity and will not apply to other motherboards.
- trace_delay_offset = {0: 0.0e-0,
- 1: 69.0e-12}[self.slot_idx]
- offset = synchronizer.run(
- num_meas=[512, 128],
- target_offset = trace_delay_offset)
- offset_error = abs(offset)
- if offset_error > 100e-12:
- self.log.error("Clock synchronizer measured an offset of {:.1f} ps!".format(
- offset_error*1e12
- ))
- raise RuntimeError("Clock synchronizer measured an offset of {:.1f} ps!".format(
- offset_error*1e12
- ))
- else:
- self.log.debug("Residual synchronization error: {:.1f} ps.".format(
- offset_error*1e12
- ))
- synchronizer = None
- self.log.debug("Sample Clock Synchronization Complete!")
- ## Go, go, go!
# Sanity checks and input validation:
self.log.debug("init() called with args `{}'".format(
",".join(['{}={}'.format(x, args[x]) for x in args])
@@ -404,9 +282,13 @@ class Magnesium(DboardManagerBase):
error_msg = "Cannot run init(), peripherals are not initialized!"
self.log.error(error_msg)
raise RuntimeError(error_msg)
+ fast_reinit = True
if 'ref_clk_freq' in args:
- self.ref_clock_freq = float(args['ref_clk_freq'])
- assert self.ref_clock_freq in (10e6, 20e6, 25e6)
+ new_ref_clock_freq = float(args['ref_clk_freq'])
+ assert new_ref_clock_freq in (10e6, 20e6, 25e6)
+ if new_ref_clock_freq != self.ref_clock_freq:
+ fast_reinit = False
+ self.ref_clock_freq = float(args['ref_clk_freq'])
assert self.ref_clock_freq is not None
master_clock_rate = \
float(args.get('master_clock_rate',
@@ -416,380 +298,13 @@ class Magnesium(DboardManagerBase):
master_clock_rate / 1e6)
master_clock_rate_changed = master_clock_rate != self.master_clock_rate
if master_clock_rate_changed:
+ fast_reinit = False
self.master_clock_rate = master_clock_rate
self.log.debug("Updating master clock rate to {:.02f} MHz!".format(
self.master_clock_rate / 1e6
))
- # Init some more periphs:
- # The following peripherals are only used during init, so we don't want
- # to hang on to them for the full lifetime of the Magnesium class. This
- # helps us close file descriptors associated with the UIO objects.
- with open_uio(
- label="dboard-regs-{}".format(self.slot_idx),
- read_only=False
- ) as dboard_ctrl_regs:
- self.log.trace("Creating jesdcore object...")
- jesdcore = nijesdcore.NIMgJESDCore(dboard_ctrl_regs, self.slot_idx)
- # Now get cracking with the actual init sequence:
- self.log.trace("Creating dboard clock control object...")
- db_clk_control = DboardClockControl(dboard_ctrl_regs, self.log)
- self.log.debug("Reset Dboard Clocking and JESD204B interfaces...")
- db_clk_control.reset_mmcm()
- jesdcore.reset()
- self.log.trace("Initializing LMK...")
- self.lmk = _init_lmk(
- self._spi_ifaces['lmk'],
- self.ref_clock_freq,
- self.master_clock_rate,
- self._spi_ifaces['phase_dac'],
- self.INIT_PHASE_DAC_WORD,
- self.PHASE_DAC_SPI_ADDR,
- )
- db_clk_control.enable_mmcm()
- # Synchronize DB Clocks
- _sync_db_clock()
- self.log.debug("Sample Clocks and Phase DAC Configured Successfully!")
- # Clocks and PPS are now fully active!
- self.mykonos.set_master_clock_rate(self.master_clock_rate)
- self.init_jesd(jesdcore, args)
- jesdcore = None # Help with garbage collection
- # That's all that requires access to the dboard regs!
- if bool(args.get('rfic_digital_loopback')):
- self.log.warning("RF Functionality Disabled: JESD204b digital loopback " \
- "enabled inside Mykonos!")
- self.mykonos.enable_jesd_loopback(1)
- else:
- self.mykonos.start_radio()
- return True
-
- def _parse_and_convert_cal_args(self, table, cal_args):
- """Parse calibration string and convert it to a number
-
- Arguments:
- table {dictionary} -- a look up table that map a type of calibration
- to its bit mask.(defined in AD9375-UG992)
- cal_args {string} -- string arguments from user in form of "CAL1|CAL2|CAL3"
- or "CAL1 CAL2 CAL3" or "CAL1;CAL2;CAL3"
-
- Returns:
- int -- calibration value bit mask.
- """
- value = 0
- try:
- return int(cal_args, 0)
- except ValueError:
- pass
- for key in re.split(r'[;|\s]\s*', cal_args):
- value_tmp = table.get(key.upper())
- if (value_tmp) != None:
- value |= value_tmp
- else:
- self.log.warning(
- "Calibration key `%s' is not in calibration table. "
- "Ignoring this key.",
- key.upper()
- )
- return value
-
- def init_rf_cal(self, args):
- " Setup RF CAL "
- self.log.debug("Setting up RF CAL...")
- try:
- self._init_cals_mask = \
- self._parse_and_convert_cal_args(
- INIT_CALIBRATION_TABLE,
- args.get('init_cals', 'DEFAULT')
- )
- self._tracking_cals_mask = \
- self._parse_and_convert_cal_args(
- TRACKING_CALIBRATION_TABLE,
- args.get('tracking_cals', 'DEFAULT')
- )
- self._init_cals_timeout = int(
- args.get('init_cals_timeout',
- str(self.mykonos.DEFAULT_INIT_CALS_TIMEOUT))
- , 0
- )
- except ValueError as ex:
- self.log.warning("init() args missing or error using default \
- value seeing following exception print out.")
- self.log.warning("{}".format(ex))
- self._init_cals_mask = self._parse_and_convert_cal_args(
- INIT_CALIBRATION_TABLE, 'DEFAULT')
- self._tracking_cals_mask = self._parse_and_convert_cal_args(
- TRACKING_CALIBRATION_TABLE, 'DEFAULT')
- self._init_cals_timeout = self.mykonos.DEFAULT_INIT_CALS_TIMEOUT
- self.log.debug("args[init_cals]=0x{:02X}"
- .format(self._init_cals_mask))
- self.log.debug("args[tracking_cals]=0x{:02X}"
- .format(self._tracking_cals_mask))
- async_exec(
- self.mykonos,
- "setup_cal",
- self._init_cals_mask,
- self._tracking_cals_mask,
- self._init_cals_timeout
- )
-
- def init_lo_source(self, args):
- """Set all LO
-
- This function will initialize all LO to user specified sources.
- If there's no source is specified, the default one will be used.
-
- Arguments:
- args {string:string} -- device arguments.
- """
- self.log.debug("Setting up LO source..")
- rx_lo_source = args.get("rx_lo_source", "internal")
- tx_lo_source = args.get("tx_lo_source", "internal")
- self.mykonos.set_lo_source("RX", rx_lo_source)
- self.mykonos.set_lo_source("TX", tx_lo_source)
- self.log.debug("RX LO source is set at {}".format(self.mykonos.get_lo_source("RX")))
- self.log.debug("TX LO source is set at {}".format(self.mykonos.get_lo_source("TX")))
-
- def init_jesd(self, jesdcore, args):
- """
- Bring up the JESD link between Mykonos and the N310.
- All clocks must be set up and stable before starting this routine.
- """
- jesdcore.check_core()
-
- # JESD Lane Rate only depends on the master_clock_rate selection, since all
- # other link parameters (LMFS,N) remain constant.
- L = 4
- M = 4
- F = 2
- S = 1
- N = 16
- new_rate = self.master_clock_rate * M * N * (10.0/8) / L / S
- self.log.trace("Calculated JESD204b lane rate is {} Gbps".format(new_rate/1e9))
- self.set_jesd_rate(jesdcore, new_rate)
-
- self.log.trace("Pulsing Mykonos Hard Reset...")
- self.cpld.reset_mykonos()
- self.log.trace("Initializing Mykonos...")
- self.init_lo_source(args)
- self.mykonos.begin_initialization()
- # Multi-chip Sync requires two SYSREF pulses at least 17us apart.
- jesdcore.send_sysref_pulse()
- time.sleep(0.001) # 17us... ish.
- jesdcore.send_sysref_pulse()
- async_exec(self.mykonos, "finish_initialization")
- # TODO:can we call this after JESD?
- self.init_rf_cal(args)
- self.log.trace("Starting JESD204b Link Initialization...")
- # Generally, enable the source before the sink. Start with the DAC side.
- self.log.trace("Starting FPGA framer...")
- jesdcore.init_framer()
- self.log.trace("Starting Mykonos deframer...")
- self.mykonos.start_jesd_rx()
- # Now for the ADC link. Note that the Mykonos framer will not start issuing CGS
- # characters until SYSREF is received by the framer. Therefore we enable the
- # framer in Mykonos and the FPGA, send a SYSREF pulse to everyone, and then
- # start the deframer in the FPGA.
- self.log.trace("Starting Mykonos framer...")
- self.mykonos.start_jesd_tx()
- jesdcore.enable_lmfc(True)
- jesdcore.send_sysref_pulse()
- # Allow a bit of time for SYSREF to reach Mykonos and then CGS to appear. In
- # several experiments this time requirement was only in the 100s of nanoseconds.
- time.sleep(0.001)
- self.log.trace("Starting FPGA deframer...")
- jesdcore.init_deframer()
-
- # Allow a bit of time for CGS/ILA to complete.
- time.sleep(0.100)
- error_flag = False
- if not jesdcore.get_framer_status():
- self.log.error("JESD204b FPGA Core Framer is not synced!")
- error_flag = True
- if not self.check_mykonos_deframer_status():
- self.log.error("Mykonos JESD204b Deframer is not synced!")
- error_flag = True
- if not jesdcore.get_deframer_status():
- self.log.error("JESD204b FPGA Core Deframer is not synced!")
- error_flag = True
- if not self.check_mykonos_framer_status():
- self.log.error("Mykonos JESD204b Framer is not synced!")
- error_flag = True
- if (self.mykonos.get_multichip_sync_status() & 0xB) != 0xB:
- self.log.error("Mykonos Multi-chip Sync failed!")
- error_flag = True
- if error_flag:
- raise RuntimeError('JESD204B Link Initialization Failed. See MPM logs for details.')
- self.log.debug("JESD204B Link Initialization & Training Complete")
-
- def check_mykonos_framer_status(self):
- " Return True if Mykonos Framer is in good state "
- rb = self.mykonos.get_framer_status()
- self.log.trace("Mykonos Framer Status Register: 0x{:04X}".format(rb & 0xFF))
- tx_state = {0: 'CGS',
- 1: 'ILAS',
- 2: 'ADC Data'}[rb & 0b11]
- ilas_state = {0: 'CGS',
- 1: '1st Multframe',
- 2: '2nd Multframe',
- 3: '3rd Multframe',
- 4: '4th Multframe',
- 5: 'Last Multframe',
- 6: 'invalid state',
- 7: 'ILAS Complete'}[(rb & 0b11100) >> 2]
- sysref_rx = (rb & (0b1 << 5)) > 0
- fifo_ptr_delta_changed = (rb & (0b1 << 6)) > 0
- sysref_phase_error = (rb & (0b1 << 7)) > 0
- # According to emails with ADI, fifo_ptr_delta_changed may be buggy.
- # Deterministic latency is still achieved even when this bit is toggled, so
- # ADI's recommendation is to ignore it. The expected state of this bit 0, but
- # occasionally it toggles to 1. It is unclear why exactly this happens.
- success = ((tx_state == 'ADC Data') &
- (ilas_state == 'ILAS Complete') &
- sysref_rx &
- (not sysref_phase_error))
- logger = self.log.trace if success else self.log.warning
- logger("Mykonos Framer, TX State: %s", tx_state)
- logger("Mykonos Framer, ILAS State: %s", ilas_state)
- logger("Mykonos Framer, SYSREF Received: {}".format(sysref_rx))
- logger("Mykonos Framer, FIFO Ptr Delta Change: {} (ignored, possibly buggy)".format(fifo_ptr_delta_changed))
- logger("Mykonos Framer, SYSREF Phase Error: {}".format(sysref_phase_error))
- return success
-
- def check_mykonos_deframer_status(self):
- " Return True if Mykonos Deframer is in good state "
- rb = self.mykonos.get_deframer_status()
- self.log.trace("Mykonos Deframer Status Register: 0x{:04X}".format(rb & 0xFF))
-
- frame_symbol_error = (rb & (0b1 << 0)) > 0
- ilas_multifrm_error = (rb & (0b1 << 1)) > 0
- ilas_framing_error = (rb & (0b1 << 2)) > 0
- ilas_checksum_valid = (rb & (0b1 << 3)) > 0
- prbs_error = (rb & (0b1 << 4)) > 0
- sysref_received = (rb & (0b1 << 5)) > 0
- deframer_irq = (rb & (0b1 << 6)) > 0
- success = ((not frame_symbol_error) &
- (not ilas_multifrm_error) &
- (not ilas_framing_error) &
- ilas_checksum_valid &
- (not prbs_error) &
- sysref_received &
- (not deframer_irq))
- logger = self.log.trace if success else self.log.warning
- logger("Mykonos Deframer, Frame Symbol Error: {}".format(frame_symbol_error))
- logger("Mykonos Deframer, ILAS Multiframe Error: {}".format(ilas_multifrm_error))
- logger("Mykonos Deframer, ILAS Frame Error: {}".format(ilas_framing_error))
- logger("Mykonos Deframer, ILAS Checksum Valid: {}".format(ilas_checksum_valid))
- logger("Mykonos Deframer, PRBS Error: {}".format(prbs_error))
- logger("Mykonos Deframer, SYSREF Received: {}".format(sysref_received))
- logger("Mykonos Deframer, Deframer IRQ Received: {}".format(deframer_irq))
- return success
-
- def set_jesd_rate(self, jesdcore, new_rate, force=False):
- """
- Make the QPLL and GTX changes required to change the JESD204B core rate.
- """
- # The core is directly compiled for 125 MHz sample rate, which
- # corresponds to a lane rate of 2.5 Gbps. The same QPLL and GTX settings apply
- # for the 122.88 MHz sample rate.
- #
- # The higher LTE rate, 153.6 MHz, requires changes to the default configuration
- # of the MGT components. This function performs the required changes in the
- # following order (as recommended by UG476).
- #
- # 1) Modify any QPLL settings.
- # 2) Perform the QPLL reset routine by pulsing reset then waiting for lock.
- # 3) Modify any GTX settings.
- # 4) Perform the GTX reset routine by pulsing reset and waiting for reset done.
-
- assert new_rate in (2457.6e6, 2500e6, 3072e6)
-
- # On first run, we have no idea how the FPGA is configured... so let's force an
- # update to our rate.
- force = force or (self.current_jesd_rate is None)
-
- skip_drp = False
- if not force:
- # Current New Skip?
- skip_drp = {2457.6e6 : {2457.6e6: True, 2500.0e6: True, 3072.0e6:False},
- 2500.0e6 : {2457.6e6: True, 2500.0e6: True, 3072.0e6:False},
- 3072.0e6 : {2457.6e6: False, 2500.0e6: False, 3072.0e6:True}}[self.current_jesd_rate][new_rate]
-
- if skip_drp:
- self.log.trace("Current lane rate is compatible with the new rate. Skipping "
- "reconfiguration.")
-
- # These are the only registers in the QPLL and GTX that change based on the
- # selected line rate. The MGT wizard IP was generated for each of the rates and
- # reference clock frequencies and then diffed to create this table.
- QPLL_CFG = {2457.6e6: 0x680181, 2500e6: 0x680181, 3072e6: 0x06801C1}[new_rate]
- QPLL_FBDIV = {2457.6e6: 0x120, 2500e6: 0x120, 3072e6: 0x80}[new_rate]
- MGT_PMA_RSV = {2457.6e6: 0x1E7080, 2500e6: 0x1E7080, 3072e6: 0x18480}[new_rate]
- MGT_RX_CLK25_DIV = {2457.6e6: 5, 2500e6: 5, 3072e6: 7}[new_rate]
- MGT_TX_CLK25_DIV = {2457.6e6: 5, 2500e6: 5, 3072e6: 7}[new_rate]
- MGT_RXOUT_DIV = {2457.6e6: 4, 2500e6: 4, 3072e6: 2}[new_rate]
- MGT_TXOUT_DIV = {2457.6e6: 4, 2500e6: 4, 3072e6: 2}[new_rate]
- MGT_RXCDR_CFG = {2457.6e6:0x03000023ff10100020, 2500e6:0x03000023ff10100020, 3072e6:0x03000023ff10200020}[new_rate]
-
-
- # 1-2) Do the QPLL first
- if not skip_drp:
- self.log.trace("Changing QPLL settings to support {} Gbps".format(new_rate/1e9))
- jesdcore.set_drp_target('qpll', 0)
- # QPLL_CONFIG is spread across two regs: 0x32 (dedicated) and 0x33 (shared)
- reg_x32 = QPLL_CFG & 0xFFFF # [16:0] -> [16:0]
- reg_x33 = jesdcore.drp_access(rd=True, addr=0x33)
- reg_x33 = (reg_x33 & 0xF800) | ((QPLL_CFG >> 16) & 0x7FF) # [26:16] -> [11:0]
- jesdcore.drp_access(rd=False, addr=0x32, wr_data=reg_x32)
- jesdcore.drp_access(rd=False, addr=0x33, wr_data=reg_x33)
- # QPLL_FBDIV is shared with other settings in reg 0x36
- reg_x36 = jesdcore.drp_access(rd=True, addr=0x36)
- reg_x36 = (reg_x36 & 0xFC00) | (QPLL_FBDIV & 0x3FF) # in bits [9:0]
- jesdcore.drp_access(rd=False, addr=0x36, wr_data=reg_x36)
-
- # Run the QPLL reset sequence and prep the MGTs for modification.
- jesdcore.init()
-
- # 3-4) And the 4 MGTs second
- if not skip_drp:
- self.log.trace("Changing MGT settings to support {} Gbps"
- .format(new_rate/1e9))
- for lane in range(4):
- jesdcore.set_drp_target('mgt', lane)
- # MGT_PMA_RSV is split over 0x99 (LSBs) and 0x9A
- reg_x99 = MGT_PMA_RSV & 0xFFFF
- reg_x9a = (MGT_PMA_RSV >> 16) & 0xFFFF
- jesdcore.drp_access(rd=False, addr=0x99, wr_data=reg_x99)
- jesdcore.drp_access(rd=False, addr=0x9A, wr_data=reg_x9a)
- # MGT_RX_CLK25_DIV is embedded with others in 0x11. The
- # encoding for the DRP register value is one less than the
- # desired value.
- reg_x11 = jesdcore.drp_access(rd=True, addr=0x11)
- reg_x11 = (reg_x11 & 0xF83F) | \
- ((MGT_RX_CLK25_DIV-1 & 0x1F) << 6) # [10:6]
- jesdcore.drp_access(rd=False, addr=0x11, wr_data=reg_x11)
- # MGT_TX_CLK25_DIV is embedded with others in 0x6A. The
- # encoding for the DRP register value is one less than the
- # desired value.
- reg_x6a = jesdcore.drp_access(rd=True, addr=0x6A)
- reg_x6a = (reg_x6a & 0xFFE0) | (MGT_TX_CLK25_DIV-1 & 0x1F) # [4:0]
- jesdcore.drp_access(rd=False, addr=0x6A, wr_data=reg_x6a)
- # MGT_RXCDR_CFG is split over 0xA8 (LSBs) through 0xAD
- for reg_num, reg_addr in enumerate(range(0xA8, 0xAE)):
- reg_data = (MGT_RXCDR_CFG >> 16*reg_num) & 0xFFFF
- jesdcore.drp_access(rd=False, addr=reg_addr, wr_data=reg_data)
- # MGT_RXOUT_DIV and MGT_TXOUT_DIV are embedded together in
- # 0x88. The encoding for the DRP register value is
- # drp_val=log2(attribute)
- reg_x88 = (int(math.log(MGT_RXOUT_DIV, 2)) & 0x7) | \
- ((int(math.log(MGT_TXOUT_DIV, 2)) & 0x7) << 4) # RX=[2:0] TX=[6:4]
- jesdcore.drp_access(rd=False, addr=0x88, wr_data=reg_x88)
- self.log.trace("GTX settings changed to support {} Gbps"
- .format(new_rate/1e9))
- jesdcore.disable_drp_target()
-
- self.log.trace("JESD204b Lane Rate set to {} Gbps!"
- .format(new_rate/1e9))
- self.current_jesd_rate = new_rate
- return
+ return MagnesiumInitManager(self, self._spi_ifaces).init(
+ args, fast_reinit)
def get_user_eeprom_data(self):
"""
@@ -996,3 +511,4 @@ class Magnesium(DboardManagerBase):
) as dboard_ctrl_regs:
self.log.trace("Writing DB Core Register 0x{:04X} with 0x{:08X}...".format(addr, data))
dboard_ctrl_regs.poke32(addr, data)
+