diff options
Diffstat (limited to 'mpm/python')
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/rh_periphs.py | 74 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/rhodium.py | 73 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py | 2 |
3 files changed, 145 insertions, 4 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/rh_periphs.py b/mpm/python/usrp_mpm/dboard_manager/rh_periphs.py index e9b171c5e..2d631e509 100644 --- a/mpm/python/usrp_mpm/dboard_manager/rh_periphs.py +++ b/mpm/python/usrp_mpm/dboard_manager/rh_periphs.py @@ -26,8 +26,7 @@ class TCA6408(object): ) def __init__(self, i2c_dev): - if i2c_dev is None: - raise RuntimeError("Need to specify i2c device to use the TCA6408") + assert i2c_dev is not None self._gpios = SysFSGPIO({'label': 'tca6408'}, 0x3F, 0x00, 0x00, i2c_dev) def set(self, name, value=None): @@ -50,6 +49,77 @@ class TCA6408(object): assert name in self.pins return self._gpios.get(self.pins.index(name)) +class FPGAtoLoDist(object): + """ + Abstraction layer for the port/gpio expander on the LO Distribution board + """ + EXPECTED_BOARD_REV = 0 + POWER_ON_TIMEOUT = 20 #ms + POWER_ON_POLL_INTERVAL = 1 #ms + + pins = ( + 'BD_REV_0', #Board revision bit 0 + 'BD_REV_1', #Board revision bit 1 + 'BD_REV_2', #Board revision bit 2 + 'P6_8V_PG', #6.8V Power good + '4', #No connect + '5', #No connect + '6', #No connect + '7', #No connect + 'RX_OUT0_CTRL', #RX Out0 Port Termination Switch + 'RX_OUT1_CTRL', #RX Out1 Port Termination Switch + 'RX_OUT2_CTRL', #RX Out2 Port Termination Switch + 'RX_OUT3_CTRL', #RX Out3 Port Termination Switch + 'RX_INSWITCH_CTRL', #RX 1:4 splitter input select + 'TX_OUT0_CTRL', #TX Out0 Port Termination Switch + 'TX_OUT1_CTRL', #TX Out1 Port Termination Switch + 'TX_OUT2_CTRL', #TX Out2 Port Termination Switch + 'TX_OUT3_CTRL', #TX Out3 Port Termination Switch + 'TX_INSWITCH_CTRL', #TX 1:4 splitter input select + 'P6_8V_EN', #6.8V supply enable + 'P6_5V_LDO_EN', #6.5V LDO enable + 'P3_3V_RF_EN' #3.3V LDO for RF enable + ) + + def __init__(self, i2c_dev): + assert i2c_dev is not None + self._gpios = SysFSGPIO({'label': 'tca6424', 'device/of_node/name': 'rhodium-lodist-gpio'}, 0x1FFF0F, 0x1FFF00, 0x00A500, i2c_dev) + board_rev = self._gpios.get(self.pins.index('BD_REV_0')) + \ + self._gpios.get(self.pins.index('BD_REV_1')) << 1 + \ + self._gpios.get(self.pins.index('BD_REV_2')) << 2 + if board_rev != self.EXPECTED_BOARD_REV: + raise RuntimeError('LO distribution board revision did not match: Expected: {0} Actual: {1}'.format(self.EXPECTED_BOARD_REV, board_rev)) + self._gpios.set(self.pins.index('P6_8V_EN'), 1) + if not poll_with_timeout( + lambda: bool(self._gpios.get(self.pins.index('P6_8V_PG'))), + self.POWER_ON_TIMEOUT, + self.POWER_ON_POLL_INTERVAL): + self._gpios.set(self.pins.index('P6_8V_EN'), 0) + raise RuntimeError('Power on failure for LO Distribution board') + self._gpios.set(self.pins.index('P6_5V_LDO_EN'), 1) + self._gpios.set(self.pins.index('P3_3V_RF_EN'), 1) + + 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 + """ + assert name in self.pins + 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 FPGAtoDbGPIO(GPIOBank): """ diff --git a/mpm/python/usrp_mpm/dboard_manager/rhodium.py b/mpm/python/usrp_mpm/dboard_manager/rhodium.py index 81ca221a7..81c67ffa3 100644 --- a/mpm/python/usrp_mpm/dboard_manager/rhodium.py +++ b/mpm/python/usrp_mpm/dboard_manager/rhodium.py @@ -13,7 +13,7 @@ import threading 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.rh_periphs import TCA6408, FPGAtoDbGPIO +from usrp_mpm.dboard_manager.rh_periphs import TCA6408, FPGAtoDbGPIO, FPGAtoLoDist from usrp_mpm.dboard_manager.rh_init import RhodiumInitManager from usrp_mpm.dboard_manager.rh_periphs import RhCPLD from usrp_mpm.dboard_manager.rh_periphs import DboardClockControl @@ -24,6 +24,7 @@ from usrp_mpm.mpmlog import get_logger from usrp_mpm.sys_utils.uio import UIO from usrp_mpm.sys_utils.udev import get_eeprom_paths from usrp_mpm.bfrfs import BufferFS +from usrp_mpm.sys_utils.dtoverlay import apply_overlay_safe, rm_overlay_safe ############################################################################### @@ -174,6 +175,25 @@ class Rhodium(DboardManagerBase): default_time_source = 'internal' default_current_jesd_rate = 4915.2e6 + # Provide a mapping of direction and pin number to + # pin name and active state (0 = active-low) for + # LO out ports + lo_out_pin_map = { + 'RX' : [('RX_OUT0_CTRL', 0), + ('RX_OUT1_CTRL', 1), + ('RX_OUT2_CTRL', 0), + ('RX_OUT3_CTRL', 1)], + 'TX' : [('TX_OUT0_CTRL', 0), + ('TX_OUT1_CTRL', 1), + ('TX_OUT2_CTRL', 0), + ('TX_OUT3_CTRL', 1)]} + + # Provide mapping of direction to pin name for LO + # in port + lo_in_pin_map = { + 'RX' : 'RX_INSWITCH_CTRL', + 'TX' : 'TX_INSWITCH_CTRL'} + def __init__(self, slot_idx, **kwargs): super(Rhodium, self).__init__(slot_idx, **kwargs) self.log = get_logger("Rhodium-{}".format(slot_idx)) @@ -191,6 +211,7 @@ class Rhodium(DboardManagerBase): # Predeclare some attributes to make linter happy: self.lmk = None self._port_expander = None + self._lo_dist = None self.cpld = None # If _init_args is None, it means that init() hasn't yet been called. self._init_args = None @@ -235,6 +256,14 @@ class Rhodium(DboardManagerBase): ) self._port_expander = TCA6408(_get_i2c_dev()) self._daughterboard_gpio = FPGAtoDbGPIO(self.slot_idx) + # TODO: applying the overlay without checking for the presence of the + # LO dist board will create a kernel error. Fix this when the I2C API + # is implemented by checking if the board is present before applying. + try: + apply_overlay_safe('n321') + self._lo_dist = FPGAtoLoDist(_get_i2c_dev()) + except RuntimeError: + self._lo_dist = None self.log.debug("Turning on Module and RF power supplies") self._power_on() self._spi_ifaces = _init_spi_devices() @@ -411,6 +440,48 @@ class Rhodium(DboardManagerBase): # This does not stop anyone from killing this process (and the thread) # while the EEPROM write is happening, though. + def enable_lo_export(self, direction, enable): + """ + For N321 devices. If enable is true, connect the RX 1:4 splitter to the + daughterboard LO export. If enable is false, connect the splitter to + LO input port 1 instead. + + Asserts if there is no LO distribution board attached (e.g. device is + not an N321, or this is the daughterboard in slot B) + """ + + assert self._lo_dist is not None + assert direction in ('RX', 'TX') + pin = self.lo_in_pin_map[direction] + pin_val = 0 if enable else 1 + self.log.debug("LO Distribution: 1:4 splitter connected to {0} {1}".format( + direction, {True: "DB export", False: "Input 0"}[enable])) + self.log.trace("Net name: {0}, Pin value: {1}".format(pin, pin_val)) + self._lo_dist.set(pin, pin_val) + + def enable_lo_output(self, direction, port_number, enable): + """ + For N321 devices. If enable is true, connect the RX 1:4 splitter to the + daughterboard LO export. If enable is false, connect the splitter to + LO input port 1 instead. + + Asserts if there is no LO distribution board attached (e.g. device is + not an N321, or this is the daughterboard in slot B) + """ + + assert self._lo_dist is not None + assert direction in ('RX', 'TX') + assert port_number in (0, 1, 2, 3) + pin_info = self.lo_out_pin_map[direction][port_number] + # enable XNOR active_high = desired pinout value + pin_val = 1 if not (enable ^ pin_info[1]) else 0 + self.log.debug("LO Distribution: {0} Out{1} is {2}".format( + direction, port_number, {True: "active", False: "terminated"}[enable])) + self.log.trace("Net name: {0}, Pin value: {1}".format(pin_info[0], pin_val)) + self._lo_dist.set(pin_info[0], pin_val) + + def is_lo_dist_present(self): + return self._lo_dist is not None ########################################################################## # Clocking control APIs diff --git a/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py b/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py index 775431050..5622285f6 100644 --- a/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py +++ b/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py @@ -99,7 +99,7 @@ class TCA6424(object): self.pins = self.pins_list[1] default_val = 0x860101 if rev == 2 else 0x860780 - self._gpios = SysFSGPIO({'label': 'tca6424'}, 0xFFF7FF, 0x86F7FF, default_val) + self._gpios = SysFSGPIO({'label': 'tca6424', 'device/of_node/name': 'gpio'}, 0xFFF7FF, 0x86F7FF, default_val) def set(self, name, value=None): """ |