1# Copyright (c) 2024 Gerson Fernando Budke 2# SPDX-License-Identifier: Apache-2.0 3 4""" 5Utility to autogenerate pinctrl definitions. 6 7Usage:: 8 python3 bflbpinctrl.py [-i /path/to/configs] [-o /path/to/include] 9""" 10 11import argparse 12from collections import OrderedDict 13from datetime import date 14from pathlib import Path 15import re 16 17from natsort import natsorted 18import yaml 19 20 21REPO_ROOT = Path(__file__).absolute().parents[1] 22"""Repository root.""" 23 24current_date = date.today() 25 26HEADER = """/* 27 * Autogenerated file 28 * Copyright (c) {} BFLB Pinctrl Generator <nandojve@gmail.com> 29 * SPDX-License-Identifier: Apache-2.0 30 */ 31""".format(current_date.year) 32"""Header for the generated files.""" 33 34 35def get_header_fname(serie): 36 """Get header file name. 37 38 Args: 39 serie: Series. 40 41 Returns: 42 Header file name. 43 """ 44 45 return f"bl{serie}x-pinctrl.h" 46 47 48def get_port_pin(pin_name): 49 """Obtain port and pin number from a pin name 50 51 Args: 52 pin_name: Pin name, e.g. GPIO0 53 54 Returns: 55 Port and pin, e.g. GPIO, 0. 56 """ 57 58 m = re.match(r"(GPIO)(\d+)", pin_name.upper()) 59 if not m: 60 raise ValueError(f"Unexpected pin name: {pin_name}") 61 62 return m.group(1), str(int(m.group(2))) 63 64 65def get_normalized_name(name): 66 sname_norm = name.replace(".", "_") 67 sname_norm = sname_norm.replace("-", "_") 68 return sname_norm.upper() 69 70 71def write_periph_index(f, periph, value): 72 define = f"#define BFLB_PINMUX_FUN_INST_{periph.lower()}" 73 define_val = f"{value:#06x}" 74 f.write(f"{define:<56}{define_val}\n") 75 76 77def write_signal_index(f, signal, value): 78 define = f"#define BFLB_PINMUX_SIGNAL_{signal.lower()}" 79 define_val = f"{value:#04x}" 80 f.write(f"{define:<56}{define_val}\n") 81 82 83def generate_bflb_series_header(outdir, family, peripherals, signals, signal_cfgs): 84 """Generate Bouffalo Lab header with pin configurations. 85 86 Args: 87 outdir: Output base directory. 88 family: Bouffalo Lab family. 89 peripherals: The peripheral itself. 90 signals: Signals. 91 signal_cfgs: Signal configurations. 92 """ 93 94 sname = f"{family}-pinctrl.h" 95 sname_norm = get_normalized_name(sname) 96 ofname = outdir / sname 97 with open(ofname, "w") as f: 98 f.write(HEADER) 99 f.write(f"\n#ifndef DT_BINDINGS_PINCTRL_BFLB_{sname_norm}_") 100 f.write(f"\n#define DT_BINDINGS_PINCTRL_BFLB_{sname_norm}_\n\n") 101 102 for periph, index, *instancies in peripherals: 103 if instancies: 104 for inst in instancies: 105 write_periph_index(f, periph + str(inst), index + inst * 256) 106 continue 107 write_periph_index(f, periph, index) 108 109 f.write("\n") 110 111 for signal in signal_cfgs: 112 value = 0 113 if signal in signals.keys(): 114 value = signals[signal] 115 write_signal_index(f, signal, value) 116 117 f.write(f"\n#endif /* DT_BINDINGS_PINCTRL_BFLB_{sname_norm}_ */\n") 118 119 120def write_periph_function(f, port, pin_num, periph, signal, fmap, function): 121 f.write(f"\n/* {port.lower()}{pin_num}_{periph}_{signal} " 122 f"*/\n") 123 define = f"#define {port.upper()}{pin_num.upper()}_{periph.upper()}_{signal.upper()}" 124 define_val = f"{fmap}({pin_num}, {periph.lower()}, {signal.lower()}, {function.lower()})" 125 f.write(f"{define} \\\n\t{define_val}\n") 126 127 128def generate_bflb_bl_header(outdir, family, fmap, serie, pin_cfgs): 129 """Generate Bouffalo Lab header with pin configurations. 130 131 Args: 132 outdir: Output base directory. 133 family: Bouffalo Lab family. 134 fmap: Function to map pinctrl. 135 series: MCU Series. 136 pin_cfgs: Pin configurations. 137 """ 138 139 sname = get_header_fname(serie) 140 sname_norm = sname.replace(".", "_") 141 sname_norm = sname_norm.replace("-", "_") 142 sname_norm = sname_norm.upper() 143 ofname = outdir / sname 144 with open(ofname, "w") as f: 145 f.write(HEADER) 146 f.write(f"\n#ifndef DT_BINDINGS_PINCTRL_BFLB_{sname_norm}_") 147 f.write(f"\n#define DT_BINDINGS_PINCTRL_BFLB_{sname_norm}_\n") 148 f.write(f"\n#include <dt-bindings/pinctrl/{family}-pinctrl.h>") 149 f.write("\n#include <dt-bindings/pinctrl/bflb-common-pinctrl.h>\n") 150 151 for port, pin_num, periph, signal, function in pin_cfgs: 152 write_periph_function(f, port, pin_num, periph, str(signal), fmap, function) 153 154 f.write(f"\n#endif /* DT_BINDINGS_PINCTRL_BFLB_{sname_norm}_ */\n") 155 156 157def build_bflb_bl_sets(pin_cfgs, pin, pin_lst, serie, function): 158 """Build Bouffalo Lab pin configurations sets. 159 160 Args: 161 pin_cfgs: Pin Configuration. 162 pin: Pin description. 163 pin_lst: Pins List. 164 serie: MCU Serie. 165 function: Function of the pin. 166 167 Returns: 168 Dictionary with pins configuration. 169 """ 170 171 if len(pin_lst[0]) > 0: 172 for periph, signals in pin_lst: 173 port, pin_num = get_port_pin(pin) 174 175 for signal in signals: 176 pin_cfgs.append((port, pin_num, periph, signal, function)) 177 178 179def build_bflb_bl_pin_cfgs(serie, pins): 180 """Build Bouffalo Lab BLxxx pin configurations. 181 182 Args: 183 serie: MCU Series. 184 pins: Pins description. 185 186 Returns: 187 Dictionary with pins configuration. 188 """ 189 190 pin_cfgs = [] 191 192 pins = OrderedDict(natsorted(pins.items(), key=lambda kv: kv[0])) 193 194 for pin, pin_cfg in pins.items(): 195 if serie not in pin_cfg["series"]: 196 continue 197 198 if "periph" in pin_cfg.keys(): 199 build_bflb_bl_sets(pin_cfgs, pin, pin_cfg["periph"], serie, "periph") 200 if "analog" in pin_cfg.keys(): 201 build_bflb_bl_sets(pin_cfgs, pin, pin_cfg["analog"], serie, "analog") 202 if "input" in pin_cfg.keys(): 203 build_bflb_bl_sets(pin_cfgs, pin, pin_cfg["input"], serie, "input") 204 if "output" in pin_cfg.keys(): 205 build_bflb_bl_sets(pin_cfgs, pin, pin_cfg["output"], serie, "output") 206 207 return pin_cfgs 208 209 210def generate_bflb_generate_signal_list(pins): 211 signal_cfgs = [] 212 213 for _, pin_cfg in pins.items(): 214 for prop, periph_signal_lst in pin_cfg.items(): 215 if prop == "series": 216 continue 217 for _, signal_lst in periph_signal_lst: 218 for signal in signal_lst: 219 if signal not in signal_cfgs: 220 signal_cfgs.append(signal) 221 222 signal_cfgs = natsorted(signal_cfgs, key=lambda kv: kv[0]) 223 224 return signal_cfgs 225 226 227def main(indir, outdir) -> None: 228 """Entry point. 229 230 Args: 231 indir: Directory with pin configuration files. 232 outdir: Output directory 233 """ 234 235 if outdir.exists(): 236 for entry in outdir.glob("bl*-pinctrl.h"): 237 entry.unlink() 238 else: 239 outdir.mkdir() 240 241 for entry in indir.iterdir(): 242 if not entry.is_file() or entry.suffix not in (".yml", ".yaml"): 243 continue 244 245 config = yaml.load(open(entry), Loader=yaml.Loader) 246 247 model = config["model"] 248 family = config["family"] 249 fmap = config["map"] 250 series = config["series"] 251 peripherals = config["peripherals"] 252 signals = config["signals"] 253 pins = config["pins"] 254 255 if model == "bflb,bl": 256 signal_cfgs = generate_bflb_generate_signal_list(pins) 257 signals = OrderedDict(natsorted(signals, key=lambda kv: kv[0])) 258 generate_bflb_series_header(outdir, family, peripherals, signals, signal_cfgs) 259 for serie in series: 260 pin_cfgs = build_bflb_bl_pin_cfgs(serie, pins) 261 generate_bflb_bl_header(outdir, family, fmap, serie, pin_cfgs) 262 else: 263 raise ValueError(f"Unexpected model: {model}") 264 265 266if __name__ == "__main__": 267 parser = argparse.ArgumentParser() 268 parser.add_argument( 269 "-i", 270 "--indir", 271 type=Path, 272 default=REPO_ROOT / "pinconfigs", 273 help="Directory with pin configuration files", 274 ) 275 parser.add_argument( 276 "-o", 277 "--outdir", 278 type=Path, 279 default=REPO_ROOT / "include" / "zephyr" / "dt-bindings" / "pinctrl", 280 help="Output directory", 281 ) 282 args = parser.parse_args() 283 284 main(args.indir, args.outdir) 285