aboutsummaryrefslogtreecommitdiffstats
path: root/mpm
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2018-02-14 15:39:49 -0800
committerMartin Braun <martin.braun@ettus.com>2018-02-14 15:46:39 -0800
commit2a508aabd38a512d1c91c180b3e97fe027a1e80e (patch)
tree27db014ce9ea1910441ecb7a123ff1f434297d86 /mpm
parentd58cadb8b090b8bb4b083a103903800bdb7716df (diff)
downloaduhd-2a508aabd38a512d1c91c180b3e97fe027a1e80e.tar.gz
uhd-2a508aabd38a512d1c91c180b3e97fe027a1e80e.tar.bz2
uhd-2a508aabd38a512d1c91c180b3e97fe027a1e80e.zip
mpm: mg: Move MgCPLD, TCA6408, DboardClockControl class to own module
Diffstat (limited to 'mpm')
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt9
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/magnesium.py193
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/mg_periphs.py202
3 files changed, 209 insertions, 195 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt b/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt
index 99184fcd3..542497898 100644
--- a/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt
+++ b/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2017 Ettus Research, National Instruments Company
+# Copyright 2017 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: GPL-3.0
#
@@ -11,13 +11,14 @@ SET(USRP_MPM_FILES ${USRP_MPM_FILES})
SET(USRP_MPM_DBMGR_FILES
${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/base.py
- ${CMAKE_CURRENT_SOURCE_DIR}/test.py
- ${CMAKE_CURRENT_SOURCE_DIR}/magnesium.py
${CMAKE_CURRENT_SOURCE_DIR}/eiscat.py
${CMAKE_CURRENT_SOURCE_DIR}/lmk_eiscat.py
${CMAKE_CURRENT_SOURCE_DIR}/lmk_mg.py
- ${CMAKE_CURRENT_SOURCE_DIR}/unknown.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/magnesium.py
${CMAKE_CURRENT_SOURCE_DIR}/magnesium_update_cpld.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/mg_periphs.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/test.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/unknown.py
)
LIST(APPEND USRP_MPM_FILES ${USRP_MPM_DBMGR_FILES})
SET(USRP_MPM_FILES ${USRP_MPM_FILES} PARENT_SCOPE)
diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
index 205796844..f933d1f14 100644
--- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py
+++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
@@ -17,14 +17,14 @@ 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.mpmlog import get_logger
from usrp_mpm.sys_utils.uio import open_uio
from usrp_mpm.sys_utils.udev import get_eeprom_paths
-from usrp_mpm.sys_utils.sysfs_gpio import SysFSGPIO
from usrp_mpm.cores import ClockSynchronizer
from usrp_mpm.bfrfs import BufferFS
-from usrp_mpm.mpmutils import poll_with_timeout
INIT_CALIBRATION_TABLE = {"TX_BB_FILTER" : 0x0001,
"ADC_TUNER" : 0x0002,
@@ -108,195 +108,6 @@ def create_spidev_iface_phasedac(dev_node):
###############################################################################
# Peripherals
###############################################################################
-class TCA6408(object):
- """
- Abstraction layer for the port/gpio expander
- """
- pins = (
- 'PWR-GOOD-3.6V', #3.6V
- 'PWR-EN-3.6V', #3.6V
- 'PWR-GOOD-1.5V', #1.5V
- 'PWR-EN-1.5V', #1.5V
- 'PWR-GOOD-5.5V', #5.5V
- 'PWR-EN-5.5V', #5.5V
- '6',
- 'LED',
- )
-
- def __init__(self, i2c_dev):
- if i2c_dev is None:
- raise RuntimeError("Need to specify i2c device to use the TCA6408")
- self._gpios = SysFSGPIO('tca6408', 0xBF, 0xAA, 0xAA, i2c_dev)
-
- def set(self, name, value=None):
- """
- Assert a pin by name
- """
- assert name in self.pins
- self._gpios.set(self.pins.index(name), value=value)
-
- def reset(self, name):
- """
- Deassert a pin by name
- """
- self.set(name, value=0)
-
- def get(self, name):
- """
- Read back a pin by name
- """
- assert name in self.pins
- return self._gpios.get(self.pins.index(name))
-
-class DboardClockControl(object):
- """
- Control the FPGA MMCM for Radio Clock control.
- """
- # Clocking Register address constants
- RADIO_CLK_MMCM = 0x0020
- PHASE_SHIFT_CONTROL = 0x0024
- RADIO_CLK_ENABLES = 0x0028
- MGT_REF_CLK_STATUS = 0x0030
-
- def __init__(self, regs, log):
- self.log = log
- self.regs = regs
- self.poke32 = self.regs.poke32
- self.peek32 = self.regs.peek32
-
- def enable_outputs(self, enable=True):
- """
- Enables or disables the MMCM outputs.
- """
- if enable:
- self.poke32(self.RADIO_CLK_ENABLES, 0x011)
- else:
- self.poke32(self.RADIO_CLK_ENABLES, 0x000)
-
- def reset_mmcm(self):
- """
- Uninitialize and reset the MMCM
- """
- self.log.trace("Disabling all Radio Clocks, then resetting FPGA MMCM...")
- self.enable_outputs(False)
- self.poke32(self.RADIO_CLK_MMCM, 0x1)
-
- def enable_mmcm(self):
- """
- Unreset MMCM and poll lock indicators
-
- If MMCM is not locked after unreset, an exception is thrown.
- """
- self.log.trace("Enabling FPGA Radio Clock MMCM...")
- self.poke32(self.RADIO_CLK_MMCM, 0x2)
- if not poll_with_timeout(
- lambda: bool(self.peek32(self.RADIO_CLK_MMCM) & 0x10),
- 500,
- 10,
- ):
- self.log.error("FPGA Radio Clock MMCM not locked!")
- raise RuntimeError("FPGA Radio Clock MMCM not locked!")
- self.log.trace("FPGA Radio Clock MMCM locked. Enabling clocks to design...")
- self.enable_outputs(True)
-
- def check_refclk(self):
- """
- Not technically a clocking reg, but related.
- """
- return bool(self.peek32(self.MGT_REF_CLK_STATUS) & 0x1)
-
-class MgCPLD(object):
- """
- Control class for the CPLD
- """
- CPLD_SIGNATURE = 0xCAFE # Expected signature ("magic number")
- CPLD_MINOR_REV = 0
- CPLD_MAJOR_REV = 5
-
- REG_SIGNATURE = 0x0000
- REG_MINOR_REVISION = 0x0001
- REG_MAJOR_REVISION = 0x0002
- REG_BUILD_CODE_LSB = 0x0003
- REG_BUILD_CODE_MSB = 0x0004
- REG_SCRATCH = 0x0005
- REG_CPLD_CTRL = 0x0010
- REG_LMK_CTRL = 0x0011
- REG_LO_STATUS = 0x0012
- REG_MYK_CTRL = 0x0013
-
- def __init__(self, regs, log):
- self.log = log.getChild("CPLD")
- self.log.debug("Initializing CPLD...")
- self.regs = regs
- self.poke16 = self.regs.poke16
- self.peek16 = self.regs.peek16
- signature = self.peek16(self.REG_SIGNATURE)
- if signature != self.CPLD_SIGNATURE:
- self.log.error(
- "CPLD Signature Mismatch! " \
- "Expected: 0x{:04X} Got: 0x{:04X}".format(
- self.CPLD_SIGNATURE, signature))
- raise RuntimeError("CPLD Signature Check Failed! Incorrect signature readback.")
- self.minor_rev = self.peek16(self.REG_MINOR_REVISION)
- self.major_rev = self.peek16(self.REG_MAJOR_REVISION)
- if self.major_rev != self.CPLD_MAJOR_REV:
- self.log.error(
- "CPLD Major Revision check mismatch! Expected: %d Got: %d",
- self.CPLD_MAJOR_REV,
- self.major_rev
- )
- raise RuntimeError("CPLD Revision Check Failed! MPM is not compatible with " \
- "the loaded CPLD image.")
- date_code = self.peek16(self.REG_BUILD_CODE_LSB) | \
- (self.peek16(self.REG_BUILD_CODE_MSB) << 16)
- self.log.debug(
- "CPLD Signature: 0x{:04X} "
- "Revision: {}.{} "
- "Date code: 0x{:08X}"
- .format(signature, self.major_rev, self.minor_rev, date_code))
-
- def set_scratch(self, val):
- " Write to the scratch register "
- self.poke16(self.REG_SCRATCH, val & 0xFFFF)
-
- def get_scratch(self):
- " Read from the scratch register "
- return self.peek16(self.REG_SCRATCH)
-
- def reset(self):
- " Reset entire CPLD "
- self.log.trace("Resetting CPLD...")
- self.poke16(self.REG_CPLD_CTRL, 0x1)
- self.poke16(self.REG_CPLD_CTRL, 0x0)
-
- def set_pdac_control(self, enb):
- """
- If enb is True, the Phase DAC will exclusively control the VCXO voltage
- """
- self.log.trace("Giving Phase %s control over VCXO voltage...",
- "exclusive" if bool(enb) else "non-exclusive")
- reg_val = (1<<4) if enb else 0
- self.poke16(self.REG_LMK_CTRL, reg_val)
-
- def get_lo_lock_status(self, which):
- """
- Returns True if the 'which' LO is locked. 'which' is either 'tx' or
- 'rx'.
- """
- mask = (1<<4) if which.lower() == 'tx' else 1
- return bool(self.peek16(self.REG_LO_STATUS & mask))
-
- def reset_mykonos(self):
- """
- Hard-resets Mykonos
- """
- self.log.debug("Resetting AD9371!")
- self.poke16(self.REG_MYK_CTRL, 0x1)
- time.sleep(0.001) # No spec here, but give it some time to reset.
- self.poke16(self.REG_MYK_CTRL, 0x0)
- time.sleep(0.001) # No spec here, but give it some time to reset.
-
-
###############################################################################
# Main dboard control class
###############################################################################
diff --git a/mpm/python/usrp_mpm/dboard_manager/mg_periphs.py b/mpm/python/usrp_mpm/dboard_manager/mg_periphs.py
new file mode 100644
index 000000000..77ce4ce89
--- /dev/null
+++ b/mpm/python/usrp_mpm/dboard_manager/mg_periphs.py
@@ -0,0 +1,202 @@
+#
+# Copyright 2017 Ettus Research, a National Instruments Company
+#
+# SPDX-License-Identifier: GPL-3.0
+#
+"""
+Magnesium dboard peripherals (CPLD, port expander, dboard regs)
+"""
+
+import time
+from usrp_mpm.sys_utils.sysfs_gpio import SysFSGPIO
+from usrp_mpm.mpmutils import poll_with_timeout
+
+class TCA6408(object):
+ """
+ Abstraction layer for the port/gpio expander
+ """
+ pins = (
+ 'PWR-GOOD-3.6V', #3.6V
+ 'PWR-EN-3.6V', #3.6V
+ 'PWR-GOOD-1.5V', #1.5V
+ 'PWR-EN-1.5V', #1.5V
+ 'PWR-GOOD-5.5V', #5.5V
+ 'PWR-EN-5.5V', #5.5V
+ '6',
+ 'LED',
+ )
+
+ def __init__(self, i2c_dev):
+ if i2c_dev is None:
+ raise RuntimeError("Need to specify i2c device to use the TCA6408")
+ self._gpios = SysFSGPIO('tca6408', 0xBF, 0xAA, 0xAA, i2c_dev)
+
+ def set(self, name, value=None):
+ """
+ Assert a pin by name
+ """
+ assert name in self.pins
+ self._gpios.set(self.pins.index(name), value=value)
+
+ def reset(self, name):
+ """
+ Deassert a pin by name
+ """
+ self.set(name, value=0)
+
+ def get(self, name):
+ """
+ Read back a pin by name
+ """
+ assert name in self.pins
+ return self._gpios.get(self.pins.index(name))
+
+class DboardClockControl(object):
+ """
+ Control the FPGA MMCM for Radio Clock control.
+ """
+ # Clocking Register address constants
+ RADIO_CLK_MMCM = 0x0020
+ PHASE_SHIFT_CONTROL = 0x0024
+ RADIO_CLK_ENABLES = 0x0028
+ MGT_REF_CLK_STATUS = 0x0030
+
+ def __init__(self, regs, log):
+ self.log = log
+ self.regs = regs
+ self.poke32 = self.regs.poke32
+ self.peek32 = self.regs.peek32
+
+ def enable_outputs(self, enable=True):
+ """
+ Enables or disables the MMCM outputs.
+ """
+ if enable:
+ self.poke32(self.RADIO_CLK_ENABLES, 0x011)
+ else:
+ self.poke32(self.RADIO_CLK_ENABLES, 0x000)
+
+ def reset_mmcm(self):
+ """
+ Uninitialize and reset the MMCM
+ """
+ self.log.trace("Disabling all Radio Clocks, then resetting MMCM...")
+ self.enable_outputs(False)
+ self.poke32(self.RADIO_CLK_MMCM, 0x1)
+
+ def enable_mmcm(self):
+ """
+ Unreset MMCM and poll lock indicators
+
+ If MMCM is not locked after unreset, an exception is thrown.
+ """
+ self.log.trace("Enabling FPGA Radio Clock MMCM...")
+ self.poke32(self.RADIO_CLK_MMCM, 0x2)
+ if not poll_with_timeout(
+ lambda: bool(self.peek32(self.RADIO_CLK_MMCM) & 0x10),
+ 500,
+ 10,
+ ):
+ self.log.error("FPGA Radio Clock MMCM not locked!")
+ raise RuntimeError("FPGA Radio Clock MMCM not locked!")
+ self.log.trace("Radio Clock MMCM locked. Enabling clocks to design...")
+ self.enable_outputs(True)
+
+ def check_refclk(self):
+ """
+ Not technically a clocking reg, but related.
+ """
+ return bool(self.peek32(self.MGT_REF_CLK_STATUS) & 0x1)
+
+class MgCPLD(object):
+ """
+ Control class for the CPLD
+ """
+ CPLD_SIGNATURE = 0xCAFE # Expected signature ("magic number")
+ CPLD_MINOR_REV = 0
+ CPLD_MAJOR_REV = 5
+
+ REG_SIGNATURE = 0x0000
+ REG_MINOR_REVISION = 0x0001
+ REG_MAJOR_REVISION = 0x0002
+ REG_BUILD_CODE_LSB = 0x0003
+ REG_BUILD_CODE_MSB = 0x0004
+ REG_SCRATCH = 0x0005
+ REG_CPLD_CTRL = 0x0010
+ REG_LMK_CTRL = 0x0011
+ REG_LO_STATUS = 0x0012
+ REG_MYK_CTRL = 0x0013
+
+ def __init__(self, regs, log):
+ self.log = log.getChild("CPLD")
+ self.log.debug("Initializing CPLD...")
+ self.regs = regs
+ self.poke16 = self.regs.poke16
+ self.peek16 = self.regs.peek16
+ signature = self.peek16(self.REG_SIGNATURE)
+ if signature != self.CPLD_SIGNATURE:
+ self.log.error(
+ "CPLD Signature Mismatch! " \
+ "Expected: 0x{:04X} Got: 0x{:04X}".format(
+ self.CPLD_SIGNATURE, signature))
+ raise RuntimeError("CPLD Signature Check Failed! "
+ "Incorrect signature readback.")
+ self.minor_rev = self.peek16(self.REG_MINOR_REVISION)
+ self.major_rev = self.peek16(self.REG_MAJOR_REVISION)
+ if self.major_rev != self.CPLD_MAJOR_REV:
+ self.log.error(
+ "CPLD Major Revision check mismatch! Expected: %d Got: %d",
+ self.CPLD_MAJOR_REV,
+ self.major_rev
+ )
+ raise RuntimeError("CPLD Revision Check Failed! MPM is not "
+ "compatible with the loaded CPLD image.")
+ date_code = self.peek16(self.REG_BUILD_CODE_LSB) | \
+ (self.peek16(self.REG_BUILD_CODE_MSB) << 16)
+ self.log.debug(
+ "CPLD Signature: 0x{:04X} "
+ "Revision: {}.{} "
+ "Date code: 0x{:08X}"
+ .format(signature, self.major_rev, self.minor_rev, date_code))
+
+ def set_scratch(self, val):
+ " Write to the scratch register "
+ self.poke16(self.REG_SCRATCH, val & 0xFFFF)
+
+ def get_scratch(self):
+ " Read from the scratch register "
+ return self.peek16(self.REG_SCRATCH)
+
+ def reset(self):
+ " Reset entire CPLD "
+ self.log.trace("Resetting CPLD...")
+ self.poke16(self.REG_CPLD_CTRL, 0x1)
+ self.poke16(self.REG_CPLD_CTRL, 0x0)
+
+ def set_pdac_control(self, enb):
+ """
+ If enb is True, the Phase DAC will exclusively control the VCXO voltage
+ """
+ self.log.trace("Giving Phase %s control over VCXO voltage...",
+ "exclusive" if bool(enb) else "non-exclusive")
+ reg_val = (1<<4) if enb else 0
+ self.poke16(self.REG_LMK_CTRL, reg_val)
+
+ def get_lo_lock_status(self, which):
+ """
+ Returns True if the 'which' LO is locked. 'which' is either 'tx' or
+ 'rx'.
+ """
+ mask = (1<<4) if which.lower() == 'tx' else 1
+ return bool(self.peek16(self.REG_LO_STATUS & mask))
+
+ def reset_mykonos(self):
+ """
+ Hard-resets Mykonos
+ """
+ self.log.debug("Resetting AD9371!")
+ self.poke16(self.REG_MYK_CTRL, 0x1)
+ time.sleep(0.001) # No spec here, but give it some time to reset.
+ self.poke16(self.REG_MYK_CTRL, 0x0)
+ time.sleep(0.001) # No spec here, but give it some time to reset.
+