diff --git a/boards/arm/gd32f403z_eval/CMakeLists.txt b/boards/arm/gd32f403z_eval/CMakeLists.txt deleted file mode 100644 index 159b5bc2592c9..0000000000000 --- a/boards/arm/gd32f403z_eval/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() -zephyr_library_sources(board.c) diff --git a/boards/arm/gd32f403z_eval/board.c b/boards/arm/gd32f403z_eval/board.c deleted file mode 100644 index 9786e5339e5c0..0000000000000 --- a/boards/arm/gd32f403z_eval/board.c +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2021 ATL Electronics - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -static int board_init(const struct device *dev) -{ - rcu_periph_clock_enable(RCU_GPIOA); - - gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); - gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); - - return 0; -} - -SYS_INIT(board_init, PRE_KERNEL_1, CONFIG_BOARD_INIT_PRIORITY); diff --git a/boards/arm/gd32f403z_eval/gd32f403z_eval-pinctrl.dtsi b/boards/arm/gd32f403z_eval/gd32f403z_eval-pinctrl.dtsi new file mode 100644 index 0000000000000..bcd17d6692cc8 --- /dev/null +++ b/boards/arm/gd32f403z_eval/gd32f403z_eval-pinctrl.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021, Teslabs Engineering S.L. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + usart0_default: usart0_default { + group1 { + pinmux = , ; + }; + }; +}; diff --git a/boards/arm/gd32f403z_eval/gd32f403z_eval.dts b/boards/arm/gd32f403z_eval/gd32f403z_eval.dts index 6dda970076793..29ba67b12a717 100644 --- a/boards/arm/gd32f403z_eval/gd32f403z_eval.dts +++ b/boards/arm/gd32f403z_eval/gd32f403z_eval.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include "gd32f403z_eval-pinctrl.dtsi" / { model = "GigaDevice GD32F403Z Evaluation Kit"; @@ -21,6 +22,7 @@ &usart0 { status = "okay"; - current-speed = <115200>; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; }; diff --git a/boards/arm/gd32f450i_eval/CMakeLists.txt b/boards/arm/gd32f450i_eval/CMakeLists.txt deleted file mode 100644 index abca855a4b82a..0000000000000 --- a/boards/arm/gd32f450i_eval/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021, Teslabs Engineering S.L. -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() -zephyr_library_sources(board.c) diff --git a/boards/arm/gd32f450i_eval/board.c b/boards/arm/gd32f450i_eval/board.c deleted file mode 100644 index 28555ee344c73..0000000000000 --- a/boards/arm/gd32f450i_eval/board.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2021, Teslabs Engineering S.L. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -static int board_init(const struct device *dev) -{ - rcu_periph_clock_enable(RCU_GPIOA); - - /* PA9: USART0 TX */ - gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9); - gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9); - gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_9); - - /* PA10: USART0 RX */ - gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10); - gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10); - gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_10); - - rcu_periph_clock_disable(RCU_GPIOA); - - return 0; -} - -SYS_INIT(board_init, PRE_KERNEL_1, CONFIG_BOARD_INIT_PRIORITY); diff --git a/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi b/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi new file mode 100644 index 0000000000000..3ba9e064d4765 --- /dev/null +++ b/boards/arm/gd32f450i_eval/gd32f450i_eval-pinctrl.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021, Teslabs Engineering S.L. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + usart0_default: usart0_default { + group1 { + pinmux = , ; + }; + }; +}; diff --git a/boards/arm/gd32f450i_eval/gd32f450i_eval.dts b/boards/arm/gd32f450i_eval/gd32f450i_eval.dts index 56d6757461cf0..729468a5cca5b 100644 --- a/boards/arm/gd32f450i_eval/gd32f450i_eval.dts +++ b/boards/arm/gd32f450i_eval/gd32f450i_eval.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include "gd32f450i_eval-pinctrl.dtsi" / { model = "GigaDevice GD32F450I-EVAL"; @@ -22,4 +23,6 @@ &usart0 { status = "okay"; current-speed = <115200>; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; }; diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index cd3eca95d8d74..4bee9b55c8a71 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_library() zephyr_library_sources(common.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AF pinctrl_gd32_af.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AFIO pinctrl_gd32_afio.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 7e1a67175b84c..7744ea475b002 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -29,4 +29,6 @@ config PINCTRL_DYNAMIC runtime. This can be useful, for example, to change the pins assigned to a peripheral at early boot stages depending on a certain input. +source "drivers/pinctrl/Kconfig.gd32" + endif # PINCTRL diff --git a/drivers/pinctrl/Kconfig.gd32 b/drivers/pinctrl/Kconfig.gd32 new file mode 100644 index 0000000000000..7822033f0169e --- /dev/null +++ b/drivers/pinctrl/Kconfig.gd32 @@ -0,0 +1,21 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AF := gd,gd32-pinctrl-af +DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AFIO := gd,gd32-pinctrl-afio + +config PINCTRL_GD32_AF + bool "GD32 AF pin controller driver" + depends on SOC_FAMILY_GD32 && GD32_HAS_AF_PINMUX + default $(dt_compat_enabled,$(DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AF)) + help + GD32 AF pin controller driver. This driver is used by series using the + AF pin multiplexing model. + +config PINCTRL_GD32_AFIO + bool "GD32 AFIO pin controller driver" + depends on SOC_FAMILY_GD32 && GD32_HAS_AFIO_PINMUX + default $(dt_compat_enabled,$(DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AFIO)) + help + GD32 AFIO pin controller driver. This driver is used by series using the + AFIO pin multiplexing model. diff --git a/drivers/pinctrl/pinctrl_gd32_af.c b/drivers/pinctrl/pinctrl_gd32_af.c new file mode 100644 index 0000000000000..d86b36e2e0ddc --- /dev/null +++ b/drivers/pinctrl/pinctrl_gd32_af.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2021 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +BUILD_ASSERT((GD32_PUPD_NONE == GPIO_PUPD_NONE) && + (GD32_PUPD_PULLUP == GPIO_PUPD_PULLUP) && + (GD32_PUPD_PULLDOWN == GPIO_PUPD_PULLDOWN), + "pinctrl pull-up/down definitions != HAL definitions"); + +BUILD_ASSERT((GD32_OTYPE_PP == GPIO_OTYPE_PP) && + (GD32_OTYPE_OD == GPIO_OTYPE_OD), + "pinctrl output type definitions != HAL definitions"); + +BUILD_ASSERT((GD32_OSPEED_2MHZ == GPIO_OSPEED_2MHZ) && + (GD32_OSPEED_25MHZ == GPIO_OSPEED_25MHZ) && + (GD32_OSPEED_50MHZ == GPIO_OSPEED_50MHZ) && + (GD32_OSPEED_200MHZ == GPIO_OSPEED_200MHZ), + "pinctrl output speed definitions != HAL definitions"); + +/** Utility macro that expands to the GPIO port address if it exists */ +#define GD32_PORT_ADDR_OR_NONE(nodelabel) \ + COND_CODE_1(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \ + (DT_REG_ADDR(DT_NODELABEL(nodelabel)),), ()) + +/** Utility macro that expands to the GPIO RCU if it exists */ +#define GD32_PORT_RCU_OR_NONE(nodelabel) \ + COND_CODE_1(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \ + (DT_PROP(DT_NODELABEL(nodelabel), rcu_periph_clock),), ()) + +/** GD32 port addresses */ +static const uint32_t gd32_port_addrs[] = { + GD32_PORT_ADDR_OR_NONE(gpioa) + GD32_PORT_ADDR_OR_NONE(gpiob) + GD32_PORT_ADDR_OR_NONE(gpioc) + GD32_PORT_ADDR_OR_NONE(gpiod) + GD32_PORT_ADDR_OR_NONE(gpioe) + GD32_PORT_ADDR_OR_NONE(gpiof) + GD32_PORT_ADDR_OR_NONE(gpiog) + GD32_PORT_ADDR_OR_NONE(gpioh) + GD32_PORT_ADDR_OR_NONE(gpioi) +}; + +/** GD32 port RCUs */ +static const uint32_t gd32_port_rcus[] = { + GD32_PORT_RCU_OR_NONE(gpioa) + GD32_PORT_RCU_OR_NONE(gpiob) + GD32_PORT_RCU_OR_NONE(gpioc) + GD32_PORT_RCU_OR_NONE(gpiod) + GD32_PORT_RCU_OR_NONE(gpioe) + GD32_PORT_RCU_OR_NONE(gpiof) + GD32_PORT_RCU_OR_NONE(gpiog) + GD32_PORT_RCU_OR_NONE(gpioh) + GD32_PORT_RCU_OR_NONE(gpioi) +}; + +/** + * @brief Configure a pin. + * + * @param pin The pin to configure. + */ +static void pinctrl_configure_pin(pinctrl_soc_pin_t pin) +{ + uint8_t port_idx; + uint32_t rcu, port, pin_num, af, mode; + + port_idx = GD32_PORT_GET(pin); + __ASSERT_NO_MSG(port_idx < ARRAY_SIZE(gd32_port_addrs)); + + rcu = gd32_port_rcus[port_idx]; + port = gd32_port_addrs[port_idx]; + pin_num = BIT(GD32_PIN_GET(pin)); + af = GD32_AF_GET(pin); + + rcu_periph_clock_enable(rcu); + + if (af != GD32_ANALOG) { + mode = GPIO_MODE_AF; + gpio_af_set(port, af, pin_num); + } else { + mode = GPIO_MODE_ANALOG; + } + + gpio_mode_set(port, mode, GD32_PUPD_GET(pin), pin_num); + gpio_output_options_set(port, GD32_OTYPE_GET(pin), + GD32_OSPEED_GET(pin), pin_num); + + rcu_periph_clock_disable(rcu); +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, + uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (uint8_t i = 0U; i < pin_cnt; i++) { + pinctrl_configure_pin(pins[i]); + } + + return 0; +} diff --git a/drivers/pinctrl/pinctrl_gd32_afio.c b/drivers/pinctrl/pinctrl_gd32_afio.c new file mode 100644 index 0000000000000..409d0c4f012ae --- /dev/null +++ b/drivers/pinctrl/pinctrl_gd32_afio.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2021 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/** AFIO DT node */ +#define AFIO_NODE DT_NODELABEL(afio) + +/** GPIO mode: input floating (CTL bits) */ +#define GPIO_MODE_INP_FLOAT 0x4U +/** GPIO mode: input with pull-up/down (CTL bits) */ +#define GPIO_MODE_INP_PUPD 0x8U +/** GPIO mode: output push-pull (CTL bits) */ +#define GPIO_MODE_ALT_PP 0x8U +/** GPIO mode: output open-drain (CTL bits) */ +#define GPIO_MODE_ALT_OD 0xCU + +/** Utility macro that expands to the GPIO port address if it exists */ +#define GD32_PORT_ADDR_OR_NONE(nodelabel) \ + COND_CODE_1(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \ + (DT_REG_ADDR(DT_NODELABEL(nodelabel)),), ()) + +/** Utility macro that expands to the GPIO RCU if it exists */ +#define GD32_PORT_RCU_OR_NONE(nodelabel) \ + COND_CODE_1(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \ + (DT_PROP(DT_NODELABEL(nodelabel), rcu_periph_clock),), ()) + +/** GD32 port addresses */ +static const uint32_t gd32_port_addrs[] = { + GD32_PORT_ADDR_OR_NONE(gpioa) + GD32_PORT_ADDR_OR_NONE(gpiob) + GD32_PORT_ADDR_OR_NONE(gpioc) + GD32_PORT_ADDR_OR_NONE(gpiod) + GD32_PORT_ADDR_OR_NONE(gpioe) + GD32_PORT_ADDR_OR_NONE(gpiof) + GD32_PORT_ADDR_OR_NONE(gpiog) +}; + +/** GD32 port RCUs */ +static const uint32_t gd32_port_rcus[] = { + GD32_PORT_RCU_OR_NONE(gpioa) + GD32_PORT_RCU_OR_NONE(gpiob) + GD32_PORT_RCU_OR_NONE(gpioc) + GD32_PORT_RCU_OR_NONE(gpiod) + GD32_PORT_RCU_OR_NONE(gpioe) + GD32_PORT_RCU_OR_NONE(gpiof) + GD32_PORT_RCU_OR_NONE(gpiog) +}; + +/** + * @brief Initialize AFIO + * + * This function enables AFIO clock and configures the I/O compensation if + * available and enabled in Devicetree. + * + * @retval 0 Always + */ +static int afio_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + rcu_periph_clock_enable(DT_PROP(AFIO_NODE, rcu_periph_clock)); + +#ifdef AFIO_CPSCTL + if (DT_PROP(AFIO_NODE, enable_cps)) { + gpio_compensation_config(GPIO_COMPENSATION_ENABLE); + while (gpio_compensation_flag_get() == RESET) + ; + } +#endif /* AFIO_CPSCTL */ + + return 0; +} + +SYS_INIT(afio_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +/** + * @brief Helper function to configure the SPD register if available. + * + * @param port GPIO port address. + * @param pin_bit GPIO pin, set as bit position. + * @param speed GPIO speed. + * + * @return Value of the mode register (speed) that should be set later. + */ +static inline uint8_t configure_spd(uint32_t port, uint32_t pin_bit, + uint8_t speed) +{ + switch (speed) { + case GD32_OSPEED_MAX: +#ifdef GPIOx_SPD + GPIOx_SPD(port) |= pin_bit; +#endif /* GPIOx_SPD */ + return speed; + default: +#ifdef GPIOx_SPD + GPIOx_SPD(port) &= ~pin_bit; +#endif /* GPIOx_SPD */ + return speed + 1U; + } +} + +/** + * @brief Configure a pin. + * + * @param pin The pin to configure. + */ +static void configure_pin(pinctrl_soc_pin_t pin) +{ + uint8_t port_idx, mode, pin_num; + uint32_t rcu, port, pin_bit, reg_val; + volatile uint32_t *reg; + + port_idx = GD32_PORT_GET(pin); + __ASSERT_NO_MSG(port_idx < ARRAY_SIZE(gd32_port_addrs)); + + rcu = gd32_port_rcus[port_idx]; + port = gd32_port_addrs[port_idx]; + pin_num = GD32_PIN_GET(pin); + pin_bit = BIT(pin_num); + mode = GD32_MODE_GET(pin); + + if (pin_num < 8U) { + reg = &GPIO_CTL0(port); + } else { + reg = &GPIO_CTL1(port); + pin_num -= 8U; + } + + rcu_periph_clock_enable(rcu); + + reg_val = *reg; + reg_val &= ~GPIO_MODE_MASK(pin_num); + + if (mode == GD32_MODE_ALTERNATE) { + uint8_t mode; + + mode = configure_spd(port, pin_bit, GD32_OSPEED_GET(pin)); + + if (GD32_OTYPE_GET(pin) == GD32_OTYPE_PP) { + mode |= GPIO_MODE_ALT_PP; + } else { + mode |= GPIO_MODE_ALT_OD; + } + + reg_val |= GPIO_MODE_SET(pin_num, mode); + } else if (mode == GD32_MODE_GPIO_IN) { + uint8_t pupd = GD32_PUPD_GET(pin); + + if (pupd == GD32_PUPD_NONE) { + reg_val |= GPIO_MODE_SET(pin_num, GPIO_MODE_INP_FLOAT); + } else { + reg_val |= GPIO_MODE_SET(pin_num, GPIO_MODE_INP_PUPD); + + if (pupd == GD32_PUPD_PULLDOWN) { + GPIO_BC(port) = pin_bit; + } else if (pupd == GD32_PUPD_PULLUP) { + GPIO_BOP(port) = pin_bit; + } + } + } + + *reg = reg_val; + + rcu_periph_clock_disable(rcu); +} + +/** + * @brief Configure remap. + * + * @param remap Remap bit field as encoded by #GD32_REMAP. + */ +static void configure_remap(uint16_t remap) +{ + uint8_t pos; + uint32_t reg_val; + volatile uint32_t *reg; + + /* not remappable */ + if (remap == GD32_NORMP) { + return; + } + + if (GD32_REMAP_REG_GET(remap) == 0U) { + reg = &AFIO_PCF0; + } else { + reg = &AFIO_PCF1; + } + + pos = GD32_REMAP_POS_GET(remap); + + reg_val = *reg; + reg_val &= ~(GD32_REMAP_MSK_GET(remap) << pos); + reg_val |= GD32_REMAP_VAL_GET(remap) << pos; + *reg = reg_val; +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, + uintptr_t reg) +{ + ARG_UNUSED(reg); + + if (pin_cnt == 0U) { + return -EINVAL; + } + + /* same remap is encoded in all pins, so just pick the first */ + configure_remap(GD32_REMAP_GET(pins[0])); + + /* configure all pins */ + for (uint8_t i = 0U; i < pin_cnt; i++) { + configure_pin(pins[i]); + } + + return 0; +} diff --git a/drivers/serial/usart_gd32.c b/drivers/serial/usart_gd32.c index 012824a7c202f..16486ef769b25 100644 --- a/drivers/serial/usart_gd32.c +++ b/drivers/serial/usart_gd32.c @@ -5,11 +5,13 @@ #define DT_DRV_COMPAT gd_gd32_usart +#include #include struct gd32_usart_config { uint32_t reg; uint32_t rcu_periph_clock; + const struct pinctrl_dev_config *pcfg; }; struct gd32_usart_data { @@ -20,8 +22,12 @@ static int usart_gd32_init(const struct device *dev) { const struct gd32_usart_config *const cfg = dev->config; struct gd32_usart_data *const data = dev->data; + int ret; - /* NOTE: pins are configured at board_init till pinctrl be available */ + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } rcu_periph_clock_enable(cfg->rcu_periph_clock); usart_deinit(cfg->reg); @@ -100,12 +106,14 @@ static const struct uart_driver_api usart_gd32_driver_api = { }; #define GD32_USART_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n) \ static struct gd32_usart_data usart##n##_gd32_data = { \ .baud_rate = DT_INST_PROP(n, current_speed), \ }; \ static const struct gd32_usart_config usart##n##_gd32_config = { \ .reg = DT_INST_REG_ADDR(n), \ .rcu_periph_clock = DT_INST_PROP(n, rcu_periph_clock), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ }; \ DEVICE_DT_INST_DEFINE(n, &usart_gd32_init, \ NULL, \ diff --git a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi index c6b81fea778c9..9aa5ea2e09711 100644 --- a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi +++ b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi @@ -46,6 +46,79 @@ }; }; + afio: afio@40010000 { + compatible = "gd,gd32-afio"; + reg = <0x40010000 0x400>; + rcu-periph-clock = <0x600>; + status = "okay"; + label = "AFIO"; + }; + + pinctrl: pin-controller@40010800 { + compatible = "gd,gd32-pinctrl-afio"; + reg = <0x40010800 0x1c00>; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + label = "PINCTRL"; + + gpioa: gpio@40010800 { + compatible = "gd,gd32-gpio"; + reg = <0x40010800 0x400>; + rcu-periph-clock = <0x602>; + status = "disabled"; + label = "GPIOA"; + }; + + gpiob: gpio@40010c00 { + compatible = "gd,gd32-gpio"; + reg = <0x40010c00 0x400>; + rcu-periph-clock = <0x603>; + status = "disabled"; + label = "GPIOB"; + }; + + gpioc: gpio@40011000 { + compatible = "gd,gd32-gpio"; + reg = <0x40011000 0x400>; + rcu-periph-clock = <0x604>; + status = "disabled"; + label = "GPIOC"; + }; + + gpiod: gpio@40011400 { + compatible = "gd,gd32-gpio"; + reg = <0x40011400 0x400>; + rcu-periph-clock = <0x605>; + status = "disabled"; + label = "GPIOD"; + }; + + gpioe: gpio@40011800 { + compatible = "gd,gd32-gpio"; + reg = <0x40011800 0x400>; + rcu-periph-clock = <0x606>; + status = "disabled"; + label = "GPIOE"; + }; + + gpiof: gpio@40011c00 { + compatible = "gd,gd32-gpio"; + reg = <0x40011c00 0x400>; + rcu-periph-clock = <0x607>; + status = "disabled"; + label = "GPIOF"; + }; + + gpiog: gpio@40012000 { + compatible = "gd,gd32-gpio"; + reg = <0x40012000 0x400>; + rcu-periph-clock = <0x608>; + status = "disabled"; + label = "GPIOG"; + }; + }; + usart0: usart@40013800 { compatible = "gd,gd32-usart"; reg = <0x40013800 0x400>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi index 6dd0d177dd9a1..f85500e262d20 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi +++ b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi @@ -53,6 +53,87 @@ status = "disabled"; label = "USART0"; }; + + pinctrl: pin-controller@40020000 { + compatible = "gd,gd32-pinctrl-af"; + reg = <0x40020000 0x2400>; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + label = "PINCTRL"; + + gpioa: gpio@40020000 { + compatible = "gd,gd32-gpio"; + reg = <0x40020000 0x400>; + rcu-periph-clock = <0xc00>; + status = "disabled"; + label = "GPIOA"; + }; + + gpiob: gpio@40020400 { + compatible = "gd,gd32-gpio"; + reg = <0x40020400 0x400>; + rcu-periph-clock = <0xc01>; + status = "disabled"; + label = "GPIOB"; + }; + + gpioc: gpio@40020800 { + compatible = "gd,gd32-gpio"; + reg = <0x40020800 0x400>; + rcu-periph-clock = <0xc02>; + status = "disabled"; + label = "GPIOC"; + }; + + gpiod: gpio@40020c00 { + compatible = "gd,gd32-gpio"; + reg = <0x40020c00 0x400>; + rcu-periph-clock = <0xc03>; + status = "disabled"; + label = "GPIOD"; + }; + + gpioe: gpio@40021000 { + compatible = "gd,gd32-gpio"; + reg = <0x40021000 0x400>; + rcu-periph-clock = <0xc04>; + status = "disabled"; + label = "GPIOE"; + }; + + gpiof: gpio@40021400 { + compatible = "gd,gd32-gpio"; + reg = <0x40021400 0x400>; + rcu-periph-clock = <0xc05>; + status = "disabled"; + label = "GPIOF"; + }; + + gpiog: gpio@40021800 { + compatible = "gd,gd32-gpio"; + reg = <0x40021800 0x400>; + rcu-periph-clock = <0xc06>; + status = "disabled"; + label = "GPIOG"; + }; + + gpioh: gpio@40021c00 { + compatible = "gd,gd32-gpio"; + reg = <0x40021c00 0x400>; + rcu-periph-clock = <0xc07>; + status = "disabled"; + label = "GPIOH"; + }; + + gpioi: gpio@40022000 { + compatible = "gd,gd32-gpio"; + reg = <0x40022000 0x400>; + rcu-periph-clock = <0xc08>; + status = "disabled"; + label = "GPIOI"; + }; + }; }; }; diff --git a/dts/bindings/gpio/gd,gd32-gpio.yaml b/dts/bindings/gpio/gd,gd32-gpio.yaml new file mode 100644 index 0000000000000..36c9ef1e6be3c --- /dev/null +++ b/dts/bindings/gpio/gd,gd32-gpio.yaml @@ -0,0 +1,27 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: GD32 GPIO node + +compatible: "gd,gd32-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + label: + required: true + + rcu-periph-clock: + type: int + description: Reset Control Unit Peripheral Clock ID + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/pinctrl/gd,gd32-afio.yaml b/dts/bindings/pinctrl/gd,gd32-afio.yaml new file mode 100644 index 0000000000000..f47b541c89f27 --- /dev/null +++ b/dts/bindings/pinctrl/gd,gd32-afio.yaml @@ -0,0 +1,30 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: | + The AFIO peripheral is used to configure pin remapping, EXTI sources and, + when available, enable the I/O compensation cell. + +compatible: "gd,gd32-afio" + +include: base.yaml + +properties: + reg: + required: true + + label: + required: true + + rcu-periph-clock: + type: int + description: Reset Control Unit Peripheral Clock ID + required: true + + enable-cps: + required: false + type: boolean + description: | + Enable the I/O compensation cell. This option should be enabled when the + output speed is greater than 50MHz to reduce the I/O noise effects on + the power supply. This option is only available on certain GD32 series. diff --git a/dts/bindings/pinctrl/gd,gd32-pinctrl-af.yaml b/dts/bindings/pinctrl/gd,gd32-pinctrl-af.yaml new file mode 100644 index 0000000000000..2089e72b26101 --- /dev/null +++ b/dts/bindings/pinctrl/gd,gd32-pinctrl-af.yaml @@ -0,0 +1,111 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: | + The GD32 pin controller (AF model) is a singleton node responsible for + controlling pin function selection and pin properties. For example, you can + use this node to route USART0 RX to pin PA10 and enable the pull-up resistor + on the pin. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as shown in this example: + + /* You can put this in places like a board-pinctrl.dtsi file in + * your board directory, or a devicetree overlay in your application. + */ + + /* include pre-defined combinations for the SoC variant used by the board */ + #include + + &pinctrl { + /* configuration for the usart0 "default" state */ + usart0_default: usart0_default { + /* group 1 */ + group1 { + /* configure PA9 as USART0 TX and PA11 as USART0 CTS */ + pinmux = , ; + }; + /* group 2 */ + group2 { + /* configure PA10 as USART0 RX and PA12 as USART0 RTS */ + pinmux = , ; + /* both PA10 and PA12 have pull-up enabled */ + bias-pull-up; + }; + + /* configuration for the usart0 "sleep" state */ + usart0_sleep: usart0_sleep { + /* group 1 */ + group1 { + /* configure PA9, PA10, PA11 and PA12 in analog mode */ + pinmux = , , , ; + }; + }; + + The 'usart0_default' child node encodes the pin configurations for a + particular state of a device; in this case, the default (that is, active) + state. Similarly, 'usart0_sleep' child node encodes the pin configurations + for the sleep state (used in device low power mode). Note that analog mode + is used for low power states because it disconnects the pin pull-up/down + resistor, schmitt trigger, and output buffer. + + As shown, pin configurations are organized in groups within each child node. + Each group can specify a list of pin function selections in the 'pinmux' + property. + + A group can also specify shared pin properties common to all the specified + pins, such as the 'bias-pull-up' property in group 2. Here is a list of + supported standard pin properties: + + - drive-push-pull: Push-pull drive mode (default, not required). + - drive-open-drain: Open-drain drive mode. + - bias-disable: Disable pull-up/down (default, not required). + - bias-pull-up: Enable pull-up resistor. + - bias-pull-down: Enable pull-down resistor. + - slew-rate: Set the maximum speed (and so the slew-rate) of the output + signal (default: 2MHz). + + Note that drive and bias options are mutually exclusive. + + To link pin configurations with a device, use a pinctrl-N property for some + number N, like this example you could place in your board's DTS file: + + #include "board-pinctrl.dtsi" + + &usart0 { + pinctrl-0 = <&usart0_default>; + pinctrl-1 = <&usart0_sleep>; + pinctrl-names = "default", "sleep"; + }; + +compatible: "gd,gd32-pinctrl-af" + +include: gd,gd32-pinctrl-common.yaml + +child-binding: + description: | + Each child node defines the configuration for a particular state. + child-binding: + description: | + The grandchild nodes group pins that share the same pin configuration. + properties: + slew-rate: + required: false + type: string + default: "max-speed-2mhz" + enum: + - "max-speed-2mhz" + - "max-speed-25mhz" + - "max-speed-50mhz" + - "max-speed-200mhz" + description: | + Set the maximum speed of a pin. This setting effectively limits the + slew rate of the output signal. Defaults to "max-speed-2mhz", the SoC + default. diff --git a/dts/bindings/pinctrl/gd,gd32-pinctrl-afio.yaml b/dts/bindings/pinctrl/gd,gd32-pinctrl-afio.yaml new file mode 100644 index 0000000000000..265db6112757f --- /dev/null +++ b/dts/bindings/pinctrl/gd,gd32-pinctrl-afio.yaml @@ -0,0 +1,137 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: | + The GD32 pin controller (AFIO model) is a singleton node responsible for + controlling pin function selection and pin properties. For example, you can + use this node to route USART0 RX to pin PA10 and enable the pull-up resistor + on the pin. Remapping is also supported. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as shown in this example: + + /* You can put this in places like a board-pinctrl.dtsi file in + * your board directory, or a devicetree overlay in your application. + */ + + /* include pre-defined combinations for the SoC variant used by the board */ + #include + + &pinctrl { + /* configuration for the usart0 "default" state */ + usart0_default: usart0_default { + /* group 1 */ + group1 { + /* configure PA9 as USART0 TX and PA11 as USART0 CTS (no remap) */ + pinmux = , ; + }; + /* group 2 */ + group2 { + /* configure PA10 as USART0 RX and PA12 as USART0 RTS (no remap) */ + pinmux = , ; + /* both PA10 and PA12 have pull-up enabled */ + bias-pull-up; + }; + + /* configuration for the usart0 "sleep" state */ + usart0_sleep: usart0_sleep { + /* group 1 */ + group1 { + /* configure PA9, PA10, PA11 and PA12 in analog mode */ + pinmux = , , , ; + }; + }; + + The 'usart0_default' child node encodes the pin configurations for a + particular state of a device; in this case, the default (that is, active) + state. Similarly, 'usart0_sleep' child node encodes the pin configurations + for the sleep state (used in device low power mode). Note that analog mode + is used for low power states because it disconnects the pin pull-up/down + resistor, schmitt trigger, and output buffer. + + As shown, pin configurations are organized in groups within each child node. + Each group can specify a list of pin function selections in the 'pinmux' + property. + + A group can also specify shared pin properties common to all the specified + pins, such as the 'bias-pull-up' property in group 2. Here is a list of + supported standard pin properties: + + - drive-push-pull: Push-pull drive mode (default, not required). Only + applies for GPIO_IN mode. + - drive-open-drain: Open-drain drive mode. Only applies for GPIO_IN mode. + - bias-disable: Disable pull-up/down (default, not required). Only applies + for GPIO_IN mode. + - bias-pull-up: Enable pull-up resistor. Only applies for GPIO_IN mode. + - bias-pull-down: Enable pull-down resistor. Only applies for GPIO_IN mode. + - slew-rate: Set the maximum speed (and so the slew-rate) of the output + signal (default: 2MHz). Only applies for ALTERNATE mode. + + Note that drive and bias options are mutually exclusive. + + Peripherals that are remappable will have their pre-defined macros suffixed + with the remap option being selected, for example: + + - CAN0_RX_PA11_NORMP: No remap + - CAN0_RX_PB8_PRMP: Partial remap + - CAN0_RX_PD0_FRMP: Full remap + + It is important that **ALL** pinmux entries share the same remap. For + example: + + &pinctrl { + can0_default: can0_default { + group1 { + pinmux = , ; + /* ^^^^ ^^^^ */ + /* CAN0 pins are remapped choosing the full remap option */ + }; + }; + }; + + To link pin configurations with a device, use a pinctrl-N property for some + number N, like this example you could place in your board's DTS file: + + #include "board-pinctrl.dtsi" + + &usart0 { + pinctrl-0 = <&usart0_default>; + pinctrl-1 = <&usart0_sleep>; + pinctrl-names = "default", "sleep"; + }; + +compatible: "gd,gd32-pinctrl-afio" + +include: gd,gd32-pinctrl-common.yaml + +child-binding: + description: | + Each child node defines the configuration for a particular state. + child-binding: + description: | + The grandchild nodes group pins that share the same pin configuration. + properties: + slew-rate: + required: false + type: string + default: "max-speed-2mhz" + enum: + - "max-speed-10mhz" + - "max-speed-2mhz" + - "max-speed-50mhz" + - "max-speed-highest" + description: | + Set the maximum speed of a pin. This setting effectively limits the + slew rate of the output signal. Defaults to "max-speed-2mhz", the SoC + default. The max-speed-highest option may not be available on all SoC + variants. If selected and not available the 50 MHz maximum speed will + be used instead. Note that usage of max-speed-highest may require + enabling the I/O compensation cell (refer to the gd,gd32-afio binding + for more details). diff --git a/dts/bindings/pinctrl/gd,gd32-pinctrl-common.yaml b/dts/bindings/pinctrl/gd,gd32-pinctrl-common.yaml new file mode 100644 index 0000000000000..c8f1dfbba0082 --- /dev/null +++ b/dts/bindings/pinctrl/gd,gd32-pinctrl-common.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +include: + - name: base.yaml + - name: pincfg-node-group.yaml + child-binding: + child-binding: + property-allowlist: + - drive-push-pull + - drive-open-drain + - bias-disable + - bias-pull-down + - bias-pull-up + +child-binding: + child-binding: + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. The pins should + be defined using pre-defined macros or, alternatively, using the + GD32_PINMUX_AF or GD32_PINMUX_AFIO utility macros depending on the + pinmux model used by the SoC series. diff --git a/dts/bindings/serial/gd,gd32-usart.yaml b/dts/bindings/serial/gd,gd32-usart.yaml index b12eca413276a..1110c3bea3305 100644 --- a/dts/bindings/serial/gd,gd32-usart.yaml +++ b/dts/bindings/serial/gd,gd32-usart.yaml @@ -5,7 +5,7 @@ description: GigaDevice USART compatible: "gd,gd32-usart" -include: uart-controller.yaml +include: [uart-controller.yaml, pinctrl-device.yaml] properties: reg: diff --git a/modules/hal_gigadevice/CMakeLists.txt b/modules/hal_gigadevice/CMakeLists.txt index d19c83fb88a82..9315c9b9a35d5 100644 --- a/modules/hal_gigadevice/CMakeLists.txt +++ b/modules/hal_gigadevice/CMakeLists.txt @@ -17,6 +17,7 @@ zephyr_compile_definitions(${gd32_soc_uc}) # Global includes to be used outside hal_gigadevice zephyr_include_directories(${gd32_cmsis_dir}/include) zephyr_include_directories(${gd32_std_dir}/include) +zephyr_include_directories(${ZEPHYR_HAL_GIGADEVICE_MODULE_DIR}/include) zephyr_library_sources(${gd32_cmsis_dir}/source/system_${CONFIG_SOC_SERIES}.c) diff --git a/modules/hal_gigadevice/Kconfig b/modules/hal_gigadevice/Kconfig index 542c65620dbcc..21c60b0ec6009 100644 --- a/modules/hal_gigadevice/Kconfig +++ b/modules/hal_gigadevice/Kconfig @@ -4,6 +4,16 @@ config ZEPHYR_HAL_GIGADEVICE_MODULE bool +config GD32_HAS_AF_PINMUX + bool + help + This option should be selected if the series use an AF pinmux model. + +config GD32_HAS_AFIO_PINMUX + bool + help + This option should be selected if the series use an AFIO pinmux model. + config HAS_GD32_HAL bool select HAS_CMSIS_CORE if SOC_FAMILY_GD32_ARM diff --git a/soc/arm/gigadevice/CMakeLists.txt b/soc/arm/gigadevice/CMakeLists.txt index 6c5e7b454f67f..e6525b0312829 100644 --- a/soc/arm/gigadevice/CMakeLists.txt +++ b/soc/arm/gigadevice/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright (c) 2021, ATL Electronics # SPDX-License-Identifier: Apache-2.0 +add_subdirectory(common) add_subdirectory(${SOC_SERIES}) diff --git a/soc/arm/gigadevice/Kconfig.defconfig b/soc/arm/gigadevice/Kconfig.defconfig index 1a17f737aec90..72911e9335cc4 100644 --- a/soc/arm/gigadevice/Kconfig.defconfig +++ b/soc/arm/gigadevice/Kconfig.defconfig @@ -1,4 +1,11 @@ # Copyright (c) 2021, ATL Electronics # SPDX-License-Identifier: Apache-2.0 +if SOC_FAMILY_GD32 + source "soc/arm/gigadevice/*/Kconfig.defconfig.series" + +config PINCTRL + default y + +endif # SOC_FAMILY_GD32 diff --git a/soc/arm/gigadevice/common/CMakeLists.txt b/soc/arm/gigadevice/common/CMakeLists.txt new file mode 100644 index 0000000000000..83dce5d012756 --- /dev/null +++ b/soc/arm/gigadevice/common/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) diff --git a/soc/arm/gigadevice/common/pinctrl_soc.h b/soc/arm/gigadevice/common/pinctrl_soc.h new file mode 100644 index 0000000000000..979a9eb465a55 --- /dev/null +++ b/soc/arm/gigadevice/common/pinctrl_soc.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2021 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * Gigadevice SoC specific helpers for pinctrl driver + */ + +#ifndef ZEPHYR_SOC_ARM_GIGADEVICE_COMMON_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_GIGADEVICE_COMMON_PINCTRL_SOC_H_ + +#include +#include + +#ifdef CONFIG_PINCTRL_GD32_AF +#include +#else +#include +#endif /* CONFIG_PINCTRL_GD32_AF */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +/** @brief Type for GD32 pin. + * + * Bits (AF model): + * - 0-12: GD32_PINMUX_AF bit field. + * - 13-25: Reserved. + * - 26-31: Pin configuration bit field (@ref GD32_PINCFG). + * + * Bits (AFIO model): + * - 0-19: GD32_PINMUX_AFIO bit field. + * - 20-25: Reserved. + * - 26-31: Pin configuration bit field (@ref GD32_PINCFG). + */ +typedef uint32_t pinctrl_soc_pin_t; + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param prop Property name. + * @param idx Property entry index. + */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + (DT_PROP_BY_IDX(node_id, prop, idx) | \ + ((GD32_PUPD_PULLUP * DT_PROP(node_id, bias_pull_up)) \ + << GD32_PUPD_POS) | \ + ((GD32_PUPD_PULLDOWN * DT_PROP(node_id, bias_pull_down)) \ + << GD32_PUPD_POS) | \ + ((GD32_OTYPE_OD * DT_PROP(node_id, drive_open_drain)) \ + << GD32_OTYPE_POS) | \ + (DT_ENUM_IDX(node_id, slew_rate) << GD32_OSPEED_POS)), + +/** + * @brief Utility macro to initialize state pins contained in a given property. + * + * @param node_id Node identifier. + * @param prop Property name describing state pins. + */ +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + {DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), \ + DT_FOREACH_PROP_ELEM, pinmux, \ + Z_PINCTRL_STATE_PIN_INIT)} + +/** @endcond */ + +/** + * @name GD32 PUPD (values match the ones in the HAL for AF model). + * @{ + */ + +/** No pull-up/down */ +#define GD32_PUPD_NONE 0U +/** Pull-up */ +#define GD32_PUPD_PULLUP 1U +/** Pull-down */ +#define GD32_PUPD_PULLDOWN 2U + +/** @} */ + +/** + * @name GD32 OTYPE (values match the ones in the HAL for AF model). + * @{ + */ + +/** Push-pull */ +#define GD32_OTYPE_PP 0U +/** Open-drain */ +#define GD32_OTYPE_OD 1U + +/** @} */ + +/** + * @name GD32 OSPEED (values match the ones in the HAL for AF model, mode minus + * one for AFIO model). + * @{ + */ + +#ifdef CONFIG_PINCTRL_GD32_AF +/** Maximum 2MHz */ +#define GD32_OSPEED_2MHZ 0U +/** Maximum 25MHz */ +#define GD32_OSPEED_25MHZ 1U +/** Maximum 50MHz */ +#define GD32_OSPEED_50MHZ 2U +/** Maximum 200MHz */ +#define GD32_OSPEED_200MHZ 3U +#else +/** Maximum 10MHz */ +#define GD32_OSPEED_10MHZ 0U +/** Maximum 2MHz */ +#define GD32_OSPEED_2MHZ 1U +/** Maximum 50MHz */ +#define GD32_OSPEED_50MHZ 2U +/** Maximum speed */ +#define GD32_OSPEED_MAX 3U +#endif /* CONFIG_PINCTRL_GD32_AF */ + +/** @} */ + +/** + * @name GD32 pin configuration bit field mask and positions. + * @anchor GD32_PINCFG + * + * Fields: + * + * - 31..29: Pull-up/down + * - 28: Output type + * - 27..26: Output speed + * + * @{ + */ + +/** PUPD field mask. */ +#define GD32_PUPD_MSK 0x3U +/** PUPD field position. */ +#define GD32_PUPD_POS 29U +/** OTYPE field mask. */ +#define GD32_OTYPE_MSK 0x1U +/** OTYPE field position. */ +#define GD32_OTYPE_POS 28U +/** OSPEED field mask. */ +#define GD32_OSPEED_MSK 0x3U +/** OSPEED field position. */ +#define GD32_OSPEED_POS 26U + +/** @} */ + +/** + * Obtain PUPD field from pinctrl_soc_pin_t configuration. + * + * @param pincfg pinctrl_soc_pin_t bit field value. + */ +#define GD32_PUPD_GET(pincfg) \ + (((pincfg) >> GD32_PUPD_POS) & GD32_PUPD_MSK) + +/** + * Obtain OTYPE field from pinctrl_soc_pin_t configuration. + * + * @param pincfg pinctrl_soc_pin_t bit field value. + */ +#define GD32_OTYPE_GET(pincfg) \ + (((pincfg) >> GD32_OTYPE_POS) & GD32_OTYPE_MSK) + +/** + * Obtain OSPEED field from pinctrl_soc_pin_t configuration. + * + * @param pincfg pinctrl_soc_pin_t bit field value. + */ +#define GD32_OSPEED_GET(pincfg) \ + (((pincfg) >> GD32_OSPEED_POS) & GD32_OSPEED_MSK) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_ARM_GIGADEVICE_COMMON_PINCTRL_SOC_H_ */ diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.series b/soc/arm/gigadevice/gd32f403/Kconfig.series index 9fe193e62c656..c96e1c731dde6 100644 --- a/soc/arm/gigadevice/gd32f403/Kconfig.series +++ b/soc/arm/gigadevice/gd32f403/Kconfig.series @@ -10,5 +10,6 @@ config SOC_SERIES_GD32F403 select CPU_CORTEX_M_HAS_SYSTICK select CPU_CORTEX_M_HAS_VTOR select SOC_FAMILY_GD32_ARM + select GD32_HAS_AFIO_PINMUX help Enable support for GigaDevice GD32F403 MCU series diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.series b/soc/arm/gigadevice/gd32f4xx/Kconfig.series index 7fcfca925816a..722666d91a78f 100644 --- a/soc/arm/gigadevice/gd32f4xx/Kconfig.series +++ b/soc/arm/gigadevice/gd32f4xx/Kconfig.series @@ -8,5 +8,6 @@ config SOC_SERIES_GD32F4XX select CPU_HAS_FPU select CPU_CORTEX_M4 select SOC_FAMILY_GD32_ARM + select GD32_HAS_AF_PINMUX help Enable support for GigaDevice GD32F4XX MCU series diff --git a/tests/drivers/pinctrl/gd32/CMakeLists.txt b/tests/drivers/pinctrl/gd32/CMakeLists.txt new file mode 100644 index 0000000000000..0595ab1980116 --- /dev/null +++ b/tests/drivers/pinctrl/gd32/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(pinctrl_gd32) + +target_sources(app PRIVATE ../common/test_device.c) +if(CONFIG_PINCTRL_GD32_AF) + target_sources(app PRIVATE src/main_af.c) +elseif(CONFIG_PINCTRL_GD32_AFIO) + target_sources(app PRIVATE src/main_afio.c) +endif() diff --git a/tests/drivers/pinctrl/gd32/Kconfig b/tests/drivers/pinctrl/gd32/Kconfig new file mode 100644 index 0000000000000..363b78eff6443 --- /dev/null +++ b/tests/drivers/pinctrl/gd32/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "pinctrl GD32 DT Test" + +source "Kconfig.zephyr" + +config PINCTRL_TEST_NON_STATIC + bool "Enable access to pin control configuration" + select PINCTRL_NON_STATIC + help + This option should be selected by unit tests that need to access the pin + control configuration defined in a device driver. diff --git a/tests/drivers/pinctrl/gd32/boards/gd32f403z_eval.overlay b/tests/drivers/pinctrl/gd32/boards/gd32f403z_eval.overlay new file mode 100644 index 0000000000000..08255bf651750 --- /dev/null +++ b/tests/drivers/pinctrl/gd32/boards/gd32f403z_eval.overlay @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 Teslabs Engineering S.L. + * SPDX-License-Identifier: Apache-2.0 + */ + +#define GD32_TEST_DEVICE_RMP GD32_REMAP(0, 0, 0x1U, 1) + +/ { + test_device: test_device { + compatible = "vnd,pinctrl-device"; + pinctrl-0 = <&test_device_default>; + pinctrl-names = "default"; + }; +}; + +&pinctrl { + test_device_default: test_device_default { + /* Note: the groups are just meant for testing if properties and + pins are parsed correctly, but do not necessarily represent a + feasible combination */ + pins1 { + pinmux = , + , + ; + }; + pins2 { + pinmux = , + ; + }; + pins3 { + pinmux = ; + drive-push-pull; + }; + pins4 { + pinmux = ; + drive-open-drain; + }; + pins5 { + pinmux = ; + bias-disable; + }; + pins6 { + pinmux = ; + bias-pull-up; + }; + pins7 { + pinmux = ; + bias-pull-down; + }; + pins8 { + pinmux = ; + slew-rate = "max-speed-2mhz"; + }; + pins9 { + pinmux = ; + slew-rate = "max-speed-10mhz"; + }; + pins10 { + pinmux = ; + slew-rate = "max-speed-50mhz"; + }; + pins11 { + pinmux = ; + slew-rate = "max-speed-highest"; + }; + }; +}; diff --git a/tests/drivers/pinctrl/gd32/boards/gd32f450i_eval.overlay b/tests/drivers/pinctrl/gd32/boards/gd32f450i_eval.overlay new file mode 100644 index 0000000000000..361605f5d5d2b --- /dev/null +++ b/tests/drivers/pinctrl/gd32/boards/gd32f450i_eval.overlay @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 Teslabs Engineering S.L. + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test_device: test_device { + compatible = "vnd,pinctrl-device"; + pinctrl-0 = <&test_device_default>; + pinctrl-names = "default"; + }; +}; + +&pinctrl { + test_device_default: test_device_default { + /* Note: the groups are just meant for testing if properties and + pins are parsed correctly, but do not necessarily represent a + feasible combination */ + pins1 { + pinmux = , + ; + }; + pins2 { + pinmux = ; + drive-push-pull; + }; + pins3 { + pinmux = ; + drive-open-drain; + }; + pins4 { + pinmux = ; + bias-disable; + }; + pins5 { + pinmux = ; + bias-pull-up; + }; + pins6 { + pinmux = ; + bias-pull-down; + }; + pins7 { + pinmux = ; + slew-rate = "max-speed-2mhz"; + }; + pins8 { + pinmux = ; + slew-rate = "max-speed-25mhz"; + }; + pins9 { + pinmux = ; + slew-rate = "max-speed-50mhz"; + }; + pins10 { + pinmux = ; + slew-rate = "max-speed-200mhz"; + }; + pins11 { + pinmux = ; + }; + }; +}; diff --git a/tests/drivers/pinctrl/gd32/prj.conf b/tests/drivers/pinctrl/gd32/prj.conf new file mode 100644 index 0000000000000..bb844ad2efa15 --- /dev/null +++ b/tests/drivers/pinctrl/gd32/prj.conf @@ -0,0 +1,5 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_PINCTRL_TEST_NON_STATIC=y diff --git a/tests/drivers/pinctrl/gd32/src/main_af.c b/tests/drivers/pinctrl/gd32/src/main_af.c new file mode 100644 index 0000000000000..f38ed74c3b042 --- /dev/null +++ b/tests/drivers/pinctrl/gd32/src/main_af.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2021 Teslabs Engineering S.L. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* pin configuration for test device */ +#define TEST_DEVICE DT_NODELABEL(test_device) +PINCTRL_DT_DEV_CONFIG_DECLARE(TEST_DEVICE); +static const struct pinctrl_dev_config *pcfg = PINCTRL_DT_DEV_CONFIG_GET(TEST_DEVICE); + +static void test_dt_extract(void) +{ + const struct pinctrl_state *scfg; + pinctrl_soc_pin_t pin; + + zassert_equal(pcfg->state_cnt, 1U, NULL); + + scfg = &pcfg->states[0]; + + zassert_equal(scfg->id, PINCTRL_STATE_DEFAULT, NULL); + zassert_equal(scfg->pin_cnt, 12U, NULL); + + pin = scfg->pins[0]; + zassert_equal(GD32_PORT_GET(pin), 0, NULL); + zassert_equal(GD32_PIN_GET(pin), 0, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF0, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[1]; + zassert_equal(GD32_PORT_GET(pin), 1, NULL); + zassert_equal(GD32_PIN_GET(pin), 1, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF1, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[2]; + zassert_equal(GD32_PORT_GET(pin), 2, NULL); + zassert_equal(GD32_PIN_GET(pin), 2, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF2, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[3]; + zassert_equal(GD32_PORT_GET(pin), 0, NULL); + zassert_equal(GD32_PIN_GET(pin), 3, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF3, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_OD, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[4]; + zassert_equal(GD32_PORT_GET(pin), 1, NULL); + zassert_equal(GD32_PIN_GET(pin), 4, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF4, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[5]; + zassert_equal(GD32_PORT_GET(pin), 2, NULL); + zassert_equal(GD32_PIN_GET(pin), 5, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF5, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_PULLUP, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[6]; + zassert_equal(GD32_PORT_GET(pin), 0, NULL); + zassert_equal(GD32_PIN_GET(pin), 6, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF6, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_PULLDOWN, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[7]; + zassert_equal(GD32_PORT_GET(pin), 1, NULL); + zassert_equal(GD32_PIN_GET(pin), 7, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF7, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[8]; + zassert_equal(GD32_PORT_GET(pin), 2, NULL); + zassert_equal(GD32_PIN_GET(pin), 8, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF8, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_25MHZ, NULL); + + pin = scfg->pins[9]; + zassert_equal(GD32_PORT_GET(pin), 0, NULL); + zassert_equal(GD32_PIN_GET(pin), 9, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF9, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_50MHZ, NULL); + + pin = scfg->pins[10]; + zassert_equal(GD32_PORT_GET(pin), 1, NULL); + zassert_equal(GD32_PIN_GET(pin), 10, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_AF10, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_200MHZ, NULL); + + pin = scfg->pins[11]; + zassert_equal(GD32_PORT_GET(pin), 2, NULL); + zassert_equal(GD32_PIN_GET(pin), 11, NULL); + zassert_equal(GD32_AF_GET(pin), GD32_ANALOG, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); +} + +void test_main(void) +{ + ztest_test_suite(pinctrl_gd32, + ztest_unit_test(test_dt_extract)); + ztest_run_test_suite(pinctrl_gd32); +} diff --git a/tests/drivers/pinctrl/gd32/src/main_afio.c b/tests/drivers/pinctrl/gd32/src/main_afio.c new file mode 100644 index 0000000000000..97ad8550eecea --- /dev/null +++ b/tests/drivers/pinctrl/gd32/src/main_afio.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2021 Teslabs Engineering S.L. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* pin configuration for test device */ +#define TEST_DEVICE DT_NODELABEL(test_device) +PINCTRL_DT_DEV_CONFIG_DECLARE(TEST_DEVICE); +static const struct pinctrl_dev_config *pcfg = PINCTRL_DT_DEV_CONFIG_GET(TEST_DEVICE); + +static void test_dt_extract(void) +{ + const struct pinctrl_state *scfg; + pinctrl_soc_pin_t pin; + + zassert_equal(pcfg->state_cnt, 1U, NULL); + + scfg = &pcfg->states[0]; + + zassert_equal(scfg->id, PINCTRL_STATE_DEFAULT, NULL); + zassert_equal(scfg->pin_cnt, 14U, NULL); + + pin = scfg->pins[0]; + zassert_equal(GD32_PORT_GET(pin), 0, NULL); + zassert_equal(GD32_PIN_GET(pin), 0, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_ANALOG, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + + pin = scfg->pins[1]; + zassert_equal(GD32_PORT_GET(pin), 1, NULL); + zassert_equal(GD32_PIN_GET(pin), 1, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_ALTERNATE, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[2]; + zassert_equal(GD32_PORT_GET(pin), 2, NULL); + zassert_equal(GD32_PIN_GET(pin), 2, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_GPIO_IN, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + + pin = scfg->pins[3]; + zassert_equal(GD32_PORT_GET(pin), 0, NULL); + zassert_equal(GD32_PIN_GET(pin), 3, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_GPIO_IN, NULL); + zassert_equal(GD32_REMAP_REG_GET(GD32_REMAP_GET(pin)), 0, NULL); + zassert_equal(GD32_REMAP_POS_GET(GD32_REMAP_GET(pin)), 0, NULL); + zassert_equal(GD32_REMAP_MSK_GET(GD32_REMAP_GET(pin)), 0x1, NULL); + zassert_equal(GD32_REMAP_VAL_GET(GD32_REMAP_GET(pin)), 1, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + + pin = scfg->pins[4]; + zassert_equal(GD32_PORT_GET(pin), 1, NULL); + zassert_equal(GD32_PIN_GET(pin), 4, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_ALTERNATE, NULL); + zassert_equal(GD32_REMAP_REG_GET(GD32_REMAP_GET(pin)), 0, NULL); + zassert_equal(GD32_REMAP_POS_GET(GD32_REMAP_GET(pin)), 0, NULL); + zassert_equal(GD32_REMAP_MSK_GET(GD32_REMAP_GET(pin)), 0x1, NULL); + zassert_equal(GD32_REMAP_VAL_GET(GD32_REMAP_GET(pin)), 1, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[5]; + zassert_equal(GD32_PORT_GET(pin), 2, NULL); + zassert_equal(GD32_PIN_GET(pin), 5, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_GPIO_IN, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + + pin = scfg->pins[6]; + zassert_equal(GD32_PORT_GET(pin), 0, NULL); + zassert_equal(GD32_PIN_GET(pin), 6, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_GPIO_IN, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_OD, NULL); + + pin = scfg->pins[7]; + zassert_equal(GD32_PORT_GET(pin), 1, NULL); + zassert_equal(GD32_PIN_GET(pin), 7, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_GPIO_IN, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_NONE, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + + pin = scfg->pins[8]; + zassert_equal(GD32_PORT_GET(pin), 2, NULL); + zassert_equal(GD32_PIN_GET(pin), 8, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_GPIO_IN, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_PULLUP, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + + pin = scfg->pins[9]; + zassert_equal(GD32_PORT_GET(pin), 0, NULL); + zassert_equal(GD32_PIN_GET(pin), 9, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_GPIO_IN, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_PUPD_GET(pin), GD32_PUPD_PULLDOWN, NULL); + zassert_equal(GD32_OTYPE_GET(pin), GD32_OTYPE_PP, NULL); + + pin = scfg->pins[10]; + zassert_equal(GD32_PORT_GET(pin), 1, NULL); + zassert_equal(GD32_PIN_GET(pin), 10, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_ALTERNATE, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_2MHZ, NULL); + + pin = scfg->pins[11]; + zassert_equal(GD32_PORT_GET(pin), 2, NULL); + zassert_equal(GD32_PIN_GET(pin), 11, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_ALTERNATE, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_10MHZ, NULL); + + pin = scfg->pins[12]; + zassert_equal(GD32_PORT_GET(pin), 0, NULL); + zassert_equal(GD32_PIN_GET(pin), 12, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_ALTERNATE, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_50MHZ, NULL); + + pin = scfg->pins[13]; + zassert_equal(GD32_PORT_GET(pin), 1, NULL); + zassert_equal(GD32_PIN_GET(pin), 13, NULL); + zassert_equal(GD32_MODE_GET(pin), GD32_MODE_ALTERNATE, NULL); + zassert_equal(GD32_REMAP_GET(pin), GD32_NORMP, NULL); + zassert_equal(GD32_OSPEED_GET(pin), GD32_OSPEED_MAX, NULL); +} + +void test_main(void) +{ + ztest_test_suite(pinctrl_gd32, + ztest_unit_test(test_dt_extract)); + ztest_run_test_suite(pinctrl_gd32); +} diff --git a/tests/drivers/pinctrl/gd32/testcase.yaml b/tests/drivers/pinctrl/gd32/testcase.yaml new file mode 100644 index 0000000000000..2d4e164b65196 --- /dev/null +++ b/tests/drivers/pinctrl/gd32/testcase.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +tests: + drivers.pinctrl.gd32_af: + tags: drivers pinctrl + platform_allow: gd32f450i_eval + drivers.pinctrl.gd32_afio: + tags: drivers pinctrl + platform_allow: gd32f403z_eval