diff options
Diffstat (limited to 'mpm/python')
-rwxr-xr-x | mpm/python/n3xx_bist | 13 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/bist.py | 4 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/base.py | 38 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/n3xx.py | 98 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py | 4 |
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 |