Skip to content

Commit e23eb09

Browse files
mcux: Update kinetis signal XML conversion script to use class
Update kinetis signal XMl conversion script to use classes, instead of methods Signed-off-by: Daniel DeGrasse <[email protected]>
1 parent 9fb4094 commit e23eb09

File tree

2 files changed

+198
-162
lines changed

2 files changed

+198
-162
lines changed

mcux/scripts/kinetis_gen_dts.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (c) 2022, NXP
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
import logging
8+
9+
from kinetis_signal2dts import NXPSdkUtil
10+
11+
xml = "signal_configuration.xml"
12+
13+
gen = NXPSdkUtil(xml, log_level = logging.INFO)
14+
gen.write_pinctrl_defs("pinctrl.dtsi")

mcux/scripts/kinetis_signal2dts.py

Lines changed: 184 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,183 +1,205 @@
11
#!/usr/bin/env python3
22
#
33
# Copyright (c) 2021, Linaro Limited.
4+
# Copyright (c) 2022, NXP
45
#
56
# SPDX-License-Identifier: Apache-2.0
67

8+
"""
9+
Implements a configuration file parser for kinetis MCUs, which can generate
10+
pinctrl definitions for Zephyr
11+
"""
12+
713
import xml.etree.ElementTree as ET
814
import re
9-
import os
10-
import sys
1115
import collections
1216
import logging
1317

1418
# layout/index of pins tuple
1519
PIN = collections.namedtuple('PIN', ['PERIPH', 'NAME_PART', 'SIGNAL', 'PORT',
1620
'PIN', 'CH', 'MUX_FUNC'])
1721

18-
19-
def parse_signal_xml(signal_fn):
20-
signal_tree = ET.parse(signal_fn)
21-
signal_root = signal_tree.getroot()
22-
23-
pins = []
24-
25-
partNum = signal_root.find("./part_information/part_number").get('id')
26-
27-
print(f"################## {partNum} ###########")
28-
29-
periphs_node = signal_root.find("peripherals")
30-
periphs = []
31-
for p in periphs_node:
32-
id = p.attrib.get("id")
33-
name = p.attrib.get("name")
34-
35-
if id != name:
36-
logging.warn("id and name don't match")
37-
38-
periphs.append(id)
39-
40-
pins_node = signal_root.find("pins")
41-
for p in pins_node:
42-
name = p.attrib.get("name")
43-
44-
# Kinetis family uses PT[A-Z][0-31]
45-
if "PT" in name:
46-
logging.debug(name)
47-
48-
num_conns = 0
49-
50-
for conns in p.findall("connections"):
51-
num_conns += 1
52-
logging.debug(f"\t{num_conns} - {conns.tag} {conns.attrib}")
53-
name_part = conns.attrib.get("name_part")
54-
# func = conns.attrib.get("package_function")
55-
56-
conns_tree = ET.ElementTree(conns)
57-
periph = None
58-
59-
num_periph_sig = 0
60-
61-
for c in conns_tree.iter('peripheral_signal_ref'):
62-
num_periph_sig += 1
63-
logging.debug(f"\t\t{num_periph_sig} - {c.tag} {c.attrib}")
64-
signal = c.attrib.get("signal")
65-
periph = c.attrib.get("peripheral")
66-
ch = c.attrib.get("channel")
67-
68-
if num_periph_sig > 1:
69-
logging.error(num_periph_sig)
70-
71-
# handle unrouted_pin_function_ref case (disabled pin)
72-
if periph is None:
73-
continue
74-
75-
pin = None
76-
77-
for c in conns_tree.iter('assign'):
78-
logging.debug(f"\t\t\t[ASSIGN] {c.tag} {c.attrib}")
79-
reg = c.attrib.get("register")
80-
reg_match = re.search(r"PORT([A-Z])_PCR(\d+)", reg)
81-
82-
# Only process PCR registers
83-
if reg_match:
84-
port = reg_match.group(1).lower()
85-
if len(reg_match.groups()) == 2:
86-
pin = reg_match.group(2).lower()
87-
else:
88-
pin = None
89-
else:
22+
class NXPSdkUtil:
23+
"""
24+
Class for kinetis configuration file parser
25+
"""
26+
def __init__(self, signal_file, copyright_header = "", log_level = logging.ERROR):
27+
"""
28+
Initialize SDK utilities.
29+
Providing a signal file will enable this class to parse MEX files,
30+
and generate output DTS
31+
@param signal_file: path to signal_configuration.xml file
32+
@param copyright_header: copyright string to add to any generated file header
33+
@param log_level: log level for SDK utility
34+
"""
35+
# Load the signal XML data
36+
37+
self._logger = logging.getLogger('')
38+
self._logger.setLevel(log_level)
39+
self._parse_signal_xml(signal_file)
40+
self._copyright = copyright_header
41+
logging.info("Loaded %d pinmux defs", len(self._pins))
42+
43+
def _parse_signal_xml(self, signal_fn):
44+
"""
45+
Parses signal XML configuration file. Builds a list of pins, which can
46+
be used to generate soc level DTSI file.
47+
@param signal_fn: signal_configuration.xml file to parse
48+
"""
49+
self._pins = []
50+
try:
51+
signal_tree = ET.parse(signal_fn)
52+
except ET.ParseError:
53+
logging.error("Could not parse provided signal file: %s", signal_fn)
54+
return
55+
56+
signal_root = signal_tree.getroot()
57+
58+
self._part_num = signal_root.find("./part_information/part_number").get('id')
59+
60+
logging.info("Loaded XML for %s", self._part_num)
61+
62+
periphs_node = signal_root.find("peripherals")
63+
periphs = []
64+
for pin in periphs_node:
65+
pin_id = pin.attrib.get("id")
66+
name = pin.attrib.get("name")
67+
68+
if pin_id != name:
69+
logging.warning("id and name don't match")
70+
71+
periphs.append(pin_id)
72+
73+
pins_node = signal_root.find("pins")
74+
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:
90106
continue
91107

