Skip to content

Commit c26b0af

Browse files
scripts: Update signal2dts to use SignalPin class structure
Rework signal2dts to use SignalPin class structure, so that pin defaults can be captured. Signed-off-by: Daniel DeGrasse <[email protected]>
1 parent e23eb09 commit c26b0af

File tree

1 file changed

+252
-73
lines changed

1 file changed

+252
-73
lines changed

mcux/scripts/kinetis_signal2dts.py

Lines changed: 252 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,239 @@
1919
PIN = collections.namedtuple('PIN', ['PERIPH', 'NAME_PART', 'SIGNAL', 'PORT',
2020
'PIN', 'CH', 'MUX_FUNC'])
2121

22+
NAMESPACES = {'mex': 'http://mcuxpresso.nxp.com/XSD/mex_configuration_10'}
23+
24+
class MUXOption:
25+
"""
26+
Internal class representing a mux option on the SOC
27+
"""
28+
def __init__(self, connection):
29+
"""
30+
Initializes a mux option
31+
@param connection XML connection option from signal_configuration.xml
32+
"""
33+
self._name = connection.attrib.get('name_part')
34+
logging.debug("\t\t %s", self._name)
35+
if self._name is None:
36+
self._name = ''
37+
return
38+
# Get MUX settings
39+
self._port = None
40+
for periph in connection.iter('peripheral_signal_ref'):
41+
self._periph = periph.attrib.get('peripheral')
42+
for assign in connection.iter('assign'):
43+
reg = assign.attrib.get('register')
44+
val = assign.attrib.get('bit_field_value')
45+
logging.debug('\t\t\t [ASSIGN] %s %s', reg, val)
46+
# Only process PCR registers
47+
match = re.match(r'PORT([A-Z])_PCR(\d+)', reg)
48+
if match:
49+
self._name += f"_PT{match.group(1)}{match.group(2)}"
50+
self._port = match.group(1)
51+
self._pin = int(match.group(2))
52+
self._mux = int(val, 16)
53+
if self._port is None:
54+
# Not a valid port mapping. Clear name
55+
self._name = ''
56+
57+
def __repr__(self):
58+
"""
59+
String representation of object
60+
"""
61+
return "MUXOption(%s)" % (self._name)
62+
63+
def get_name(self):
64+
"""
65+
Get mux option name
66+
"""
67+
return self._name
68+
69+
def get_port(self):
70+
"""
71+
Get mux port
72+
"""
73+
return self._port
74+
75+
def get_pin(self):
76+
"""
77+
Get mux pin
78+
"""
79+
return self._pin
80+
81+
def get_mux(self):
82+
"""
83+
Get mux register write value
84+
"""
85+
return self._mux
86+
87+
def get_periph(self):
88+
"""
89+
Get peripheral name
90+
"""
91+
return self._periph
92+
93+
def __hash__(self):
94+
"""
95+
Override hash method to return pin name as hash
96+
"""
97+
return hash(self._name)
98+
99+
def __eq__(self, obj):
100+
"""
101+
Like the hash method, we override the eq method to return true if two
102+
objects have the same pin name
103+
"""
104+
return isinstance(obj, SignalPin) and self._name == obj._name
105+
106+
def __lt__(self, obj):
107+
"""
108+
Compare objects based on name
109+
"""
110+
if not isinstance(obj, SignalPin):
111+
return True
112+
return self._name < obj._name
113+
114+
115+
class SignalPin:
116+
"""
117+
Internal class representing a signal on the SOC
118+
"""
119+
def __init__(self, pin):
120+
"""
121+
Initializes a SignalPin object
122+
@param pin: pin XML object from signal_configuration.xml
123+
"""
124+
# Kinetis pin names are formatted as [PT[Port][Pin]]
125+
pin_regex = re.search(r'PT([A-Z])(\d+)', pin.attrib['name'])
126+
if pin_regex is None:
127+
logging.debug('Could not match pin name %s', pin.attrib['name'])
128+
self._name = ''
129+
return
130+
self._name = pin_regex.group(0)
131+
self._port = pin_regex.group(1)
132+
self._pin = pin_regex.group(2)
133+
self._properties = self._get_pin_properties(pin.find('functional_properties'))
134+
self._mux_options = {}
135+
for connections in pin.findall('connections'):
136+
mux_opt = MUXOption(connections)
137+
# Only append mux options with a valid name
138+
if mux_opt.get_name() != '':
139+
self._mux_options[mux_opt.get_name()] = mux_opt
140+
141+
def __repr__(self):
142+
"""
143+
String representation of object
144+
"""
145+
return "SignalPin(%s)" % (self._name)
146+
147+
def __hash__(self):
148+
"""
149+
Override hash method to return pin name as hash
150+
"""
151+
return hash(self._name)
152+
153+
def __eq__(self, obj):
154+
"""
155+
Like the hash method, we override the eq method to return true if two
156+
objects have the same pin name
157+
"""
158+
return isinstance(obj, SignalPin) and self._name == obj._name
159+
160+
def __lt__(self, obj):
161+
"""
162+
Compare objects based on name
163+
"""
164+
if not isinstance(obj, SignalPin):
165+
return True
166+
return self._name < obj._name
167+
168+
def get_name(self):
169+
"""
170+
Get name of pin
171+
"""
172+
return self._name
173+
174+
def get_port(self):
175+
"""
176+
Get PORT this signal is defined for
177+
"""
178+
return self._port
179+
180+
def get_pin(self):
181+
"""
182+
Get pin this signal is defined for
183+
"""
184+
return self._pin
185+
186+
def get_mux_connection(self, signal):
187+
"""
188+
Gets an MUXOption object for the relevant signal name
189+
@param signal: Signal name on pin to get mux option for
190+
"""
191+
if signal in self._mux_options:
192+
return self._mux_options[signal]
193+
return None
194+
195+
def get_mux_options(self):
196+
"""
197+
Gets all unique settings for IOMUX on the specific pin
198+
"""
199+
return set(self._mux_options.values())
200+
201+
def get_pin_properties(self):
202+
"""
203+
Gets array of pin property names
204+
"""
205+
return self._properties.keys()
206+
207+
def get_pin_property_default(self, prop):
208+
"""
209+
Gets name of default pin property
210+
@param prop: name of pin property
211+
"""
212+
return self._properties[prop]['default']
213+
214+
def get_pin_defaults(self):
215+
"""
216+
Gets mapping of all pin property names to default value names
217+
"""
218+
pin_defaults = {}
219+
for prop in self.get_pin_properties():
220+
pin_default = self.get_pin_property_default(prop)
221+
pin_defaults[prop] = pin_default
222+
return pin_defaults
223+
224+
def get_pin_property_value(self, prop, selection):
225+
"""
226+
Gets bit value for pin property
227+
@param prop: name of pin property
228+
@param selection: name of option selected for property
229+
"""
230+
return self._properties[prop][selection]
231+
232+
def _get_pin_properties(self, props):
233+
"""
234+
Builds dictionary with all pin properties
235+
@param props: pin function_properties XML object in signal_configuration.xml
236+
"""
237+
prop_mapping = {}
238+
for prop in props.findall('functional_property'):
239+
if len(prop.findall('state/configuration/assign')) == 0:
240+
# Not configurable property. Skip
241+
continue
242+
prop_id = prop.attrib['id']
243+
if not 'default' in prop.attrib:
244+
# No default property. Skip
245+
continue
246+
prop_mapping[prop_id] = {}
247+
prop_mapping[prop_id]['default'] = prop.attrib['default']
248+
for state in prop.findall('state'):
249+
reg_assign = state.find('configuration/assign')
250+
bit_value = int(reg_assign.attrib['bit_field_value'], 0)
251+
prop_mapping[prop_id][state.attrib['id']] = bit_value
252+
return prop_mapping
253+
254+
22255
class NXPSdkUtil:
23256
"""
24257
Class for kinetis configuration file parser
@@ -38,15 +271,15 @@ def __init__(self, signal_file, copyright_header = "", log_level = logging.ERROR
38271
self._logger.setLevel(log_level)
39272
self._parse_signal_xml(signal_file)
40273
self._copyright = copyright_header
41-
logging.info("Loaded %d pinmux defs", len(self._pins))
274+
logging.info("Loaded %d pin defs", len(self._pins))
42275

43276
def _parse_signal_xml(self, signal_fn):
44277
"""
45278
Parses signal XML configuration file. Builds a list of pins, which can
46279
be used to generate soc level DTSI file.
47280
@param signal_fn: signal_configuration.xml file to parse
48281
"""
49-
self._pins = []
282+
self._pins = {}
50283
try:
51284
signal_tree = ET.parse(signal_fn)
52285
except ET.ParseError:
@@ -72,69 +305,10 @@ def _parse_signal_xml(self, signal_fn):
72305

73306
pins_node = signal_root.find("pins")
74307
for pin in pins_node:
75-
name = pin.attrib.get("name")
76-
77-
# Kinetis family uses PT[A-Z][0-31]
78-
if "PT" in name:
79-
logging.debug(name)
80-
81-
num_conns = 0
82-
83-
for conns in pin.findall("connections"):
84-
num_conns += 1
85-
logging.debug("\t%s - %s %s", num_conns, conns.tag, conns.attrib)
86-
name_part = conns.attrib.get("name_part")
87-
# func = conns.attrib.get("package_function")
88-
89-
conns_tree = ET.ElementTree(conns)
90-
periph = None
91-
92-
num_periph_sig = 0
93-
94-
for ref in conns_tree.iter('peripheral_signal_ref'):
95-
num_periph_sig += 1
96-
logging.debug("\t\t%s - %s %s", num_periph_sig, ref.tag, ref.attrib)
97-
signal = ref.attrib.get("signal")
98-
periph = ref.attrib.get("peripheral")
99-
channel = ref.attrib.get("channel")
100-
101-
if num_periph_sig > 1:
102-
logging.error(num_periph_sig)
103-
104-
# handle unrouted_pin_function_ref case (disabled pin)
105-
if periph is None:
106-
continue
107-
108-
pin = None
109-
110-
for ref in conns_tree.iter('assign'):
111-
logging.debug("\t\t\t[ASSIGN] %s %s", ref.tag, ref.attrib)
112-
reg = ref.attrib.get("register")
113-
reg_match = re.search(r"PORT([A-Z])_PCR(\d+)", reg)
114-
115-
# Only process PCR registers
116-
if reg_match:
117-
port = reg_match.group(1).lower()
118-
if len(reg_match.groups()) == 2:
119-
pin = reg_match.group(2).lower()
120-
else:
121-
pin = None
122-
else:
123-
continue
124-
125-
logging.debug(ref.attrib)
126-
127-
val = ref.attrib.get("bit_field_value")
128-
129-
pin_data = PIN(PERIPH=periph,
130-
NAME_PART=name_part,
131-
SIGNAL=signal,
132-
PORT=port,
133-
PIN=int(pin),
134-
CH=channel,
135-
MUX_FUNC=int(val, 16))
136-
logging.debug(pin_data)
137-
self._pins.append(pin_data)
308+
signal = SignalPin(pin)
309+
# Only add valid signal pins to list
310+
if signal.get_name() != '':
311+
self._pins[signal.get_name()] = signal
138312

139313
def _write_pins(self, which_port, pins, file):
140314
"""
@@ -144,30 +318,30 @@ def _write_pins(self, which_port, pins, file):
144318
@param pins: list of pin mux options to write
145319
@param file: output file to write to
146320
"""
147-
port_pins = list(filter(lambda p: (p.PORT.lower() == which_port), pins))
321+
port_pins = list(filter(lambda p: (p.get_port().lower() == which_port), pins))
148322

149323
if (len(port_pins)) == 0:
150324
return
151325

152-
port_pins.sort(key=lambda p: (p.PIN, p.MUX_FUNC))
326+
port_pins.sort(key=lambda p: (p.get_pin(), p.get_mux()))
153327

154328
seen_nodes = []
155329

156330
file.write(f"&port{which_port} {{\n")
157331
for pin_data in port_pins:
158-
port_name = f"PT{pin_data.PORT.upper()}{pin_data.PIN}"
332+
port_name = f"PT{pin_data.get_port().upper()}{pin_data.get_pin()}"
159333
# Special case handle GPIO so that it will be of the form:
160334
# PT[A-E][0-31]: GPIO[A-E]_PT[A-E][0-31]: ...
161335
#
162336
# eg:
163337
# PTA3: GPIOA_PTA3: gpioa_pta3 { .... };
164-
if pin_data.PERIPH.startswith("GPIO"):
165-
node = f"{pin_data.PERIPH.lower()}_{port_name.lower()}"
338+
if pin_data.get_periph().startswith("GPIO"):
339+
node = f"{pin_data.get_periph().lower()}_{port_name.lower()}"
166340
label = f"{port_name}: {node.upper()}"
167341
else:
168-
label = f"{pin_data.NAME_PART}_{port_name}"
342+
label = pin_data.get_name()
169343
node = label.lower()
170-
k_port_pins_prop = f"< {pin_data.PIN} {pin_data.MUX_FUNC} >"
344+
k_port_pins_prop = f"< {pin_data.get_pin()} {pin_data.get_mux()} >"
171345

172346
if node in seen_nodes:
173347
continue
@@ -187,7 +361,11 @@ def write_pinctrl_defs(self, outputfile):
187361
can include this pinctrl dtsi file to access pin control defintions.
188362
@param outputfile: file to write output pinctrl defs to
189363
"""
190-
pcr_pins = list(filter(lambda p: (p.PERIPH not in ["FB", "EZPORT"]), self._pins))
364+
# Create list of all pin mux options
365+
pinmux_opts = []
366+
for pin in self._pins.values():
367+
pinmux_opts.extend(pin.get_mux_options())
368+
pcr_pins = list(filter(lambda p: (p.get_periph() not in ["FB", "EZPORT"]), pinmux_opts))
191369
file_header = ("/*\n"
192370
" * NOTE: Autogenerated file by kinetis_signal2dts.py\n"
193371
f" * for {self._part_num}/signal_configuration.xml\n"
@@ -203,3 +381,4 @@ def write_pinctrl_defs(self, outputfile):
203381
self._write_pins('c', pcr_pins, file)
204382
self._write_pins('d', pcr_pins, file)
205383
self._write_pins('e', pcr_pins, file)
384+

0 commit comments

Comments
 (0)