aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python
diff options
context:
space:
mode:
Diffstat (limited to 'mpm/python')
-rwxr-xr-xmpm/python/n3xx_bist13
-rw-r--r--mpm/python/usrp_mpm/bist.py4
-rw-r--r--mpm/python/usrp_mpm/periph_manager/base.py38
-rw-r--r--mpm/python/usrp_mpm/periph_manager/n3xx.py98
-rw-r--r--mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py4
5 files changed, 120 insertions, 37 deletions
diff --git a/mpm/python/n3xx_bist b/mpm/python/n3xx_bist
index a8bda66f5..1202fe121 100755
--- a/mpm/python/n3xx_bist
+++ b/mpm/python/n3xx_bist
@@ -472,8 +472,8 @@ class N3XXBIST(bist.UsrpBIST):
- read_patterns: A list of patterns that were read back
"""
assert 'gpio' in self.tests_to_run
- # patterns = list(range(64))
- GPIO_WIDTH = 12
+ # Our FP-GPIO has 12 programmable pins
+ gpio_width = 12
patterns = range(64)
if self.args.dry_run:
return True, {
@@ -484,16 +484,17 @@ class N3XXBIST(bist.UsrpBIST):
gpio_tca6424 = n3xx_periphs.TCA6424(self.mb_rev)
gpio_tca6424.set("FPGA-GPIO-EN")
mb_regs = n3xx_periphs.MboardRegsControl(n3xx.n3xx.mboard_regs_label, self.log)
+ # We set all 12 pins to be driven by the PS
mb_regs.set_fp_gpio_master(0xFFF)
# Allow some time for the front-panel GPIOs to become usable
time.sleep(.5)
- ddr1 = 0x03f
- ddr2 = 0xfc0
+ ddr1 = 0x03f # Lower 6 pins are outputs
+ ddr2 = 0xfc0 # Upper 6 pins are inputs
def _run_gpio(ddr, patterns):
" Run a GPIO test for a given set of patterns "
gpio_ctrl = n3xx_periphs.FrontpanelGPIO(ddr)
for pattern in patterns:
- bist.gpio_set_all(gpio_ctrl, pattern, GPIO_WIDTH, ddr)
+ bist.gpio_set_all(gpio_ctrl, pattern, gpio_width, ddr)
time.sleep(0.1)
gpio_rb = gpio_ctrl.get_all()
if pattern != gpio_rb:
@@ -502,7 +503,7 @@ class N3XXBIST(bist.UsrpBIST):
return True, {'write_patterns': list(patterns),
'read_patterns': list(patterns)}
status, data = _run_gpio(ddr1, patterns)
- if not status:
+ if not status:
return status, data
status, data = _run_gpio(ddr2, patterns)
return status, data
diff --git a/mpm/python/usrp_mpm/bist.py b/mpm/python/usrp_mpm/bist.py
index e26d6d36c..b20020e1f 100644
--- a/mpm/python/usrp_mpm/bist.py
+++ b/mpm/python/usrp_mpm/bist.py
@@ -246,7 +246,9 @@ def get_tpm_caps_info():
return result
def gpio_set_all(gpio_bank, value, gpio_size, ddr_mask):
- """Helper function for set gpio.
+ """
+ Helper function to set GPIOs
+
What this function do is take decimal value and convert to a binary string
then try to set those individual bits to the gpio_bank.
Arguments:
diff --git a/mpm/python/usrp_mpm/periph_manager/base.py b/mpm/python/usrp_mpm/periph_manager/base.py
index 6d363fd89..8f75a97c6 100644
--- a/mpm/python/usrp_mpm/periph_manager/base.py
+++ b/mpm/python/usrp_mpm/periph_manager/base.py
@@ -925,3 +925,41 @@ class PeriphManagerBase(object):
Gets the RFNoC-related clocks present in the FPGA design
"""
raise NotImplementedError("get_clocks() not implemented.")
+
+ #######################################################################
+ # GPIO API
+ #######################################################################
+ def get_gpio_banks(self):
+ """
+ Returns a list of GPIO banks over which MPM has any control
+ """
+ self.log.debug("get_gpio_banks(): No banks defined on this device.")
+ return []
+
+ def get_gpio_srcs(self, bank):
+ """
+ Return a list of valid GPIO sources for a given bank
+ """
+ assert bank in self.get_gpio_banks(), \
+ "Invalid GPIO bank: {}".format(bank)
+ return []
+
+ def get_gpio_src(self, bank):
+ """
+ Return the currently selected GPIO source for a given bank. The return
+ value is a list of strings. The length of the vector is identical to
+ the number of controllable GPIO pins on this bank.
+ """
+ assert bank in self.get_gpio_banks(), \
+ "Invalid GPIO bank: {}".format(bank)
+ raise NotImplementedError("get_gpio_src() not available on this device!")
+
+ def set_gpio_src(self, bank, src):
+ """
+ Set the GPIO source for a given bank.
+ """
+ assert bank in self.get_gpio_banks(), \
+ "Invalid GPIO bank: {}".format(bank)
+ assert src in self.get_gpio_srcs(bank), \
+ "Invalid GPIO source: {}".format(src)
+ raise NotImplementedError("set_gpio_src() not available on this device!")
diff --git a/mpm/python/usrp_mpm/periph_manager/n3xx.py b/mpm/python/usrp_mpm/periph_manager/n3xx.py
index fc9a91e7d..d7b50a5f9 100644
--- a/mpm/python/usrp_mpm/periph_manager/n3xx.py
+++ b/mpm/python/usrp_mpm/periph_manager/n3xx.py
@@ -44,6 +44,9 @@ N32X_QSFP_I2C_LABEL = 'qsfp-i2c'
N3XX_FPGA_COMPAT = (7, 0)
N3XX_MONITOR_THREAD_INTERVAL = 1.0 # seconds
N3XX_BUS_CLK = 200e6
+N3XX_GPIO_BANKS = "FP0"
+N3XX_GPIO_SRC_PS = "PS"
+N3XX_FPGPIO_WIDTH = 12
# Import daughterboard PIDs from their respective classes
MG_PID = Magnesium.pids[0]
@@ -362,6 +365,17 @@ class n3xx(ZynqComponents, PeriphManagerBase):
"(e.g., HG, XG images).")
# Init FPGA type
self._update_fpga_type()
+ # Init FP-GPIO sources
+ self._fp_gpio_srcs = [N3XX_GPIO_SRC_PS,]
+ if self.device_info['product'] == 'n320':
+ for chan_idx in range(len(self.dboards)):
+ self._fp_gpio_srcs.append("RF{}".format(chan_idx))
+ else:
+ for chan_idx in range(len(self.dboards)):
+ self._fp_gpio_srcs.append("RF{}".format(2*chan_idx))
+ self._fp_gpio_srcs.append("RF{}".format(2*chan_idx+1))
+ self.log.debug("Found the following GPIO sources: {}"
+ .format(",".join(self._fp_gpio_srcs)))
# Init CHDR transports
self._xport_mgrs = {
'udp': N3xxXportMgrUDP(self.log.getChild('UDP'), args),
@@ -727,41 +741,67 @@ class n3xx(ZynqComponents, PeriphManagerBase):
'gpsdo': 20e6,
}[self._clock_source]
- def set_fp_gpio_master(self, value):
- """set driver for front panel GPIO
- Arguments:
- value {unsigned} -- value is a single bit bit mask of 12 pins GPIO
+ ###########################################################################
+ # GPIO API
+ ###########################################################################
+ def get_gpio_banks(self):
+ """
+ Returns a list of GPIO banks over which MPM has any control
"""
- self.mboard_regs_control.set_fp_gpio_master(value)
+ return N3XX_GPIO_BANKS
- def get_fp_gpio_master(self):
- """get "who" is driving front panel gpio
- The return value is a bit mask of 12 pins GPIO.
- 0: means the pin is driven by PL
- 1: means the pin is driven by PS
+ def get_gpio_srcs(self, bank):
+ """
+ Return a list of valid GPIO sources for a given bank
"""
- return self.mboard_regs_control.get_fp_gpio_master()
+ assert bank in self.get_gpio_banks(), "Invalid GPIO bank: {}".format(bank)
+ return self._fp_gpio_srcs
- def set_fp_gpio_radio_src(self, value):
- """set driver for front panel GPIO
- Arguments:
- value {unsigned} -- value is 2-bit bit mask of 12 pins GPIO
- 00: means the pin is driven by radio 0
- 01: means the pin is driven by radio 1
- 10: means the pin is driven by radio 2
- 11: means the pin is driven by radio 3
+ def get_gpio_src(self, bank):
+ """
+ Return the currently selected GPIO source for a given bank. The return
+ value is a list of strings. The length of the vector is identical to
+ the number of controllable GPIO pins on this bank.
+ """
+ assert bank in self.get_gpio_banks(), "Invalid GPIO bank: {}".format(bank)
+ gpio_master_reg = self.mboard_regs_control.get_fp_gpio_master()
+ gpio_radio_src_reg = self.mboard_regs_control.get_fp_gpio_radio_src()
+ def get_gpio_src_i(gpio_pin_index):
+ """
+ Return the current radio source given a pin index.
+ """
+ if gpio_master_reg & (1 << gpio_pin_index):
+ return N3XX_GPIO_SRC_PS
+ radio_src = (gpio_radio_src_reg >> (2 * gpio_pin_index)) & 0b11
+ return "RF{}".format(radio_src)
+ return [get_gpio_src_i(i) for i in range(N3XX_FPGPIO_WIDTH)]
+
+ def set_gpio_src(self, bank, src):
+ """
+ Set the GPIO source for a given bank.
"""
- self.mboard_regs_control.set_fp_gpio_radio_src(value)
+ assert bank in self.get_gpio_banks(), "Invalid GPIO bank: {}".format(bank)
+ assert len(src) == N3XX_FPGPIO_WIDTH, \
+ "Invalid number of GPIO sources!"
+ gpio_master_reg = 0x000
+ gpio_radio_src_reg = self.mboard_regs_control.get_fp_gpio_radio_src()
+ for src_index, src_name in enumerate(src):
+ if src_name not in self.get_gpio_srcs(bank):
+ raise RuntimeError(
+ "Invalid GPIO source name `{}' at bit position {}!"
+ .format(src_name, src_index))
+ gpio_master_flag = (src_name == N3XX_GPIO_SRC_PS)
+ gpio_master_reg = gpio_master_reg | (gpio_master_flag << src_index)
+ if gpio_master_flag:
+ continue
+ # If PS is not the master, we also need to update the radio source:
+ radio_index = int(src_name[2:]) & 0b11
+ gpio_radio_src_reg = gpio_radio_src_reg | (radio_index << (2*src_index))
+ self.log.trace("Updating GPIO source: master==0x{:03X} radio_src={:06X}"
+ .format(gpio_master_reg, gpio_radio_src_reg))
+ self.mboard_regs_control.set_fp_gpio_master(gpio_master_reg)
+ self.mboard_regs_control.set_fp_gpio_radio_src(gpio_radio_src_reg)
- def get_fp_gpio_radio_src(self):
- """get which radio is driving front panel gpio
- The return value is 2-bit bit mask of 12 pins GPIO.
- 00: means the pin is driven by radio 0
- 01: means the pin is driven by radio 1
- 10: means the pin is driven by radio 2
- 11: means the pin is driven by radio 3
- """
- return self.mboard_regs_control.get_fp_gpio_radio_src()
###########################################################################
# Hardware periphal controls
###########################################################################
diff --git a/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py b/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py
index ef2372e62..bcff03c8e 100644
--- a/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py
+++ b/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py
@@ -195,6 +195,8 @@ class MboardRegsControl(MboardRegsCommon):
"""set driver for front panel GPIO
Arguments:
value {unsigned} -- value is a single bit bit mask of 12 pins GPIO
+ 0: means the pin is driven by PL
+ 1: means the pin is driven by PS
"""
with self.regs:
return self.poke32(self.MB_GPIO_MASTER, value)
@@ -211,7 +213,7 @@ class MboardRegsControl(MboardRegsCommon):
def set_fp_gpio_radio_src(self, value):
"""set driver for front panel GPIO
Arguments:
- value {unsigned} -- value is 2-bit bit mask of 12 pins GPIO
+ value {unsigned} -- value is 2x12 bits, two bits per GPIO pin
00: means the pin is driven by radio 0
01: means the pin is driven by radio 1
10: means the pin is driven by radio 2