92-
logging.debug(c.attrib)
108+
pin = None
93109

94-
val = c.attrib.get("bit_field_value")
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)
95114

96-
pin_data = PIN(PERIPH=periph,
97-
NAME_PART=name_part,
98-
SIGNAL=signal,
99-
PORT=port,
100-
PIN=int(pin),
101-
CH=ch,
102-
MUX_FUNC=int(val, 16))
103-
logging.debug(pin_data)
104-
pins.append(pin_data)
105-
106-
return (partNum, pins)
107-
108-
109-
def write_pins(whichPort, pins, f):
110-
port_pins = list(filter(lambda p: (p.PORT.lower() == whichPort), pins))
111-
112-
if (len(port_pins)) == 0:
113-
return
114-
115-
port_pins.sort(key=lambda p: (p.PIN, p.MUX_FUNC))
116-
117-
seen_nodes = []
118-
119-
f.write(f"&port{whichPort} {{\n")
120-
for pin_data in port_pins:
121-
port_name = f"PT{pin_data.PORT.upper()}{pin_data.PIN}"
122-
# Special case handle GPIO so that it will be of the form:
123-
# PT[A-E][0-31]: GPIO[A-E]_PT[A-E][0-31]: ...
124-
#
125-
# eg:
126-
# PTA3: GPIOA_PTA3: gpioa_pta3 { .... };
127-
if pin_data.PERIPH.startswith("GPIO"):
128-
node = f"{pin_data.PERIPH.lower()}_{port_name.lower()}"
129-
label = f"{port_name}: {node.upper()}"
130-
else:
131-
label = f"{pin_data.NAME_PART}_{port_name}"
132-
node = label.lower()
133-
k_port_pins_prop = f"< {pin_data.PIN} {pin_data.MUX_FUNC} >"
134-
135-
if node in seen_nodes:
136-
continue
137-
else:
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)
138+
139+
def _write_pins(self, which_port, pins, file):
140+
"""
141+
Writes all pin mux nodes for a specific pin port to soc pinctrl dtsi
142+
file.
143+
@param which_port: pin port to define
144+
@param pins: list of pin mux options to write
145+
@param file: output file to write to
146+
"""
147+
port_pins = list(filter(lambda p: (p.PORT.lower() == which_port), pins))
148+
149+
if (len(port_pins)) == 0:
150+
return
151+
152+
port_pins.sort(key=lambda p: (p.PIN, p.MUX_FUNC))
153+
154+
seen_nodes = []
155+
156+
file.write(f"&port{which_port} {{\n")
157+
for pin_data in port_pins:
158+
port_name = f"PT{pin_data.PORT.upper()}{pin_data.PIN}"
159+
# Special case handle GPIO so that it will be of the form:
160+
# PT[A-E][0-31]: GPIO[A-E]_PT[A-E][0-31]: ...
161+
#
162+
# eg:
163+
# PTA3: GPIOA_PTA3: gpioa_pta3 { .... };
164+
if pin_data.PERIPH.startswith("GPIO"):
165+
node = f"{pin_data.PERIPH.lower()}_{port_name.lower()}"
166+
label = f"{port_name}: {node.upper()}"
167+
else:
168+
label = f"{pin_data.NAME_PART}_{port_name}"
169+
node = label.lower()
170+
k_port_pins_prop = f"< {pin_data.PIN} {pin_data.MUX_FUNC} >"
171+
172+
if node in seen_nodes:
173+
continue
138174
seen_nodes.append(node)
139175

