From 48dd81906cdf7744f23894e033c72b8f94dc565b Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:11:36 +0800 Subject: [PATCH 01/12] soc: artery: Add AT32F405 soc related code and configuration files. Add AT32F405 soc related code and configuration files. Signed-off-by: jun tan --- soc/artery/at32/CMakeLists.txt | 5 + soc/artery/at32/Kconfig | 13 ++ soc/artery/at32/Kconfig.defconfig | 14 ++ soc/artery/at32/Kconfig.soc | 12 ++ soc/artery/at32/at32f402_405/CMakeLists.txt | 7 + soc/artery/at32/at32f402_405/Kconfig | 10 ++ .../at32/at32f402_405/Kconfig.defconfig | 8 + .../at32f402_405/Kconfig.defconfig.at32f405 | 9 + soc/artery/at32/at32f402_405/Kconfig.soc | 23 +++ soc/artery/at32/at32f402_405/at32_regs.h | 26 +++ soc/artery/at32/at32f402_405/linker.xx | 6 + soc/artery/at32/at32f402_405/soc.c | 14 ++ soc/artery/at32/at32f402_405/soc.h | 15 ++ soc/artery/at32/common/CMakeLists.txt | 4 + soc/artery/at32/common/pinctrl_soc.h | 157 ++++++++++++++++++ soc/artery/at32/soc.yml | 7 + 16 files changed, 330 insertions(+) create mode 100644 soc/artery/at32/CMakeLists.txt create mode 100644 soc/artery/at32/Kconfig create mode 100644 soc/artery/at32/Kconfig.defconfig create mode 100644 soc/artery/at32/Kconfig.soc create mode 100644 soc/artery/at32/at32f402_405/CMakeLists.txt create mode 100644 soc/artery/at32/at32f402_405/Kconfig create mode 100644 soc/artery/at32/at32f402_405/Kconfig.defconfig create mode 100644 soc/artery/at32/at32f402_405/Kconfig.defconfig.at32f405 create mode 100644 soc/artery/at32/at32f402_405/Kconfig.soc create mode 100644 soc/artery/at32/at32f402_405/at32_regs.h create mode 100644 soc/artery/at32/at32f402_405/linker.xx create mode 100644 soc/artery/at32/at32f402_405/soc.c create mode 100644 soc/artery/at32/at32f402_405/soc.h create mode 100644 soc/artery/at32/common/CMakeLists.txt create mode 100644 soc/artery/at32/common/pinctrl_soc.h create mode 100644 soc/artery/at32/soc.yml diff --git a/soc/artery/at32/CMakeLists.txt b/soc/artery/at32/CMakeLists.txt new file mode 100644 index 0000000000000..c1a010fdbd219 --- /dev/null +++ b/soc/artery/at32/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024, Maxjta +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(common) +add_subdirectory(${SOC_SERIES}) diff --git a/soc/artery/at32/Kconfig b/soc/artery/at32/Kconfig new file mode 100644 index 0000000000000..381477c5473a5 --- /dev/null +++ b/soc/artery/at32/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2022, Maxjta +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_AT32 + select HAS_AT32_HAL + select BUILD_OUTPUT_HEX + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + +if SOC_FAMILY_AT32 + +rsource "*/Kconfig" + +endif # SOC_FAMILY_AT32 diff --git a/soc/artery/at32/Kconfig.defconfig b/soc/artery/at32/Kconfig.defconfig new file mode 100644 index 0000000000000..f9777785cbb6b --- /dev/null +++ b/soc/artery/at32/Kconfig.defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024, Maxjta +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_AT32 + +rsource "*/Kconfig.defconfig" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/clocks/sysclk,clock-frequency) + +config CLOCK_CONTROL + default y + +endif # SOC_FAMILY_AT32 diff --git a/soc/artery/at32/Kconfig.soc b/soc/artery/at32/Kconfig.soc new file mode 100644 index 0000000000000..3c8d1fef65095 --- /dev/null +++ b/soc/artery/at32/Kconfig.soc @@ -0,0 +1,12 @@ +# Artery AT32 MCU line + +# Copyright (c) 2024, Maxjta +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_AT32 + bool + +config SOC_FAMILY + default "at32" if SOC_FAMILY_AT32 + +rsource "*/Kconfig.soc" diff --git a/soc/artery/at32/at32f402_405/CMakeLists.txt b/soc/artery/at32/at32f402_405/CMakeLists.txt new file mode 100644 index 0000000000000..a918155ff0559 --- /dev/null +++ b/soc/artery/at32/at32f402_405/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Maxjta +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/artery/at32/at32f402_405/Kconfig b/soc/artery/at32/at32f402_405/Kconfig new file mode 100644 index 0000000000000..f5b8d08d417a8 --- /dev/null +++ b/soc/artery/at32/at32f402_405/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2021, Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_AT32F402_405 + select ARM + select CPU_HAS_ARM_MPU + select CPU_HAS_FPU + select CPU_CORTEX_M4 + select AT32_HAS_PINMUX + select SOC_EARLY_INIT_HOOK diff --git a/soc/artery/at32/at32f402_405/Kconfig.defconfig b/soc/artery/at32/at32f402_405/Kconfig.defconfig new file mode 100644 index 0000000000000..b45898a15054a --- /dev/null +++ b/soc/artery/at32/at32f402_405/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Maxjta +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_AT32F402_405 + +rsource "Kconfig.defconfig.at32*" + +endif # SOC_SERIES_AT32F402_405 diff --git a/soc/artery/at32/at32f402_405/Kconfig.defconfig.at32f405 b/soc/artery/at32/at32f402_405/Kconfig.defconfig.at32f405 new file mode 100644 index 0000000000000..0b093a4dd6346 --- /dev/null +++ b/soc/artery/at32/at32f402_405/Kconfig.defconfig.at32f405 @@ -0,0 +1,9 @@ +# Copyright (c) 2021, ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_AT32F405 + +config NUM_IRQS + default 104 + +endif # SOC_AT32F405 diff --git a/soc/artery/at32/at32f402_405/Kconfig.soc b/soc/artery/at32/at32f402_405/Kconfig.soc new file mode 100644 index 0000000000000..b1b12774a40b8 --- /dev/null +++ b/soc/artery/at32/at32f402_405/Kconfig.soc @@ -0,0 +1,23 @@ +# Copyright (c) 2024, Maxjta +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_AT32F402_405 + bool + select SOC_FAMILY_AT32 + help + Enable support for Artery AT32F402_405 MCU series + +config SOC_SERIES + default "at32f402_405" if SOC_SERIES_AT32F402_405 + +config SOC_AT32F405 + bool + select SOC_SERIES_AT32F402_405 + +config SOC_AT32F402 + bool + select SOC_SERIES_AT32F402_405 + +config SOC + default "at32f405" if SOC_AT32F405 + default "at32f402" if SOC_AT32F402 diff --git a/soc/artery/at32/at32f402_405/at32_regs.h b/soc/artery/at32/at32f402_405/at32_regs.h new file mode 100644 index 0000000000000..af6f12f250de8 --- /dev/null +++ b/soc/artery/at32/at32f402_405/at32_regs.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022, Teslabs Engineering S.L. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_ARM_ARTERY_AT32F402_405_AT32_REGS_H_ +#define SOC_ARM_ARTERY_AT32F402_405_AT32_REGS_H_ + +#include + +/* CRM */ +#define CRM_CFG_OFFSET 0x08U +#define CRM_AHB1EN_OFFSET 0x30U +#define CRM_AHB2EN_OFFSET 0x34U +#define CRM_AHB3EN_OFFSET 0x38U +#define CRM_APB1EN_OFFSET 0x40U +#define CRM_APB2EN_OFFSET 0x44U + +#define CRM_CFG_AHBDIV_POS 4U +#define CRM_CFG_AHBDIV_MSK (BIT_MASK(4) << CRM_CFG_AHBDIV_POS) +#define CRM_CFG_APB1DIV_POS 10U +#define CRM_CFG_APB1DIV_MSK (BIT_MASK(3) << CRM_CFG_APB1DIV_POS) +#define CRM_CFG_APB2DIV_POS 13U +#define CRM_CFG_APB2DIV_MSK (BIT_MASK(3) << CRM_CFG_APB2DIV_POS) + +#endif /* SOC_ARM_ARTERY_AT32F402_405_AT32_REGS_H_ */ diff --git a/soc/artery/at32/at32f402_405/linker.xx b/soc/artery/at32/at32f402_405/linker.xx new file mode 100644 index 0000000000000..21f8fbad5c4a3 --- /dev/null +++ b/soc/artery/at32/at32f402_405/linker.xx @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2024, Maxjta + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/artery/at32/at32f402_405/soc.c b/soc/artery/at32/at32f402_405/soc.c new file mode 100644 index 0000000000000..e4bd8404484e5 --- /dev/null +++ b/soc/artery/at32/at32f402_405/soc.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2024, Maxjta + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +void soc_early_init_hook(void) +{ + SystemInit(); +} diff --git a/soc/artery/at32/at32f402_405/soc.h b/soc/artery/at32/at32f402_405/soc.h new file mode 100644 index 0000000000000..a22db922d0226 --- /dev/null +++ b/soc/artery/at32/at32f402_405/soc.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2024, Maxjta + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOC_ARM_ARTERY_AT32F402_405_SOC_H_ +#define _SOC_ARM_ARTERY_AT32F402_405_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#endif /* _ASMLANGUAGE */ + +#endif /* _SOC_ARM_ARTERY_AT32F405_SOC_H_ */ diff --git a/soc/artery/at32/common/CMakeLists.txt b/soc/artery/at32/common/CMakeLists.txt new file mode 100644 index 0000000000000..18e2904e70153 --- /dev/null +++ b/soc/artery/at32/common/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Maxjta +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) diff --git a/soc/artery/at32/common/pinctrl_soc.h b/soc/artery/at32/common/pinctrl_soc.h new file mode 100644 index 0000000000000..723826630788b --- /dev/null +++ b/soc/artery/at32/common/pinctrl_soc.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024 Maxjta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * Artery SoC specific helpers for pinctrl driver + */ + +#ifndef ZEPHYR_SOC_ARM_ARTERY_AT32_COMMON_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_ARTERY_AT32_COMMON_PINCTRL_SOC_H_ + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +/** @brief Type for AT32 pin. + * + * Bits (mux model): + * - 0-12: AT32_PIN_MUX bit field. + * - 13-25: Reserved. + * - 26-31: Pin configuration bit field (@ref AT32_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) | \ + ((AT32_PULL_UP * DT_PROP(node_id, bias_pull_up)) \ + << AT32_PUPD_POS) | \ + ((AT32_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) \ + << AT32_PUPD_POS) | \ + ((AT32_OUTPUT_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) \ + << AT32_OMODE_POS) | \ + (DT_ENUM_IDX(node_id, slew_rate) << AT32_DRIVE_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 AT32 PULL (GPIO pull-up/pull-donw). + * @{ + */ + +/** No pull-up/down */ +#define AT32_PULL_NONE 0U +/** Pull-up */ +#define AT32_PULL_UP 1U +/** Pull-down */ +#define AT32_PULL_DOWN 2U + +/** @} */ + +/** + * @name AT32 OMODE (GPIO output mode). + * @{ + */ + +/** Push-pull */ +#define AT32_OUTPUT_PUSH_PULL 0U +/** Open-drain */ +#define AT32_OUTPUT_OPEN_DRAIN 1U + +/** @} */ + +/** + * @name AT32 ODRVR (GPIO output drive capability). + * @{ + */ + + /** GPIO stronger sourcing/sinking strength */ +#define AT32_DRIVE_STRENGTH_STRONGER 1U + /** GPIO moderate sourcing/sinking strength */ +#define AT32_DRIVE_STRENGTH_MODERATE 2U + +/** @} */ + +/** + * @name AT32 pin configuration bit field mask and positions. + * @anchor AT32_PINCFG + * + * Fields: + * + * - 31..29: Pull-up/down + * - 28: Output type + * - 27..26: Output drive capability + * + * @{ + */ + +/** PUPD field mask. */ +#define AT32_PUPD_MSK 0x3U +/** PUPD field position. */ +#define AT32_PUPD_POS 29U +/** OMODE field mask. */ +#define AT32_OMODE_MSK 0x1U +/** OMODE field position. */ +#define AT32_OMODE_POS 28U +/** DRIVE field mask. */ +#define AT32_DRIVE_MSK 0x3U +/** DRIVE field position. */ +#define AT32_DRIVE_POS 26U + +/** @} */ + +/** + * Obtain PUPD field from pinctrl_soc_pin_t configuration. + * + * @param pincfg pinctrl_soc_pin_t bit field value. + */ +#define AT32_PUPD_GET(pincfg) (((pincfg) >> AT32_PUPD_POS) & AT32_PUPD_MSK) + +/** + * Obtain OMODE field from pinctrl_soc_pin_t configuration. + * + * @param pincfg pinctrl_soc_pin_t bit field value. + */ +#define AT32_OMODE_GET(pincfg) (((pincfg) >> AT32_OMODE_POS) & AT32_OMODE_MSK) + +/** + * Obtain DRIVE field from pinctrl_soc_pin_t configuration. + * + * @param pincfg pinctrl_soc_pin_t bit field value. + */ +#define AT32_DRIVE_GET(pincfg) (((pincfg) >> AT32_DRIVE_POS) & AT32_DRIVE_MSK) + + +#ifdef __cplusplus +} +#endif +#endif /* ZEPHYR_SOC_ARM_ARTERY_AT32_COMMON_PINCTRL_SOC_H_ */ diff --git a/soc/artery/at32/soc.yml b/soc/artery/at32/soc.yml new file mode 100644 index 0000000000000..2d82828f19900 --- /dev/null +++ b/soc/artery/at32/soc.yml @@ -0,0 +1,7 @@ +family: +- name: at32 + series: + - name: at32f402_405 + socs: + - name: at32f405 + - name: at32f402 From c7d0bf3bce4d9ee5e9deeb8019085b2a779d0eaf Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:13:54 +0800 Subject: [PATCH 02/12] driver: clock_control: add clock control driver Add clock control driver to support AT32F405 Signed-off-by: jun tan --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.at32 | 8 + drivers/clock_control/clock_control_at32.c | 280 +++++++++++++++++++++ 4 files changed, 291 insertions(+) create mode 100644 drivers/clock_control/Kconfig.at32 create mode 100644 drivers/clock_control/clock_control_at32.c diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 886c92b635788..57c3e391c32fe 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BEETLE beetle_clock_control.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ADSP clock_control_adsp.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ARM_SCMI clock_control_arm_scmi.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AT32 clock_control_at32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ESP32 clock_control_esp32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK clock_control_fixed_rate.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_GD32 clock_control_gd32.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index f528aa2dad327..1956fba69e415 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -76,6 +76,8 @@ source "drivers/clock_control/Kconfig.aspeed" source "drivers/clock_control/Kconfig.gd32" +source "drivers/clock_control/Kconfig.at32" + source "drivers/clock_control/Kconfig.sam" source "drivers/clock_control/Kconfig.si32" diff --git a/drivers/clock_control/Kconfig.at32 b/drivers/clock_control/Kconfig.at32 new file mode 100644 index 0000000000000..b5afd32c42f70 --- /dev/null +++ b/drivers/clock_control/Kconfig.at32 @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 +config CLOCK_CONTROL_AT32 + bool "AT32 clock control" + default y + depends on DT_HAS_ARTERY_AT32_CCTL_ENABLED + help + Enable driver for AT32 Reset Clock Unit (CRM). diff --git a/drivers/clock_control/clock_control_at32.c b/drivers/clock_control/clock_control_at32.c new file mode 100644 index 0000000000000..9e5a40b90df5f --- /dev/null +++ b/drivers/clock_control/clock_control_at32.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2022 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT artery_at32_cctl + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/** offset (from id cell) */ +#define AT32_CLOCK_ID_OFFSET(id) (((id) >> 6U) & 0xFFU) +/** configuration bit (from id cell) */ +#define AT32_CLOCK_ID_BIT(id) ((id)&0x1FU) + +#define CPU_FREQ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC + +/** AHB prescaler exponents */ +static const uint8_t ahb_exp[16] = { + 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U, 6U, 7U, 8U, 9U, +}; +/** APB1 prescaler exponents */ +static const uint8_t apb1_exp[8] = { + 0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U, +}; +/** APB2 prescaler exponents */ +static const uint8_t apb2_exp[8] = { + 0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U, +}; + +struct clock_control_at32_config { + uint32_t base; +}; + +#if defined(FLASH_WAIT_CYCLE) +static int clock_wait_cycle_config(void) +{ + if (CPU_FREQ > 192000000) { + flash_psr_set(FLASH_WAIT_CYCLE_6); + } else if (CPU_FREQ > 160000000) { + flash_psr_set(FLASH_WAIT_CYCLE_5); + } else if (CPU_FREQ > 128000000) { + flash_psr_set(FLASH_WAIT_CYCLE_4); + } else if (CPU_FREQ > 96000000) { + flash_psr_set(FLASH_WAIT_CYCLE_3); + } else if (CPU_FREQ > 64000000) { + flash_psr_set(FLASH_WAIT_CYCLE_2); + } else { + flash_psr_set(FLASH_WAIT_CYCLE_1); + } + + return 0; +} +#endif + +static int clock_enable_hext(void) +{ + if (IS_ENABLED(AT32_HEXT_ENABLED)) { + crm_clock_source_enable(CRM_CLOCK_SOURCE_HEXT, TRUE); + + /* wait till hext is ready */ + while (crm_hext_stable_wait() == ERROR) { + } + } + + return 0; +} + +static int clock_enable_pll(void) +{ + if (IS_ENABLED(AT32_SYSCLK_SRC_PLL)) { + /* config pll clock resource */ + if (IS_ENABLED(AT32_PLL_SRC_HEXT)) { + crm_pll_config(CRM_PLL_SOURCE_HEXT, DT_PROP(DT_NODELABEL(pll), mul_ns), + DT_PROP(DT_NODELABEL(pll), div_ms), + DT_PROP(DT_NODELABEL(pll), div_fp)); + } else { + crm_pll_config(CRM_PLL_SOURCE_HICK, DT_PROP(DT_NODELABEL(pll), mul_ns), + DT_PROP(DT_NODELABEL(pll), div_ms), + DT_PROP(DT_NODELABEL(pll), div_fp)); + } +#if defined(CRM_PLL_FU) + crm_pllu_div_set(DT_PROP(DT_NODELABEL(pll), div_fu)); + crm_pllu_output_set(TRUE); +#endif + /* enable pll */ + crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE); + + /* wait till pll is ready */ + while (crm_flag_get(CRM_PLL_STABLE_FLAG) != SET) { + } + } + return 0; +} + +static int clock_control_at32_on(const struct device *dev, clock_control_subsys_t sys) +{ + const struct clock_control_at32_config *config = dev->config; + uint16_t id = *(uint16_t *)sys; + + sys_set_bit(config->base + AT32_CLOCK_ID_OFFSET(id), AT32_CLOCK_ID_BIT(id)); + + return 0; +} + +static int clock_control_at32_off(const struct device *dev, clock_control_subsys_t sys) +{ + const struct clock_control_at32_config *config = dev->config; + uint16_t id = *(uint16_t *)sys; + + sys_clear_bit(config->base + AT32_CLOCK_ID_OFFSET(id), AT32_CLOCK_ID_BIT(id)); + + return 0; +} + +static int clock_control_at32_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + const struct clock_control_at32_config *config = dev->config; + uint16_t id = *(uint16_t *)sys; + uint32_t cfg; + uint8_t psc; + + cfg = sys_read32(config->base + CRM_CFG_OFFSET); + + switch (AT32_CLOCK_ID_OFFSET(id)) { + case CRM_AHB1EN_OFFSET: + case CRM_AHB2EN_OFFSET: + case CRM_AHB3EN_OFFSET: + psc = (cfg & CRM_CFG_AHBDIV_MSK) >> CRM_CFG_AHBDIV_POS; + *rate = CPU_FREQ >> ahb_exp[psc]; + break; + case CRM_APB1EN_OFFSET: + psc = (cfg & CRM_CFG_APB1DIV_MSK) >> CRM_CFG_APB1DIV_POS; + *rate = CPU_FREQ >> apb1_exp[psc]; + break; + case CRM_APB2EN_OFFSET: + psc = (cfg & CRM_CFG_APB2DIV_MSK) >> CRM_CFG_APB2DIV_POS; + *rate = CPU_FREQ >> apb2_exp[psc]; + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static enum clock_control_status clock_control_at32_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + const struct clock_control_at32_config *config = dev->config; + uint16_t id = *(uint16_t *)sys; + + if (sys_test_bit(config->base + AT32_CLOCK_ID_OFFSET(id), AT32_CLOCK_ID_BIT(id)) != 0) { + return CLOCK_CONTROL_STATUS_ON; + } + + return CLOCK_CONTROL_STATUS_OFF; +} + +static DEVICE_API(clock_control, clock_control_at32_api) = { + .on = clock_control_at32_on, + .off = clock_control_at32_off, + .get_rate = clock_control_at32_get_rate, + .get_status = clock_control_at32_get_status, +}; + +/** + * @brief Initialize clocks for the at32 + * + * This routine is called to enable and configure the clocks and PLL + * of the soc on the board. It depends on the board definition. + * This function is called on the startup and also to restore the config + * when exiting for low power mode. + * + * @param dev clock device struct + * + * @return 0 + */ +int at32_clock_control_init(const struct device *dev) +{ + int clk_div = 0; + /* set hick as system clock */ + crm_sysclk_switch(CRM_SCLK_HICK); + + /* wait till pll is used as system clock source */ + while (crm_sysclk_switch_status_get() != CRM_SCLK_HICK) { + } + + crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE); +#if defined(PWC_LDO_OUTPUT) + pwc_ldo_output_voltage_set(PWC_LDO_OUTPUT_MAX); +#endif + /* disable pll */ + crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, FALSE); +#if defined(FLASH_WAIT_CYCLE) + clock_wait_cycle_config(); +#endif + /* config hext */ + clock_enable_hext(); + + /* config pll */ + clock_enable_pll(); + + /* config ahbclk */ + clk_div = DT_PROP(DT_NODELABEL(crm), ahb_prescaler); + if (clk_div == 1) { + clk_div = CRM_AHB_DIV_1; + } else { + clk_div = (clk_div - 2) + 8; + } + crm_ahb_div_set(clk_div); + + /* config apb2clk */ + clk_div = DT_PROP(DT_NODELABEL(crm), apb2_prescaler); + if (clk_div == 1) { + clk_div = CRM_APB2_DIV_1; + } else { + clk_div = (clk_div - 2) + 4; + } + crm_apb2_div_set(clk_div); + + /* config apb1clk */ + clk_div = DT_PROP(DT_NODELABEL(crm), apb1_prescaler); + if (clk_div == 1) { + clk_div = CRM_APB1_DIV_1; + } else { + clk_div = (clk_div - 2) + 4; + } + + crm_apb1_div_set(clk_div); + + /* enable auto step mode */ + crm_auto_step_mode_enable(TRUE); + + if (IS_ENABLED(AT32_SYSCLK_SRC_PLL)) { + /* select pll as system clock source */ + crm_sysclk_switch(CRM_SCLK_PLL); + + /* wait till pll is used as system clock source */ + while (crm_sysclk_switch_status_get() != CRM_SCLK_PLL) { + } + } else if (IS_ENABLED(AT32_SYSCLK_SRC_HEXT)) { + /* select hext as system clock source */ + crm_sysclk_switch(CRM_SCLK_HEXT); + + /* wait till hext is used as system clock source */ + while (crm_sysclk_switch_status_get() != CRM_SCLK_HEXT) { + } + } else { + /* select hick as system clock source */ + crm_sysclk_switch(CRM_SCLK_HICK); + + /* wait till hick is used as system clock source */ + while (crm_sysclk_switch_status_get() != CRM_SCLK_HICK) { + } + } + + /* disable auto step mode */ + crm_auto_step_mode_enable(FALSE); + return 0; +} + +static const struct clock_control_at32_config config = { + .base = DT_REG_ADDR(DT_INST_PARENT(0)), +}; + +DEVICE_DT_INST_DEFINE(0, at32_clock_control_init, NULL, NULL, &config, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_at32_api); From c56465a056f4f500d2ecf606db348d844720a7b9 Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:15:18 +0800 Subject: [PATCH 03/12] driver: gpio: add gpio driver to support AT32F405 Add gpio driver to support AT32F405 Signed-off-by: jun tan --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 1 + drivers/gpio/Kconfig.at32 | 11 ++ drivers/gpio/gpio_at32.c | 248 ++++++++++++++++++++++++++++++++++++ 4 files changed, 261 insertions(+) create mode 100644 drivers/gpio/Kconfig.at32 create mode 100644 drivers/gpio/gpio_at32.c diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 728a883e1093c..937d3cf9fb3a2 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_ADS1X4S0X gpio_ads1x4s0x.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ALTERA_PIO gpio_altera_pio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AMBIQ gpio_ambiq.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ANDES_ATCGPIO100 gpio_andes_atcgpio100.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_AT32 gpio_at32.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AW9523B gpio_aw9523b.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AXP192 gpio_axp192.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e95aded5613a8..a2fa791782c97 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -100,6 +100,7 @@ source "drivers/gpio/Kconfig.ads1x4s0x" source "drivers/gpio/Kconfig.altera" source "drivers/gpio/Kconfig.ambiq" source "drivers/gpio/Kconfig.andes_atcgpio100" +source "drivers/gpio/Kconfig.at32" source "drivers/gpio/Kconfig.aw9523b" source "drivers/gpio/Kconfig.axp192" source "drivers/gpio/Kconfig.b91" diff --git a/drivers/gpio/Kconfig.at32 b/drivers/gpio/Kconfig.at32 new file mode 100644 index 0000000000000..1bc508b9d50ad --- /dev/null +++ b/drivers/gpio/Kconfig.at32 @@ -0,0 +1,11 @@ +# AT32 GPIO configuration + +# Copyright (c) 2016 Open-RnD Sp. z o.o. +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_AT32 + bool "GPIO Driver for AT32 family of MCUs" + default y + depends on DT_HAS_ARTERY_AT32_GPIO_ENABLED + help + Enable GPIO driver for AT32 line of MCUs diff --git a/drivers/gpio/gpio_at32.c b/drivers/gpio/gpio_at32.c new file mode 100644 index 0000000000000..ef14876ffc1d7 --- /dev/null +++ b/drivers/gpio/gpio_at32.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2025 Maxjta + * Copyright (c) 2021 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT artery_at32_gpio + +#include +#include +#include +#include +#include +#include +#include + +#include + +/** SYSCFG DT node */ +#define SYSCFG_NODE DT_NODELABEL(syscfg) + +/** EXINT mask */ +#define EXINT_MSK 0xFU +/** EXINT line step size */ +#define EXINT_STEP 4U +/** EXINT line shift */ +#define EXINT_LINE_SHIFT(pin) (EXINT_STEP * ((pin) % EXINT_STEP)) + +/* GPIO mode configuration values */ +#define GPIO_MODE_SET(n, mode) ((uint32_t)((uint32_t)(mode) << (2U * (n)))) +#define GPIO_MODE_MASK(n) ((uint32_t)((uint32_t)0x00000003U << (2U * (n)))) +#define GPIO_PIN_OFFSET(n) (1 << n) + +/* GPIO pull-up/pull-down values */ +#define GPIO_PUPD_SET(n, pupd) ((uint32_t)((uint32_t)(pupd) << (2U * (n)))) +#define GPIO_PUPD_MASK(n) ((uint32_t)((uint32_t)0x00000003U << (2U * (n)))) + +struct gpio_at32_config { + struct gpio_driver_config common; + uint32_t reg; + uint32_t clkid; + uint32_t clkid_exint; + struct reset_dt_spec reset; +}; + +struct gpio_at32_data { + struct gpio_driver_data common; + sys_slist_t callbacks; +}; + +/** + * @brief EXINT ISR callback. + * + * @param line EXINT line (equals to GPIO pin number). + * @param arg GPIO port instance. + */ +static void gpio_at32_isr(uint32_t line, void *arg) +{ + const struct device *dev = arg; + struct gpio_at32_data *data = dev->data; + + gpio_fire_callbacks(&data->callbacks, dev, line); +} + +/** + * @brief Configure EXINT source selection register. + * + * @param port GPIO port instance. + * @param pin GPIO pin number. + * + * @retval 0 on success. + * @retval -EINVAL if pin is not valid. + */ +static int gpio_at32_configure_extiss(const struct device *port, gpio_pin_t pin) +{ + const struct gpio_at32_config *config = port->config; + + at32_exint_set_line_src_port(pin, config->reg); + return 0; +} + +static inline int gpio_at32_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct gpio_at32_config *config = port->config; + gpio_type *gpio = (gpio_type *)config->reg; + gpio_init_type init_config; + + gpio_default_para_init(&init_config); + + init_config.gpio_pins = GPIO_PIN_OFFSET(pin); + + if ((flags & GPIO_OUTPUT) != 0U) { + init_config.gpio_mode = GPIO_MODE_OUTPUT; + if ((flags & GPIO_SINGLE_ENDED) != 0U) { + if ((flags & GPIO_LINE_OPEN_DRAIN) != 0U) { + init_config.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN; + } else { + return -ENOTSUP; + } + } else { + init_config.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; + } + } else if ((flags & GPIO_INPUT) != 0U) { + init_config.gpio_mode = GPIO_MODE_INPUT; + } else { + init_config.gpio_mode = GPIO_MODE_ANALOG; + } + + if ((flags & GPIO_PULL_UP) != 0U) { + init_config.gpio_pull = AT32_PULL_UP; + } else if ((flags & GPIO_PULL_DOWN) != 0U) { + init_config.gpio_pull = AT32_PULL_DOWN; + } else { + init_config.gpio_pull = AT32_PULL_NONE; + } + + gpio_init(gpio, &init_config); + return 0; +} + +static int gpio_at32_port_get_raw(const struct device *port, uint32_t *value) +{ + const struct gpio_at32_config *config = port->config; + gpio_type *gpio = (gpio_type *)config->reg; + *value = gpio->idt; + return 0; +} + +static int gpio_at32_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct gpio_at32_config *config = port->config; + gpio_type *gpio = (gpio_type *)config->reg; + + gpio->odt = (gpio->odt & ~mask) | (value & mask); + return 0; +} + +static int gpio_at32_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_at32_config *config = port->config; + gpio_type *gpio = (gpio_type *)config->reg; + + gpio->scr = pins; + return 0; +} + +static int gpio_at32_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_at32_config *config = port->config; + gpio_type *gpio = (gpio_type *)config->reg; + + gpio->clr = pins; + return 0; +} + +static int gpio_at32_port_toggle_bits(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_at32_config *config = port->config; + gpio_type *gpio = (gpio_type *)config->reg; + + gpio->odt ^= pins; + return 0; +} + +static int gpio_at32_pin_interrupt_configure(const struct device *port, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + if (mode == GPIO_INT_MODE_DISABLED) { + at32_exint_intc_disable_line(BIT(pin)); + at32_exint_intc_select_line_trigger(BIT(pin), AT32_GPIO_IRQ_TRIG_NONE); + at32_exint_intc_remove_irq_callback(BIT(pin)); + } else if (mode == GPIO_INT_MODE_EDGE) { + int ret; + + at32_exint_intc_set_irq_callback(BIT(pin), gpio_at32_isr, (void *)port); + ret = gpio_at32_configure_extiss(port, pin); + if (ret < 0) { + return ret; + } + + switch (trig) { + case GPIO_INT_TRIG_LOW: + at32_exint_intc_select_line_trigger(BIT(pin), AT32_GPIO_IRQ_TRIG_FALLING); + break; + case GPIO_INT_TRIG_HIGH: + at32_exint_intc_select_line_trigger(BIT(pin), AT32_GPIO_IRQ_TRIG_RISING); + break; + case GPIO_INT_TRIG_BOTH: + at32_exint_intc_select_line_trigger(BIT(pin), AT32_GPIO_IRQ_TRIG_BOTH); + break; + default: + return -ENOTSUP; + } + at32_exint_intc_enable_line(BIT(pin)); + } else { + return -ENOTSUP; + } + return 0; +} + +static int gpio_at32_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct gpio_at32_data *data = dev->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} +static DEVICE_API(gpio, gpio_at32_api) = { + .pin_configure = gpio_at32_configure, + .port_get_raw = gpio_at32_port_get_raw, + .port_set_masked_raw = gpio_at32_port_set_masked_raw, + .port_set_bits_raw = gpio_at32_port_set_bits_raw, + .port_clear_bits_raw = gpio_at32_port_clear_bits_raw, + .port_toggle_bits = gpio_at32_port_toggle_bits, + .pin_interrupt_configure = gpio_at32_pin_interrupt_configure, + .manage_callback = gpio_at32_manage_callback, +}; + +static int gpio_at32_init(const struct device *port) +{ + const struct gpio_at32_config *config = port->config; + + (void)clock_control_on(AT32_CLOCK_CONTROLLER, (clock_control_subsys_t *)&config->clkid); + + (void)clock_control_on(AT32_CLOCK_CONTROLLER, + (clock_control_subsys_t *)&config->clkid_exint); + return 0; +} + +#define GPIO_AT32_DEFINE(n) \ + static const struct gpio_at32_config gpio_at32_config##n = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .reg = DT_INST_REG_ADDR(n), \ + .clkid = DT_INST_CLOCKS_CELL(n, id), \ + .clkid_exint = DT_CLOCKS_CELL(SYSCFG_NODE, id), \ + }; \ + \ + static struct gpio_at32_data gpio_at32_data##n; \ + \ + DEVICE_DT_INST_DEFINE(n, &gpio_at32_init, NULL, &gpio_at32_data##n, &gpio_at32_config##n, \ + PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, &gpio_at32_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_AT32_DEFINE) From 866c8dcba96b3717a3f6f0cd324ab9cebed99236 Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:16:16 +0800 Subject: [PATCH 04/12] driver: interrupt_controller: add interrupt controller driver. Add interrupt controller driver to support AT32F405. Signed-off-by: jun tan --- drivers/interrupt_controller/CMakeLists.txt | 1 + drivers/interrupt_controller/Kconfig | 2 + drivers/interrupt_controller/Kconfig.at32 | 12 + .../interrupt_controller/intc_exint_at32.c | 304 ++++++++++++++++++ 4 files changed, 319 insertions(+) create mode 100644 drivers/interrupt_controller/Kconfig.at32 create mode 100644 drivers/interrupt_controller/intc_exint_at32.c diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 2bb2dbe16336d..af63f8d59ab39 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -7,6 +7,7 @@ zephyr_library_sources_ifdef(CONFIG_CAVS_ICTL intc_cavs.c) zephyr_library_sources_ifdef(CONFIG_DW_ICTL intc_dw.c) zephyr_library_sources_ifdef(CONFIG_DW_ICTL_ACE intc_dw_ace.c) zephyr_library_sources_ifdef(CONFIG_EXTI_STM32 intc_exti_stm32.c) +zephyr_library_sources_ifdef(CONFIG_AT32_EXINT intc_exint_at32.c) zephyr_library_sources_ifdef(CONFIG_GD32_EXTI intc_gd32_exti.c) zephyr_library_sources_ifdef(CONFIG_GIC_V1 intc_gic.c) zephyr_library_sources_ifdef(CONFIG_GIC_V2 intc_gic.c) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index 3468cf4f3f233..72e402b9f2925 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -72,6 +72,8 @@ source "drivers/interrupt_controller/Kconfig.it8xxx2" source "drivers/interrupt_controller/Kconfig.stm32" +source "drivers/interrupt_controller/Kconfig.at32" + source "drivers/interrupt_controller/Kconfig.cavs" source "drivers/interrupt_controller/Kconfig.rv32m1" diff --git a/drivers/interrupt_controller/Kconfig.at32 b/drivers/interrupt_controller/Kconfig.at32 new file mode 100644 index 0000000000000..83f0e79a4c585 --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.at32 @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +config AT32_EXINT + bool "AT32 Extended Interrupts and Events (EXINT) Controller" + default y + depends on DT_HAS_ARTERY_AT32_EXINT_ENABLED + select USE_AT32_EXINT + select USE_AT32_SYSCFG + help + Enable the AT32 Extended Interrupts and Events (EXINT) + controller driver. diff --git a/drivers/interrupt_controller/intc_exint_at32.c b/drivers/interrupt_controller/intc_exint_at32.c new file mode 100644 index 0000000000000..f498288f3a221 --- /dev/null +++ b/drivers/interrupt_controller/intc_exint_at32.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2016 Open-RnD Sp. z o.o. + * Copyright (c) 2017 RnDity Sp. z o.o. + * Copyright (c) 2019-23 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Driver for External interrupt/event controller in AT32 MCUs + */ + +#define EXINT_NODE DT_INST(0, artery_at32_exint) + +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXINT_NOTSUP 0xFFU + +/** @brief EXINT lines range mapped to a single interrupt line */ +struct at32_exint_range { + /** Start of the range */ + uint8_t start; + /** Range length */ + uint8_t len; +}; + +#define NUM_EXINT_LINES DT_PROP(DT_NODELABEL(exint), num_lines) + +static IRQn_Type exint_irq_table[NUM_EXINT_LINES] = {[0 ... NUM_EXINT_LINES - 1] = 0xFF}; + +/* User callback wrapper */ +struct __exti_cb { + at32_exint_irq_cb_t cb; + void *data; +}; + +/* EXINT driver data */ +struct at32_exint_data { + /* per-line callbacks */ + struct __exti_cb cb[NUM_EXINT_LINES]; +}; +static scfg_port_source_type get_source_port(uint32_t port) +{ + uint32_t port_index; + + port_index = (port - (uint32_t)GPIOA) / ((uint32_t)GPIOB - (uint32_t)GPIOA); + return (scfg_port_source_type)port_index; +} + +static uint32_t scfg_get_exint_port(scfg_pins_source_type pin_source) +{ + uint32_t tmp = 0x00; + + tmp = ((uint32_t)0x0F) << (0x04 * (pin_source & (uint8_t)0x03)); + + switch (pin_source >> 0x02) { + case 0: + return (SCFG->exintc1 >> (0x04 * (pin_source & (uint8_t)0x03))) & 0x0F; + case 1: + return (SCFG->exintc2 >> (0x04 * (pin_source & (uint8_t)0x03))) & 0x0F; + case 2: + return (SCFG->exintc3 >> (0x04 * (pin_source & (uint8_t)0x03))) & 0x0F; + case 3: + return (SCFG->exintc4 >> (0x04 * (pin_source & (uint8_t)0x03))) & 0x0F; + default: + return 0; + } + return 0; +} + +/** + * @returns the LL__EXINT_LINE_xxx define that corresponds to specified @p linenum + * This value can be used with the EXUBT source configuration functions. + */ +static inline uint32_t at32_exint_linenum_to_src_cfg_line(gpio_pin_t linenum) +{ + return (0xF << ((linenum % 4 * 4) + 16)) | (linenum / 4); +} + +/** + * @brief Checks interrupt pending bit for specified EXINT line + * + * @param line EXINT line number + */ +static inline int at32_exint_is_pending(at32_irq_line_t line) +{ + return exint_flag_get(line); +} + +/** + * @brief Clears interrupt pending bit for specified EXINT line + * + * @param line EXINT line number + */ +static inline void at32_exint_clear_pending(at32_irq_line_t line) +{ + exint_flag_clear(line); +} + +/** + * @returns the EXINT_LINE_x define for EXINT line number @p linenum + */ +static inline at32_irq_line_t linenum_to_exint_line(gpio_pin_t linenum) +{ + return BIT(linenum); +} + +/** + * @returns EXINT line number for EXINT_LINE_n define + */ +static inline gpio_pin_t exint_line_to_linenum(at32_irq_line_t line) +{ + return LOG2(line); +} + +/** + * @brief EXINT ISR handler + * + * Check EXINT lines in exti_range for pending interrupts + * + * @param EXINT_range Pointer to a exti_range structure + */ +static void at32_exint_isr(const void *exint_range) +{ + const struct device *dev = DEVICE_DT_GET(EXINT_NODE); + struct at32_exint_data *data = dev->data; + const struct at32_exint_range *range = exint_range; + at32_irq_line_t line; + uint32_t line_num; + + /* see which bits are set */ + for (uint8_t i = 0; i <= range->len; i++) { + line_num = range->start + i; + line = linenum_to_exint_line(line_num); + /* check if interrupt is pending */ + if (at32_exint_is_pending(line) != 0) { + /* clear pending interrupt */ + at32_exint_clear_pending(line); + /* run callback only if one is registered */ + if (!data->cb[line_num].cb) { + continue; + } + /* `line` can be passed as-is because EXINT_LINE_x is (1 << x) */ + data->cb[line_num].cb(line, data->cb[line_num].data); + } + } +} + +/** Enables the peripheral clock required to access EXINT registers */ +static int at32_exint_enable_registers(void) +{ + /* Initialize to 0 for series where there is nothing to do. */ + int ret = 0; + return ret; +} + +static void at32_fill_irq_table(int8_t start, int8_t len, int32_t irqn) +{ + for (int i = 0; i < len; i++) { + exint_irq_table[start + i] = irqn; + } +} + +/* This macro: + * - populates line_range_x from line_range dt property + * - fill exti_irq_table through at32_fill_irq_table() + * - calls IRQ_CONNECT for each interrupt and matching line_range + */ +#define AT32_EXINT_INIT_LINE_RANGE(node_id, interrupts, idx) \ + static const struct at32_exint_range line_range_##idx = { \ + DT_PROP_BY_IDX(node_id, line_ranges, UTIL_X2(idx)), \ + DT_PROP_BY_IDX(node_id, line_ranges, UTIL_INC(UTIL_X2(idx)))}; \ + at32_fill_irq_table(line_range_##idx.start, line_range_##idx.len, \ + DT_IRQ_BY_IDX(node_id, idx, irq)); \ + IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), DT_IRQ_BY_IDX(node_id, idx, priority), \ + at32_exint_isr, &line_range_##idx, 0); +/** + * @brief Initializes the EXINT interrupt controller driver + */ +static int at32_exint_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + DT_FOREACH_PROP_ELEM(DT_NODELABEL(exint), interrupt_names, AT32_EXINT_INIT_LINE_RANGE); + return at32_exint_enable_registers(); +} + +static struct at32_exint_data exint_data; +DEVICE_DT_DEFINE(EXINT_NODE, &at32_exint_init, NULL, &exint_data, NULL, PRE_KERNEL_1, + CONFIG_INTC_INIT_PRIORITY, NULL); + +/** + * @brief EXINT GPIO interrupt controller API implementation + */ + +/** + * @internal + * AT32 EXINT driver: + * The type @ref at32_exint_irq_line_t is used to hold the EXINT_LINE_x + * defines of the EXINT API that corresponds to the provided pin. + * + * @endinternal + */ +at32_irq_line_t at32_exint_intc_get_pin_irq_line(uint32_t port, gpio_pin_t pin) +{ + ARG_UNUSED(port); + return linenum_to_exint_line(pin); +} + +void at32_exint_intc_enable_line(at32_irq_line_t line) +{ + unsigned int irqnum; + uint32_t line_num = exint_line_to_linenum(line); + + __ASSERT_NO_MSG(line_num < NUM_EXINT_LINES); + /* Get matching exint irq provided line thanks to irq_table */ + irqnum = exint_irq_table[line_num]; + __ASSERT_NO_MSG(irqnum != 0xFF); + + exint_interrupt_enable(line, TRUE); + /* Enable exint irq interrupt */ + irq_enable(irqnum); +} + +void at32_exint_intc_disable_line(at32_irq_line_t line) +{ + exint_interrupt_enable(line, FALSE); +} + +void at32_exint_intc_select_line_trigger(at32_irq_line_t line, uint32_t trigger) +{ + switch (trigger) { + case AT32_GPIO_IRQ_TRIG_NONE: + EXINT->polcfg1 &= ~line; + EXINT->polcfg2 &= ~line; + break; + case AT32_GPIO_IRQ_TRIG_RISING: + EXINT->polcfg1 |= line; + EXINT->polcfg2 &= ~line; + break; + case AT32_GPIO_IRQ_TRIG_FALLING: + EXINT->polcfg1 &= ~line; + EXINT->polcfg2 |= line; + break; + case AT32_GPIO_IRQ_TRIG_BOTH: + EXINT->polcfg1 |= line; + EXINT->polcfg2 |= line; + break; + default: + __ASSERT_NO_MSG(0); + break; + } +} + +int at32_exint_intc_set_irq_callback(at32_irq_line_t line, at32_exint_irq_cb_t cb, void *arg) +{ + const struct device *const dev = DEVICE_DT_GET(EXINT_NODE); + struct at32_exint_data *data = dev->data; + uint32_t line_num = exint_line_to_linenum(line); + + if ((data->cb[line_num].cb == cb) && (data->cb[line_num].data == arg)) { + return 0; + } + + /* if callback already exists/maybe-running return busy */ + if (data->cb[line_num].cb != NULL) { + return -EBUSY; + } + + data->cb[line_num].cb = cb; + data->cb[line_num].data = arg; + + return 0; +} + +void at32_exint_intc_remove_irq_callback(at32_irq_line_t line) +{ + const struct device *const dev = DEVICE_DT_GET(EXINT_NODE); + struct at32_exint_data *data = dev->data; + uint32_t line_num = exint_line_to_linenum(line); + + data->cb[line_num].cb = NULL; + data->cb[line_num].data = NULL; +} + +void at32_exint_set_line_src_port(gpio_pin_t pin, uint32_t port) +{ + scfg_exint_line_config(get_source_port(port), pin); +} + +uint32_t at32_exint_get_line_src_port(gpio_pin_t pin) +{ + uint32_t port; + + port = scfg_get_exint_port((scfg_pins_source_type)pin); + return port; +} From 71589169dc7b3e39c5d5598b95a7d039de98196c Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:19:48 +0800 Subject: [PATCH 05/12] driver: usart: add usart driver to support AT32F405 Add usart driver to support AT32F405 Signed-off-by: jun tan --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 1 + drivers/serial/Kconfig.at32 | 13 ++ drivers/serial/usart_at32.c | 346 ++++++++++++++++++++++++++++++++++ 4 files changed, 361 insertions(+) create mode 100644 drivers/serial/Kconfig.at32 create mode 100644 drivers/serial/usart_at32.c diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 9881217d5b009..c6b91c5d21998 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -99,6 +99,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_XEN_HVC_CONSOLEIO uart_hvc_xen_consolei zephyr_library_sources_ifdef(CONFIG_UART_XLNX_PS uart_xlnx_ps.c) zephyr_library_sources_ifdef(CONFIG_UART_XLNX_UARTLITE uart_xlnx_uartlite.c) zephyr_library_sources_ifdef(CONFIG_UART_XMC4XXX uart_xmc4xxx.c) +zephyr_library_sources_ifdef(CONFIG_USART_AT32 usart_at32.c) zephyr_library_sources_ifdef(CONFIG_USART_GD32 usart_gd32.c) zephyr_library_sources_ifdef(CONFIG_USART_SAM usart_sam.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ea3fbed123bac..4b54bcd6777df 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -162,6 +162,7 @@ rsource "Kconfig.altera" rsource "Kconfig.altera_jtag" rsource "Kconfig.ambiq" rsource "Kconfig.apbuart" +rsource "Kconfig.at32" rsource "Kconfig.b91" rsource "Kconfig.bcm2711" rsource "Kconfig.bflb" diff --git a/drivers/serial/Kconfig.at32 b/drivers/serial/Kconfig.at32 new file mode 100644 index 0000000000000..aebf1d1326f2a --- /dev/null +++ b/drivers/serial/Kconfig.at32 @@ -0,0 +1,13 @@ +# Copyright (c) 2021 ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +config USART_AT32 + bool "AT32 serial driver" + default y + depends on DT_HAS_ARTERY_AT32_USART_ENABLED + select PINCTRL + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + select USE_AT32_USART + help + This option enables the USART driver for AT32 SoC family. diff --git a/drivers/serial/usart_at32.c b/drivers/serial/usart_at32.c new file mode 100644 index 0000000000000..e104e38f58dc2 --- /dev/null +++ b/drivers/serial/usart_at32.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2021, ATL Electronics + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT artery_at32_usart + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define AT32_USART(reg) ((usart_type *) reg) + +struct at32_usart_config { + uint32_t reg; + uint16_t clkid; + struct reset_dt_spec reset; + const struct pinctrl_dev_config *pcfg; + uint32_t parity; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_config_func_t irq_config_func; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +struct at32_usart_data { + uint32_t baud_rate; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t user_cb; + void *user_data; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static void usart_at32_isr(const struct device *dev) +{ + struct at32_usart_data *const data = dev->data; + + if (data->user_cb) { + data->user_cb(dev, data->user_data); + } +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static int usart_at32_init(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + struct at32_usart_data *const data = dev->data; + usart_data_bit_num_type word_length; + usart_parity_selection_type parity; + int ret; + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + /** + * In order to keep the transfer data size to 8 bits(1 byte), + * append word length to 9BIT if parity bit enabled. + */ + switch (cfg->parity) { + case UART_CFG_PARITY_NONE: + parity = USART_PARITY_NONE; + word_length = USART_DATA_8BITS; + break; + case UART_CFG_PARITY_ODD: + parity = USART_PARITY_ODD; + word_length = USART_DATA_9BITS; + break; + case UART_CFG_PARITY_EVEN: + parity = USART_PARITY_EVEN; + word_length = USART_DATA_9BITS; + break; + default: + return -ENOTSUP; + } + + (void)clock_control_on(AT32_CLOCK_CONTROLLER, + (clock_control_subsys_t)&cfg->clkid); + + (void)reset_line_toggle_dt(&cfg->reset); + + usart_init(AT32_USART(cfg->reg), data->baud_rate, + word_length, USART_STOP_1_BIT); + usart_parity_selection_config(AT32_USART(cfg->reg), parity); + usart_receiver_enable(AT32_USART(cfg->reg), TRUE); + usart_transmitter_enable(AT32_USART(cfg->reg), TRUE); + usart_enable((AT32_USART(cfg->reg)), TRUE); + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + cfg->irq_config_func(dev); +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + return 0; +} + +static int usart_at32_poll_in(const struct device *dev, unsigned char *c) +{ + const struct at32_usart_config *const cfg = dev->config; + uint32_t status; + + status = (uint32_t)usart_flag_get(AT32_USART(cfg->reg), USART_RDBF_FLAG); + + if (!status) { + return -EPERM; + } + + *c = usart_data_receive(AT32_USART(cfg->reg)); + + return 0; +} + +static void usart_at32_poll_out(const struct device *dev, unsigned char c) +{ + const struct at32_usart_config *const cfg = dev->config; + + usart_data_transmit(AT32_USART(cfg->reg), c); + + while (usart_flag_get(AT32_USART(cfg->reg), USART_TDBE_FLAG) == RESET) { + ; + } +} + +static int usart_at32_err_check(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + uint32_t status = usart->sts; + int errors = 0; + + if (status & USART_ROERR_FLAG) { + usart_flag_clear(usart, USART_ROERR_FLAG); + + errors |= UART_ERROR_OVERRUN; + } + + if (status & USART_PERR_FLAG) { + usart_flag_clear(usart, USART_PERR_FLAG); + + errors |= UART_ERROR_PARITY; + } + + if (status & USART_FERR_FLAG) { + usart_flag_clear(usart, USART_FERR_FLAG); + + errors |= UART_ERROR_FRAMING; + } + + usart_flag_clear(usart, USART_NERR_FLAG); + + return errors; +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +int usart_at32_fifo_fill(const struct device *dev, const uint8_t *tx_data, + int len) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + uint8_t num_tx = 0U; + + while ((len - num_tx > 0) && + usart_flag_get(usart, USART_TDBE_FLAG)) { + usart_data_transmit(usart, tx_data[num_tx++]); + } + return num_tx; +} + +int usart_at32_fifo_read(const struct device *dev, uint8_t *rx_data, + const int size) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + uint8_t num_rx = 0U; + + while ((size - num_rx > 0) && + usart_flag_get(usart, USART_RDBF_FLAG)) { + rx_data[num_rx++] = usart_data_receive(usart); + } + return num_rx; +} + +void usart_at32_irq_tx_enable(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + usart_interrupt_enable(usart, USART_TDC_INT, TRUE); +} + +void usart_at32_irq_tx_disable(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + usart_interrupt_enable(usart, USART_TDC_INT, FALSE); +} + +int usart_at32_irq_tx_ready(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + return usart_flag_get(usart, USART_TDBE_FLAG) && + usart_interrupt_flag_get(usart, USART_TDC_FLAG); +} + +int usart_at32_irq_tx_complete(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + return (int)usart_flag_get(usart, USART_TDC_FLAG); +} + +void usart_at32_irq_rx_enable(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + usart_interrupt_enable(usart, USART_RDBF_INT, TRUE); +} + +void usart_at32_irq_rx_disable(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + usart_interrupt_enable(usart, USART_RDBF_INT, FALSE); +} + +int usart_at32_irq_rx_ready(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + return usart_flag_get(usart, USART_RDBF_FLAG); +} + +void usart_at32_irq_err_enable(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + usart_interrupt_enable(usart, USART_ERR_INT, TRUE); + usart_interrupt_enable(usart, USART_PERR_INT, TRUE); +} + +void usart_at32_irq_err_disable(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + usart_interrupt_enable(usart, USART_ERR_INT, FALSE); + usart_interrupt_enable(usart, USART_PERR_INT, FALSE); +} + +int usart_at32_irq_is_pending(const struct device *dev) +{ + const struct at32_usart_config *const cfg = dev->config; + usart_type *usart = AT32_USART(cfg->reg); + + return ((usart_flag_get(usart, USART_RDBF_FLAG) && + usart_interrupt_flag_get(usart, USART_RDBF_FLAG)) || + (usart_flag_get(usart, USART_TDC_FLAG) && + usart_interrupt_flag_get(usart, USART_TDC_FLAG))); +} + +void usart_at32_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *user_data) +{ + struct at32_usart_data *const data = dev->data; + + data->user_cb = cb; + data->user_data = user_data; +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static DEVICE_API(uart, usart_at32_driver_api) = { + .poll_in = usart_at32_poll_in, + .poll_out = usart_at32_poll_out, + .err_check = usart_at32_err_check, +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = usart_at32_fifo_fill, + .fifo_read = usart_at32_fifo_read, + .irq_tx_enable = usart_at32_irq_tx_enable, + .irq_tx_disable = usart_at32_irq_tx_disable, + .irq_tx_ready = usart_at32_irq_tx_ready, + .irq_tx_complete = usart_at32_irq_tx_complete, + .irq_rx_enable = usart_at32_irq_rx_enable, + .irq_rx_disable = usart_at32_irq_rx_disable, + .irq_rx_ready = usart_at32_irq_rx_ready, + .irq_err_enable = usart_at32_irq_err_enable, + .irq_err_disable = usart_at32_irq_err_disable, + .irq_is_pending = usart_at32_irq_is_pending, + .irq_callback_set = usart_at32_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#define AT32_USART_IRQ_HANDLER(n) \ + static void usart_at32_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + usart_at32_isr, \ + DEVICE_DT_INST_GET(n), \ + 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } +#define AT32_USART_IRQ_HANDLER_FUNC_INIT(n) \ + .irq_config_func = usart_at32_config_func_##n +#else /* CONFIG_UART_INTERRUPT_DRIVEN */ +#define AT32_USART_IRQ_HANDLER(n) +#define AT32_USART_IRQ_HANDLER_FUNC_INIT(n) +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +#define AT32_USART_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + AT32_USART_IRQ_HANDLER(n) \ + static struct at32_usart_data usart_at32_data_##n = { \ + .baud_rate = DT_INST_PROP(n, current_speed), \ + }; \ + static const struct at32_usart_config usart_at32_config_##n = { \ + .reg = DT_INST_REG_ADDR(n), \ + .clkid = DT_INST_CLOCKS_CELL(n, id), \ + .reset = RESET_DT_SPEC_INST_GET(n), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .parity = DT_INST_ENUM_IDX_OR(n, parity, UART_CFG_PARITY_NONE), \ + AT32_USART_IRQ_HANDLER_FUNC_INIT(n) \ + }; \ + DEVICE_DT_INST_DEFINE(n, usart_at32_init, \ + NULL, \ + &usart_at32_data_##n, \ + &usart_at32_config_##n, PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, \ + &usart_at32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(AT32_USART_INIT) From 696dfe717d22d859fb29de1bd45d21d3a29758c4 Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:21:46 +0800 Subject: [PATCH 06/12] driver: pinctrl: add pinctrl driver. Add pinctrl driver to support AT32F405. Signed-off-by: jun tan --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.at32 | 10 +++ drivers/pinctrl/pinctrl_at32_mux.c | 100 +++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.at32 create mode 100644 drivers/pinctrl/pinctrl_at32_mux.c diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index b325217c6a929..2a1bfbb777168 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -12,6 +12,7 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_ARM_V2M_BEETLE pinctrl_arm_v2m_beetl zephyr_library_sources_ifdef(CONFIG_PINCTRL_BFLB pinctrl_bflb.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) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_AT32_MUX pinctrl_at32_mux.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_ITE_IT8XXX2 pinctrl_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NPCX pinctrl_npcx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NUMICRO pinctrl_numicro.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index a47c4392a78ad..bcead8c43b7b6 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -40,6 +40,7 @@ source "drivers/pinctrl/Kconfig.ambiq" source "drivers/pinctrl/Kconfig.arm_mps2" source "drivers/pinctrl/Kconfig.arm_mps3" source "drivers/pinctrl/Kconfig.arm_v2m_beetle" +source "drivers/pinctrl/Kconfig.at32" source "drivers/pinctrl/Kconfig.gd32" source "drivers/pinctrl/Kconfig.it8xxx2" source "drivers/pinctrl/Kconfig.npcx" diff --git a/drivers/pinctrl/Kconfig.at32 b/drivers/pinctrl/Kconfig.at32 new file mode 100644 index 0000000000000..263cf1f0cc8bd --- /dev/null +++ b/drivers/pinctrl/Kconfig.at32 @@ -0,0 +1,10 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_AT32_MUX + bool "AT32 MUX pin controller driver" + default y + depends on DT_HAS_ARTERY_AT32_PINCTRL_MUX_ENABLED + help + AT32 MUX pin controller driver. This driver is used by series using the + AF pin multiplexing model. diff --git a/drivers/pinctrl/pinctrl_at32_mux.c b/drivers/pinctrl/pinctrl_at32_mux.c new file mode 100644 index 0000000000000..5e3417294034e --- /dev/null +++ b/drivers/pinctrl/pinctrl_at32_mux.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +/** Utility macro that expands to the GPIO port address if it exists */ +#define AT32_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 clock id if it exists */ +#define AT32_PORT_CLOCK_ID_OR_NONE(nodelabel) \ + COND_CODE_1(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \ + (DT_CLOCKS_CELL(DT_NODELABEL(nodelabel), id),), ()) +#define GPIO_PIN_OFFSET(n) (1 << n) +/** GD32 port addresses */ +static const uint32_t at32_port_addrs[] = { + AT32_PORT_ADDR_OR_NONE(gpioa) + AT32_PORT_ADDR_OR_NONE(gpiob) + AT32_PORT_ADDR_OR_NONE(gpioc) + AT32_PORT_ADDR_OR_NONE(gpiod) + AT32_PORT_ADDR_OR_NONE(gpioe) + AT32_PORT_ADDR_OR_NONE(gpiof) + AT32_PORT_ADDR_OR_NONE(gpiog) + AT32_PORT_ADDR_OR_NONE(gpioh) + AT32_PORT_ADDR_OR_NONE(gpioi) +}; + +/** GD32 port clock identifiers */ +static const uint16_t at32_port_clkids[] = { + AT32_PORT_CLOCK_ID_OR_NONE(gpioa) + AT32_PORT_CLOCK_ID_OR_NONE(gpiob) + AT32_PORT_CLOCK_ID_OR_NONE(gpioc) + AT32_PORT_CLOCK_ID_OR_NONE(gpiod) + AT32_PORT_CLOCK_ID_OR_NONE(gpioe) + AT32_PORT_CLOCK_ID_OR_NONE(gpiof) + AT32_PORT_CLOCK_ID_OR_NONE(gpiog) + AT32_PORT_CLOCK_ID_OR_NONE(gpioh) + AT32_PORT_CLOCK_ID_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 port, pin_num, mux; + uint16_t clkid; + gpio_init_type init; + gpio_type *gpio; + uint32_t gpio_pins = 0; + + port_idx = AT32_PORT_GET(pin); + __ASSERT_NO_MSG(port_idx < ARRAY_SIZE(at32_port_addrs)); + + clkid = at32_port_clkids[port_idx]; + port = at32_port_addrs[port_idx]; + pin_num = AT32_PIN_GET(pin); + gpio_pins = GPIO_PIN_OFFSET(pin_num); + mux = AT32_MUX_GET(pin); + + gpio = (gpio_type *)port; + + init.gpio_pins = gpio_pins; + if (mux != AT32_ANALOG) { + init.gpio_mode = GPIO_MODE_MUX; + } else { + init.gpio_mode = GPIO_MODE_ANALOG; + } + + init.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; + + (void)clock_control_on(AT32_CLOCK_CONTROLLER, + (clock_control_subsys_t)&clkid); + + gpio_init(gpio, &init); + gpio_pin_mux_config(gpio, pin_num, mux); +} + +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; +} From f831b5724dfc3c25d38b0d46dc0a0f19a0f456e2 Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:23:17 +0800 Subject: [PATCH 07/12] driver: reset: add reset driver. Add reset driver to support AT32F405. Signed-off-by: jun tan --- drivers/reset/CMakeLists.txt | 1 + drivers/reset/Kconfig | 1 + drivers/reset/Kconfig.at32 | 7 ++++ drivers/reset/reset_at32.c | 74 ++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 drivers/reset/Kconfig.at32 create mode 100644 drivers/reset/reset_at32.c diff --git a/drivers/reset/CMakeLists.txt b/drivers/reset/CMakeLists.txt index e94d51e2d2aa4..4c9908d65d711 100644 --- a/drivers/reset/CMakeLists.txt +++ b/drivers/reset/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/reset.h) zephyr_library() zephyr_library_sources_ifdef(CONFIG_RESET_GD32 reset_gd32.c) +zephyr_library_sources_ifdef(CONFIG_RESET_AT32 reset_at32.c) zephyr_library_sources_ifdef(CONFIG_RESET_RPI_PICO reset_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_RESET_AST10X0 reset_ast10x0.c) zephyr_library_sources_ifdef(CONFIG_RESET_STM32 reset_stm32.c) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 10e34c47f0b4f..c6a3485d7e20d 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -29,6 +29,7 @@ comment "Reset Controller Drivers" rsource "Kconfig.rpi_pico" rsource "Kconfig.gd32" +rsource "Kconfig.at32" rsource "Kconfig.aspeed" rsource "Kconfig.stm32" rsource "Kconfig.numaker" diff --git a/drivers/reset/Kconfig.at32 b/drivers/reset/Kconfig.at32 new file mode 100644 index 0000000000000..863c012f1a084 --- /dev/null +++ b/drivers/reset/Kconfig.at32 @@ -0,0 +1,7 @@ +# Copyright (c) 2022 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +config RESET_AT32 + bool "AT32 Reset Controller Driver" + default y + depends on DT_HAS_ARTERY_AT32_RCTL_ENABLED diff --git a/drivers/reset/reset_at32.c b/drivers/reset/reset_at32.c new file mode 100644 index 0000000000000..531e9ae2b7dfc --- /dev/null +++ b/drivers/reset/reset_at32.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT artery_at32_rctl + +#include +#include +#include +#include + +/** CRM offset (from id field) */ +#define AT32_RESET_ID_OFFSET(id) (((id) >> 6U) & 0xFFU) +/** CRM configuration bit (from id field) */ +#define AT32_RESET_ID_BIT(id) ((id) & 0x1FU) + +struct reset_at32_config { + uint32_t base; +}; + +static int reset_at32_status(const struct device *dev, uint32_t id, + uint8_t *status) +{ + const struct reset_at32_config *config = dev->config; + + *status = !!sys_test_bit(config->base + AT32_RESET_ID_OFFSET(id), + AT32_RESET_ID_BIT(id)); + + return 0; +} + +static int reset_at32_line_assert(const struct device *dev, uint32_t id) +{ + const struct reset_at32_config *config = dev->config; + + sys_set_bit(config->base + AT32_RESET_ID_OFFSET(id), + AT32_RESET_ID_BIT(id)); + + return 0; +} + +static int reset_at32_line_deassert(const struct device *dev, uint32_t id) +{ + const struct reset_at32_config *config = dev->config; + + sys_clear_bit(config->base + AT32_RESET_ID_OFFSET(id), + AT32_RESET_ID_BIT(id)); + + return 0; +} + +static int reset_at32_line_toggle(const struct device *dev, uint32_t id) +{ + (void)reset_at32_line_assert(dev, id); + (void)reset_at32_line_deassert(dev, id); + + return 0; +} + +static DEVICE_API(reset, reset_at32_driver_api) = { + .status = reset_at32_status, + .line_assert = reset_at32_line_assert, + .line_deassert = reset_at32_line_deassert, + .line_toggle = reset_at32_line_toggle, +}; + +static const struct reset_at32_config config = { + .base = DT_REG_ADDR(DT_INST_PARENT(0)), +}; + +DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, &config, PRE_KERNEL_1, + CONFIG_RESET_INIT_PRIORITY, &reset_at32_driver_api); From 333a2e3132b71ffe12885e9683508bbe45e2773c Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:25:56 +0800 Subject: [PATCH 08/12] dts: bingdings/arm: Add devicetree and dirver tree Add AT32F405 devicetree and clock, gpio, misc, usart, pinctrl drivertree. Signed-off-by: jun tan --- dts/arm/artery/at32f402_405/at32f405.dtsi | 583 ++++++++++++++++++ dts/arm/artery/at32f402_405/at32f405rct7.dtsi | 22 + dts/bindings/clock/artery,at32-cctl.yaml | 32 + dts/bindings/clock/artery,at32-crm.yaml | 93 +++ dts/bindings/clock/artery,at32-hext.yaml | 25 + dts/bindings/clock/artery,at32-pll.yaml | 51 ++ dts/bindings/gpio/artery,at32-gpio.yaml | 25 + .../artery,at32-exint.yaml | 39 ++ dts/bindings/misc/artery,at32-syscfg.yaml | 15 + .../pinctrl/artery,at32-pinctrl-common.yaml | 25 + .../pinctrl/artery,at32-pinctrl-mux.yaml | 100 +++ dts/bindings/reset/artery,at32-rctl.yaml | 32 + dts/bindings/serial/artery,at32-usart.yaml | 21 + dts/bindings/vendor-prefixes.txt | 1 + 14 files changed, 1064 insertions(+) create mode 100644 dts/arm/artery/at32f402_405/at32f405.dtsi create mode 100644 dts/arm/artery/at32f402_405/at32f405rct7.dtsi create mode 100644 dts/bindings/clock/artery,at32-cctl.yaml create mode 100644 dts/bindings/clock/artery,at32-crm.yaml create mode 100644 dts/bindings/clock/artery,at32-hext.yaml create mode 100644 dts/bindings/clock/artery,at32-pll.yaml create mode 100644 dts/bindings/gpio/artery,at32-gpio.yaml create mode 100644 dts/bindings/interrupt-controller/artery,at32-exint.yaml create mode 100644 dts/bindings/misc/artery,at32-syscfg.yaml create mode 100644 dts/bindings/pinctrl/artery,at32-pinctrl-common.yaml create mode 100644 dts/bindings/pinctrl/artery,at32-pinctrl-mux.yaml create mode 100644 dts/bindings/reset/artery,at32-rctl.yaml create mode 100644 dts/bindings/serial/artery,at32-usart.yaml diff --git a/dts/arm/artery/at32f402_405/at32f405.dtsi b/dts/arm/artery/at32f402_405/at32f405.dtsi new file mode 100644 index 0000000000000..5deb245dd700c --- /dev/null +++ b/dts/arm/artery/at32f402_405/at32f405.dtsi @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2025 Maxjta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m4f"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + }; + }; + + clocks { + clk_hext: clk-hext { + #clock-cells = <0>; + compatible = "artery,at32-hext"; + status = "disabled"; + }; + + clk_hick: clk-hick { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <8000000>; + status = "disabled"; + }; + + clk_lext: clk-lext { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + status = "disabled"; + }; + + clk_lick: clk-lick { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <40000>; + status = "disabled"; + }; + + pll: pll { + #clock-cells = <0>; + compatible = "artery,at32-pll"; + status = "disabled"; + }; + + sysclk: sysclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = ; + status = "disabled"; + }; + }; + + soc { + sram0: memory@20000000 { + compatible = "mmio-sram"; + }; + + crm: reset-clock-controller@40023800 { + compatible = "artery,at32-crm"; + reg = <0x40023800 0x400>; + #clock-cells = <2>; + status = "okay"; + + cctl: clock-controller { + compatible = "artery,at32-cctl"; + #clock-cells = <1>; + status = "okay"; + }; + + rctl: reset-controller { + compatible = "artery,at32-rctl"; + #reset-cells = <1>; + status = "okay"; + }; + }; + + syscfg: syscfg@40013800 { + compatible = "artery,at32-syscfg"; + reg = <0x40013800 0x400>; + clocks = <&cctl AT32_CLOCK_SYSCFG>; + }; + + flash: flash-controller@40023c00 { + compatible = "artery,at32-flash-controller"; + label = "FLASH_CTRL"; + reg = <0x40023c00 0x400>; + peripheral-id = <6>; + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@8000000 { + compatible = "soc-nv-flash"; + }; + }; + + exint: interrupt-controller@40013c00 { + compatible = "artery,at32-exint"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x40013c00 0x400>; + num-lines = <23>; + interrupts = <6 0>, <7 0>, <8 0>, <9 0>, <10 0>, <23 0>, + <40 0>; + interrupt-names = "line0", "line1", "line2", "line3", + "line4", "line5-9", "line10-15"; + line-ranges = <0 1>, <1 1>, <2 1>, <3 1>, + <4 1>, <5 5>, <10 6>; + status = "okay"; + }; + + pinctrl: pin-controller@40020000 { + compatible = "artery,at32-pinctrl-mux"; + reg = <0x40020000 0x2000>; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + + gpioa: gpio@40020000 { + compatible = "artery,at32-gpio"; + gpio-controller; + reg = <0x40020000 0x400>; + clocks = <&cctl AT32_CLOCK_GPIOA>; + resets = <&rctl AT32_RESET_GPIOA>; + #gpio-cells = <2>; + }; + + gpiob: gpio@40020400 { + compatible = "artery,at32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40020400 0x400>; + clocks = <&cctl AT32_CLOCK_GPIOB>; + resets = <&rctl AT32_RESET_GPIOB>; + status = "disabled"; + }; + + gpioc: gpio@40020800 { + compatible = "artery,at32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40020800 0x400>; + clocks = <&cctl AT32_CLOCK_GPIOC>; + resets = <&rctl AT32_RESET_GPIOC>; + status = "disabled"; + }; + + gpiod: gpio@40020C00 { + compatible = "artery,at32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40020C00 0x400>; + clocks = <&cctl AT32_CLOCK_GPIOD>; + resets = <&rctl AT32_RESET_GPIOD>; + status = "disabled"; + }; + + gpiof: gpio@40021400 { + compatible = "artery,at32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40021400 0x400>; + clocks = <&cctl AT32_CLOCK_GPIOF>; + resets = <&rctl AT32_RESET_GPIOF>; + status = "disabled"; + }; + }; + + usart1: usart@40011000 { + compatible = "artery,at32-usart"; + reg = <0x40011000 0x400>; + interrupts = <37 0>; + clocks = <&cctl AT32_CLOCK_USART1>; + resets = <&rctl AT32_RESET_USART1>; + status = "disabled"; + }; + + usart2: usart@40004400 { + compatible = "artery,at32-usart"; + reg = <0x40004400 0x400>; + interrupts = <38 0>; + clocks = <&cctl AT32_CLOCK_USART2>; + resets = <&rctl AT32_RESET_USART2>; + status = "disabled"; + }; + + usart3: usart@40004800 { + compatible = "artery,at32-usart"; + reg = <0x40004800 0x400>; + interrupts = <39 0>; + clocks = <&cctl AT32_CLOCK_USART3>; + resets = <&rctl AT32_RESET_USART3>; + status = "disabled"; + }; + + usart4: usart@40004c00 { + compatible = "artery,at32-usart"; + reg = <0x40004C00 0x400>; + interrupts = <52 0>; + clocks = <&cctl AT32_CLOCK_USART4>; + resets = <&rctl AT32_RESET_USART4>; + status = "disabled"; + }; + + usart5: usart@40005000 { + compatible = "artery,at32-usart"; + reg = <0x40005000 0x400>; + interrupts = <53 0>; + clocks = <&cctl AT32_CLOCK_USART5>; + resets = <&rctl AT32_RESET_USART5>; + status = "disabled"; + }; + + usart6: usart@40011400 { + compatible = "artery,at32-usart"; + reg = <0x40011400 0x400>; + interrupts = <71 0>; + clocks = <&cctl AT32_CLOCK_USART6>; + resets = <&rctl AT32_RESET_USART6>; + status = "disabled"; + }; + + uart7: usart@40007800 { + compatible = "artery,at32-usart"; + reg = <0x40007800 0x400>; + interrupts = <82 0>; + clocks = <&cctl AT32_CLOCK_UART7>; + resets = <&rctl AT32_RESET_UART7>; + status = "disabled"; + }; + + uart8: usart@40007c00 { + compatible = "artery,at32-usart"; + reg = <0x40007C00 0x400>; + interrupts = <83 0>; + clocks = <&cctl AT32_CLOCK_UART8>; + resets = <&rctl AT32_RESET_UART8>; + status = "disabled"; + }; + + usbotg_hs: usb@40040000 { + compatible = "artery,at32-otghs"; + reg = <0x40040000 0x40000>; + interrupts = <77 0>; + num-in-eps = <8>; + num-out-eps = <8>; + ram-size = <4096>; + ghwcfg1 = <0>; + ghwcfg2 = <0>; + ghwcfg4 = <0>; + clocks = <&cctl AT32_CLOCK_USBHS>; + status = "disabled"; + }; + + usbotg_fs: usb@50000000 { + compatible = "artery,at32-otgfs"; + reg = <0x50000000 0x40000>; + interrupts = <67 0>; + num-in-eps = <8>; + num-out-eps = <8>; + ram-size = <1280>; + ghwcfg1 = <0>; + ghwcfg2 = <0>; + ghwcfg4 = <0>; + clocks = <&cctl AT32_CLOCK_USBFS>; + status = "disabled"; + }; + + spi1: spi@40013000 { + compatible = "artery,at32-spi"; + reg = <0x40013000 0x400>; + interrupts = <35 0>; + clocks = <&cctl AT32_CLOCK_SPI1>; + resets = <&rctl AT32_RESET_SPI1>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + spi2: spi@40003800 { + compatible = "artery,at32-spi"; + reg = <0x40003800 0x400>; + interrupts = <36 0>; + clocks = <&cctl AT32_CLOCK_SPI2>; + resets = <&rctl AT32_RESET_SPI2>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + spi3: spi@40003c00 { + compatible = "artery,at32-spi"; + reg = <0x40003c00 0x400>; + interrupts = <51 0>; + clocks = <&cctl AT32_CLOCK_SPI3>; + resets = <&rctl AT32_RESET_SPI3>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + dma1: dma@40026000 { + compatible = "artery,at32-dma"; + reg = <0x40026000 0x400>; + interrupts = <11 0>, <12 0>, <13 0>, <14 0>, + <15 0>, <16 0>, <17 0>; + clocks = <&cctl AT32_CLOCK_DMA1>; + resets = <&rctl AT32_RESET_DMA1>; + dma-channels = <7>; + at,mem2mem; + #dma-cells = <4>; + status = "disabled"; + }; + + dma2: dma@40026400 { + compatible = "artery,at32-dma"; + reg = <0x40026400 0x400>; + interrupts = <56 0>, <57 0>, <58 0>, <59 0>, + <60 0>, <68 0>, <69 0>; + clocks = <&cctl AT32_CLOCK_DMA2>; + resets = <&rctl AT32_RESET_DMA2>; + dma-channels = <7>; + at,mem2mem; + #dma-cells = <4>; + status = "disabled"; + }; + + i2c1: i2c@40005400 { + compatible = "artery,at32-i2c"; + reg = <0x40005400 0x400>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + interrupts = <31 0>, <32 0>; + interrupt-names = "event", "error"; + clocks = <&cctl AT32_CLOCK_I2C1>; + resets = <&rctl AT32_RESET_I2C1>; + status = "disabled"; + }; + + i2c2: i2c@40005800 { + compatible = "artery,at32-i2c"; + reg = <0x40005800 0x400>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + interrupts = <33 0>, <34 0>; + interrupt-names = "event", "error"; + clocks = <&cctl AT32_CLOCK_I2C2>; + resets = <&rctl AT32_RESET_I2C2>; + status = "disabled"; + }; + + i2c3: i2c@40005c00 { + compatible = "artery,at32-i2c"; + reg = <0x40005c00 0x400>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + interrupts = <72 0>, <73 0>; + interrupt-names = "event", "error"; + clocks = <&cctl AT32_CLOCK_I2C3>; + resets = <&rctl AT32_RESET_I2C3>; + status = "disabled"; + }; + + timer1: timer@40010000 { + compatible = "artery,at32-timer"; + reg = <0x40010000 0x400>; + interrupts = <24 0>, <25 0>, <26 0>, <27 0>; + interrupt-names = "brk", "up", "trgcom", "cc"; + clocks = <&cctl AT32_CLOCK_TIMER1>; + resets = <&rctl AT32_RESET_TIMER1>; + channels = <4>; + is-advanced; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer2: timer@40000000 { + compatible = "artery,at32-timer"; + reg = <0x40000000 0x400>; + interrupts = <28 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER2>; + resets = <&rctl AT32_RESET_TIMER2>; + channels = <4>; + at,prescaler = <0>; + is-32bit; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer3: timer@40000400 { + compatible = "artery,at32-timer"; + reg = <0x40000400 0x400>; + interrupts = <29 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER3>; + resets = <&rctl AT32_RESET_TIMER3>; + channels = <4>; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer4: timer@40000800 { + compatible = "artery,at32-timer"; + reg = <0x40000800 0x400>; + interrupts = <30 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER4>; + resets = <&rctl AT32_RESET_TIMER4>; + channels = <4>; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer5: timer@40000c00 { + compatible = "artery,at32-timer"; + reg = <0x40000C00 0x400>; + interrupts = <50 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER5>; + resets = <&rctl AT32_RESET_TIMER5>; + channels = <4>; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer6: timer@40001000 { + compatible = "artery,at32-timer"; + reg = <0x40001000 0x400>; + interrupts = <54 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER6>; + resets = <&rctl AT32_RESET_TIMER6>; + channels = <0>; + status = "disabled"; + }; + + timer7: timer@40001400 { + compatible = "artery,at32-timer"; + reg = <0x40001400 0x400>; + interrupts = <55 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER7>; + resets = <&rctl AT32_RESET_TIMER7>; + channels = <0>; + status = "disabled"; + }; + + timer9: timer@40014000 { + compatible = "artery,at32-timer"; + reg = <0x40014000 0x400>; + interrupts = <24 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER9>; + resets = <&rctl AT32_RESET_TIMER9>; + channels = <2>; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer10: timer@40014400 { + compatible = "artery,at32-timer"; + reg = <0x40014400 0x400>; + interrupts = <25 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER10>; + resets = <&rctl AT32_RESET_TIMER10>; + channels = <1>; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer11: timer@40014800 { + compatible = "artery,at32-timer"; + reg = <0x40014800 0x400>; + interrupts = <46 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER11>; + resets = <&rctl AT32_RESET_TIMER11>; + channels = <1>; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer13: timer@40001c00 { + compatible = "artery,at32-timer"; + reg = <0x40001C00 0x400>; + interrupts = <44 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER13>; + resets = <&rctl AT32_RESET_TIMER13>; + channels = <1>; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer14: timer@40002000 { + compatible = "artery,at32-timer"; + reg = <0x40002000 0x400>; + interrupts = <45 0>; + interrupt-names = "global"; + clocks = <&cctl AT32_CLOCK_TIMER14>; + resets = <&rctl AT32_RESET_TIMER14>; + channels = <1>; + status = "disabled"; + + pwm { + compatible = "artery,at32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; diff --git a/dts/arm/artery/at32f402_405/at32f405rct7.dtsi b/dts/arm/artery/at32f402_405/at32f405rct7.dtsi new file mode 100644 index 0000000000000..ca6c636783b26 --- /dev/null +++ b/dts/arm/artery/at32f402_405/at32f405rct7.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024, Maxjta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + soc { + flash-controller@40023c00 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(256)>; + }; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(96)>; + }; + }; +}; diff --git a/dts/bindings/clock/artery,at32-cctl.yaml b/dts/bindings/clock/artery,at32-cctl.yaml new file mode 100644 index 0000000000000..79f5453885666 --- /dev/null +++ b/dts/bindings/clock/artery,at32-cctl.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2022, Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: | + AT32 Clock and Reset (CRM) if a multi-function peripheral in + charge of reset control (RCTL) and clock control (CCTL) for all SoC + peripherals. This binding represents the clock controller (CCTL). + + To specify the clocks in a peripheral, the standard clocks property needs + to be used, e.g.: + + gpioa: gpio@xxx { + ... + /* cell encodes CRM register offset and control bit position */ + clocks = <&cctl AT32_CLOCK_GPIOA>; + ... + } + + Predefined crm clock cells are available in + include/zephyr/dts-bindings/clock/at32{xxx}_clocks.h header files, where {xxx} + corresponds to the SoC series, e.g. f4xx. + +compatible: "artery,at32-cctl" + +include: [clock-controller.yaml, base.yaml] + +properties: + "#clock-cells": + const: 1 + +clock-cells: + - id diff --git a/dts/bindings/clock/artery,at32-crm.yaml b/dts/bindings/clock/artery,at32-crm.yaml new file mode 100644 index 0000000000000..1476f17a3d685 --- /dev/null +++ b/dts/bindings/clock/artery,at32-crm.yaml @@ -0,0 +1,93 @@ +# Copyright (c) 2021, Linaro ltd +# SPDX-License-Identifier: Apache-2.0 + +description: | + AT32 Clock and Reset controller node. + This node is in charge of system clock ('SYSCLK') source selection and controlling + clocks for AHB (Advanced High Performance) and APB (Advanced Peripheral) bus domains. + + Configuring AT32 Clock and Reset controller node: + + System clock source should be selected amongst the clock nodes available in "clocks" + node (typically 'clk_hext, clk_hick', 'pll', ...). + Core clock frequency should also be defined, using "clock-frequency" property. + Note: + Core clock frequency = SYSCLK / AHB prescaler + Last, peripheral bus clocks (typically PCLK1, PCLK2) should be configured using matching + prescaler properties. + Here is an example of correctly configured rcc node: + &rcc { + clocks = <&pll>; /* Select 80MHz pll as SYSCLK source */ + ahb-prescaler = <2>; + clock-frequency = ; /* = SYSCLK / AHB prescaler */ + apb1-presacler = <1>; + apb2-presacler = <1>; + } + +compatible: "artery,at32-crm" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#clock-cells": + const: 2 + + clock-frequency: + required: true + type: int + description: | + default frequency in Hz for clock output + + ahb-prescaler: + type: int + required: true + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + - 64 + - 128 + - 256 + - 512 + description: | + AHB prescaler. Defines actual core clock frequency (HCLK) + based on system frequency input. + The HCLK clocks CPU, AHB, memories and DMA. + + apb1-prescaler: + type: int + required: true + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + + apb2-prescaler: + type: int + required: true + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + + undershoot-prevention: + type: boolean + description: | + On some parts, it could be required to set up highest core frequencies + (>80MHz) in two steps in order to prevent undershoot. + This is done by applying an intermediate AHB prescaler before switching + System Clock source to PLL. Once done, prescaler is set back to expected + value. + +clock-cells: + - bus + - bits diff --git a/dts/bindings/clock/artery,at32-hext.yaml b/dts/bindings/clock/artery,at32-hext.yaml new file mode 100644 index 0000000000000..fbdde911e51c1 --- /dev/null +++ b/dts/bindings/clock/artery,at32-hext.yaml @@ -0,0 +1,25 @@ +# Copyright (c) 2021, Linaro ltd +# SPDX-License-Identifier: Apache-2.0 + +description: AT32 HEXT Clock + +compatible: "artery,at32-hext" + +include: [fixed-clock.yaml] + +properties: + hext-bypass: + type: boolean + description: | + HEXT crystal oscillator bypass + Set to the property to by-pass the oscillator with an external clock. + + css-enabled: + type: boolean + description: | + HEXT clock security system enabled. + + If a failure is detected on the HEXT clock, the HEXT oscillator is automatically disabled, + a clock failure event is sent to timers, and a non-maskable interrupt is generated to + inform the software about the failure, allowing the MCU to perform rescue operations. + See the MCU reference manual for details. diff --git a/dts/bindings/clock/artery,at32-pll.yaml b/dts/bindings/clock/artery,at32-pll.yaml new file mode 100644 index 0000000000000..d679e39820e29 --- /dev/null +++ b/dts/bindings/clock/artery,at32-pll.yaml @@ -0,0 +1,51 @@ +# Copyright (c) 2021, Linaro ltd +# SPDX-License-Identifier: Apache-2.0 + +description: | + AT32 Main PLL node binding: + + Takes one of clk_hext or clk_hick as input clock. + + +compatible: "artery,at32-pll" + +include: [clock-controller.yaml, base.yaml] + +properties: + "#clock-cells": + const: 0 + + clocks: + required: true + + div-ms: + type: int + required: true + description: | + Division factor for the PLL input clock + Valid range: 2 - 63 + + mul-ns: + type: int + required: true + description: | + Main PLL multiplication factor for VCO + Valid range: 50 - 432 + + div-fp: + type: int + required: true + description: | + Main PLL division factor for PLLSAI2CLK + enum: + - 2 + - 4 + - 6 + - 8 + + div-fu: + type: int + description: | + Main PLL (PLL) division factor for USB OTG FS, SDMMC and random number + generator clocks. + Valid range: 2 - 15 diff --git a/dts/bindings/gpio/artery,at32-gpio.yaml b/dts/bindings/gpio/artery,at32-gpio.yaml new file mode 100644 index 0000000000000..401e29f8dc233 --- /dev/null +++ b/dts/bindings/gpio/artery,at32-gpio.yaml @@ -0,0 +1,25 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: AT32 GPIO node + +compatible: "artery,at32-gpio" + +include: [gpio-controller.yaml, reset-device.yaml, base.yaml] + +properties: + reg: + required: true + + clocks: + required: true + + resets: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/interrupt-controller/artery,at32-exint.yaml b/dts/bindings/interrupt-controller/artery,at32-exint.yaml new file mode 100644 index 0000000000000..5484a19facdc0 --- /dev/null +++ b/dts/bindings/interrupt-controller/artery,at32-exint.yaml @@ -0,0 +1,39 @@ +description: AT32 External Interrupt Controller + +compatible: "artery,at32-exint" + +include: [base.yaml, interrupt-controller.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + "#interrupt-cells": + const: 1 + + num-lines: + type: int + required: true + description: Number of lines supported by the interrupt controller. + + line-ranges: + type: array + required: true + description: | + Description of the input lines range for each interrupt line supported + by the external interrupt controller. For each line a couple of integers is + provided: the number of the first line of the range start and the length + of the range. + As example: + line-ranges = <0 1>, <1 1>, <2 1>, <3 1>, + <4 1>, <5 5>, <10 6>; + Above property provides event-range for 7 lines. + 5 first lines contain one element + 6th line starts with input line 5 and contains 5 elements (5 to 9) + 7th line starts with inupt line 10 and contains 6 elements (10 to 15) + +interrupt-cells: + - line diff --git a/dts/bindings/misc/artery,at32-syscfg.yaml b/dts/bindings/misc/artery,at32-syscfg.yaml new file mode 100644 index 0000000000000..e5c143a1fdf42 --- /dev/null +++ b/dts/bindings/misc/artery,at32-syscfg.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: AT32 System Configuration Registers + +compatible: "artery,at32-syscfg" + +include: base.yaml + +properties: + reg: + required: true + + clocks: + required: true diff --git a/dts/bindings/pinctrl/artery,at32-pinctrl-common.yaml b/dts/bindings/pinctrl/artery,at32-pinctrl-common.yaml new file mode 100644 index 0000000000000..8ceafd44a3898 --- /dev/null +++ b/dts/bindings/pinctrl/artery,at32-pinctrl-common.yaml @@ -0,0 +1,25 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +include: base.yaml + +child-binding: + child-binding: + include: + - name: pincfg-node.yaml + property-allowlist: + - drive-push-pull + - drive-open-drain + - bias-disable + - bias-pull-down + - bias-pull-up + + 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 + AT32_PIN_MUX utility macros depending on the + pinmux model used by the SoC series. diff --git a/dts/bindings/pinctrl/artery,at32-pinctrl-mux.yaml b/dts/bindings/pinctrl/artery,at32-pinctrl-mux.yaml new file mode 100644 index 0000000000000..82742d6b774fc --- /dev/null +++ b/dts/bindings/pinctrl/artery,at32-pinctrl-mux.yaml @@ -0,0 +1,100 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: | + The AT32 pin controller (MUX model) is a singleton node responsible for + controlling pin function selection and pin properties. For example, you can + use this node to route USART1 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 usart1 "default" state */ + usart1_default: usart1_default { + /* group 1 */ + group1 { + /* configure PA9 as USART1 TX and PA11 as USART1 CTS */ + pinmux = , ; + }; + /* group 2 */ + group2 { + /* configure PA10 as USART1 RX and PA12 as USART1 RTS */ + pinmux = , ; + /* both PA10 and PA12 have pull-up enabled */ + bias-pull-up; + }; + + The 'usart1_default' child node encodes the pin configurations for a + particular state of a device; in this case, the default (that is, active) + state. Similarly, 'usart1_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" + + &usart1 { + pinctrl-0 = <&usart1_default>; + pinctrl-1 = <&usart1_sleep>; + pinctrl-names = "default", "sleep"; + }; + +compatible: "artery,at32-pinctrl-mux" + +include: artery,at32-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: + 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/reset/artery,at32-rctl.yaml b/dts/bindings/reset/artery,at32-rctl.yaml new file mode 100644 index 0000000000000..67cf2e91d885e --- /dev/null +++ b/dts/bindings/reset/artery,at32-rctl.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2022, Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: | + AT32 Clock and Reset Unit (CRM) if a multi-function peripheral in + charge of reset control (RCTL) and clock control (CCTL) for all SoC + peripherals. This binding represents the reset controller (RCTL). + + To specify the reset line in a peripheral, the standard resets property needs + to be used, e.g.: + + gpioa: gpio@xxx { + ... + /* cell encodes RCU register offset and control bit position */ + resets = <&rctl GD32_RESET_GPIOA>; + ... + } + + Predefined RCU reset cells are available in + include/zephyr/dts-bindings/reset/at32{xxx}.h header files, where {xxx} + corresponds to the SoC series, e.g. f4xx. + +compatible: "artery,at32-rctl" + +include: [reset-controller.yaml, base.yaml] + +properties: + "#reset-cells": + const: 1 + +reset-cells: + - id diff --git a/dts/bindings/serial/artery,at32-usart.yaml b/dts/bindings/serial/artery,at32-usart.yaml new file mode 100644 index 0000000000000..e92c231c69b3d --- /dev/null +++ b/dts/bindings/serial/artery,at32-usart.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2021, ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +description: AT32 USART + +compatible: "artery,at32-usart" + +include: [uart-controller.yaml, reset-device.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + clocks: + required: true diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index c6874ab32dee0..269cbd078310f 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -84,6 +84,7 @@ asc All Sensors Corporation asmedia ASMedia Technology Inc. aspeed ASPEED Technology Inc. asus AsusTek Computer Inc. +artery Artery Technology atlas Atlas Scientific LLC atmarktechno Atmark Techno, Inc. atmel Atmel Corporation From 314b1ed48e3d8c95af08ed2ddc6ad51c83d963e8 Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:27:17 +0800 Subject: [PATCH 09/12] include: add clock control/interrupt controller api. Add clock and interrupt public api and define. Signed-off-by: jun tan --- .../clock_control/at32_clock_control.h | 55 ++++++++ .../drivers/interrupt_controller/intc_at32.h | 117 ++++++++++++++++++ .../dt-bindings/clock/at32f402_405_clocks.h | 96 ++++++++++++++ .../dt-bindings/reset/at32f402_405_reset.h | 97 +++++++++++++++ 4 files changed, 365 insertions(+) create mode 100644 include/zephyr/drivers/clock_control/at32_clock_control.h create mode 100644 include/zephyr/drivers/interrupt_controller/intc_at32.h create mode 100644 include/zephyr/dt-bindings/clock/at32f402_405_clocks.h create mode 100644 include/zephyr/dt-bindings/reset/at32f402_405_reset.h diff --git a/include/zephyr/drivers/clock_control/at32_clock_control.h b/include/zephyr/drivers/clock_control/at32_clock_control.h new file mode 100644 index 0000000000000..b409c316fc2d9 --- /dev/null +++ b/include/zephyr/drivers/clock_control/at32_clock_control.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_AT32_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_AT32_H_ + +#include + +/** + * @brief Obtain a reference to the AT32 clock controller. + * + * There is a single clock controller in the AT32: ctrl. The device can be + * used without checking for it to be ready since it has no initialization + * code subject to failures. + */ +#define AT32_CLOCK_CONTROLLER DEVICE_DT_GET(DT_NODELABEL(cctl)) + +/* To enable use of IS_ENABLED utility macro, these symbols + * should not be defined directly using DT_SAME_NODE. + */ +#define DT_CRM_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(crm)) +#if DT_SAME_NODE(DT_CRM_CLOCKS_CTRL, DT_NODELABEL(pll)) +#define AT32_SYSCLK_SRC_PLL 1 +#endif +#if DT_SAME_NODE(DT_CRM_CLOCKS_CTRL, DT_NODELABEL(clk_hick)) +#define AT32_SYSCLK_SRC_HICK 1 +#endif +#if DT_SAME_NODE(DT_CRM_CLOCKS_CTRL, DT_NODELABEL(clk_hext)) +#define AT32_SYSCLK_SRC_HEXT 1 +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pll), okay) && DT_NODE_HAS_PROP(DT_NODELABEL(pll), clocks) +#define DT_PLL_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(pll)) +#if DT_SAME_NODE(DT_PLL_CLOCKS_CTRL, DT_NODELABEL(clk_hick)) +#define AT32_PLL_SRC_HICK 1 +#endif +#if DT_SAME_NODE(DT_PLL_CLOCKS_CTRL, DT_NODELABEL(clk_hext)) +#define AT32_PLL_SRC_HEXT 1 +#endif +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_hext), fixed_clock, okay) +#define AT32_HEXT_ENABLED 1 +#define AT32_HEXT_FREQ DT_PROP(DT_NODELABEL(clk_hext), clock_frequency) +#elif DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_hext), at_at32_hext, okay) +#define AT32_HEXT_ENABLED 1 +#define AT32_HEXT_FREQ DT_PROP(DT_NODELABEL(clk_hext), clock_frequency) +#else +#define AT32_HEXT_ENABLED 0 +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_AT32_H_ */ diff --git a/include/zephyr/drivers/interrupt_controller/intc_at32.h b/include/zephyr/drivers/interrupt_controller/intc_at32.h new file mode 100644 index 0000000000000..547faeaeae4bb --- /dev/null +++ b/include/zephyr/drivers/interrupt_controller/intc_at32.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016 Open-RnD Sp. z o.o. + * Copyright (c) 2024 Majtx + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief interrupt controller API for AT32 MCUs + * + * This API is used to interact with the interrupt controller + * of AT32 microcontrollers. + */ + +#ifndef ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_AT32_H_ +#define ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_AT32_H_ + +#include +#include + +/** + * @brief Opaque type representing a GPIO interrupt line + */ +typedef uint32_t at32_irq_line_t; + +/** + * @brief Get the GPIO interrupt line value corresponding + * to specified @p pin of GPIO port @p port + */ +at32_irq_line_t at32_exint_intc_get_pin_irq_line(uint32_t port, gpio_pin_t pin); + +/** + * @brief Enable GPIO interrupts for specified line + * + * @param line GPIO interrupt line + */ +void at32_exint_intc_enable_line(at32_irq_line_t line); + +/** + * @brief Disable GPIO interrupts for specified line + * + * @param line GPIO interrupt line + */ +void at32_exint_intc_disable_line(at32_irq_line_t line); + +/** + * @brief GPIO interrupt trigger flags + */ +enum at32_exint_irq_trigger { + /* No trigger */ + AT32_GPIO_IRQ_TRIG_NONE = 0x0, + /* Trigger on rising edge */ + AT32_GPIO_IRQ_TRIG_RISING = 0x1, + /* Trigger on falling edge */ + AT32_GPIO_IRQ_TRIG_FALLING = 0x2, + /* Trigger on both rising and falling edge */ + AT32_GPIO_IRQ_TRIG_BOTH = 0x3, + /* Trigger on high level */ + AT32_GPIO_IRQ_TRIG_HIGH_LEVEL = 0x4, + /* Trigger on low level */ + AT32_GPIO_IRQ_TRIG_LOW_LEVEL = 0x5 +}; + +/** + * @brief Select trigger for interrupt on specified GPIO line + * + * @param line GPIO interrupt line + * @param trg Interrupt trigger + */ +void at32_exint_intc_select_line_trigger(at32_irq_line_t line, uint32_t trg); + +/** + * @brief GPIO interrupt callback function signature + * + * @param pin GPIO pin on which interrupt occurred + * @param user @p data provided to @ref at32_exint_intc_set_irq_callback + * + * @note This callback is invoked in ISR context. + */ +typedef void (*at32_exint_irq_cb_t)(uint32_t pin, void *user); + +/** + * @brief Set callback invoked when an interrupt occurs on specified GPIO line + * + * @param line interrupt line + * @param cb Interrupt callback function + * @param data Custom data for usage by the callback + * @returns 0 on success, -EBUSY if a callback is already set for @p line + */ +int at32_exint_intc_set_irq_callback(at32_irq_line_t line, at32_exint_irq_cb_t cb, void *data); + +/** + * @brief Removes the interrupt callback of specified EXINT line + * + * @param line EXINT interrupt line + */ +void at32_exint_intc_remove_irq_callback(at32_irq_line_t line); + +/** Hardware-specific API extensions */ + +/** + * @brief Set which GPIO port triggers events on specified EXTI line. + * + * @param line EXINT line number (= pin number) + * @param port GPIO port number + */ +void at32_exint_set_line_src_port(gpio_pin_t line, uint32_t port); + +/** + * @brief Get port which is triggering events on specified EXINT line. + * + * @param pin pin line number (= pin number) + * @returns GPIO port number + */ +uint32_t at32_exint_get_line_src_port(gpio_pin_t pin); + +#endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_AT32_H_ */ diff --git a/include/zephyr/dt-bindings/clock/at32f402_405_clocks.h b/include/zephyr/dt-bindings/clock/at32f402_405_clocks.h new file mode 100644 index 0000000000000..18362dcd7ff86 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/at32f402_405_clocks.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2022 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_AT32F402_405_CLOCKS_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_AT32F402_405_CLOCKS_H_ + +/** + * Encode crm register offset and configuration bit. + * + * - 0..5: bit number + * - 6..14: offset + * - 15: reserved + * + * @param reg crm register name (expands to AT32{reg}_OFFSET) + * @param bit Configuration bit + */ +#define AT32_CLOCK_CONFIG(reg, bit) (((AT32_##reg##_OFFSET) << 6U) | (bit)) + +/** + * @name Register offsets + * @{ + */ + +#define AT32_AHB1EN_OFFSET 0x30U +#define AT32_AHB2EN_OFFSET 0x34U +#define AT32_AHB3EN_OFFSET 0x38U +#define AT32_APB1EN_OFFSET 0x40U +#define AT32_APB2EN_OFFSET 0x44U + +/** @} */ + +/** + * @name Clock enable/disable definitions for peripherals + * @{ + */ + +/* AHB1 peripherals */ +#define AT32_CLOCK_GPIOA AT32_CLOCK_CONFIG(AHB1EN, 0) +#define AT32_CLOCK_GPIOB AT32_CLOCK_CONFIG(AHB1EN, 1) +#define AT32_CLOCK_GPIOC AT32_CLOCK_CONFIG(AHB1EN, 2) +#define AT32_CLOCK_GPIOD AT32_CLOCK_CONFIG(AHB1EN, 3) +#define AT32_CLOCK_GPIOF AT32_CLOCK_CONFIG(AHB1EN, 5) +#define AT32_CLOCK_CRC AT32_CLOCK_CONFIG(AHB1EN, 12) +#define AT32_CLOCK_DMA1 AT32_CLOCK_CONFIG(AHB1EN, 22) +#define AT32_CLOCK_DMA2 AT32_CLOCK_CONFIG(AHB1EN, 24) +#define AT32_CLOCK_USBHS AT32_CLOCK_CONFIG(AHB1EN, 29) + +/* AHB2 peripherals */ +#define AT32_CLOCK_USBFS AT32_CLOCK_CONFIG(AHB2EN, 7) + +/* AHB3 peripherals */ +#define AT32_CLOCK_QSPI1 AT32_CLOCK_CONFIG(AHB3EN, 1) + +/* APB1 peripherals */ +#define AT32_CLOCK_TIMER2 AT32_CLOCK_CONFIG(APB1EN, 0) +#define AT32_CLOCK_TIMER3 AT32_CLOCK_CONFIG(APB1EN, 1) +#define AT32_CLOCK_TIMER4 AT32_CLOCK_CONFIG(APB1EN, 2) +#define AT32_CLOCK_TIMER5 AT32_CLOCK_CONFIG(APB1EN, 3) +#define AT32_CLOCK_TIMER6 AT32_CLOCK_CONFIG(APB1EN, 4) +#define AT32_CLOCK_TIMER7 AT32_CLOCK_CONFIG(APB1EN, 5) +#define AT32_CLOCK_TIMER13 AT32_CLOCK_CONFIG(APB1EN, 7) +#define AT32_CLOCK_TIMER14 AT32_CLOCK_CONFIG(APB1EN, 8) +#define AT32_CLOCK_WWDT AT32_CLOCK_CONFIG(APB1EN, 11) +#define AT32_CLOCK_SPI2 AT32_CLOCK_CONFIG(APB1EN, 14) +#define AT32_CLOCK_SPI3 AT32_CLOCK_CONFIG(APB1EN, 15) +#define AT32_CLOCK_USART2 AT32_CLOCK_CONFIG(APB1EN, 17) +#define AT32_CLOCK_USART3 AT32_CLOCK_CONFIG(APB1EN, 18) +#define AT32_CLOCK_USART4 AT32_CLOCK_CONFIG(APB1EN, 19) +#define AT32_CLOCK_USART5 AT32_CLOCK_CONFIG(APB1EN, 20) +#define AT32_CLOCK_I2C1 AT32_CLOCK_CONFIG(APB1EN, 21) +#define AT32_CLOCK_I2C2 AT32_CLOCK_CONFIG(APB1EN, 22) +#define AT32_CLOCK_I2C3 AT32_CLOCK_CONFIG(APB1EN, 23) +#define AT32_CLOCK_CAN1 AT32_CLOCK_CONFIG(APB1EN, 25) +#define AT32_CLOCK_PWC AT32_CLOCK_CONFIG(APB1EN, 28) +#define AT32_CLOCK_UART7 AT32_CLOCK_CONFIG(APB1EN, 30) +#define AT32_CLOCK_UART8 AT32_CLOCK_CONFIG(APB1EN, 31) + +/* APB2 peripherals */ +#define AT32_CLOCK_TIMER1 AT32_CLOCK_CONFIG(APB2EN, 0) +#define AT32_CLOCK_USART1 AT32_CLOCK_CONFIG(APB2EN, 4) +#define AT32_CLOCK_USART6 AT32_CLOCK_CONFIG(APB2EN, 5) +#define AT32_CLOCK_ADC1 AT32_CLOCK_CONFIG(APB2EN, 8) +#define AT32_CLOCK_SPI1 AT32_CLOCK_CONFIG(APB2EN, 12) +#define AT32_CLOCK_SYSCFG AT32_CLOCK_CONFIG(APB2EN, 14) +#define AT32_CLOCK_TIMER9 AT32_CLOCK_CONFIG(APB2EN, 16) +#define AT32_CLOCK_TIMER10 AT32_CLOCK_CONFIG(APB2EN, 17) +#define AT32_CLOCK_TIMER11 AT32_CLOCK_CONFIG(APB2EN, 18) +#define AT32_CLOCK_I2SF5 AT32_CLOCK_CONFIG(APB2EN, 20) +#define AT32_CLOCK_ACC AT32_CLOCK_CONFIG(APB2EN, 29) + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_AT32F405_CLOCKS_H_ */ diff --git a/include/zephyr/dt-bindings/reset/at32f402_405_reset.h b/include/zephyr/dt-bindings/reset/at32f402_405_reset.h new file mode 100644 index 0000000000000..a6a410d212418 --- /dev/null +++ b/include/zephyr/dt-bindings/reset/at32f402_405_reset.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2022 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_AT32F402_405_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_AT32F402_405_H_ + +/** + * Encode CRM register offset and configuration bit. + * + * - 0..5: bit number + * - 6..14: offset + * - 15: reserved + * + * @param reg CRM register name (expands to AT32_{reg}_OFFSET) + * @param bit Configuration bit + */ +#define AT32_RESET_CONFIG(reg, bit) (((AT32_##reg##_OFFSET) << 6U) | (bit)) + +/** + * @name Register offsets + * @{ + */ + +#define AT32_AHB1RST_OFFSET 0x10U +#define AT32_AHB2RST_OFFSET 0x14U +#define AT32_AHB3RST_OFFSET 0x18U +#define AT32_APB1RST_OFFSET 0x20U +#define AT32_APB2RST_OFFSET 0x24U +#define AT32_ADDAPB1RST_OFFSET 0xE0U + +/** @} */ + +/** + * @name Clock enable/disable definitions for peripherals + * @{ + */ + +/* AHB1 peripherals */ +#define AT32_RESET_GPIOA AT32_RESET_CONFIG(AHB1RST, 0) +#define AT32_RESET_GPIOB AT32_RESET_CONFIG(AHB1RST, 1) +#define AT32_RESET_GPIOC AT32_RESET_CONFIG(AHB1RST, 2) +#define AT32_RESET_GPIOD AT32_RESET_CONFIG(AHB1RST, 3) +#define AT32_RESET_GPIOF AT32_RESET_CONFIG(AHB1RST, 5) +#define AT32_RESET_CRC AT32_RESET_CONFIG(AHB1RST, 12) +#define AT32_RESET_DMA1 AT32_RESET_CONFIG(AHB1RST, 22) +#define AT32_RESET_DMA2 AT32_RESET_CONFIG(AHB1RST, 24) +#define AT32_RESET_USBHS AT32_RESET_CONFIG(AHB1RST, 29) + +/* AHB2 peripherals */ +#define AT32_RESET_USBFS AT32_RESET_CONFIG(AHB2RST, 7) + +/* AHB3 peripherals */ +#define AT32_RESET_QSPI1 AT32_RESET_CONFIG(AHB3RST, 1) + +/* APB1 peripherals */ +#define AT32_RESET_TIMER2 AT32_RESET_CONFIG(APB1RST, 0) +#define AT32_RESET_TIMER3 AT32_RESET_CONFIG(APB1RST, 1) +#define AT32_RESET_TIMER4 AT32_RESET_CONFIG(APB1RST, 2) +#define AT32_RESET_TIMER5 AT32_RESET_CONFIG(APB1RST, 3) +#define AT32_RESET_TIMER6 AT32_RESET_CONFIG(APB1RST, 4) +#define AT32_RESET_TIMER7 AT32_RESET_CONFIG(APB1RST, 5) +#define AT32_RESET_TIMER13 AT32_RESET_CONFIG(APB1RST, 7) +#define AT32_RESET_TIMER14 AT32_RESET_CONFIG(APB1RST, 8) +#define AT32_RESET_WWDT AT32_RESET_CONFIG(APB1RST, 11) +#define AT32_RESET_SPI2 AT32_RESET_CONFIG(APB1RST, 14) +#define AT32_RESET_SPI3 AT32_RESET_CONFIG(APB1RST, 15) +#define AT32_RESET_USART2 AT32_RESET_CONFIG(APB1RST, 17) +#define AT32_RESET_USART3 AT32_RESET_CONFIG(APB1RST, 18) +#define AT32_RESET_USART4 AT32_RESET_CONFIG(APB1RST, 19) +#define AT32_RESET_USART5 AT32_RESET_CONFIG(APB1RST, 20) +#define AT32_RESET_I2C1 AT32_RESET_CONFIG(APB1RST, 21) +#define AT32_RESET_I2C2 AT32_RESET_CONFIG(APB1RST, 22) +#define AT32_RESET_I2C3 AT32_RESET_CONFIG(APB1RST, 23) +#define AT32_RESET_CAN1 AT32_RESET_CONFIG(APB1RST, 25) +#define AT32_RESET_PMC AT32_RESET_CONFIG(APB1RST, 28) +#define AT32_RESET_UART7 AT32_RESET_CONFIG(APB1RST, 30) +#define AT32_RESET_UART8 AT32_RESET_CONFIG(APB1RST, 31) + +/* APB2 peripherals */ +#define AT32_RESET_TIMER1 AT32_RESET_CONFIG(APB2RST, 0) +#define AT32_RESET_USART1 AT32_RESET_CONFIG(APB2RST, 4) +#define AT32_RESET_USART6 AT32_RESET_CONFIG(APB2RST, 5) +#define AT32_RESET_ADC1 AT32_RESET_CONFIG(APB2RST, 8) +#define AT32_RESET_SPI1 AT32_RESET_CONFIG(APB2RST, 12) +#define AT32_RESET_SCFG AT32_RESET_CONFIG(APB2RST, 14) +#define AT32_RESET_TIMER9 AT32_RESET_CONFIG(APB2RST, 16) +#define AT32_RESET_TIMER10 AT32_RESET_CONFIG(APB2RST, 17) +#define AT32_RESET_TIMER11 AT32_RESET_CONFIG(APB2RST, 18) +#define AT32_RESET_I2SF5 AT32_RESET_CONFIG(APB2RST, 20) +#define AT32_RESET_ACC AT32_RESET_CONFIG(APB2RST, 29) + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_RESET_AT32F4XX_H_ */ From 360bd983505aca5566355171ec6e38e76ec54d52 Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:28:26 +0800 Subject: [PATCH 10/12] board: artery: add AT32F405 AT-START board support. Add support AT-START-F405 board. Signed-off-by: jun tan --- .../at_start_f405/Kconfig.at_start_f405 | 5 + .../at_start_f405/at_start_f405-pinctrl.dtsi | 14 +++ boards/artery/at_start_f405/at_start_f405.dts | 117 ++++++++++++++++++ .../artery/at_start_f405/at_start_f405.yaml | 13 ++ .../at_start_f405/at_start_f405_defconfig | 19 +++ boards/artery/at_start_f405/board.cmake | 8 ++ boards/artery/at_start_f405/board.yml | 5 + boards/artery/at_start_f405/doc/index.rst | 91 ++++++++++++++ boards/artery/index.rst | 10 ++ 9 files changed, 282 insertions(+) create mode 100644 boards/artery/at_start_f405/Kconfig.at_start_f405 create mode 100644 boards/artery/at_start_f405/at_start_f405-pinctrl.dtsi create mode 100644 boards/artery/at_start_f405/at_start_f405.dts create mode 100644 boards/artery/at_start_f405/at_start_f405.yaml create mode 100644 boards/artery/at_start_f405/at_start_f405_defconfig create mode 100644 boards/artery/at_start_f405/board.cmake create mode 100644 boards/artery/at_start_f405/board.yml create mode 100644 boards/artery/at_start_f405/doc/index.rst create mode 100644 boards/artery/index.rst diff --git a/boards/artery/at_start_f405/Kconfig.at_start_f405 b/boards/artery/at_start_f405/Kconfig.at_start_f405 new file mode 100644 index 0000000000000..1d90d4b97ab4a --- /dev/null +++ b/boards/artery/at_start_f405/Kconfig.at_start_f405 @@ -0,0 +1,5 @@ +# Copyright (c) 2018 Philémon Jaermann +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_AT_START_F405 + select SOC_AT32F405 diff --git a/boards/artery/at_start_f405/at_start_f405-pinctrl.dtsi b/boards/artery/at_start_f405/at_start_f405-pinctrl.dtsi new file mode 100644 index 0000000000000..1407932df77f8 --- /dev/null +++ b/boards/artery/at_start_f405/at_start_f405-pinctrl.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2025, Maxjta + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + usart1_default: usart1_default { + group1 { + pinmux = , ; + }; + }; +}; diff --git a/boards/artery/at_start_f405/at_start_f405.dts b/boards/artery/at_start_f405/at_start_f405.dts new file mode 100644 index 0000000000000..f32000906dbda --- /dev/null +++ b/boards/artery/at_start_f405/at_start_f405.dts @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2025 Maxjta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "at_start_f405-pinctrl.dtsi" +#include + +/ { + model = "Artery AT-START-F405 board"; + compatible = "artery,at_start_f405"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds: leds { + compatible = "gpio-leds"; + + red_led: led2 { + gpios = <&gpiof 4 GPIO_ACTIVE_HIGH>; + label = "User LED2"; + }; + + yellow_led: led3 { + gpios = <&gpiof 5 GPIO_ACTIVE_HIGH>; + label = "User LED3"; + }; + + green_led: led4 { + gpios = <&gpiof 6 GPIO_ACTIVE_HIGH>; + label = "User LED4"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + user_button: button { + label = "User"; + gpios = <&gpioa 0 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &red_led; + led1 = &yellow_led; + led2 = &green_led; + sw0 = &user_button; + }; +}; + +&gpioa { + status = "okay"; +}; + +&gpiob { + status = "okay"; +}; + +&gpioc { + status = "okay"; +}; + +&gpiod { + status = "okay"; +}; + +&gpiof { + status = "okay"; +}; + +&clk_hick { + status = "okay"; +}; + +&clk_hext { + clock-frequency = <12000000>; + status = "okay"; +}; + +&sysclk { + clock-frequency = ; + status = "okay"; +}; + +&pll { + div-ms = <1>; + mul-ns = <72>; + div-fp = <2>; + div-fu = <5>; + clocks = <&clk_hext>; + status = "okay"; +}; + +&crm { + clocks = <&pll>; + ahb-prescaler = <1>; + clock-frequency = <216000000>; + apb1-prescaler = <2>; + apb2-prescaler = <1>; + status = "okay"; +}; + +&usart1 { + pinctrl-0 = <&usart1_default>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; diff --git a/boards/artery/at_start_f405/at_start_f405.yaml b/boards/artery/at_start_f405/at_start_f405.yaml new file mode 100644 index 0000000000000..596bfd5e0ee0d --- /dev/null +++ b/boards/artery/at_start_f405/at_start_f405.yaml @@ -0,0 +1,13 @@ +identifier: at_start_f405 +name: Artery AT-START-F405 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - gpio +ram: 96 +flash: 256 +vendor: artery diff --git a/boards/artery/at_start_f405/at_start_f405_defconfig b/boards/artery/at_start_f405/at_start_f405_defconfig new file mode 100644 index 0000000000000..65280205f0a39 --- /dev/null +++ b/boards/artery/at_start_f405/at_start_f405_defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2025, Jun Tan +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable Console +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable reset +CONFIG_RESET=y diff --git a/boards/artery/at_start_f405/board.cmake b/boards/artery/at_start_f405/board.cmake new file mode 100644 index 0000000000000..7d3de4ac221ed --- /dev/null +++ b/boards/artery/at_start_f405/board.cmake @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +# keep first +board_runner_args(pyocd "--target=at32f405rc") +board_runner_args(jlink "--device=AT32F405RC" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/artery/at_start_f405/board.yml b/boards/artery/at_start_f405/board.yml new file mode 100644 index 0000000000000..4c97e3b077f8a --- /dev/null +++ b/boards/artery/at_start_f405/board.yml @@ -0,0 +1,5 @@ +board: + name: at_start_f405 + vendor: artery + socs: + - name: at32f405 diff --git a/boards/artery/at_start_f405/doc/index.rst b/boards/artery/at_start_f405/doc/index.rst new file mode 100644 index 0000000000000..226d76cf59535 --- /dev/null +++ b/boards/artery/at_start_f405/doc/index.rst @@ -0,0 +1,91 @@ +.. zephyr:board:: at_start_f405 + +Overview +******** + +The AT START F405 board features an ARM Cortex-M4 based AT32F405 MCU +with a wide range of connectivity support and configurations. + +Hardware +******** + +- ARM Cortex-M4F Processor +- Core clock up to 216 MHz +- 256KB Flash memory +- 96 KB SRAM +- 1x12-bit 2MSPS ADC +- Up to 6x USART and 2x UART +- Up to 3x I2C +- Up to 3x SPI +- 1x QSPI interface +- 1x CAN interface(2.0B Active) +- 1x OTGHS on chip phy, Support usb2.0 high speed +- 1x OTGFS Support usb2.0 Full speed +- Up to 14 times +- 2 x 7-channel DMA controllers + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Serial Port +=========== + +The AT-START-F405 board has one serial communication port. The default port +is USART1 with TX connected at PA9 and RX at PA10. + +Programming and Debugging +************************* + +.. zephyr:board-supported-runners:: + +Using ATLink or J-Link +======================= +The board comes with an embedded AT-Link programmer. +You need to install CMSIS-Pack which is required by pyOCD +when programming or debugging by the AT-Link programmer. +Execute the following command to install CMSIS-Pack for AT32F405CCT7 +if not installed yet. + + .. code-block:: console + + pyocd pack install at32f405cct7 + +Also, J-Link can be used to program the board via the SWD interface +(PA13/SWDIO and PA14/SWCLK). + +#. Build the Zephyr kernel and the :zephyr:code-sample:`hello_world` sample application: + + .. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: at_start_f405 + :goals: build + :compact: + +#. To flash an image: + + .. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: at_start_f405 + :goals: flash + :compact: + + When using J-Link, append ``--runner jlink`` option after ``west flash``. + + You should see blink LED2 on board AT-START-F405. + +#. To debug an image: + + .. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: at_start_f405 + :goals: debug + :compact: + + When using J-Link, append ``--runner jlink`` option after ``west debug``. + +References +********** + +.. _microbit website: https://www.arterychip.com/en/product/AT32F405.jsp diff --git a/boards/artery/index.rst b/boards/artery/index.rst new file mode 100644 index 0000000000000..61b50cdd958e3 --- /dev/null +++ b/boards/artery/index.rst @@ -0,0 +1,10 @@ +.. _boards-artery: + +Artery Technology +################# + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* From 4d73a069b6cfd182e70088ba9714875f21e0f96e Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:29:41 +0800 Subject: [PATCH 11/12] modules: artery: add new modules hal_at32 to support AT32F405. -the hal driver name: hal_at32 link: https://github.com/Maxjta/hal_at32 Signed-off-by: jun tan --- modules/Kconfig | 3 + modules/hal_at32/CMakeLists.txt | 6 + modules/hal_at32/Kconfig | 204 ++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 modules/hal_at32/CMakeLists.txt create mode 100644 modules/hal_at32/Kconfig diff --git a/modules/Kconfig b/modules/Kconfig index eda6daa16095e..342086e2041ff 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -69,6 +69,9 @@ comment "hal_bouffalolab module not available." comment "hal_gigadevice module not available." depends on !ZEPHYR_HAL_GIGADEVICE_MODULE +comment "hal_at32 module not available." + depends on !ZEPHYR_HAL_AT32_MODULE + comment "hal_nordic module not available." depends on !ZEPHYR_HAL_NORDIC_MODULE diff --git a/modules/hal_at32/CMakeLists.txt b/modules/hal_at32/CMakeLists.txt new file mode 100644 index 0000000000000..7650fa6d3cc16 --- /dev/null +++ b/modules/hal_at32/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2021 ATL-Electronics +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_HAS_AT32_HAL) + add_subdirectory(${ZEPHYR_HAL_AT32_MODULE_DIR} hal_at32) +endif() diff --git a/modules/hal_at32/Kconfig b/modules/hal_at32/Kconfig new file mode 100644 index 0000000000000..df56e1288dead --- /dev/null +++ b/modules/hal_at32/Kconfig @@ -0,0 +1,204 @@ +# Copyright (c) 2021 ATL-Electronics +# SPDX-License-Identifier: Apache-2.0 + +config ZEPHYR_HAL_AT32_MODULE + bool + +config AT32_HAS_PINMUX + bool + help + This option should be selected if the series use an AF pinmux model. + +config AT32_HAS_AFIO_PINMUX + bool + help + This option should be selected if the series use an AFIO pinmux model. + +config HAS_AT32_HAL + bool + select HAS_CMSIS_CORE if ARM + +if HAS_AT32_HAL + +config AT32_HAS_LICK_32K + bool + help + Use 32KHz oscillator for low speed internal RC Oscillator + +config AT32_HAS_LICK_40K + bool + help + Use 40KHz oscillator for low speed internal RC Oscillator + +config AT32_LOW_SPEED_LICK_FREQUENCY + int + default 32000 if AT32_HAS_LICK_32K + default 40000 if AT32_HAS_LICK_40K + help + Define value of low speed internal RC oscillator (IRC) in Hz + +config AT32_DBG_SUPPORT + bool "Use AT32 Debug features" + select USE_AT32_DBG + default y + help + Enable AT32 Debug features. + +config USE_AT32_ADC + bool + help + Enable AT32 Analog-to-Digital Converter (ADC) HAL module driver + +config USE_AT32_BPR + bool + help + Enable AT32 Battery powered domain data Registers (BPR) HAL module driver + +config USE_AT32_CAN + bool + help + Enable AT32 Controller Area Network (CAN) HAL module driver + +config USE_AT32_CMP + bool + help + Enable AT32 Comparator (CMP) HAL module driver + +config USE_AT32_CRC + bool + help + Enable AT32 Cyclic redundancy check calculation unit (CRC) HAL + module driver + +config USE_AT32_ACC + bool + help + Enable AT32 HICK Clock auto trim (ACC) HAL module driver + +config USE_AT32_DAC + bool + help + Enable AT32 Digital-to-Analog Converter (DAC) HAL module driver + +config USE_AT32_DBG + bool + help + Enable AT32 Debug (DBG) HAL module driver + +config USE_AT32_DVP + bool + help + Enable AT32 Digital Video parallel Interface (DVP) HAL module driver + +config USE_AT32_DMA + bool + help + Enable AT32 Direct Memory Access controller (DMA) HAL module driver + +config USE_AT32_EMAC + bool + help + Enable AT32 Ethernet MAC(EMAC) HAL module driver + +config USE_AT32_XMC + bool + help + Enable AT32 External Memory Controller (EXMC) HAL module driver + +config USE_AT32_MISC + bool + help + Enable AT32 (MISC) HAL module driver + +config USE_AT32_EXINT + bool + help + Enable AT32 Interrupt/Event controller (EXINT) HAL module driver + +config USE_AT32_FLASH + bool + help + Enable AT32 Flash Memory Controller (FMC) HAL module driver + +config USE_AT32_WDT + bool + help + Enable AT32 Watchdog (WDT) HAL module driver + +config USE_AT32_GPIO + bool + default y + help + Enable AT32 General-purpose and Alternate-Function I/Os + (GPIO and IOMUX) HAL module driver + +config USE_AT32_I2C + bool + help + Enable AT32 Inter-Integrated Circuit Interface (I2C) HAL module driver + +config USE_AT32_PWC + bool + help + Enable AT32 Power Control (PWC) HAL module driver + +config USE_AT32_CRM + bool + default y + help + Enable AT32 Clock and Reset (CRM) HAL module driver + +config USE_AT32_ERTC + bool + help + Enable AT32 Enhanced Real-Time Clock (RTC) HAL module driver + +config USE_AT32_RTC + bool + help + Enable AT32 Real-Time Clock (RTC) HAL module driver + +config USE_AT32_SDIO + bool + help + Enable AT32 Secure Digital Input/Output interface (SDIO) HAL module + driver + +config USE_AT32_SPI + bool + help + Enable AT32 Serial Peripheral Interface(SPI) HAL module driver + +config USE_AT32_QSPI + bool + help + Enable AT32 Serial/Quad Parallel Interface (QSPI) HAL module driver + +config USE_AT32_SYSCFG + bool + help + Enable AT32 System Configuration (SYSCFG) HAL module driver + +config USE_AT32_TIMER + bool + help + Enable AT32 Timer (TIMER) HAL module driver + +config USE_AT32_USART + bool + help + Enable AT32 Universal Synchronous/Asynchronous Receiver/Transmitter + (USART) HAL module driver + +config USE_AT32_USB + bool + help + Enable AT32 Universal Serial Bus interface (USB/OTG) + HAL module driver + +config USE_AT32_WWDT + bool + help + Enable AT32 Window Watchdog Timer (WWDT) HAL module driver + +endif # HAS_AT32_HAL From ac80b363d644fed7b7184bd2719bfe9440025e33 Mon Sep 17 00:00:00 2001 From: jun tan Date: Fri, 10 Oct 2025 14:30:54 +0800 Subject: [PATCH 12/12] MAINTAINERS: Add West project hal_at32. MAINTAINERS add west project hal_at32 and maintainers Signed-off-by: jun tan --- MAINTAINERS.yml | 11 +++++++++++ west.yml | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 3e7c3048b5384..b31c7a9f746e4 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4986,6 +4986,17 @@ West: labels: - "platform: Ambiq" +"West project: hal_at32": + status: maintained + maintainers: + - ubieda + collaborators: + - asmellby + files: + - modules/hal_at32/ + labels: + - "platform: AT32" + "West project: hal_atmel": status: maintained maintainers: diff --git a/west.yml b/west.yml index e30c383ee508c..9535294851bfd 100644 --- a/west.yml +++ b/west.yml @@ -23,6 +23,8 @@ manifest: url-base: https://github.com/zephyrproject-rtos - name: babblesim url-base: https://github.com/BabbleSim + - name: Maxjta + url-base: https://github.com/Maxjta group-filter: [-babblesim, -optional] @@ -158,6 +160,12 @@ manifest: path: modules/hal/ambiq groups: - hal + - name: hal_at32 + remote: Maxjta + revision: 2c8de655d3d6774e6412411a6f29bab0304fcdf5 + path: modules/hal/at32 + groups: + - hal - name: hal_atmel revision: ca7e4c6920f44b9d677ed5995ffa169f18a54cdf path: modules/hal/atmel