From 543a3843ff798e76e4d007b36b9e6a784222f911 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 1 Nov 2021 21:37:04 +0100 Subject: [PATCH] drivers: pinctrl: gd32: initial support for AF based SoCs Add a pin control driver for GD32 SoCs using the AF model. Signed-off-by: Gerard Marull-Paretas --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 2 + drivers/pinctrl/Kconfig.gd32 | 12 ++ drivers/pinctrl/pinctrl_gd32_af.c | 104 +++++++++++ dts/bindings/gpio/gd,gd32-gpio.yaml | 27 +++ dts/bindings/pinctrl/gd,gd32-pinctrl-af.yaml | 111 ++++++++++++ .../pinctrl/gd,gd32-pinctrl-common.yaml | 26 +++ modules/hal_gigadevice/Kconfig | 5 + soc/arm/gigadevice/CMakeLists.txt | 1 + soc/arm/gigadevice/common/CMakeLists.txt | 4 + soc/arm/gigadevice/common/pinctrl_soc.h | 162 ++++++++++++++++++ 11 files changed, 455 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.gd32 create mode 100644 drivers/pinctrl/pinctrl_gd32_af.c create mode 100644 dts/bindings/gpio/gd,gd32-gpio.yaml create mode 100644 dts/bindings/pinctrl/gd,gd32-pinctrl-af.yaml create mode 100644 dts/bindings/pinctrl/gd,gd32-pinctrl-common.yaml create mode 100644 soc/arm/gigadevice/common/CMakeLists.txt create mode 100644 soc/arm/gigadevice/common/pinctrl_soc.h diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index cd3eca95d8d..ec6cb34b0d2 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -3,3 +3,4 @@ zephyr_library() zephyr_library_sources(common.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AF pinctrl_gd32_af.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 7e1a67175b8..7744ea475b0 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 00000000000..f7ff8c3567e --- /dev/null +++ b/drivers/pinctrl/Kconfig.gd32 @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AF := gd,gd32-pinctrl-af + +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. diff --git a/drivers/pinctrl/pinctrl_gd32_af.c b/drivers/pinctrl/pinctrl_gd32_af.c new file mode 100644 index 00000000000..d86b36e2e0d --- /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/dts/bindings/gpio/gd,gd32-gpio.yaml b/dts/bindings/gpio/gd,gd32-gpio.yaml new file mode 100644 index 00000000000..36c9ef1e6be --- /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-pinctrl-af.yaml b/dts/bindings/pinctrl/gd,gd32-pinctrl-af.yaml new file mode 100644 index 00000000000..2089e72b261 --- /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-common.yaml b/dts/bindings/pinctrl/gd,gd32-pinctrl-common.yaml new file mode 100644 index 00000000000..c8f1dfbba00 --- /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/modules/hal_gigadevice/Kconfig b/modules/hal_gigadevice/Kconfig index 542c65620db..b327b9a5c71 100644 --- a/modules/hal_gigadevice/Kconfig +++ b/modules/hal_gigadevice/Kconfig @@ -4,6 +4,11 @@ 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 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 6c5e7b454f6..e6525b03128 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/common/CMakeLists.txt b/soc/arm/gigadevice/common/CMakeLists.txt new file mode 100644 index 00000000000..83dce5d0127 --- /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 00000000000..062deb5b703 --- /dev/null +++ b/soc/arm/gigadevice/common/pinctrl_soc.h @@ -0,0 +1,162 @@ +/* + * 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +/** @brief Type for GD32 pin. + * + * Bits: + * - 0-12: GD32_PINMUX_AF bit field. + * - 13-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). + * @{ + */ + +/** 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). + * @{ + */ + +/** Push-pull */ +#define GD32_OTYPE_PP 0U +/** Open-drain */ +#define GD32_OTYPE_OD 1U + +/** @} */ + +/** + * @name GD32 OSPEED (values match the ones in the HAL). + * @{ + */ + +/** 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 + +/** @} */ + +/** + * @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_ */