223 lines
10 KiB
Python
223 lines
10 KiB
Python
#!/usr/bin/env python
|
|
|
|
from collections import defaultdict
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../../tools"))
|
|
import boardgen
|
|
|
|
|
|
IOMUX_REGEXS = [
|
|
r"IOMUXC_(?P<pin>GPIO_SD_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_AD_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_EMC_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_AD_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_SD_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_EMC_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_DISP_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_LPSR_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_[SNVS_]*(?P<pin>WAKEUP[_DIG]*)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_[SNVS_]*(?P<pin>PMIC_ON_REQ[_DIG]*)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_[SNVS_]*(?P<pin>PMIC_STBY_REQ[_DIG]*)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
r"IOMUXC_(?P<pin>GPIO_SNVS_\d\d_DIG)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
|
|
]
|
|
|
|
SUPPORTED_AF_FNS = {"GPIO", "USDHC", "FLEXPWM", "TMR"}
|
|
|
|
|
|
class MimxrtPin(boardgen.Pin):
|
|
def __init__(self, cpu_pin_name):
|
|
super().__init__(cpu_pin_name)
|
|
|
|
self._afs = []
|
|
self._adc_fns = []
|
|
|
|
# Called for each AF defined in the csv file for this pin.
|
|
def add_af(self, af_idx, af_name, af):
|
|
# mimxrt-specific: Any pin in the af.csv is implicitly part of the board
|
|
# pins.csv and will therefore be in the Pin.cpu dict. This is
|
|
# equivalent to adding `,CPUNAME` to the board.csv for every pin in the
|
|
# af.csv.
|
|
self._available = True
|
|
|
|
if af_name == "ALT5":
|
|
m = re.match("GPIO([0-9]+)_IO([0-9]+)", af)
|
|
self._port = int(m.group(1))
|
|
self._pin = int(m.group(2))
|
|
|
|
if af_name.startswith("ALT"):
|
|
instance = af.split("_")[0]
|
|
fn = re.match("^([A-Z][A-Z0-9]+[A-Z])[0-9]*$", instance).group(1)
|
|
if fn not in SUPPORTED_AF_FNS:
|
|
return
|
|
iomux_config = self._generator._iomux_pin_config[self.name()]
|
|
input_reg = iomux_config[af_idx]["inputRegister"].strip("U")
|
|
input_daisy = int(iomux_config[af_idx]["inputDaisy"].strip("U"), 16)
|
|
self._afs.append((af_idx, input_reg, input_daisy, instance, fn, af))
|
|
|
|
elif af_name == "ADC":
|
|
adc_regex = r"ADC(?P<instance>\d*)_IN(?P<channel>\d*)"
|
|
lpadc_regex = r"ADC(?P<instance>\d*)_CH(?P<channel>\d*)" # LPADC for MIMXRT11xx chips
|
|
|
|
matches = re.finditer(adc_regex, af, re.MULTILINE)
|
|
for match in matches:
|
|
self._adc_fns.append(
|
|
(int(match.group("instance")), int(match.group("channel")), "ADC")
|
|
)
|
|
|
|
matches = re.finditer(lpadc_regex, af, re.MULTILINE)
|
|
for match in matches:
|
|
self._adc_fns.append(
|
|
(int(match.group("instance")), int(match.group("channel")), "LPADC")
|
|
)
|
|
|
|
# Use the PIN() macro defined in samd_prefix.c for defining the pin
|
|
# objects.
|
|
def definition(self):
|
|
if "_LPSR_" in self.name():
|
|
macro = "PIN_LPSR"
|
|
elif (
|
|
"_SNVS_" in self.name()
|
|
or self.name().startswith("PMIC_")
|
|
or self.name().startswith("WAKEUP")
|
|
):
|
|
macro = "PIN_SNVS"
|
|
else:
|
|
macro = "PIN"
|
|
|
|
# PIN(_name, _gpio, _pin, _af_list, _adc_list_len, _adc_list)
|
|
return "{:s}({:s}, GPIO{:d}, {:d}, pin_{:s}_af, {:d}, {:s})".format(
|
|
macro,
|
|
self.name(),
|
|
self._port,
|
|
self._pin,
|
|
self.name(),
|
|
len(self._adc_fns),
|
|
"pin_{:s}_adc".format(self.name()) if self._adc_fns else "NULL",
|
|
)
|
|
|
|
# This will be called at the start of the output (after the prefix) for
|
|
# each pin. Use it to emit the af and adc objects.
|
|
def print_source(self, out_source):
|
|
print(
|
|
"static const machine_pin_af_obj_t pin_{:s}_af[] = {{".format(self.name()),
|
|
file=out_source,
|
|
)
|
|
for af_idx, input_reg, input_daisy, instance, _fn, af in self._afs:
|
|
print(
|
|
" PIN_AF({:s}, PIN_AF_MODE_ALT{:d}, {:d}, {:s}, {:s}, {:s}),".format(
|
|
af, af_idx, input_daisy, instance, input_reg, "0x10B0U"
|
|
),
|
|
file=out_source,
|
|
)
|
|
print("};", file=out_source)
|
|
print(file=out_source)
|
|
|
|
if self._adc_fns:
|
|
print(
|
|
"static const machine_pin_adc_obj_t pin_{:s}_adc[] = {{".format(self.name()),
|
|
file=out_source,
|
|
)
|
|
for instance, channel, peripheral in self._adc_fns:
|
|
print(
|
|
" PIN_ADC({:s}{:d}, {:d}),".format(peripheral, instance, channel),
|
|
file=out_source,
|
|
)
|
|
print("};", file=out_source)
|
|
|
|
# mimxrt cpu names must be "GPIO_<funcs>_<num>", with zero-prefixed two-digit <num>.
|
|
@staticmethod
|
|
def validate_cpu_pin_name(cpu_pin_name):
|
|
boardgen.Pin.validate_cpu_pin_name(cpu_pin_name)
|
|
|
|
if not re.match(
|
|
"^((GPIO_((SNVS|EMC|LPSR|DISP)_)?([AS]D_)?(B[012]_)?[0-9][0-9])|WAKEUP|PMIC_(ON|STBY)_REQ)(_DIG)?$",
|
|
cpu_pin_name,
|
|
):
|
|
raise boardgen.PinGeneratorError("Invalid cpu pin name '{}'".format(cpu_pin_name))
|
|
|
|
|
|
class MimxrtPinGenerator(boardgen.PinGenerator):
|
|
def __init__(self):
|
|
# Use custom pin type above, and also enable the --af-csv argument so
|
|
# that add_af gets called on each pin.
|
|
super().__init__(
|
|
pin_type=MimxrtPin,
|
|
enable_af=True,
|
|
)
|
|
self._iomux_pin_config = {}
|
|
|
|
# Load the iomux configuration from fsl_iomuxc.h.
|
|
def load_iomux_header(self, iomux_filename):
|
|
with open(iomux_filename, "r") as ipt:
|
|
input_str = ipt.read()
|
|
for regex in IOMUX_REGEXS:
|
|
matches = re.finditer(regex, input_str, re.MULTILINE)
|
|
|
|
for match in matches:
|
|
if match.group("pin") not in self._iomux_pin_config:
|
|
self._iomux_pin_config[match.group("pin")] = {
|
|
int((match.groupdict()["muxMode"].strip("U")), 16): match.groupdict()
|
|
}
|
|
else:
|
|
self._iomux_pin_config[match.group("pin")][
|
|
int((match.groupdict()["muxMode"].strip("U")), 16)
|
|
] = match.groupdict()
|
|
|
|
# Also load the iomux header.
|
|
def load_inputs(self, out_source):
|
|
if self.args.iomux_header:
|
|
print("// --iomux-header {:s}".format(self.args.iomux_header), file=out_source)
|
|
self.load_iomux_header(self.args.iomux_header)
|
|
|
|
super().load_inputs(out_source)
|
|
|
|
# Provide a macro for each supported (pin,af) that can be used to
|
|
# initialise a struct containing a machine_pin_obj_t* and the
|
|
# corresponding af for that pin. e.g. A mimxrt_sdcard_pin_t instance can
|
|
# be initialised with GPIO_SD_B0_00_USDHC1_CMD which tells it how to get
|
|
# the CMD pin of the USDHC1 function on the GPIO_SD_B0_00 pin.
|
|
def print_module_instances(self, out_header):
|
|
print(file=out_header)
|
|
for match_fn in ("USDHC", "FLEXPWM", "TMR"):
|
|
module_instances = defaultdict(list)
|
|
for pin in self.available_pins():
|
|
for i, (_af_idx, _input_reg, _input_daisy, instance, fn, af) in enumerate(
|
|
pin._afs
|
|
):
|
|
if fn == match_fn:
|
|
module_instances[instance].append(
|
|
"#define {:s}_{:s} pin_{:s}, {:d}".format(
|
|
pin.name(), af, pin.name(), i
|
|
)
|
|
)
|
|
for k, v in module_instances.items():
|
|
print("// {:s}".format(k), file=out_header)
|
|
print("#define {:s}_AVAIL (1)".format(k), file=out_header)
|
|
if match_fn == "FLEXPWM":
|
|
print("#define {:s} {:s}".format(k, k[-4:]), file=out_header)
|
|
for i in v:
|
|
print(i, file=out_header)
|
|
|
|
# Override to also print the module instances.
|
|
def print_header(self, out_header):
|
|
super().print_header(out_header)
|
|
self.print_module_instances(out_header)
|
|
|
|
# Override the default implementation just to change the default arguments
|
|
# (extra header row, skip first column).
|
|
def parse_af_csv(self, filename):
|
|
return super().parse_af_csv(filename, header_rows=1, pin_col=0, af_col=1)
|
|
|
|
# We need to know the mcu to emit the correct AF list.
|
|
def extra_args(self, parser):
|
|
parser.add_argument("--iomux-header")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
MimxrtPinGenerator().main()
|