1#!/usr/bin/env python3 2# 3# Copyright 2023, NXP 4# 5# SPDX-License-Identifier: Apache-2.0 6 7""" 8Wrapper around support libraries for i.MX RT, LPC, and Kinetis SOCs. 9Allows user to generate pin control board files from MCUXpresso config 10tools (MEX) files 11""" 12# Standard python libraries 13import argparse 14import tempfile 15import zipfile 16import pathlib 17import sys 18import datetime 19import re 20 21# SOC configuration data support libraries 22from imx import imx_cfg_utils 23from kinetis import kinetis_cfg_utils 24from lpc import lpc_cfg_utils 25 26 27HELPSTR = """ 28Processes NXP signal configuration files 29 30Given a processor data pack, generates the SOC level pinctrl DTSI defintions 31required for Zephyr. This tool is intended to be used with the configuration 32data downloaded from NXP's MCUXpresso SDK builder. 33""" 34 35 36def parse_args(): 37 """ 38 Parses arguments, and returns object with parsed arguments 39 as properties 40 """ 41 parser = argparse.ArgumentParser(description=HELPSTR, 42 formatter_class=argparse.RawDescriptionHelpFormatter) 43 parser.add_argument('data_pack', metavar = 'DATA_PACK', 44 type=str, 45 help='Path to downloaded data package zip') 46 parser.add_argument('--copyright', action='store_true', 47 help='Enable default NXP copyright') 48 parser.add_argument('--soc-output', metavar = 'SOC_OUT', type=str, 49 help='Output directory for soc level dtsi files') 50 parser.add_argument('--controller', metavar = 'CTRL', type=str, 51 help=("SOC pin controller type." 52 "Currently supports: [IOMUX, IOCON, PORT]")) 53 54 return parser.parse_args() 55 56 57def processor_to_controller(processor_name): 58 """ 59 Returns pin controller type for processor, or None if 60 processor is unknown 61 """ 62 # Select family of pin controller based on SOC type 63 if "IMXRT1" in processor_name: 64 # Use IMX config tools 65 return 'IOMUX' 66 if "IMXRT6" in processor_name: 67 # LPC config tools 68 return 'IOCON' 69 if "IMXRT5" in processor_name: 70 # LPC config tools 71 return 'IOCON' 72 if "LPC55" in processor_name: 73 # LPC config tools 74 return 'IOCON' 75 if "MK" in processor_name: 76 # Kinetis config tools 77 return 'PORT' 78 # Unknown processor family 79 return "UNKNOWN" 80 81def get_pack_version(pack_dir): 82 """ 83 Gets datapack version 84 @param pack_dir: root directory data pack is in 85 """ 86 # Check version of the config tools archive 87 npi_data = pathlib.Path(pack_dir) / 'npidata.mf' 88 data_version = 0.0 89 with open(npi_data, 'r', encoding='UTF8') as stream: 90 line = stream.readline() 91 while line != '': 92 match = re.search(r'data_version=([\d\.]+)', line) 93 if match: 94 data_version = float(match.group(1)) 95 break 96 line = stream.readline() 97 return data_version 98 99def main(): 100 """ 101 Main entry point. Will process data pack, and generate board pin control 102 headers 103 """ 104 args = parse_args() 105 if not args.soc_output: 106 args.soc_output = "." 107 elif not pathlib.Path(args.soc_output).is_dir(): 108 print('SOC output path must be a directory') 109 sys.exit(255) 110 111 # Extract the Data pack to a temporary directory 112 temp_dir = tempfile.TemporaryDirectory() 113 zipfile.ZipFile(args.data_pack).extractall(temp_dir.name) 114 115 data_version = get_pack_version(temp_dir.name) 116 print(f"Found data pack version {data_version}") 117 if round(data_version) != 14: 118 print("Warning: This tool is only verified for data pack version 13, " 119 "other versions may not work") 120 121 # Attempt to locate the signal XML files we will generate from 122 proc_root = pathlib.Path(temp_dir.name) / 'processors' 123 search_pattern = "*/ksdk2_0/*/signal_configuration.xml" 124 # Pathlib glob returns an iteration, so use sum to count the length 125 package_count = sum(1 for _ in proc_root.glob(search_pattern)) 126 if package_count == 0: 127 print("No signal configuration files were found in this data pack") 128 sys.exit(255) 129 if args.copyright: 130 # Add default copyright 131 nxp_copyright = (f"Copyright {datetime.datetime.today().year}, NXP\n" 132 f" * SPDX-License-Identifier: Apache-2.0") 133 else: 134 nxp_copyright = "" 135 for signal_xml in proc_root.glob(search_pattern): 136 package_root = signal_xml.parent 137 package_name = package_root.name 138 if args.controller is None: 139 # Determine pin controller type using SOC package name 140 args.controller = processor_to_controller(package_name) 141 # If controller is still unknown, error out 142 if args.controller == "UNKNOWN": 143 print(f"Error: package {package_name} is not currently supported by this tool") 144 print("You can try specifying your pin controller family manually, " 145 "but this is unsupported!") 146 sys.exit(255) 147 148 # Select correct config tool script for the signal file 149 out_dir = args.soc_output.rstrip('/') 150 if args.controller == 'IOMUX': 151 cfg_util = imx_cfg_utils.NXPSdkUtil(str(package_root), 152 copyright_header=nxp_copyright) 153 out_path = f"{out_dir}/{cfg_util.get_part_num().lower()}-pinctrl.dtsi" 154 elif args.controller == 'IOCON': 155 cfg_util = lpc_cfg_utils.NXPSdkUtil(str(package_root), 156 copyright_header=nxp_copyright) 157 out_path = f"{out_dir}/{cfg_util.get_part_num().upper()}-pinctrl.h" 158 elif args.controller == 'PORT': 159 cfg_util = kinetis_cfg_utils.NXPSdkUtil(str(package_root), 160 copyright_header=nxp_copyright) 161 out_path = f"{out_dir}/{cfg_util.get_part_num().upper()}-pinctrl.h" 162 else: 163 print("Error: unknown controller type") 164 sys.exit(255) 165 166 cfg_util.write_pinctrl_defs(out_path) 167 print(f"Wrote pinctrl headers to {out_path}") 168 169 170if __name__ == "__main__": 171 main() 172