aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm
diff options
context:
space:
mode:
authorVirendra Kakade <virendra.kakade@ni.com>2022-04-21 01:59:33 -0500
committerskooNI <60897865+skooNI@users.noreply.github.com>2022-07-20 15:57:20 -0500
commit54d07516edf95959445109ee5c11b02a53da3669 (patch)
tree47884cf284c695cb33d65f35423f0b22b0ec70ae /mpm/python/usrp_mpm
parent12bcc1dc47a74c78617e9b3cf72345e614cfeb4d (diff)
downloaduhd-54d07516edf95959445109ee5c11b02a53da3669.tar.gz
uhd-54d07516edf95959445109ee5c11b02a53da3669.tar.bz2
uhd-54d07516edf95959445109ee5c11b02a53da3669.zip
mpm: add support for lattice zbx cpld
Co-authored-by: Steven Koo <steven.koo@ni.com> Signed-off-by: Virendra Kakade <virendra.kakade@ni.com>
Diffstat (limited to 'mpm/python/usrp_mpm')
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/zbx_update_cpld.py289
1 files changed, 219 insertions, 70 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/zbx_update_cpld.py b/mpm/python/usrp_mpm/dboard_manager/zbx_update_cpld.py
index 851cfe997..12cd6c0ed 100644
--- a/mpm/python/usrp_mpm/dboard_manager/zbx_update_cpld.py
+++ b/mpm/python/usrp_mpm/dboard_manager/zbx_update_cpld.py
@@ -13,7 +13,9 @@ import os
import argparse
import subprocess
import pyudev
+import re
from usrp_mpm.mpmlog import get_logger
+from usrp_mpm.mpmlog import get_main_logger
from usrp_mpm.mpmutils import check_fpga_state
from usrp_mpm.sys_utils.sysfs_gpio import GPIOBank
from usrp_mpm.periph_manager.x4xx_periphs import CtrlportRegs
@@ -22,13 +24,6 @@ from usrp_mpm.chips.max10_cpld_flash_ctrl import Max10CpldFlashCtrl
from usrp_mpm.sys_utils.udev import dt_symbol_get_spidev
OPENOCD_DIR = "/usr/share/openocd/scripts"
-CONFIGS = {
- 'axi_bitq' : {
- 'files' : ["fpga/altera-10m50.cfg"],
- 'cmd' : ["interface axi_bitq; axi_bitq_config %u %u %u; adapter_khz %u",
- "init; svf -tap 10m50.tap %s -progress -quiet;exit"]
- }
-}
AXI_BITQ_ADAPTER_SPEED = 5000
AXI_BITQ_BUS_CLK = 50000000
@@ -82,64 +77,131 @@ def find_axi_bitq_uio():
logger.error("Error while looking for axi_bitq uio nodes: {}".format(ex))
return None
-def do_update_cpld(filename, daughterboards, updater_mode):
+def do_update_cpld(dboard_update_settings):
"""
Carry out update process for the CPLD
- :param filename: path (on device) to the new CPLD image
- :param daughterboards: iterable containing dboard numbers to update
- :param updater_mode: the updater method to use- Either flash or legacy (JTAG)
+ :param dboard_update_settings: list of db and corresponding path (on device) to the new CPLD image
+ and updater mode to use
:return: True on success, False otherwise
"""
- assert updater_mode in ('flash', 'legacy'), \
- f"Invalid updater method {updater_mode} given"
+
logger = get_logger('update_cpld')
- logger.info("Programming CPLD of dboards {} with image {} using {} mode"
- .format(daughterboards, filename, updater_mode))
- if not daughterboards:
+ if not dboard_update_settings:
logger.error("Invalid daughterboard selection.")
return False
- if not os.path.exists(filename):
- logger.error("CPLD image file {} not found".format(filename))
- return False
-
if not check_fpga_state(logger=logger):
logger.error("CPLD lines are routed through fabric, FPGA is not programmed, giving up")
return False
- if updater_mode == 'legacy':
- return jtag_cpld_update(filename, daughterboards, logger)
- # updater_mode == flash:
- for dboard in daughterboards:
- dboard = int(dboard, 10)
- logger.info("Updating daughterboard slot {}...".format(dboard))
- # enable required daughterboard clock
- cpld_spi_node = dt_symbol_get_spidev('mb_cpld')
- cpld_control = MboardCPLD(cpld_spi_node, logger)
- cpld_control.enable_daughterboard_support_clock(dboard, enable=True)
- # setup flash configuration engine and required register access
- label = "ctrlport-mboard-regs"
- ctrlport_regs = CtrlportRegs(label, logger)
- regs = ctrlport_regs.get_db_cpld_iface(dboard)
- flash_control = Max10CpldFlashCtrl(
- logger, regs, RECONFIG_ENGINE_OFFSET, CPLD_MIN_REVISION)
- success = flash_control.update(filename)
- # disable clock
- cpld_control.enable_daughterboard_support_clock(dboard, enable=False)
+ for dboard_update_setting in dboard_update_settings:
+ dboard = dboard_update_setting[0]
+ filename = dboard_update_setting[1]
+ updater_mode = dboard_update_setting[2]
+ cpld_update_strategies = dboard_update_setting[3]
+
+ logger.info("Programming CPLD of dboard {} with image {} using {} mode"
+ .format(dboard, filename, updater_mode))
+
+ if not os.path.exists(filename):
+ logger.error("CPLD image file {} not found".format(filename))
+ return False
+
+ if updater_mode == 'legacy':
+ success = jtag_cpld_update(filename, dboard, cpld_update_strategies, logger)
+ elif updater_mode == 'flash':
+ success = flash_cpld_update(filename, dboard, cpld_update_strategies, logger)
+ else:
+ raise NotImplementedError("Unknown updater mode {}".format(updater_mode))
+
if not success:
return success
+
return True
-def jtag_cpld_update(filename, daughterboards, logger=None):
+def get_db_rev(slot):
+ assert slot in [0,1]
+ cmd = ['eeprom-dump', 'db{}'.format(slot)]
+ output = subprocess.check_output(
+ cmd,
+ stderr=subprocess.STDOUT,
+ ).decode('utf-8')
+ expression = re.compile("^usrp_eeprom_board_info.*rev: 0x([0-9A-Fa-f]+).*compat_rev:.*")
+ for line in output.splitlines():
+ match = expression.match(line)
+ if match:
+ rev = int(match.group(1), 16)
+ return rev
+ raise AssertionError("Cannot get rev from DB{} eeprom.: `{}'".format(slot, output))
+
+def get_cpld_update_strategies(rev):
+ """Determine the CPLD update strategies based on the rev"""
+
+ cpld_image_10m04_update_strategies = {'cpld_model': '10m04',
+ 'updaters': ['flash', 'legacy'],
+ 'default_updater': 'flash',
+ 'image_names': {'flash': ['cpld-zbx-10m04.rpd', 'usrp_zbx_cpld_10m04.rpd'],
+ 'legacy': ['cpld-zbx-10m04.svf', 'usrp_zbx_cpld_10m04.svf']},
+ 'updater_config': {'legacy': {'files' : ["fpga/altera-10m50.cfg"],
+ 'cmd' : ["interface axi_bitq; axi_bitq_config %u %u %u; adapter_khz %u",
+ "init; svf -tap 10m50.tap %s -progress -quiet;exit"]}}}
+
+ cpld_image_xo3lf_update_strategies = {'cpld_model': 'xo3lf',
+ 'updaters': ['legacy'],
+ 'default_updater': 'legacy',
+ 'image_names': {'legacy': ['cpld-zbx-xo3lf.svf', 'usrp_zbx_cpld_xo3lf.svf']},
+ 'updater_config': {'legacy': {'files' : ["fpga/lattice-xo3lf.cfg"],
+ 'cmd' : ["interface axi_bitq; axi_bitq_config %u %u %u; adapter_khz %u",
+ "init; svf -tap xo3lf.tap %s -progress -quiet;exit"]}}}
+ cpld_update_strategies = {
+ 1: cpld_image_10m04_update_strategies, # revA
+ 2: cpld_image_10m04_update_strategies, # revB
+ 3: cpld_image_10m04_update_strategies, # revC
+ 4: cpld_image_xo3lf_update_strategies, # revD
+ '10m04': cpld_image_10m04_update_strategies, # 10m04
+ 'xo3lf': cpld_image_xo3lf_update_strategies # xo3lf
+ }
+
+ if rev not in cpld_update_strategies:
+ raise NotImplementedError("The CPLD update strategy for rev or CPLD model {} is not available".format(rev))
+ return cpld_update_strategies[rev]
+
+def flash_cpld_update(filename, dboard, cpld_update_strategies=None, logger=None):
+ """
+ Carry out update process for the CPLD using flash mode
+ :param filename: path (on device) to the new CPLD image
+ :param dboard: dboard to update
+ :return: True on success, False otherwise
+ """
+ dboard = int(dboard, 10)
+ logger.info("Updating daughterboard slot {}...".format(dboard))
+ # enable required daughterboard clock
+ cpld_spi_node = dt_symbol_get_spidev('mb_cpld')
+ cpld_control = MboardCPLD(cpld_spi_node, logger)
+ cpld_control.enable_daughterboard_support_clock(dboard, enable=True)
+ # setup flash configuration engine and required register access
+ label = "ctrlport-mboard-regs"
+ ctrlport_regs = CtrlportRegs(label, logger)
+ regs = ctrlport_regs.get_db_cpld_iface(dboard)
+ flash_control = Max10CpldFlashCtrl(
+ logger, regs, RECONFIG_ENGINE_OFFSET, CPLD_MIN_REVISION)
+ success = flash_control.update(filename)
+ # disable clock
+ cpld_control.enable_daughterboard_support_clock(dboard, enable=False)
+ if success:
+ logger.trace("Done programming CPLD...")
+ return success
+
+def jtag_cpld_update(filename, dboard, cpld_update_strategies, logger=None):
"""
Carry out update process for the CPLD
:param filename: path (on device) to the new CPLD image
- :param daughterboards: iterable containing dboard numbers to update
+ :param dboard: dboard to update
+ :param cpld_update_strategies: a data struct containing updaters, image names, metadata.
:return: True on success, False otherwise
"""
- mode = 'axi_bitq'
- config = CONFIGS[mode]
+ config = cpld_update_strategies['updater_config']['legacy']
if check_openocd_files(config['files'], logger=logger):
logger.trace("Found required OpenOCD files.")
@@ -147,24 +209,23 @@ def jtag_cpld_update(filename, daughterboards, logger=None):
# check_openocd_files logs errors
return False
- for dboard in daughterboards:
- logger.info("Updating daughterboard slot {}...".format(dboard))
+ logger.info("Updating daughterboard slot {}...".format(dboard))
- uio_id = find_axi_bitq_uio()
- offset = find_offset(int(dboard, 10))
- if uio_id is None or uio_id < 0:
- logger.error('Failed to find axi_bitq uio devices. '\
- 'Make sure overlays are up to date')
- return False
+ uio_id = find_axi_bitq_uio()
+ offset = find_offset(int(dboard, 10))
+ if uio_id is None or uio_id < 0:
+ logger.error('Failed to find axi_bitq uio devices. '\
+ 'Make sure overlays are up to date')
+ return False
- cmd = [
- "openocd",
- "-c", config['cmd'][0] % (uio_id, AXI_BITQ_BUS_CLK, offset, AXI_BITQ_ADAPTER_SPEED),
- "-f", (config['files'][0]).strip(),
- "-c", config['cmd'][1] % filename]
+ cmd = [
+ "openocd",
+ "-c", config['cmd'][0] % (uio_id, AXI_BITQ_BUS_CLK, offset, AXI_BITQ_ADAPTER_SPEED),
+ "-f", (config['files'][0]).strip(),
+ "-c", config['cmd'][1] % filename]
- logger.trace("Update CPLD CMD: {}".format(" ".join(cmd)))
- subprocess.call(cmd)
+ logger.trace("Update CPLD CMD: {}".format(" ".join(cmd)))
+ subprocess.call(cmd)
logger.trace("Done programming CPLD...")
return True
@@ -177,13 +238,14 @@ def main():
def parse_args():
"""Parse the command-line arguments"""
parser = argparse.ArgumentParser(description='Update the CPLD image on ZBX daughterboard')
- parser.add_argument("--file", help="Filename of CPLD image",
- default="/lib/firmware/ni/cpld-zbx.rpd")
+ parser.add_argument("--file", help="Filename of CPLD image. Also specify the updater using"
+ " --updater arg when using this argument.",
+ default="")
parser.add_argument("--dboards", help="Slot name to program", default="0,1")
parser.add_argument("--updater",
help="The image updater method to use, either "
" 'legacy' (uses openocd) or 'flash'",
- default="flash")
+ default="")
parser.add_argument(
'-v',
'--verbose',
@@ -198,21 +260,108 @@ def main():
action="count",
default=0
)
- return parser.parse_args()
+ parser.add_argument("--force", help="Force installing the CPLD image specified by the --file " \
+ "argument if it does not match the name of the default CPLD image. " \
+ "Using the wrong CPLD image may brick your device.",
+ action="store_true", default=False, required=False)
+ parser.add_argument("--cpld_type",
+ help="Specify the CPLD type. Currently supported types are '10m04' or 'xo3lf'."
+ " Use this argument to explicitly specify the CPLD hardware type and"
+ " skip internal revision compatibilty checks. Use this only if you"
+ " fully understand the hardware being used."
+ " e.g. zbx_update_cpld --cpld_type '10m04' ",
+ default=None)
+
+ args = parser.parse_args()
+
+ dboards = args.dboards.split(",")
+ if any([x not in ('0', '1') for x in dboards]):
+ log.error("Unsupported dboards requested: %s", dboards)
+ return False
+
+ if (args.cpld_type):
+ # Hardware Specified. Skip all checks.
+ return args
+
+ if (args.file and not args.updater):
+ parser.epilog = "\nERROR: When setting --file, please also specify the updater to use " \
+ "using the --updater argument."
+ parser.print_help()
+ parser.epilog = None
+ sys.exit(1)
+
+ for dboard in dboards:
+ dboard_rev = get_db_rev(int(dboard, 10))
+ cpld_update_strategies = get_cpld_update_strategies(dboard_rev)
+
+ if args.updater and args.updater not in cpld_update_strategies['updaters']:
+ parser.epilog = "\nERROR: Valid updaters for zbx rev {} are {}, " \
+ "but you selected {}.".format(
+ dboard_rev,
+ ' and '.join(cpld_update_strategies['updaters']),
+ args.updater
+ )
+ parser.print_help()
+ parser.epilog = None
+ sys.exit(1)
+
+ default_image_names = []
+ for updater in cpld_update_strategies['updaters']:
+ default_image_names += cpld_update_strategies['image_names'][updater]
+ if args.file and (os.path.basename(args.file) not in default_image_names) and not args.force:
+ parser.epilog = "\nERROR: Valid CPLD image names for zbx rev {} are {}, " \
+ "but you selected {}. Using the wrong CPLD image may brick your device. " \
+ "Please use the --force option if you are really sure.".format(
+ dboard_rev,
+ ' and '.join(default_image_names),
+ args.file
+ )
+ parser.print_help()
+ parser.epilog = None
+ sys.exit(1)
+
+ if args.file and args.updater and (os.path.basename(args.file) not in cpld_update_strategies['image_names'][args.updater]) and not args.force:
+ parser.epilog = "\nERROR: Invalid CPLD image name and updater mode combination for zbx rev {}" \
+ "Using the wrong CPLD image may brick your device. " \
+ "Please use the --force option if you are really sure.".format(
+ dboard_rev,
+ )
+ parser.print_help()
+ parser.epilog = None
+ sys.exit(1)
+
+ return args
+
+ def get_dboard_update_settings(args, dboards):
+ """Determine the dboard cpld image and updater mappings"""
+ dboard_update_settings = []
+ for dboard in dboards:
+ dboard_rev = get_db_rev(int(dboard, 10))
+ if args.cpld_type:
+ cpld_update_strategies = get_cpld_update_strategies(args.cpld_type)
+ else:
+ cpld_update_strategies = get_cpld_update_strategies(dboard_rev)
+
+ if args.updater:
+ updater = args.updater
+ else:
+ updater = cpld_update_strategies['default_updater']
+
+ if args.file:
+ image_path = args.file
+ else:
+ image_names = cpld_update_strategies['image_names'][updater]
+ image_path = "/lib/firmware/ni/" + image_names[0]
+
+ dboard_update_settings.append([dboard, image_path, updater, cpld_update_strategies])
+ return dboard_update_settings
args = parse_args()
- # We need to make a logger if we're running stand-alone
- from usrp_mpm.mpmlog import get_main_logger
log = get_main_logger(log_default_delta=args.verbose-args.quiet)
dboards = args.dboards.split(",")
- if any([x not in ('0', '1') for x in dboards]):
- log.error("Unsupported dboards requested: %s", dboards)
- return False
-
- return do_update_cpld(args.file, dboards, args.updater)
-
+ return do_update_cpld(get_dboard_update_settings(args, dboards))
if __name__ == "__main__":
sys.exit(not main())