pinctrl: Add pinctrl script

Add initial version of pinctrl script. It creates pinctrl definitions
from a well defined pinconfig yaml file. This file is filled with all
I/O multiplexing and considerations for all Atmel SAM SoCs. The auto
generated files produced by this script should be used inside a
<board>-pinctrl.dtsi file to define the pinctrl groups.

Signed-off-by: Gerson Fernando Budke <nandojve@gmail.com>
This commit is contained in:
Gerson Fernando Budke 2022-03-11 18:45:30 -03:00
parent 45cb8f898f
commit 9597144ca1
7 changed files with 454 additions and 0 deletions

View File

@ -1 +1,2 @@
zephyr_include_directories(include)
add_subdirectory(asf)

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2022 Gerson Fernando Budke
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef DT_BINDINGS_PINCTRL_ATMEL_SAM_H_
#define DT_BINDINGS_PINCTRL_ATMEL_SAM_H_
/*
* @name Atmel SAM gpio port list.
* @{
*/
#define SAM_PINMUX_PORT_a 0U
#define SAM_PINMUX_PORT_b 1U
#define SAM_PINMUX_PORT_c 2U
#define SAM_PINMUX_PORT_d 3U
#define SAM_PINMUX_PORT_e 4U
#define SAM_PINMUX_PORT_f 5U
#define SAM_PINMUX_PORT_g 6U
#define SAM_PINMUX_PORT_h 7U
#define SAM_PINMUX_PORT_i 8U
#define SAM_PINMUX_PORT_j 9U
#define SAM_PINMUX_PORT_k 10U
#define SAM_PINMUX_PORT_l 11U
#define SAM_PINMUX_PORT_m 12U
#define SAM_PINMUX_PORT_n 13U
#define SAM_PINMUX_PORT_o 14U
#define SAM_PINMUX_PORT_p 15U
/** @} */
/**
* @name Atmel SAM peripheral list.
* @{
*/
/** GPIO */
#define SAM_PINMUX_PERIPH_gpio 0U
/** Peripherals */
#define SAM_PINMUX_PERIPH_a 0U
#define SAM_PINMUX_PERIPH_b 1U
#define SAM_PINMUX_PERIPH_c 2U
#define SAM_PINMUX_PERIPH_d 3U
#define SAM_PINMUX_PERIPH_e 4U
#define SAM_PINMUX_PERIPH_f 5U
#define SAM_PINMUX_PERIPH_g 6U
#define SAM_PINMUX_PERIPH_h 7U
#define SAM_PINMUX_PERIPH_i 8U
#define SAM_PINMUX_PERIPH_j 9U
#define SAM_PINMUX_PERIPH_k 10U
#define SAM_PINMUX_PERIPH_l 11U
#define SAM_PINMUX_PERIPH_m 12U
#define SAM_PINMUX_PERIPH_n 13U
/** Extra */
#define SAM_PINMUX_PERIPH_x 0U
/** System */
#define SAM_PINMUX_PERIPH_s 0U
/** LPM */
#define SAM_PINMUX_PERIPH_lpm 0U
/** @} */
/**
* @name Atmel SAM pin function list.
* @{
*/
/** Selects pin to be used as GPIO */
#define SAM_PINMUX_FUNC_gpio 0U
/** Selects pin to be used as by some peripheral */
#define SAM_PINMUX_FUNC_periph 1U
/** Selects pin to be used as extra function */
#define SAM_PINMUX_FUNC_extra 2U
/** Selects pin to be used as system function */
#define SAM_PINMUX_FUNC_system 3U
/** Selects and configure pin to be used in Low Power Mode */
#define SAM_PINMUX_FUNC_lpm 4U
/** @} */
/**
* @name Atmel SAM pinmux bit field mask and positions.
* @{
*/
/** Pinmux bit field position. */
#define SAM_PINCTRL_PINMUX_POS (16U)
/** Pinmux bit field mask. */
#define SAM_PINCTRL_PINMUX_MASK (0xFFFF)
/** Port field mask. */
#define SAM_PINMUX_PORT_MSK (0xFU)
/** Port field position. */
#define SAM_PINMUX_PORT_POS (0U)
/** Pin field mask. */
#define SAM_PINMUX_PIN_MSK (0x1FU)
/** Pin field position. */
#define SAM_PINMUX_PIN_POS (SAM_PINMUX_PORT_POS + 4U)
/** Function field mask. */
#define SAM_PINMUX_FUNC_MSK (0x7U)
/** Function field position. */
#define SAM_PINMUX_FUNC_POS (SAM_PINMUX_PIN_POS + 5U)
/** Peripheral field mask. */
#define SAM_PINMUX_PERIPH_MSK (0xFU)
/** Peripheral field position. */
#define SAM_PINMUX_PERIPH_POS (SAM_PINMUX_FUNC_POS + 3U)
/** @} */
/**
* @brief Atmel SAM pinmux bit field.
* @anchor SAM_PINMUX
*
* Fields:
*
* - 0..3: port
* - 4..8: pin_num
* - 9..11: func
* - 12..15: pin_mux
*
* @param port Port ('A'..'P')
* @param pin Pin (0..31)
* @param func Function (GPIO, Peripheral, System, Extra, LPM - 0..4)
* @param pin_mux Peripheral based on the Function selected (0..15)
*/
#define SAM_PINMUX(port, pin_num, pin_mux, func) \
((((SAM_PINMUX_PORT_##port) & SAM_PINMUX_PORT_MSK) \
<< SAM_PINMUX_PORT_POS) | \
(((pin_num) & SAM_PINMUX_PIN_MSK) \
<< SAM_PINMUX_PIN_POS) | \
(((SAM_PINMUX_FUNC_##func) & SAM_PINMUX_FUNC_MSK) \
<< SAM_PINMUX_FUNC_POS) | \
(((SAM_PINMUX_PERIPH_##pin_mux) & SAM_PINMUX_PERIPH_MSK) \
<< SAM_PINMUX_PERIPH_POS))
/**
* Obtain Pinmux value from pinctrl_soc_pin_t configuration.
*
* @param pincfg pinctrl_soc_pin_t bit field value.
*/
#define SAM_PINMUX_GET(pincfg) \
(((pincfg) >> SAM_PINCTRL_PINMUX_POS) & SAM_PINCTRL_PINMUX_MASK)
#define SAM_PINMUX_PORT_GET(pincfg) \
((SAM_PINMUX_GET(pincfg) >> SAM_PINMUX_PORT_POS) \
& SAM_PINMUX_PORT_MSK)
#define SAM_PINMUX_PIN_GET(pincfg) \
((SAM_PINMUX_GET(pincfg) >> SAM_PINMUX_PIN_POS) \
& SAM_PINMUX_PIN_MSK)
#define SAM_PINMUX_FUNC_GET(pincfg) \
((SAM_PINMUX_GET(pincfg) >> SAM_PINMUX_FUNC_POS) \
& SAM_PINMUX_FUNC_MSK)
#define SAM_PINMUX_PERIPH_GET(pincfg) \
((SAM_PINMUX_GET(pincfg) >> SAM_PINMUX_PERIPH_POS) \
& SAM_PINMUX_PERIPH_MSK)
#endif /* DT_BINDINGS_PINCTRL_ATMEL_SAM_H_ */

22
scripts/README.md Normal file
View File

@ -0,0 +1,22 @@
# hal_atmel scripts
This folder contains `hal_atmel` scripts.
# Dependencies
Scripts require Python 3.6+ and the Python dependencies listed in
`requirements.txt`. They can be installed by running:
```
pip install -r scripts/requirements.txt
```
# Lint
Scripts should be formatted using `black` and linted using `flake8`.
Such development tools can be installed using:
```
pip install -r scripts/requirements-dev.txt
```

View File

@ -0,0 +1,2 @@
flake8
black

2
scripts/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
pyyaml
natsort

264
scripts/sampinctrl.py Normal file
View File

@ -0,0 +1,264 @@
# Copyright (c) 2021 Teslabs Engineering S.L.
# Copyright (c) 2022 Gerson Fernando Budke
# SPDX-License-Identifier: Apache-2.0
"""
Utility to autogenerate pinctrl definitions.
Usage::
python3 sampinctrl.py [-i /path/to/configs] [-o /path/to/include]
"""
import argparse
from collections import OrderedDict
from pathlib import Path
import re
from natsort import natsorted
import yaml
REPO_ROOT = Path(__file__).absolute().parents[1]
"""Repository root."""
HEADER = """/*
* Autogenerated file
*
* SPDX-License-Identifier: Apache-2.0
*/
"""
"""Header for the generated files."""
EXCEPTION = """
/*
* WARNING: this variant has package exception.
*
* Read datasheet topics related to I/O Multiplexing and Considerations or
* Peripheral Signal Multiplexing on I/O Lines for more information.
*/
"""
def get_header_fname(serie, variant, revision):
"""Get header file name.
Args:
family: Atmel SAM family.
serie: Series.
variant: Variant information.
Returns:
Header file name.
"""
sufix = ""
if revision:
sufix = f"X{revision}"
return f"sam{serie}{variant}{sufix}-pinctrl.h"
def get_port_pin(pin_name):
"""Obtain port and pin number from a pin name
Args:
pin_name: Pin name, e.g. PA0
Returns:
Port and pin, e.g. A, 0.
"""
m = re.match(r"P([A-Z])(\d+)", pin_name.upper())
if not m:
raise ValueError(f"Unexpected pin name: {pin_name}")
return m.group(1), str(int(m.group(2)))
def write_gpio_function(f, port, pin_num, fmap, function):
f.write(f"\n/* p{port.lower()}{pin_num}_{function.lower()} */\n")
define = f"#define P{port.upper()}{pin_num.upper()}_{function.upper()}"
define_val = f"{fmap}({port.lower()}, {pin_num}, {function.lower()}, " \
f"{function.lower()})"
f.write(f"{define} \\\n\t{define_val}\n")
def write_periph_function(f, port, pin_num, pinmux, periph,
signal, fmap, function):
f.write(f"\n/* p{port.lower()}{pin_num}{pinmux}_{periph}_{signal} "
f"*/\n")
define = f"#define P{port.upper()}{pin_num.upper()}" \
f"{pinmux.upper()}_{periph.upper()}_{signal.upper()}"
define_val = f"{fmap}({port.lower()}, {pin_num}, " \
f"{pinmux.lower()}, {function.lower()})"
f.write(f"{define} \\\n\t{define_val}\n")
def generate_atmel_sam_header(outdir, family, fmap, serie,
variant, pin_cfgs, revision):
"""Generate Atmel SAM header with pin configurations.
Args:
outdir: Output base directory.
family: Atmel SAM family.
fmap: Function to map pinctrl.
series: MCU Series.
variant: Variant information.
pin_cfgs: Pin configurations.
"""
ofname = outdir / get_header_fname(serie, variant["pincode"], revision)
with open(ofname, "w") as f:
f.write(HEADER)
f.write(f'\n{"#include <dt-bindings/pinctrl/atmel_sam_pinctrl.h>"}\n')
if len(variant) > 2:
if variant["exception"]:
f.write(EXCEPTION)
for port, pin_num, pinmux, periph, signal, function in pin_cfgs:
if function in ["gpio", "lpm"]:
write_gpio_function(f, port, pin_num, fmap, function)
else:
write_periph_function(f, port, pin_num, pinmux, periph,
signal, fmap, function)
def build_atmel_sam_gpio_sets(pin_cfgs, pin):
"""Build Atmel SAM pin configurations sets.
Args:
pins: Pins description.
Returns:
Dictionary with pins configuration.
"""
port, pin_num = get_port_pin(pin)
new_item = (port, pin_num, "a", "gpio", "gpio", "gpio")
if new_item not in pin_cfgs:
pin_cfgs.append(new_item)
def build_atmel_sam_sets(pin_cfgs, pin, pin_lst, serie, variant, function):
"""Build Atmel SAM pin configurations sets.
Args:
serie: MCU Serie.
variant: Variant information.
pins: Pins description.
Returns:
Dictionary with pins configuration.
"""
if len(pin_lst[0]) > 0:
for pinmux, periph, signal, *excludes in pin_lst:
if len(excludes) > 0:
if serie in excludes[0]:
continue
if variant["pincode"] in excludes[0]:
continue
port, pin_num = get_port_pin(pin)
pin_cfgs.append((port, pin_num, pinmux, periph, signal, function))
def build_atmel_sam_pin_cfgs(serie, variant, pins):
"""Build Atmel SAM pin configurations.
Args:
serie: MCU Serie.
variant: Variant information.
pins: Pins description.
Returns:
Dictionary with pins configuration.
"""
pin_cfgs = []
pins = OrderedDict(natsorted(pins.items(), key=lambda kv: kv[0]))
for pin, pin_cfg in pins.items():
if variant["pincode"] not in pin_cfg["pincodes"]:
continue
build_atmel_sam_gpio_sets(pin_cfgs, pin)
if "periph" in pin_cfg.keys():
build_atmel_sam_sets(pin_cfgs, pin, pin_cfg["periph"],
serie, variant, "periph")
if "extra" in pin_cfg.keys():
build_atmel_sam_sets(pin_cfgs, pin, pin_cfg["extra"],
serie, variant, "extra")
if "system" in pin_cfg.keys():
build_atmel_sam_sets(pin_cfgs, pin, pin_cfg["system"],
serie, variant, "system")
if "lpm" in pin_cfg.keys():
build_atmel_sam_sets(pin_cfgs, pin, pin_cfg["lpm"],
serie, variant, "lpm")
return pin_cfgs
def main(indir, outdir) -> None:
"""Entry point.
Args:
indir: Directory with pin configuration files.
outdir: Output directory
"""
if outdir.exists():
for entry in outdir.glob("sam*-pinctrl.h"):
entry.unlink()
else:
outdir.mkdir()
for entry in indir.iterdir():
if not entry.is_file() or entry.suffix not in (".yml", ".yaml"):
continue
config = yaml.load(open(entry), Loader=yaml.Loader)
model = config["model"]
family = config["family"]
fmap = config["map"]
series = config["series"]
variants = config["variants"]
has_rev = "revisions" in config.keys()
pins = config["pins"]
if model == "atmel,sam":
for serie in series:
for variant in [v for v in variants if serie in v["series"]]:
pin_cfgs = build_atmel_sam_pin_cfgs(serie, variant, pins)
rev = config["revisions"].get(serie) if has_rev else None
generate_atmel_sam_header(outdir, family, fmap, serie,
variant, pin_cfgs, rev)
else:
raise ValueError(f"Unexpected model: {model}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"-i",
"--indir",
type=Path,
default=REPO_ROOT / "pinconfigs",
help="Directory with pin configuration files",
)
parser.add_argument(
"-o",
"--outdir",
type=Path,
default=REPO_ROOT / "include" / "dt-bindings" / "pinctrl",
help="Output directory",
)
args = parser.parse_args()
main(args.indir, args.outdir)

View File

@ -1,2 +1,4 @@
build:
cmake: .
settings:
dts_root: .