140-
f.write(f"\t{label}: {node} {{\n")
141-
f.write("\t\t/* < PIN PCR[MUX] > */\n")
142-
f.write(f"\t\tnxp,kinetis-port-pins = {k_port_pins_prop};\n")
143-
f.write("\t};\n")
144-
145-
f.write("};\n")
146-
f.write("\n")
147-
148-
149-
def process_signal_xml(filename):
150-
(partNum, pins) = parse_signal_xml(filename)
151-
152-
pcr_pins = list(filter(lambda p: (p.PERIPH not in ["FB", "EZPORT"]), pins))
153-
154-
with open(partNum + "-pinctrl.dtsi", "w", encoding="utf-8") as f:
155-
f.write("/*\n")
156-
f.write(" * NOTE: Autogenerated file by kinetis_signal2dts.py\n")
157-
f.write(f" * for {partNum}/signal_configuration.xml\n")
158-
f.write(" *\n")
159-
f.write(" * SPDX-License-Identifier: Apache-2.0\n")
160-
f.write(" */\n")
161-
f.write("\n")
162-
163-
write_pins('a', pcr_pins, f)
164-
write_pins('b', pcr_pins, f)
165-
write_pins('c', pcr_pins, f)
166-
write_pins('d', pcr_pins, f)
167-
write_pins('e', pcr_pins, f)
168-
169-
170-
logger = logging.getLogger('')
171-
172-
processor = None
173-
if len(sys.argv) > 1:
174-
processor = sys.argv[1]
175-
176-
signal_xml_fn = "signal_configuration.xml"
177-
178-
for root, dirs, files in os.walk("."):
179-
if signal_xml_fn in files:
180-
if processor and processor not in root:
181-
continue
182-
print(os.path.join(root, signal_xml_fn))
183-
process_signal_xml(os.path.join(root, signal_xml_fn))
176+
file.write(f"\t{label}: {node} {{\n")
177+
file.write("\t\t/* < PIN PCR[MUX] > */\n")
178+
file.write(f"\t\tnxp,kinetis-port-pins = {k_port_pins_prop};\n")
179+
file.write("\t};\n")
180+
181+
file.write("};\n")
182+
file.write("\n")
183+
184+
def write_pinctrl_defs(self, outputfile):
185+
"""
186+
Writes all pin mux options into pinctrl DTSI file. Board level pin groups
187+
can include this pinctrl dtsi file to access pin control defintions.
188+
@param outputfile: file to write output pinctrl defs to
189+
"""
190+
pcr_pins = list(filter(lambda p: (p.PERIPH not in ["FB", "EZPORT"]), self._pins))
191+
file_header = ("/*\n"
192+
" * NOTE: Autogenerated file by kinetis_signal2dts.py\n"
193+
f" * for {self._part_num}/signal_configuration.xml\n"
194+
" *\n"
195+
f" * {self._copyright}\n"
196+
" * SPDX-License-Identifier: Apache-2.0\n"
197+
" */\n"
198+
"\n")
199+
with open(outputfile, "w", encoding="utf8") as file:
200+
file.write(file_header)
201+
self._write_pins('a', pcr_pins, file)
202+
self._write_pins('b', pcr_pins, file)
203+
self._write_pins('c', pcr_pins, file)
204+
self._write_pins('d', pcr_pins, file)
205+
self._write_pins('e', pcr_pins, file)

0 commit comments

Comments
 (0)