From 460c210140499a5ed2c01dd2cef4de80ee09a1d9 Mon Sep 17 00:00:00 2001 From: zjian zhang Date: Wed, 18 Jun 2025 20:46:18 +0800 Subject: [PATCH 1/8] west.yml: Add Realtek HAL as a new HAL module Realtek HAL (Hardware Abstraction Layer) provides a low level peripheral configuration function. Signed-off-by: zjian zhang --- west.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/west.yml b/west.yml index fc43ee819852..62787314defa 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: nuwa + url-base: https://github.com/zjian-zhang group-filter: [-babblesim, -optional] @@ -224,6 +226,12 @@ manifest: path: modules/hal/quicklogic groups: - hal + - name: hal_realtek + remote: nuwa + path: modules/hal/realtek + revision: e3d9fcdfe0f8e65d5ba25bc36196f3b2f3047f2b + groups: + - hal - name: hal_renesas path: modules/hal/renesas revision: 9b99067e29a1b44b53192c2c797db330f5703462 From cfd995fde10f1d1ab8813c85ae8c3ee29a9e4aa3 Mon Sep 17 00:00:00 2001 From: zjian zhang Date: Wed, 18 Jun 2025 20:50:34 +0800 Subject: [PATCH 2/8] dts: arm: introduce amebad SOC Devicetree add initial version of devicetree for amebad SOC. amebad devicetree file is main platform dtsi file, which should be included from board dts (e.g rtl872xd_evb.dts) Signed-off-by: zjian zhang --- dts/arm/realtek/amebad/amebad.dtsi | 96 ++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 dts/arm/realtek/amebad/amebad.dtsi diff --git a/dts/arm/realtek/amebad/amebad.dtsi b/dts/arm/realtek/amebad/amebad.dtsi new file mode 100644 index 000000000000..0ec2d9324c03 --- /dev/null +++ b/dts/arm/realtek/amebad/amebad.dtsi @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m33"; + reg = <0>; + d-cache-line-size = <32>; + #address-cells = <1>; + #size-cells = <1>; + }; + }; + + clocks { + clk_sys: clk_sys { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = ; + }; + }; + + soc { + sram0: memory@10003020 { + compatible = "mmio-sram"; + reg = <0x10003020 0x00074000>; + }; + + ram_image2_entry: memory@10003000 { + compatible = "zephyr,memory-region"; + reg = <0x10003000 0x20>; + zephyr,memory-region = "KM4_IMG2_ENTRY"; + }; + + pinctrl: pinctrl@48000400 { + compatible = "realtek,ameba-pinctrl"; + reg = <0x48000400 0x200>; + }; + + loguart: serial@48012000 { + compatible = "realtek,ameba-loguart"; + reg = <0x48012000 0x100>; + interrupts = <3 0>; + current-speed = <1500000>; + status = "disabled"; + }; + + spic: flash-controller@48080000 { + compatible = "realtek,ameba-flash-controller"; + reg = <0x48080000 0x200>; + + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + flash0: flash@E000020 { + compatible = "soc-nv-flash"; + erase-block-size = ; + write-block-size = <4>; + }; + }; + + gpioa: gpio@48014000 { + compatible = "realtek,ameba-gpio"; + reg = <0x48014000 0x400>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <4 0>; + status = "disabled"; + }; + + gpiob: gpio@48014400 { + compatible = "realtek,ameba-gpio"; + reg = <0x48014400 0x400>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <8 0>; + status = "disabled"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; From 53df31d9fab15722eb8842ba5bc0c3f90d21900d Mon Sep 17 00:00:00 2001 From: zjian zhang Date: Thu, 19 Jun 2025 10:11:01 +0800 Subject: [PATCH 3/8] soc: add realtek amebad SOC integration Add initial version of Amebad Soc integration Signed-off-by: zjian zhang --- soc/realtek/ameba/CMakeLists.txt | 7 + soc/realtek/ameba/Kconfig | 12 ++ soc/realtek/ameba/Kconfig.defconfig | 8 + soc/realtek/ameba/Kconfig.soc | 10 ++ soc/realtek/ameba/amebad/CMakeLists.txt | 10 ++ soc/realtek/ameba/amebad/Kconfig | 16 ++ soc/realtek/ameba/amebad/Kconfig.defconfig | 15 ++ soc/realtek/ameba/amebad/Kconfig.soc | 9 ++ soc/realtek/ameba/amebad/boot_section.ld | 27 ++++ soc/realtek/ameba/amebad/soc.c | 47 ++++++ soc/realtek/ameba/amebad/soc.h | 17 +++ soc/realtek/ameba/amebad/soc_cpu_idle.h | 8 + soc/realtek/ameba/common/CMakeLists.txt | 4 + .../ameba/common/os_wrapper/CMakeLists.txt | 4 + .../common/os_wrapper/include/os_wrapper.h | 47 ++++++ .../os_wrapper/include/os_wrapper_critical.h | 31 ++++ .../os_wrapper/include/os_wrapper_memory.h | 68 +++++++++ .../os_wrapper/include/os_wrapper_mutex.h | 138 +++++++++++++++++ .../os_wrapper/include/os_wrapper_queue.h | 90 ++++++++++++ .../os_wrapper/include/os_wrapper_semaphore.h | 122 +++++++++++++++ .../os_wrapper/include/os_wrapper_task.h | 139 ++++++++++++++++++ .../os_wrapper/include/os_wrapper_time.h | 51 +++++++ .../os_wrapper/include/os_wrapper_timer.h | 129 ++++++++++++++++ .../os_wrapper/include/platform_stdlib.h | 16 ++ soc/realtek/ameba/soc.yml | 4 + 25 files changed, 1029 insertions(+) create mode 100644 soc/realtek/ameba/CMakeLists.txt create mode 100644 soc/realtek/ameba/Kconfig create mode 100644 soc/realtek/ameba/Kconfig.defconfig create mode 100644 soc/realtek/ameba/Kconfig.soc create mode 100644 soc/realtek/ameba/amebad/CMakeLists.txt create mode 100644 soc/realtek/ameba/amebad/Kconfig create mode 100644 soc/realtek/ameba/amebad/Kconfig.defconfig create mode 100644 soc/realtek/ameba/amebad/Kconfig.soc create mode 100644 soc/realtek/ameba/amebad/boot_section.ld create mode 100644 soc/realtek/ameba/amebad/soc.c create mode 100644 soc/realtek/ameba/amebad/soc.h create mode 100644 soc/realtek/ameba/amebad/soc_cpu_idle.h create mode 100644 soc/realtek/ameba/common/CMakeLists.txt create mode 100644 soc/realtek/ameba/common/os_wrapper/CMakeLists.txt create mode 100644 soc/realtek/ameba/common/os_wrapper/include/os_wrapper.h create mode 100644 soc/realtek/ameba/common/os_wrapper/include/os_wrapper_critical.h create mode 100644 soc/realtek/ameba/common/os_wrapper/include/os_wrapper_memory.h create mode 100644 soc/realtek/ameba/common/os_wrapper/include/os_wrapper_mutex.h create mode 100644 soc/realtek/ameba/common/os_wrapper/include/os_wrapper_queue.h create mode 100644 soc/realtek/ameba/common/os_wrapper/include/os_wrapper_semaphore.h create mode 100644 soc/realtek/ameba/common/os_wrapper/include/os_wrapper_task.h create mode 100644 soc/realtek/ameba/common/os_wrapper/include/os_wrapper_time.h create mode 100644 soc/realtek/ameba/common/os_wrapper/include/os_wrapper_timer.h create mode 100644 soc/realtek/ameba/common/os_wrapper/include/platform_stdlib.h create mode 100644 soc/realtek/ameba/soc.yml diff --git a/soc/realtek/ameba/CMakeLists.txt b/soc/realtek/ameba/CMakeLists.txt new file mode 100644 index 000000000000..b770b597e60a --- /dev/null +++ b/soc/realtek/ameba/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(common) + +add_subdirectory(common) +add_subdirectory(${CONFIG_SOC}) diff --git a/soc/realtek/ameba/Kconfig b/soc/realtek/ameba/Kconfig new file mode 100644 index 000000000000..b51759e89007 --- /dev/null +++ b/soc/realtek/ameba/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_REALTEK_AMEBA + select BUILD_OUTPUT_HEX + select SOC_EARLY_INIT_HOOK + +if SOC_FAMILY_REALTEK_AMEBA + +rsource "*/Kconfig" + +endif # SOC_FAMILY_REALTEK_AMEBA diff --git a/soc/realtek/ameba/Kconfig.defconfig b/soc/realtek/ameba/Kconfig.defconfig new file mode 100644 index 000000000000..d4e73efa3d45 --- /dev/null +++ b/soc/realtek/ameba/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_REALTEK_AMEBA + +rsource "*/Kconfig.defconfig" + +endif # SOC_FAMILY_REALTEK_AMEBA diff --git a/soc/realtek/ameba/Kconfig.soc b/soc/realtek/ameba/Kconfig.soc new file mode 100644 index 000000000000..2c1a5f11b316 --- /dev/null +++ b/soc/realtek/ameba/Kconfig.soc @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_REALTEK_AMEBA + bool + +config SOC_FAMILY + default "realtek_ameba" if SOC_FAMILY_REALTEK_AMEBA + +rsource "*/Kconfig.soc" diff --git a/soc/realtek/ameba/amebad/CMakeLists.txt b/soc/realtek/ameba/amebad/CMakeLists.txt new file mode 100644 index 000000000000..c6443d35e919 --- /dev/null +++ b/soc/realtek/ameba/amebad/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(${ZEPHYR_BASE}/drivers) +zephyr_include_directories(.) + +zephyr_sources(soc.c) + +zephyr_linker_sources(SECTIONS boot_section.ld) +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/realtek/ameba/amebad/Kconfig b/soc/realtek/ameba/amebad/Kconfig new file mode 100644 index 000000000000..34589cf5bd58 --- /dev/null +++ b/soc/realtek/ameba/amebad/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_AMEBAD + select ARM + select CPU_CORTEX_M33 + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + select CPU_HAS_ARM_SAU + select CPU_HAS_FPU + select CPU_HAS_VFP + select ARMV8_M_DSP + select CPU_HAS_ARM_MPU + select ARM_MPU + select ARM_TRUSTZONE_M + select ARM_ON_EXIT_CPU_IDLE diff --git a/soc/realtek/ameba/amebad/Kconfig.defconfig b/soc/realtek/ameba/amebad/Kconfig.defconfig new file mode 100644 index 000000000000..fc99e462b552 --- /dev/null +++ b/soc/realtek/ameba/amebad/Kconfig.defconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_AMEBAD + +config NUM_IRQS + default 64 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/clocks/clk_sys,clock-frequency) + +config CACHE_MANAGEMENT + default y + +endif #SOC_AMEBAD diff --git a/soc/realtek/ameba/amebad/Kconfig.soc b/soc/realtek/ameba/amebad/Kconfig.soc new file mode 100644 index 000000000000..5ebb034fe236 --- /dev/null +++ b/soc/realtek/ameba/amebad/Kconfig.soc @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_AMEBAD + bool + select SOC_FAMILY_REALTEK_AMEBA + +config SOC + default "amebad" if SOC_AMEBAD diff --git a/soc/realtek/ameba/amebad/boot_section.ld b/soc/realtek/ameba/amebad/boot_section.ld new file mode 100644 index 000000000000..ed1d7a4c0216 --- /dev/null +++ b/soc/realtek/ameba/amebad/boot_section.ld @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + + SECTION_PROLOGUE(.ram_image2.entry,,SUBALIGN(32)) + { + __image2_entry_func__ = .; + KEEP(*(SORT(.image2.entry.data*))) + . = ALIGN(32); + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) + + SECTION_PROLOGUE(.psram_image2.text.data,,) + { + __image2_backtrace_start__ = .; + *(*.sramdram.only.text) + + . = ALIGN (4); + __ipc_table_start__ = .; + KEEP(*(*.ipc.table.data*)) + __ipc_table_end__ = .; + /*-----------------*/ + __image2_backtrace_end__ = .; + + . = ALIGN (32); + } GROUP_LINK_IN(ROMABLE_REGION) diff --git a/soc/realtek/ameba/amebad/soc.c b/soc/realtek/ameba/amebad/soc.c new file mode 100644 index 000000000000..45cde922282e --- /dev/null +++ b/soc/realtek/ameba/amebad/soc.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include "ameba_system.h" + +void z_arm_reset(void); + +IMAGE2_ENTRY_SECTION +RAM_START_FUNCTION Img2EntryFun0 = {z_arm_reset, NULL, /* BOOT_RAM_WakeFromPG, */ + (uint32_t)NewVectorTable}; + +static void app_vdd1833_detect(void) +{ + u32 temp; + + if (FALSE == is_power_supply18()) { + temp = HAL_READ32(SYSTEM_CTRL_BASE_HP, REG_HS_RFAFE_IND_VIO1833); + temp |= BIT_RFAFE_IND_VIO1833; + HAL_WRITE32(SYSTEM_CTRL_BASE_HP, REG_HS_RFAFE_IND_VIO1833, temp); + } + + printk("REG_HS_RFAFE_IND_VIO1833 (0 is 1.8V): %x\n", + HAL_READ32(SYSTEM_CTRL_BASE_HP, REG_HS_RFAFE_IND_VIO1833)); +} + +void soc_early_init_hook(void) +{ + /* + * Cache is enabled by default at reset, disable it before + * sys_cache*-functions can enable them. + */ + Cache_Enable(DISABLE); + sys_cache_data_enable(); + sys_cache_instr_enable(); + + SystemSetCpuClk(CLK_KM4_200M); + + app_vdd1833_detect(); +} diff --git a/soc/realtek/ameba/amebad/soc.h b/soc/realtek/ameba/amebad/soc.h new file mode 100644 index 000000000000..f29948817bd3 --- /dev/null +++ b/soc/realtek/ameba/amebad/soc.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_REALTEK_AMEBA_AMEBAD_H_ +#define ZEPHYR_SOC_REALTEK_AMEBA_AMEBAD_H_ + +#ifndef _ASMLANGUAGE + +#include +#include "cmsis_cpu.h" + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_SOC_REALTEK_AMEBA_AMEBAD_H_ */ diff --git a/soc/realtek/ameba/amebad/soc_cpu_idle.h b/soc/realtek/ameba/amebad/soc_cpu_idle.h new file mode 100644 index 000000000000..a730b7e37c29 --- /dev/null +++ b/soc/realtek/ameba/amebad/soc_cpu_idle.h @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Workaround for WFI fused instruction issue */ +#define SOC_ON_EXIT_CPU_IDLE __NOP(); diff --git a/soc/realtek/ameba/common/CMakeLists.txt b/soc/realtek/ameba/common/CMakeLists.txt new file mode 100644 index 000000000000..10252c5c3308 --- /dev/null +++ b/soc/realtek/ameba/common/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(os_wrapper) diff --git a/soc/realtek/ameba/common/os_wrapper/CMakeLists.txt b/soc/realtek/ameba/common/os_wrapper/CMakeLists.txt new file mode 100644 index 000000000000..4a9540b9b93d --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(include) diff --git a/soc/realtek/ameba/common/os_wrapper/include/os_wrapper.h b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper.h new file mode 100644 index 000000000000..92dde9d8cb3c --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OS_WRAPPER_H__ +#define __OS_WRAPPER_H__ + +/** + * @brief Necessary headers + */ +#include +#include +#include + +#include "platform_autoconf.h" +#include "ameba.h" +#include + +/** + * @brief Common header file + */ +#ifdef __cplusplus +extern "C" { +#endif +#include "os_wrapper_semaphore.h" +#include "os_wrapper_critical.h" +#include "os_wrapper_memory.h" +#include "os_wrapper_mutex.h" +#include "os_wrapper_queue.h" +#include "os_wrapper_semaphore.h" +#include "os_wrapper_task.h" +#include "os_wrapper_time.h" +#include "os_wrapper_timer.h" +#ifdef __cplusplus +} +#endif + +/** + * @brief General macro definition + */ + +#define RTOS_MAX_DELAY 0xFFFFFFFFUL +#define RTOS_MAX_TIMEOUT 0xFFFFFFFFUL + +#endif diff --git a/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_critical.h b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_critical.h new file mode 100644 index 000000000000..d1534243cbd4 --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_critical.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OS_WRAPPER_CRITCAL_H__ +#define __OS_WRAPPER_CRITCAL_H__ + +/** + * @brief Check if in task interrupt + * @retval 1: interrupt; 0: context + */ +int rtos_critical_is_in_interrupt(void); + +/** + * @brief Internally handles interrupt status (PRIMASK/CPSR) save + */ +void rtos_critical_enter(void); + +/** + * @brief Internally handles interrupt status(PRIMASK/CPSR) restore + */ +void rtos_critical_exit(void); + +/** + * @brief get task enter critical state + * @retval >0: in critical state; 0: exit critical state + */ +uint32_t rtos_get_critical_state(void); +#endif diff --git a/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_memory.h b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_memory.h new file mode 100644 index 000000000000..f52f2e0342cd --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_memory.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OS_WRAPPER_MEMORY_H__ +#define __OS_WRAPPER_MEMORY_H__ + +/** + * @brief Initialize dynamic memory pool + */ +void rtos_mem_init(void); + +/** + * @brief Allocate memory from the heap. The buffer value is random + * @note The return buffer size/address is cacheline size aligned + * @param size: buffer size in byte + * @retval Pointer to memory the caller can now use + */ +void *rtos_mem_malloc(uint32_t size); + +/** + * @brief Allocate memory from the heap. The buffer value is zero + * @note The return buffer size/address is cacheline size aligned + * @param size: buffer size in byte + * @retval Pointer to memory the caller can now use + */ +void *rtos_mem_zmalloc(uint32_t size); + +/** + * @brief Allocate memory from the heap. The buffer value is zero + * @note The return buffer size/address is cacheline size aligned + * @param elementNum: Number of elements, memory size is elementNum*elementSize + * @param elementSize: Size of each array element (in bytes). + * @retval Pointer to memory the caller can now use + */ +void *rtos_mem_calloc(uint32_t elementNum, uint32_t elementSize); + +/** + * @brief Reuse or extend memory previously allocated by the malloc(), calloc(), and realloc() + * functions + * @note The return buffer size/address is cacheline size aligned + * @param pbuf: Pointer containing the address + * @param size: The number of bytes of memory to be newly allocated. + * @retval Pointer to memory the caller can now use + */ +void *rtos_mem_realloc(void *pbuf, uint32_t size); + +/** + * @brief Deallocate memory from the heap. + * @param pbuf: a pointer to memory previously allocated + */ +void rtos_mem_free(void *pbuf); + +/** + * @brief Get free heap size. + * @retval Free heap size in byte + */ +uint32_t rtos_mem_get_free_heap_size(void); + +/** + * @brief Get minimum ever free heap size. + * @retval Minimum ever free heap size in byte + */ +uint32_t rtos_mem_get_minimum_ever_free_heap_size(void); + +#endif diff --git a/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_mutex.h b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_mutex.h new file mode 100644 index 000000000000..9f8bcc39d8c0 --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_mutex.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OS_WRAPPER_MUTEX_H__ +#define __OS_WRAPPER_MUTEX_H__ + +/** + * @brief mutex handle type + */ +typedef void *rtos_mutex_t; + +#define MUTEX_WAIT_TIMEOUT 0xFFFFFFFFU /* will be replaced by common max timeout later */ + +/** + * @brief Static memory allocation implementation of rtos_mutex_create + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_create_static(rtos_mutex_t *pp_handle); + +/** + * @brief Static memory allocation implementation of rtos_mutex_delete + * @param p_handle: Address of the mutex + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_delete_static(rtos_mutex_t p_handle); + +/** + * @brief Static memory allocation implementation of rtos_mutex_recursive_create + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_recursive_create_static(rtos_mutex_t *pp_handle); + +/** + * @brief Static memory allocation implementation of rtos_mutex_recursive_delete + * @param p_handle: Address of the mutex + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_recursive_delete_static(rtos_mutex_t p_handle); + +/** + * @brief Compared to semaphores, Mutex has a priority inheritance mechanism. + * Dynamic allocate memory. + * @note Usage example: + * Create: + * rtos_mutex_t mutex_handle; + * rtos_mutex_create(&mutex_handle); + * Give: + * rtos_mutex_give(mutex_handle); + * Take: + * rtos_mutex_take(mutex_handle, 100); + * Delete: + * rtos_mutex_delete(mutex_handle); + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_create(rtos_mutex_t *pp_handle); + +/** + * @brief Delete a mutex. + * @note Do not delete mutex if held by a task + * @param p_handle: Address of the mutex + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_delete(rtos_mutex_t p_handle); + +/** + * @brief Take a mutex. + * The API internally determines whether it is in the interrupt state and calls the + * corresponding RTOS interface. + * @param p_handle: Address of the mutex + * @param wait_ms: The time in milliseconds to wait, 0xFFFFFFFF means Block infinitely until the + * semaphore taken. + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_take(rtos_mutex_t p_handle, uint32_t wait_ms); + +/** + * @brief Give a semaphore. + * The API internally determines whether it is in the interrupt state and calls the + * corresponding RTOS interface. + * @param p_handle: Address of the mutex + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_give(rtos_mutex_t p_handle); + +/** + * @brief Creates a new recursive mutex, compared to semaphores, Mutex has a priority inheritance + * mechanism. Dynamic allocate memory. + * @note Usage example: + * Create: + * rtos_mutex_t mutex_handle; + * rtos_mutex_recursive_create(&mutex_handle); + * Give: + * rtos_mutex_recursive_give(mutex_handle); + * Take: + * rtos_mutex_recursive_take(mutex_handle, 100); + * Delete: + * rtos_mutex_recursive_delete(mutex_handle); + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_recursive_create(rtos_mutex_t *pp_handle); + +/** + * @brief Delete a mutex. + * @param p_handle: Address of the mutex + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_recursive_delete(rtos_mutex_t p_handle); + +/** + * @brief Take a mutex. + * @note recursive mutexes cannot be used in interrupt service routines. + * @param p_handle: Address of the mutex + * @param wait_ms: The time in milliseconds to wait, 0xFFFFFFFF means Block infinitely until the + * semaphore taken. + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_recursive_take(rtos_mutex_t p_handle, uint32_t wait_ms); + +/** + * @brief Give a semaphore. + * @note Recursive mutexes cannot be used in interrupt service routines. + * @param p_handle: Address of the mutex + * @retval The status is SUCCESS or FAIL + */ +int rtos_mutex_recursive_give(rtos_mutex_t p_handle); + +#endif diff --git a/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_queue.h b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_queue.h new file mode 100644 index 000000000000..141e7a506d42 --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_queue.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OS_WRAPPER_QUEUE_H__ +#define __OS_WRAPPER_QUEUE_H__ + +/** + * @brief queue handle type + */ +typedef void *rtos_queue_t; + +/** + * @brief Creates a new queue instance + * @note Usage example: + * Create: + * rtos_queue_t queue_handle; + * rtos_queue_create(&queue_handle, 5, sizeof(uint32_t)); + * Send: + * rtos_queue_send(queue_handle, p_msg, portMAX_DELAY); + * Receive: + * rtos_queue_receive(queue_handle, p_msg, portMAX_DELAY); + * Delete: + * rtos_queue_delete(queue_handle); + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @param msg_num: Maximum number of messages that can be queued. + * @param msg_size: Message size (in bytes). + * @retval The status is SUCCESS or FAIL + */ +int rtos_queue_create(rtos_queue_t *pp_handle, uint32_t msg_num, uint32_t msg_size); + +/** + * @brief Delete a queue - freeing all the memory allocated for storing of items placed on the + * queue. + * @param p_handle: A handle to the queue to be deleted. + * @retval The status is SUCCESS or FAIL + */ +int rtos_queue_delete(rtos_queue_t p_handle); + +/** + * @brief Return the number of messages stored in a queue. + * @param p_handle: A handle to the queue being queried. + * @retval The number of messages available in the queue. + */ +uint32_t rtos_queue_message_waiting(rtos_queue_t p_handle); + +/** + * @brief Send a message to a message queue in a "first in, first out" manner. + * @param p_handle: Address of the message queue. + * @param p_msg: Pointer to the message. + * @param wait_ms: Waiting period to add the message, 0xFFFFFFFF means Block infinitely. + * @retval The status is SUCCESS or FAIL + */ +int rtos_queue_send(rtos_queue_t p_handle, void *p_msg, uint32_t wait_ms); + +/** + * @brief Send a message to the head of message queue in a "last in, first out" manner. + * @param p_handle: Address of the message queue. + * @param p_msg: Pointer to the message. + * @param wait_ms: Waiting period to add the message, 0xFFFFFFFF means Block infinitely. + * @retval The status is SUCCESS or FAIL + */ +int rtos_queue_send_to_front(rtos_queue_t p_handle, void *p_msg, uint32_t wait_ms); + +/** + * @brief Receive a message from a message queue in a "first in, first out" manner. + * Messages are received from the queue and removed from the queue, so the queue's state + * changes. + * @param p_handle: Address of the message queue. + * @param p_msg: Address of area to hold the received message. + * @param wait_ms: Waiting period to add the message, 0xFFFFFFFF means Block infinitely. + * @retval The status is SUCCESS or FAIL + */ +int rtos_queue_receive(rtos_queue_t p_handle, void *p_msg, uint32_t wait_ms); + +/** + * @brief Peek/read a message from a message queue in a "first in, first out" manner. + * Simply viewing the next message in the queue does not remove it from the queue, + * so the state of the queue remains unchanged. + * @param p_handle: Address of the message queue. + * @param p_msg: Address of area to hold the received message. + * @param wait_ms: Waiting period to add the message, 0xFFFFFFFF means Block infinitely. + * @retval The status is SUCCESS or FAIL + */ +int rtos_queue_peek(rtos_queue_t p_handle, void *p_msg, uint32_t wait_ms); + +#endif diff --git a/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_semaphore.h b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_semaphore.h new file mode 100644 index 000000000000..d2b3188e647b --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_semaphore.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OS_WRAPPER_SEMA_H__ +#define __OS_WRAPPER_SEMA_H__ + +#define RTOS_SEMA_MIN_COUNT 0x0UL +#define RTOS_SEMA_MAX_COUNT 0xFFFFFFFFUL + +/** + * @brief semaphore handle type + */ +typedef void *rtos_sema_t; + +/** + * @brief Static memory allocation implementation of rtos_sema_create + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @param init_count: The count value assigned to the semaphore when it is created. + * @param max_count: The maximum count value that can be reached. + * @retval The status is SUCCESS or FAIL + */ +int rtos_sema_create_static(rtos_sema_t *pp_handle, uint32_t init_count, uint32_t max_count); + +/** + * @brief Static memory allocation implementation of rtos_sema_create_binary + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @retval The status is SUCCESS or FAIL + */ +int rtos_sema_create_binary_static(rtos_sema_t *pp_handle); + +/** + * @brief Static memory allocation implementation of rtos_sema_delete + * @param p_handle: Address of the semaphore + * @retval The status is SUCCESS or FAIL + */ +int rtos_sema_delete_static(rtos_sema_t p_handle); + +/** + * @brief Creates a new counting semaphore instance + * Dynamic allocate memory. + * @note Usage example: + * Create: + * rtos_sema_t sema_handle; + * rtos_sema_create(&sema_handle, 0, 10); + * Give: + * rtos_sema_give(sema_handle); + * Take: + * rtos_sema_take(sema_handle, 100); + * Delete: + * rtos_sema_delete(sema_handle); + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @param init_count: The count value assigned to the semaphore when it is created. + * @param max_count: The maximum count value that can be reached. + * @retval The status is SUCCESS or FAIL + */ +int rtos_sema_create(rtos_sema_t *pp_handle, uint32_t init_count, uint32_t max_count); + +/** + * @brief Creates a new binary semaphore instance + * Dynamic allocate memory. + * @note The semaphore must first be 'given' before it can be 'taken'. + * Usage example: + * Create: + * rtos_sema_t sema_handle; + * rtos_sema_create_binary(&sema_handle); + * Give: + * rtos_sema_give(sema_handle); + * Take: + * rtos_sema_take(sema_handle, 100); + * Delete: + * rtos_sema_delete(sema_handle); + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @retval The status is SUCCESS or FAIL + */ +int rtos_sema_create_binary(rtos_sema_t *pp_handle); + +/** + * @brief Delete a semaphore. + * @param p_handle: A handle to the semaphore to be deleted. + * @retval The status is SUCCESS or FAIL + */ +int rtos_sema_delete(rtos_sema_t p_handle); + +/** + * @brief Take a semaphore. + * The API internally determines whether it is in the interrupt state and calls the + * corresponding RTOS interface. + * + * @note If timeout_ms is set to the maximum value, + * then if the semaphore cannot be obtained consistently, the log will be printed every 10 + * seconds. + * @param p_handle: Address of the semaphore. + * @param timeout_ms: Waiting period to add the message, 0xFFFFFFFF means Block infinitely. + * @retval The status is SUCCESS or FAIL + */ +int rtos_sema_take(rtos_sema_t p_handle, uint32_t timeout_ms); + +/** + * @brief Give a semaphore. + * The API internally determines whether it is in the interrupt state and calls the + * corresponding RTOS interface. + * @param p_handle: Address of the semaphore. + * @retval The status is SUCCESS or FAIL + */ +int rtos_sema_give(rtos_sema_t p_handle); + +/** + * @brief Get a semaphore's count. If the semaphore is a binary semaphore then returns 1 if the + * semaphore is available, and 0 if the semaphore is not available. + * @param p_handle: Address of the semaphore. + * @retval Current semaphore count. + */ +uint32_t rtos_sema_get_count(rtos_sema_t p_handle); + +#endif diff --git a/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_task.h b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_task.h new file mode 100644 index 000000000000..82ad32e33185 --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_task.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OS_WRAPPER_TASK_H__ +#define __OS_WRAPPER_TASK_H__ + +/* CONFIG_NUM_COOP_PRIORITIES shall be 0 */ +#define RTOS_TASK_MAX_PRIORITIES (CONFIG_NUM_PREEMPT_PRIORITIES) +#define RTOS_MINIMAL_STACK_SIZE (1024) +#define RTOS_MINIMAL_SECURE_STACK_SIZE (1024) + +#define RTOS_SCHED_SUSPENDED 0x0UL +#define RTOS_SCHED_NOT_STARTED 0x1UL +#define RTOS_SCHED_RUNNING 0x2UL + +/** + * @brief task handle and function type + */ +typedef void *rtos_task_t; +typedef void (*rtos_task_function_t)(void *); + +/** + * @brief Start os kernel scheduler + * @retval return SUCCESS Only + */ +int rtos_sched_start(void); + +/** + * @brief Stop os kernel scheduler + * @retval return SUCCESS Only + */ +int rtos_sched_stop(void); + +/** + * @brief Suspend os kernel scheduler + * @retval return SUCCESS Only + */ +int rtos_sched_suspend(void); + +/** + * @brief Resume os kernel scheduler + * @retval return SUCCESS Only + */ +int rtos_sched_resume(void); + +/** + * @brief Get scheduler status. + * @retval RTOS_SCHED_SUSPENDED / RTOS_SCHED_NOT_STARTED / RTOS_SCHED_RUNNING + */ +int rtos_sched_get_state(void); + +/** + * @brief Create os level task routine. + * @note Usage example: + * Create: + * rtos_task_t handle; + * rtos_task_create(&handle, "test_task", task, NULL, 1024, 2); + * Suspend: + * rtos_task_suspend(handle); + * Resume: + * rtos_task_resume(handle); + * Delete: + * rtos_task_delete(handle); + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @param p_name: A descriptive name for the task. + * @param p_routine: Pointer to the task entry function. Tasks must be implemented to never return + * (i.e. continuous loop). + * @param p_param: Pointer that will be used as the parameter + * @param stack_size_in_byte: The size of the task stack specified + * @param priority: The priority at which the task should run (higher value, higher priority) + * @retval SUCCESS(0) / FAIL(-1) + */ +int rtos_task_create(rtos_task_t *pp_handle, const char *p_name, rtos_task_function_t p_routine, + void *p_param, uint16_t stack_size_in_byte, uint16_t priority); + +/** + * @brief Delete os level task routine. + * @param p_handle: Task handle. If a null pointer is passed, the task itself is deleted. + * @retval return SUCCESS Only + */ +int rtos_task_delete(rtos_task_t p_handle); + +/** + * @brief Suspend os level task routine. + * @param p_handle: Task handle. + * @retval return SUCCESS Only + */ +int rtos_task_suspend(rtos_task_t p_handle); + +/** + * @brief Resume os level task routine. + * @param p_handle: Task handle. + * @retval return SUCCESS Only + */ +int rtos_task_resume(rtos_task_t p_handle); + +/** + * @brief Yield current os level task routine. + * @retval return SUCCESS Only + */ +int rtos_task_yield(void); + +/** + * @brief Get current os level task routine handle. + * @retval The task handle pointer + */ +rtos_task_t rtos_task_handle_get(void); + +/** + * @brief Get os level task routine priority. + * @param p_handle: Task handle. + * @retval Task priority value + */ +uint32_t rtos_task_priority_get(rtos_task_t p_handle); + +/** + * @brief Set os level task routine priority. + * @param p_handle: Task handle. + * @param priority: The priority at which the task should run (higher value, higher priority) + * @retval return SUCCESS Only + */ +int rtos_task_priority_set(rtos_task_t p_handle, uint16_t priority); + +/** + * @brief Print current task status + */ +void rtos_task_out_current_status(void); + +/** + * @brief Allocate a secure context for the task. + * @note trustzone is required. Otherwise it's just an empty implementation. + */ +void rtos_create_secure_context(uint32_t size); + +#endif diff --git a/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_time.h b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_time.h new file mode 100644 index 000000000000..4c08f10f0d88 --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_time.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OS_WRAPPER_TIME_H__ +#define __OS_WRAPPER_TIME_H__ + +#define RTOS_TICK_RATE_HZ 1000UL +#define RTOS_TICK_RATE_MS (1000UL / RTOS_TICK_RATE_HZ) + +#define RTOS_TIME_GET_PASSING_TIME_MS(start) (rtos_time_get_current_system_time_ms() - (start)) + +#define RTOS_TIME_GET_TIME_INTERVAL_MS(start, end) ((end) - (start)) +#define RTOS_TIME_SET_MS_TO_SYSTIME(time) (time / RTOS_TICK_RATE_MS) + +/** + * @brief If the current system is in a scheduling and non-interrupted state, it will switch to + * other tasks. Otherwise, the nop instruction will be executed. + * @param ms: Delay time in milliseconds + */ +void rtos_time_delay_ms(uint32_t ms); + +/** + * @brief The system will execute the nop instruction without scheduling. + * @param us: Delay time in microseconds + */ +void rtos_time_delay_us(uint32_t us); + +/** + * @brief Get the count of ticks since rtos_sched_start was called, and convert the return value to + * milliseconds. + * @note This interface does not consider systick overflow issues. + */ +uint32_t rtos_time_get_current_system_time_ms(void); + +/** + * @brief Return value to in microseconds. + * @note This interface does not consider systick overflow issues. + */ +uint64_t rtos_time_get_current_system_time_us(void); + +/** + * @brief Return value to in nanoseconds. + * @note This interface does not consider systick overflow issues. The accuracy is the clk + * frequency of the CPU + */ +uint64_t rtos_time_get_current_system_time_ns(void); + +#endif diff --git a/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_timer.h b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_timer.h new file mode 100644 index 000000000000..3485619c1529 --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/os_wrapper_timer.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OS_WRAPPER_TIMER_H__ +#define __OS_WRAPPER_TIMER_H__ + +#define RTOS_TIMER_MAX_DELAY 0xFFFFFFFFUL + +/** + * @brief timer handle type + */ +typedef void *rtos_timer_t; + +/** + * @brief Static memory allocation implementation of rtos_timer_create + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @param p_timer_name: A descriptive name for the timer. + * @param timer_id: An identifier that is assigned to the timer being created. Typically this would + * be used in the timer callback function to identify which timer expired when the same callback + * function is assigned to more than one timer. + * @param interval_ms: The timer period in milliseconds. + * @param reload: Used to set the timer as a periodic or one-shot timer. + * @param p_timer_callback: The function to call when the timer expires. + * @retval The status is SUCCESS or FAIL + */ +int rtos_timer_create_static(rtos_timer_t *pp_handle, const char *p_timer_name, uint32_t timer_id, + uint32_t interval_ms, uint8_t reload, + void (*p_timer_callback)(void *)); + +/** + * @brief Static memory allocation implementation of rtos_timer_delete + * @param p_handle: The handle of the timer being deleted. + * @param wait_ms: Specifies the time that the calling task should be held in the Blocked state + * to wait for the delete command to be successfully sent to the timer command + * queue. + * @retval The status is SUCCESS or FAIL + */ +int rtos_timer_delete_static(rtos_timer_t p_handle, uint32_t wait_ms); + +/** + * @brief Create a new software timer instance. This allocates the storage required by the new + * timer, initializes the new timers internal state, and returns a handle by which the new timer can + * be referenced. + * @note Usage example: + * Create: + * rtos_timer_t timer_handle; + * rtos_timer_create(&timer_handle, "timer_test", timer_id, delay_ms, is_reload, + * timer_cb_function); Start: rtos_timer_start(timer_handle, wait_ms); Stop: + * rtos_timer_stop(timer_handle, wait_ms); + * Delete: + * rtos_timer_delete(timer_handle, wait_ms); + * @param pp_handle: The handle itself is a pointer, and the pp_handle means a pointer to the + * handle. + * @param p_timer_name: A descriptive name for the timer. + * @param timer_id: An identifier that is assigned to the timer being created. Typically this would + * be used in the timer callback function to identify which timer expired when the same callback + * function is assigned to more than one timer. + * @param interval_ms: The timer period in milliseconds. + * @param reload: Used to set the timer as a periodic or one-shot timer. + * @param p_timer_callback: The function to call when the timer expires. + * @retval The status is SUCCESS or FAIL + */ +int rtos_timer_create(rtos_timer_t *pp_handle, const char *p_timer_name, uint32_t timer_id, + uint32_t interval_ms, uint8_t reload, void (*p_timer_callback)(void *)); + +/** + * @brief Delete a timer that was previously created using a call to rtos_timer_create. + * @param p_handle: The handle of the timer being deleted. + * @param wait_ms: Specifies the time that the calling task should be held in the Blocked state + * to wait for the delete command to be successfully sent to the timer command + * queue. + * @retval The status is SUCCESS or FAIL + */ +int rtos_timer_delete(rtos_timer_t p_handle, uint32_t wait_ms); + +/** + * @brief Start a timer that was previously created using a call to rtos_timer_create. + * @param p_handle: The handle of the created timer + * @param wait_ms: Specifies the time that the calling task should be held in the Blocked state + * to wait for the start command to be successfully sent to the timer command + * queue. + * @retval The status is SUCCESS or FAIL + */ +int rtos_timer_start(rtos_timer_t p_handle, uint32_t wait_ms); + +/** + * @brief Stopping a timer ensures the timer is not in the active state. + * @param p_handle: The handle of the created timer + * @param wait_ms: Specifies the time that the calling task should be held in the Blocked state + * to wait for the stop command to be successfully sent to the timer command queue. + * @retval The status is SUCCESS or FAIL + */ +int rtos_timer_stop(rtos_timer_t p_handle, uint32_t wait_ms); + +/** + * @brief changes the period of a timer that was previously created using a call to + * rtos_timer_create. + * @param p_handle: The handle of the created timer + * @param interval_ms: The new period for xTimer. + * @param wait_ms: Specifies the time that the calling task should be held in the Blocked state + * to wait for the change command to be successfully sent to the timer command + * queue. + * @retval The status is SUCCESS or FAIL + */ +int rtos_timer_change_period(rtos_timer_t p_handle, uint32_t interval_ms, uint32_t wait_ms); + +/** + * @brief Queries a timer to see if it is active or dormant. A timer will be dormant if: + * 1) It has been created but not started, or + * 2) It is an expired one-shot timer that has not been restarted. + * @note non-interrupt safety + * @param p_handle: The handle of the created timer + * @retval Timer is active or not. + */ +uint32_t rtos_timer_is_timer_active(rtos_timer_t p_handle); + +/** + * @brief Get the ID assigned to the timer when created. + * @note non-interrupt safety + * @param p_handle: Pointer to the created timer handle. + * @retval the ID assigned to the timer. + */ +uint32_t rtos_timer_get_id(rtos_timer_t p_handle); + +#endif diff --git a/soc/realtek/ameba/common/os_wrapper/include/platform_stdlib.h b/soc/realtek/ameba/common/os_wrapper/include/platform_stdlib.h new file mode 100644 index 000000000000..84f34943284b --- /dev/null +++ b/soc/realtek/ameba/common/os_wrapper/include/platform_stdlib.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __PLATFORM_STDLIB_H__ +#define __PLATFORM_STDLIB_H__ + +#include +#include +#include +#include +#include /* va_list */ + +#endif diff --git a/soc/realtek/ameba/soc.yml b/soc/realtek/ameba/soc.yml new file mode 100644 index 000000000000..58a4eb2b9522 --- /dev/null +++ b/soc/realtek/ameba/soc.yml @@ -0,0 +1,4 @@ +family: +- name: realtek_ameba + socs: + - name: amebad From 07502682cc50fee82399492c79ddd69ce0df0ad9 Mon Sep 17 00:00:00 2001 From: zjian zhang Date: Thu, 19 Jun 2025 10:15:43 +0800 Subject: [PATCH 4/8] drivers: pinctrl: add amebad pin controller driver add amebad pin controller driver Signed-off-by: zjian zhang --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.ameba | 9 ++ drivers/pinctrl/pinctrl_ameba.c | 85 ++++++++++++++++++ .../pinctrl/realtek,ameba-pinctrl.yaml | 88 +++++++++++++++++++ .../dt-bindings/pinctrl/amebad-pinctrl.h | 54 ++++++++++++ soc/realtek/ameba/common/pinctrl_soc.h | 54 ++++++++++++ 7 files changed, 292 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.ameba create mode 100644 drivers/pinctrl/pinctrl_ameba.c create mode 100644 dts/bindings/pinctrl/realtek,ameba-pinctrl.yaml create mode 100644 include/zephyr/dt-bindings/pinctrl/amebad-pinctrl.h create mode 100644 soc/realtek/ameba/common/pinctrl_soc.h diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 839c288c394e..9ed8e033b54c 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -45,6 +45,7 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_EMSDP pinctrl_emsdp.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_CC32XX pinctrl_ti_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NUMAKER pinctrl_numaker.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_QUICKLOGIC_EOS_S3 pinctrl_eos_s3.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_AMEBA pinctrl_ameba.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_MCI_IO_MUX pinctrl_mci_io_mux.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_ENE_KB1200 pinctrl_ene_kb1200.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCU pinctrl_imx_scu.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e13c4e427ff7..13a2d4c6b036 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -72,6 +72,7 @@ source "drivers/pinctrl/Kconfig.emsdp" source "drivers/pinctrl/Kconfig.ti_cc32xx" source "drivers/pinctrl/Kconfig.numaker" source "drivers/pinctrl/Kconfig.eos_s3" +source "drivers/pinctrl/Kconfig.ameba" source "drivers/pinctrl/Kconfig.mci_io_mux" source "drivers/pinctrl/Kconfig.ene" source "drivers/pinctrl/Kconfig.zynqmp" diff --git a/drivers/pinctrl/Kconfig.ameba b/drivers/pinctrl/Kconfig.ameba new file mode 100644 index 000000000000..3a168ee8467d --- /dev/null +++ b/drivers/pinctrl/Kconfig.ameba @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_AMEBA + bool "Pin controller driver for Realtek Ameba series SoC" + default y + depends on DT_HAS_REALTEK_AMEBA_PINCTRL_ENABLED + help + Enable pin controller driver for Realtek Ameba series SoC diff --git a/drivers/pinctrl/pinctrl_ameba.c b/drivers/pinctrl/pinctrl_ameba.c new file mode 100644 index 000000000000..6ecb09efdd64 --- /dev/null +++ b/drivers/pinctrl/pinctrl_ameba.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Include before to avoid redefining unlikely() macro */ +#include +#include + +#include + +#define AMEBA_GET_PORT_NUM(pin_mux) ((pin_mux >> 13) & 0x03) +#define AMEBA_GET_PIN_NUM(pin_mux) ((pin_mux >> 8) & 0x1f) +#define AMEBA_GET_PIMNUX_ID(pin_mux) (pin_mux & 0xFF) + +#define AMEBA_GPIO_PINNAME(PORT, PIN) (((PORT) << 5) | ((PIN) & 0x1F)) + +static int ameba_configure_pin(const pinctrl_soc_pin_t *pin) +{ + uint32_t port_idx, pin_idx; + uint8_t gpio_pin; + uint32_t function_id; + + port_idx = AMEBA_GET_PORT_NUM(pin->pinmux); + pin_idx = AMEBA_GET_PIN_NUM(pin->pinmux); + function_id = AMEBA_GET_PIMNUX_ID(pin->pinmux); + gpio_pin = AMEBA_GPIO_PINNAME(port_idx, pin_idx); + + Pinmux_Config(gpio_pin, function_id); + + if (pin->pull_up) { + PAD_PullCtrl(gpio_pin, GPIO_PuPd_UP); + PAD_SleepPullCtrl(gpio_pin, GPIO_PuPd_UP); + } else if (pin->pull_down) { + PAD_PullCtrl(gpio_pin, GPIO_PuPd_DOWN); + PAD_SleepPullCtrl(gpio_pin, GPIO_PuPd_DOWN); + } else { + PAD_PullCtrl(gpio_pin, GPIO_PuPd_NOPULL); + PAD_SleepPullCtrl(gpio_pin, GPIO_PuPd_NOPULL); + } + + /* default slew rate fast */ + if (pin->slew_rate_slow) { + PAD_SlewRateCtrl(gpio_pin, PAD_SlewRate_Slow); + } + + /* Set the PAD driving strength to PAD_DRV_ABILITITY_LOW, default PAD_DRV_ABILITITY_HIGH */ + if (pin->drive_strength_low) { + PAD_DrvStrength(gpio_pin, PAD_DRV_ABILITITY_LOW); + } + + /* default enable digital path input. */ + if (pin->digital_input_disable) { + PAD_InputCtrl(gpio_pin, DISABLE); + } + + /* default enable schmitt */ + if (pin->schmitt_disable) { + PAD_SchmitCtrl(gpio_pin, DISABLE); + } + + if (pin->swd_off) { + Pinmux_Swdoff(); + } + + return 0; +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + int ret = 0; + + ARG_UNUSED(reg); + + for (int i = 0; i < pin_cnt; i++) { + ret = ameba_configure_pin(&pins[i]); + + if (ret < 0) { + return ret; + } + } + + return 0; +} diff --git a/dts/bindings/pinctrl/realtek,ameba-pinctrl.yaml b/dts/bindings/pinctrl/realtek,ameba-pinctrl.yaml new file mode 100644 index 000000000000..bf9d285b8868 --- /dev/null +++ b/dts/bindings/pinctrl/realtek,ameba-pinctrl.yaml @@ -0,0 +1,88 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Realtek Ameba pinctrl is a singleton node responsible for controlling pin function selection + and pin properties. For example, you can use this node to route UART0 TX to pin PB_17 + and enable the pull-up resistor on the pin. + + All device pin configurations should be placed in child nodes of the 'pinctrl' node, + as shown in this example: + /* put this example in places like a board-pinctrl.dtsi file in your board directory, + * or a devicetree overlay in your application. + */ + &pinctrl { + /* configuration for uart0 device, default state */ + uart0_default: uart0_default { + /* 'group1' name is arbitrary, if pin's settings are not same, + * add other group like group2 {} + */ + group1 { + pinmux = , + ; + bias-pull-up; + }; + }; + }; + + The 'uart0_default' child node encodes the pin configurations for a particular state of a device; + in this case, the default (that is, active) state. You would specify the low-power configuration + for the same device in a separate child node. + + 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. The AMEBA_PINMUX macro is + used to specify a pin function selection and pin configuration. You could choose pinmux specified + function to specified pin. And you could configure driver direction, driver state and pull state + for the specified pad. + + To link this pin configuration with a device, use a pinctrl-N property for some number N, + like this example you could place in your board's DTS file: + &uart0 { + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; + }; + +compatible: "realtek,ameba-pinctrl" + +include: base.yaml + +properties: + reg: + required: true +child-binding: + description: | + Realtek Ameba pin controller pin group for a pinctrl state. + child-binding: + description: | + Realtek Ameba pin controller pin configuration node. + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-disable + - bias-pull-down + - bias-pull-up + - input-schmitt-disable + properties: + pinmux: + required: true + type: array + description: | + Pin mux selections for this group. An array of pins sharing the same group properties. + Each element of the array is an integer constructed from the pin number and + the alternative function of the pin. + slew-rate-slow: + type: boolean + description: | + Pin output slew rate.If not set, default value is fast. + drive-strength-low: + type: boolean + description: | + Drive strength of the output pin.If not set, default ability is high. + digital-input-disable: + type: boolean + description: | + Disable the digital input function. + swd-off: + type: boolean + description: | + Disable the SWD function. diff --git a/include/zephyr/dt-bindings/pinctrl/amebad-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/amebad-pinctrl.h new file mode 100644 index 000000000000..da68b684ae86 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/amebad-pinctrl.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_AMEBAD_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_AMEBAD_PINCTRL_H_ + +/* PINMUX Function definitions */ +#define AMEBA_GPIO 0 +#define AMEBA_UART 1 +#define AMEBA_UART_RTSCTS 2 +#define AMEBA_LOGUART 2 +#define AMEBA_SPIM 3 +#define AMEBA_SPIS 3 +#define AMEBA_RTC 4 +#define AMEBA_TIMINPUT 4 +#define AMEBA_IR 5 +#define AMEBA_SPIF 6 +#define AMEBA_I2C 7 +#define AMEBA_SDIOD 8 +#define AMEBA_SDIOH 8 +#define AMEBA_PWM 9 +#define AMEBA_PWM_HS 9 +#define AMEBA_PWM_LP 10 +#define AMEBA_SWD 11 +#define AMEBA_I2S 12 +#define AMEBA_DMIC 12 +#define AMEBA_LCD 13 +#define AMEBA_USB 14 +#define AMEBA_QDEC 15 +#define AMEBA_SGPIO 16 +#define AMEBA_RFE 18 +#define AMEBA_BTCOEX 19 +#define AMEBA_WIFIFW 20 +#define AMEBA_EXT_PCM 20 +#define AMEBA_EXT_BT 20 +#define AMEBA_BB_PIN 21 +#define AMEBA_SIC 22 +#define AMEBA_TIMINPUT_HS 22 +#define AMEBA_DBGPORT 23 +#define AMEBA_BBDBG 25 +#define AMEBA_EXT32K 28 +#define AMEBA_RTCOUT 28 +#define AMEBA_KEYSCAN_ROW 29 +#define AMEBA_KEYSCAN_COL 30 +#define AMEBA_WAKEUP 31 + +/* Define pins number: bit[14:13] port, bit[12:8] pin, bit[7:0] function ID */ +#define AMEBA_PORT_PIN(port, line) ((((port) - 'A') << 5) + (line)) +#define AMEBA_PINMUX(port, line, funcid) (((AMEBA_PORT_PIN(port, line)) << 8) | (funcid)) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_AMEBAD_PINCTRL_H_ */ diff --git a/soc/realtek/ameba/common/pinctrl_soc.h b/soc/realtek/ameba/common/pinctrl_soc.h new file mode 100644 index 000000000000..52bd8aab63ad --- /dev/null +++ b/soc/realtek/ameba/common/pinctrl_soc.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_REALTEK_AMEBA_COMMON_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_REALTEK_AMEBA_COMMON_PINCTRL_SOC_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct pinctrl_soc_pin { + uint32_t pinmux: 15; + /* bit[14:13] port + * bit[12:8] pin + * bit[7:0] function ID + */ + uint32_t pull_down: 1; + uint32_t pull_up: 1; + uint32_t schmitt_disable: 1; + uint32_t slew_rate_slow: 1; + uint32_t drive_strength_low: 1; + uint32_t digital_input_disable: 1; + uint32_t swd_off: 1; +}; + +typedef struct pinctrl_soc_pin pinctrl_soc_pin_t; + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + .pinmux = DT_PROP_BY_IDX(node_id, prop, idx), \ + .pull_down = DT_PROP(node_id, bias_pull_down), \ + .pull_up = DT_PROP(node_id, bias_pull_up), \ + .schmitt_disable = DT_PROP(node_id, input_schmitt_disable), \ + .slew_rate_slow = DT_PROP(node_id, slew_rate_slow), \ + .drive_strength_low = DT_PROP(node_id, drive_strength_low), \ + .digital_input_disable = DT_PROP(node_id, digital_input_disable), \ + .swd_off = DT_PROP(node_id, swd_off), \ + }, + +#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)} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_REALTEK_AMEBA_COMMON_PINCTRL_SOC_H_ */ From 799198b6c968c75c3df2c8d5bd75de7c7801f8c4 Mon Sep 17 00:00:00 2001 From: zjian zhang Date: Thu, 19 Jun 2025 10:24:02 +0800 Subject: [PATCH 5/8] drivers: serial: add amebad loguart driver loguart driver for amebad Signed-off-by: zjian zhang --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 1 + drivers/serial/Kconfig.ameba_loguart | 11 + drivers/serial/uart_ameba_loguart.c | 319 ++++++++++++++++++ .../serial/realtek,ameba-loguart.yaml | 16 + 5 files changed, 348 insertions(+) create mode 100644 drivers/serial/Kconfig.ameba_loguart create mode 100644 drivers/serial/uart_ameba_loguart.c create mode 100644 dts/bindings/serial/realtek,ameba-loguart.yaml diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 9881217d5b00..916b0d475e29 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_AESC uart_aesc.c) zephyr_library_sources_ifdef(CONFIG_UART_ALTERA uart_altera.c) zephyr_library_sources_ifdef(CONFIG_UART_ALTERA_JTAG uart_altera_jtag.c) zephyr_library_sources_ifdef(CONFIG_UART_AMBIQ uart_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_UART_AMEBA_LOGUART uart_ameba_loguart.c) zephyr_library_sources_ifdef(CONFIG_UART_APBUART uart_apbuart.c) zephyr_library_sources_ifdef(CONFIG_UART_BCM2711_MU uart_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_UART_BFLB uart_bflb.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ea3fbed123ba..82162de6795e 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -161,6 +161,7 @@ rsource "Kconfig.aesc" rsource "Kconfig.altera" rsource "Kconfig.altera_jtag" rsource "Kconfig.ambiq" +rsource "Kconfig.ameba_loguart" rsource "Kconfig.apbuart" rsource "Kconfig.b91" rsource "Kconfig.bcm2711" diff --git a/drivers/serial/Kconfig.ameba_loguart b/drivers/serial/Kconfig.ameba_loguart new file mode 100644 index 000000000000..5e42cf6ec07f --- /dev/null +++ b/drivers/serial/Kconfig.ameba_loguart @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +config UART_AMEBA_LOGUART + bool "Ameba LOGUART driver" + default y + depends on DT_HAS_REALTEK_AMEBA_LOGUART_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + help + This option enables the LOGUART driver for Realtek Ameba SoCs. diff --git a/drivers/serial/uart_ameba_loguart.c b/drivers/serial/uart_ameba_loguart.c new file mode 100644 index 000000000000..b862106d7784 --- /dev/null +++ b/drivers/serial/uart_ameba_loguart.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Driver for Realtek Ameba LOGUART + */ + +/* Include before to avoid redefining unlikely() macro */ +#include +#include + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(loguart_ameba, CONFIG_UART_LOG_LEVEL); + +/* + * Extract information from devicetree. + * + * This driver only supports one instance of this IP block, so the + * instance number is always 0. + */ +#define DT_DRV_COMPAT realtek_ameba_loguart + +/* Device config structure */ +struct loguart_ameba_config { +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) + uart_irq_config_func_t irq_config_func; +#endif +}; + +/* Device data structure */ +struct loguart_ameba_data { + struct uart_config config; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t user_cb; + void *user_data; + bool tx_int_en; + bool rx_int_en; +#endif +}; + +/** + * @brief Poll the device for input. + * + * @param dev UART device struct + * @param c Pointer to character + * + * @return 0 if a character arrived, -1 if the input buffer if empty. + */ +static int loguart_ameba_poll_in(const struct device *dev, unsigned char *c) +{ + ARG_UNUSED(dev); + + if (!LOGUART_Readable()) { + return -1; + } + + *c = LOGUART_GetChar(false); + return 0; +} + +/** + * @brief Output a character in polled mode. + * + * @param dev UART device struct + * @param c Character to send + */ +static void loguart_ameba_poll_out(const struct device *dev, unsigned char c) +{ + ARG_UNUSED(dev); + LOGUART_PutChar(c); +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +static int loguart_ameba_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) +{ + ARG_UNUSED(dev); + + uint8_t num_tx = 0U; + unsigned int key; + + if (!LOGUART_Writable()) { + return num_tx; + } + + /* Lock interrupts to prevent nested interrupts or thread switch */ + + key = irq_lock(); + + while ((len - num_tx > 0) && LOGUART_Writable()) { + LOGUART_PutChar((uint8_t)tx_data[num_tx++]); + } + + irq_unlock(key); + + return num_tx; +} + +static int loguart_ameba_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + ARG_UNUSED(dev); + + uint8_t num_rx = 0U; + + while ((size - num_rx > 0) && LOGUART_Readable()) { + rx_data[num_rx++] = LOGUART_GetChar(false); + } + + /* Clear timeout int flag */ + if (LOGUART_GetStatus(LOGUART_DEV) & LOGUART_BIT_TIMEOUT_INT) { + LOGUART_INTClear(LOGUART_DEV, LOGUART_BIT_TOICF); + } + + return num_rx; +} + +static void loguart_ameba_irq_tx_enable(const struct device *dev) +{ + u32 sts; + struct loguart_ameba_data *data = dev->data; + + /* Disable IRQ Interrupts and Save Previous Status. */ + sts = irq_disable_save(); + + data->tx_int_en = true; + /* KM4: TX_PATH1 */ + LOGUART_INTConfig(LOGUART_DEV, LOGUART_TX_EMPTY_PATH_1_INTR, ENABLE); + + /* Enable IRQ Interrupts according to Previous Status. */ + irq_enable_restore(sts); +} + +static void loguart_ameba_irq_tx_disable(const struct device *dev) +{ + u32 sts; + struct loguart_ameba_data *data = dev->data; + + /* Disable IRQ Interrupts and Save Previous Status. */ + sts = irq_disable_save(); + + LOGUART_INTConfig(LOGUART_DEV, LOGUART_TX_EMPTY_PATH_1_INTR, DISABLE); + data->tx_int_en = false; + + /* Enable IRQ Interrupts according to Previous Status. */ + irq_enable_restore(sts); +} + +static int loguart_ameba_irq_tx_ready(const struct device *dev) +{ + struct loguart_ameba_data *data = dev->data; + + /* KM4: TX_PATH1 */ + return (LOGUART_GetStatus(LOGUART_DEV) & LOGUART_BIT_TP1F_EMPTY) && data->tx_int_en; +} + +static int loguart_ameba_irq_tx_complete(const struct device *dev) +{ + return loguart_ameba_irq_tx_ready(dev); +} + +static void loguart_ameba_irq_rx_enable(const struct device *dev) +{ + struct loguart_ameba_data *data = dev->data; + + data->rx_int_en = true; + LOGUART_INTConfig(LOGUART_DEV, LOGUART_BIT_ERBI | LOGUART_BIT_ETOI, ENABLE); +} + +static void loguart_ameba_irq_rx_disable(const struct device *dev) +{ + struct loguart_ameba_data *data = dev->data; + + data->rx_int_en = false; + LOGUART_INTConfig(LOGUART_DEV, LOGUART_BIT_ERBI | LOGUART_BIT_ETOI, DISABLE); +} + +static int loguart_ameba_irq_rx_ready(const struct device *dev) +{ + struct loguart_ameba_data *data = dev->data; + + return (LOGUART_GetStatus(LOGUART_DEV) & + (LOGUART_BIT_DRDY | LOGUART_BIT_RXFIFO_INT | LOGUART_BIT_TIMEOUT_INT)) && + data->rx_int_en; +} + +static void loguart_ameba_irq_err_enable(const struct device *dev) +{ + ARG_UNUSED(dev); + + LOGUART_INTConfig(LOGUART_DEV, LOGUART_BIT_ELSI, ENABLE); +} + +static void loguart_ameba_irq_err_disable(const struct device *dev) +{ + ARG_UNUSED(dev); + + LOGUART_INTConfig(LOGUART_DEV, LOGUART_BIT_ELSI, DISABLE); +} + +static int loguart_ameba_irq_is_pending(const struct device *dev) +{ + return loguart_ameba_irq_tx_ready(dev) || loguart_ameba_irq_rx_ready(dev); +} + +static int loguart_ameba_irq_update(const struct device *dev) +{ + return 1; +} + +static void loguart_ameba_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, void *cb_data) +{ + struct loguart_ameba_data *data = dev->data; + + data->user_cb = cb; + data->user_data = cb_data; +} + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +/** + * @brief Initialize UART channel + * + * This routine is called to reset the chip in a quiescent state. + * It is assumed that this function is called only once per UART. + * + * @param dev UART device struct + * + * @return 0 on success + */ +static int loguart_ameba_init(const struct device *dev) +{ + LOGUART_RxCmd(LOGUART_DEV, DISABLE); + LOGUART_INT_NP2AP(); +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) + const struct loguart_ameba_config *config = dev->config; + + config->irq_config_func(dev); +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + + LOGUART_RxCmd(LOGUART_DEV, ENABLE); + + return 0; +} + +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) +#define AMEBA_LOGUART_IRQ_HANDLER_DECL \ + static void loguart_ameba_irq_config_func(const struct device *dev); +#define AMEBA_LOGUART_IRQ_HANDLER \ + static void loguart_ameba_irq_config_func(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), loguart_ameba_isr, \ + DEVICE_DT_INST_GET(0), 0); \ + irq_enable(DT_INST_IRQN(0)); \ + } +#define AMEBA_LOGUART_IRQ_HANDLER_FUNC .irq_config_func = loguart_ameba_irq_config_func, +#else +#define AMEBA_LOGUART_IRQ_HANDLER_DECL /* Not used */ +#define AMEBA_LOGUART_IRQ_HANDLER /* Not used */ +#define AMEBA_LOGUART_IRQ_HANDLER_FUNC /* Not used */ +#endif + +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) + +static void loguart_ameba_isr(const struct device *dev) +{ + struct loguart_ameba_data *data = dev->data; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + if (data->user_cb) { + data->user_cb(dev, data->user_data); + } +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static const struct uart_driver_api loguart_ameba_driver_api = { + .poll_in = loguart_ameba_poll_in, + .poll_out = loguart_ameba_poll_out, +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = loguart_ameba_fifo_fill, + .fifo_read = loguart_ameba_fifo_read, + .irq_tx_enable = loguart_ameba_irq_tx_enable, + .irq_tx_disable = loguart_ameba_irq_tx_disable, + .irq_tx_ready = loguart_ameba_irq_tx_ready, + .irq_rx_enable = loguart_ameba_irq_rx_enable, + .irq_rx_disable = loguart_ameba_irq_rx_disable, + .irq_tx_complete = loguart_ameba_irq_tx_complete, + .irq_rx_ready = loguart_ameba_irq_rx_ready, + .irq_err_enable = loguart_ameba_irq_err_enable, + .irq_err_disable = loguart_ameba_irq_err_disable, + .irq_is_pending = loguart_ameba_irq_is_pending, + .irq_update = loguart_ameba_irq_update, + .irq_callback_set = loguart_ameba_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +AMEBA_LOGUART_IRQ_HANDLER_DECL +AMEBA_LOGUART_IRQ_HANDLER + +static const struct loguart_ameba_config loguart_config = {AMEBA_LOGUART_IRQ_HANDLER_FUNC}; + +static struct loguart_ameba_data loguart_data = {.config = { + .stop_bits = UART_CFG_STOP_BITS_1, + .data_bits = UART_CFG_DATA_BITS_8, + .baudrate = DT_INST_PROP(0, current_speed), + .parity = UART_CFG_PARITY_NONE, + .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, + }}; + +DEVICE_DT_INST_DEFINE(0, loguart_ameba_init, NULL, &loguart_data, &loguart_config, PRE_KERNEL_1, + CONFIG_SERIAL_INIT_PRIORITY, &loguart_ameba_driver_api); diff --git a/dts/bindings/serial/realtek,ameba-loguart.yaml b/dts/bindings/serial/realtek,ameba-loguart.yaml new file mode 100644 index 000000000000..68926503fc74 --- /dev/null +++ b/dts/bindings/serial/realtek,ameba-loguart.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +description: Ameba LOGUART +compatible: "realtek,ameba-loguart" + +include: [uart-controller.yaml, base.yaml, pinctrl-device.yaml] + +bus: uart + +properties: + reg: + required: true + + interrupts: + required: true From 727f63bc15eea45f644e22aaea3ee4fde8c92ded Mon Sep 17 00:00:00 2001 From: zjian zhang Date: Thu, 19 Jun 2025 10:25:22 +0800 Subject: [PATCH 6/8] drivers: gpio: add amebad gpio driver GPIO driver for amebad Signed-off-by: zjian zhang --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.ameba | 18 ++ drivers/gpio/gpio_ameba.c | 291 ++++++++++++++++++++++ dts/bindings/gpio/realtek,ameba-gpio.yaml | 22 ++ 5 files changed, 334 insertions(+) create mode 100644 drivers/gpio/Kconfig.ameba create mode 100644 drivers/gpio/gpio_ameba.c create mode 100644 dts/bindings/gpio/realtek,ameba-gpio.yaml diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 728a883e1093..66311e543ac5 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_ADP5585 gpio_adp5585.c) 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_AMEBA gpio_ameba.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ANDES_ATCGPIO100 gpio_andes_atcgpio100.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AW9523B gpio_aw9523b.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AXP192 gpio_axp192.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e95aded5613a..9339808d0f63 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -202,4 +202,6 @@ source "drivers/gpio/Kconfig.xlnx_ps" source "drivers/gpio/Kconfig.xmc4xxx" # zephyr-keep-sorted-stop +source "drivers/gpio/Kconfig.ameba" + endif # GPIO diff --git a/drivers/gpio/Kconfig.ameba b/drivers/gpio/Kconfig.ameba new file mode 100644 index 000000000000..58a27a8f039b --- /dev/null +++ b/drivers/gpio/Kconfig.ameba @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_AMEBA + bool "GPIO controller driver for Realtek Ameba series SoC" + default y + depends on DT_HAS_REALTEK_AMEBA_GPIO_ENABLED + help + Enable GPIO controller driver for Realtek Ameba series SoC + +config GPIO_DEBOUNCE_EN + bool "Ameba GPIO Interrupt Debounce Enable" + depends on GPIO_AMEBA + default y + help + When Enable GPIO Interrupt Debounce, the external signal can be debounced to + remove any spurious glitches that are less than one period(about 32us) of + the external debouncing clock. diff --git a/drivers/gpio/gpio_ameba.c b/drivers/gpio/gpio_ameba.c new file mode 100644 index 000000000000..788d501da414 --- /dev/null +++ b/drivers/gpio/gpio_ameba.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT realtek_ameba_gpio + +/* Include before to avoid redefining unlikely() macro */ +#include +#include + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(gpio_ameba, CONFIG_GPIO_LOG_LEVEL); + +#define GPIO_PINNAME(PORT, PIN) (((PORT) << 5) | ((PIN) & 0x1F)) + +struct gpio_ameba_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + /* port base address */ + uint32_t base; + /* IO port */ + int port; +}; + +struct gpio_ameba_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + /* port ISR callback routine address */ + sys_slist_t callbacks; +}; + +static int gpio_ameba_port_get_raw(const struct device *dev, uint32_t *value) +{ + const struct gpio_ameba_config *cfg = dev->config; + + *value = GPIO_PortRead(cfg->port, cfg->common.port_pin_mask); + + return 0; +} + +static int gpio_ameba_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) +{ + const struct gpio_ameba_config *cfg = dev->config; + + GPIO_PortDirection(cfg->port, mask, GPIO_Mode_OUT); + GPIO_PortWrite(cfg->port, mask, value); + + return 0; +} + +static int gpio_ameba_port_set_bits_raw(const struct device *dev, uint32_t mask) +{ + const struct gpio_ameba_config *cfg = dev->config; + + GPIO_PortWrite(cfg->port, mask, cfg->common.port_pin_mask); + + return 0; +} + +static int gpio_ameba_port_clear_bits_raw(const struct device *dev, uint32_t mask) +{ + const struct gpio_ameba_config *cfg = dev->config; + + GPIO_PortWrite(cfg->port, mask, 0); + + return 0; +} + +static int gpio_ameba_port_toggle_bits(const struct device *dev, uint32_t mask) +{ + const struct gpio_ameba_config *cfg = dev->config; + u32 gpio_pin; + u32 value; + uint8_t i; + + for (i = 0; i < 32; i++) { + if (mask & 0x1) { + gpio_pin = GPIO_PINNAME(cfg->port, i); + value = GPIO_ReadDataBit(gpio_pin); + GPIO_WriteBit(gpio_pin, (~value) & 0x1); + } + mask >>= 1; + if (mask == 0) { + break; + } + } + + return 0; +} + +static int gpio_ameba_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct gpio_ameba_config *cfg = dev->config; + + GPIO_InitTypeDef gpio_initstruct; + u32 gpio_pin; + + if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) { + return -ENOTSUP; + } + + if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == 0) { + return -ENOTSUP; + } + + gpio_pin = GPIO_PINNAME(cfg->port, pin); + gpio_initstruct.GPIO_Pin = gpio_pin; + + if (flags & GPIO_INPUT) { + gpio_initstruct.GPIO_Mode = GPIO_Mode_IN; + } else { + gpio_initstruct.GPIO_Mode = GPIO_Mode_OUT; + } + + if (flags & GPIO_PULL_UP) { + gpio_initstruct.GPIO_PuPd = GPIO_PuPd_UP; + } else if (flags & GPIO_PULL_DOWN) { + gpio_initstruct.GPIO_PuPd = GPIO_PuPd_DOWN; + } else { + gpio_initstruct.GPIO_PuPd = GPIO_PuPd_NOPULL; + } + + GPIO_Init(&gpio_initstruct); + + if (flags & GPIO_OUTPUT) { + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { + gpio_ameba_port_set_bits_raw(dev, BIT(pin)); + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { + gpio_ameba_port_clear_bits_raw(dev, BIT(pin)); + } + } + + return 0; +} + +static int gpio_ameba_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct gpio_ameba_config *cfg = dev->config; + u32 gpio_pin; + + gpio_pin = GPIO_PINNAME(cfg->port, pin); + GPIO_InitTypeDef gpio_initstruct; + + gpio_initstruct.GPIO_Pin = gpio_pin; + + GPIO_INTConfig(gpio_pin, DISABLE); + + LOG_DBG("Config GPIO int:%d-%d, mode:%x, flag:0x%x\n", cfg->port, pin, mode, trig); + gpio_initstruct.GPIO_Pin = gpio_pin; + gpio_initstruct.GPIO_PuPd = GPIO_PuPd_NOPULL; + gpio_initstruct.GPIO_Mode = GPIO_Mode_INT; + gpio_initstruct.GPIO_ITDebounce = GPIO_INT_DEBOUNCE_DISABLE; + + if (mode != GPIO_INT_MODE_DISABLED) { + if (mode & GPIO_INT_MODE_EDGE) { + switch (trig) { + case GPIO_INT_TRIG_LOW: + gpio_initstruct.GPIO_ITTrigger = GPIO_INT_Trigger_EDGE; + gpio_initstruct.GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_LOW; + break; + case GPIO_INT_TRIG_HIGH: + gpio_initstruct.GPIO_ITTrigger = GPIO_INT_Trigger_EDGE; + gpio_initstruct.GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_HIGH; + break; + case GPIO_INT_TRIG_BOTH: + gpio_initstruct.GPIO_ITTrigger = GPIO_INT_Trigger_BOTHEDGE; + break; + default: + LOG_ERR("GPIO Edge interrupt type invalid \r\n"); + return -ENOTSUP; + } + } else { + gpio_initstruct.GPIO_ITTrigger = GPIO_INT_Trigger_LEVEL; + switch (trig) { + case GPIO_INT_TRIG_LOW: + gpio_initstruct.GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_LOW; + gpio_initstruct.GPIO_PuPd = GPIO_PuPd_UP; + break; + case GPIO_INT_TRIG_HIGH: + gpio_initstruct.GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_HIGH; + gpio_initstruct.GPIO_PuPd = GPIO_PuPd_DOWN; + break; + default: + LOG_ERR("GPIO level interrupt doesn't support both high and low"); + return -ENOTSUP; + } + } + +#if defined(CONFIG_GPIO_DEBOUNCE_EN) + gpio_initstruct.GPIO_ITDebounce = GPIO_INT_DEBOUNCE_ENABLE; + /* GPIO_DebounceClock(cfg->port, DEBOUNCE_DIV_CNT); */ + GPIO_Init(&gpio_initstruct); + DelayUs(64); + GPIO_INTConfig(gpio_pin, ENABLE); +#else + GPIO_Init(&gpio_initstruct); + GPIO_INTConfig(gpio_pin, ENABLE); +#endif + } else { + GPIO_Direction(gpio_pin, GPIO_Mode_IN); + PAD_PullCtrl(gpio_pin, gpio_initstruct.GPIO_PuPd); + + GPIO_INTMode(gpio_pin, DISABLE, 0, 0, 0); + } + + return 0; +} + +static int gpio_ameba_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct gpio_ameba_data *data = dev->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static uint32_t gpio_ameba_get_pending_int(const struct device *dev) +{ + uint32_t irq_status; + const struct gpio_ameba_config *cfg = dev->config; + uint32_t port = cfg->port; + + irq_status = GPIO_INTStatusGet(port); + + return irq_status; +} + +static void gpio_ameba_isr(const struct device *dev) +{ + uint32_t int_status; + struct gpio_ameba_data *data = dev->data; + const struct gpio_ameba_config *cfg = dev->config; + uint32_t port = cfg->port; + + /* Get the int status */ + int_status = GPIO_INTStatusGet(port); + + /* Clear pending edge interrupt */ + GPIO_INTStatusClearEdge(port); + + /* Call the registered callbacks */ + gpio_fire_callbacks(&data->callbacks, dev, int_status); +} + +static const struct gpio_driver_api gpio_ameba_driver_api = { + .pin_configure = gpio_ameba_configure, + .port_get_raw = gpio_ameba_port_get_raw, + .port_set_masked_raw = gpio_ameba_port_set_masked_raw, + .port_set_bits_raw = gpio_ameba_port_set_bits_raw, + .port_clear_bits_raw = gpio_ameba_port_clear_bits_raw, + .port_toggle_bits = gpio_ameba_port_toggle_bits, + .pin_interrupt_configure = gpio_ameba_pin_interrupt_configure, + .manage_callback = gpio_ameba_manage_callback, + .get_pending_int = gpio_ameba_get_pending_int, +}; + +#define GPIO_AMEBA_INIT(n) \ + static int gpio_ameba_port##n##_init(const struct device *dev) \ + { \ + const struct gpio_ameba_config *cfg = dev->config; \ + LOG_INF("GPIO%d INIT, IRQ %d\n", cfg->port, DT_INST_IRQN(n)); \ + \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_ameba_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + \ + return 0; \ + } \ + static struct gpio_ameba_data gpio_ameba_port##n##_data; \ + \ + static const struct gpio_ameba_config gpio_ameba_port##n##_config = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .base = DT_INST_REG_ADDR(n), \ + .port = n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_ameba_port##n##_init, NULL, &gpio_ameba_port##n##_data, \ + &gpio_ameba_port##n##_config, POST_KERNEL, \ + CONFIG_GPIO_INIT_PRIORITY, &gpio_ameba_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_AMEBA_INIT) diff --git a/dts/bindings/gpio/realtek,ameba-gpio.yaml b/dts/bindings/gpio/realtek,ameba-gpio.yaml new file mode 100644 index 000000000000..4eab82fd2316 --- /dev/null +++ b/dts/bindings/gpio/realtek,ameba-gpio.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +description: Realtek Ameba GPIO controller + +compatible: "realtek,ameba-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags From 91bd0973c7e1f668c922650218ee3e0fbfc4c4e6 Mon Sep 17 00:00:00 2001 From: zjian zhang Date: Thu, 19 Jun 2025 10:32:38 +0800 Subject: [PATCH 7/8] boards: add rtl872xd_evb board add initial version of rtl872xd_evb board Signed-off-by: zjian zhang --- .../realtek/rtl872xd_evb/Kconfig.rtl872xd_evb | 5 ++ boards/realtek/rtl872xd_evb/board.cmake | 6 ++ boards/realtek/rtl872xd_evb/board.yml | 5 ++ boards/realtek/rtl872xd_evb/doc/index.rst | 77 ++++++++++++++++++ .../rtl872xd_evb/doc/rtl872xda_evb.webp | Bin 0 -> 81232 bytes .../rtl872xd_evb/rtl872xd_evb-pinctrl.dtsi | 20 +++++ boards/realtek/rtl872xd_evb/rtl872xd_evb.dts | 31 +++++++ boards/realtek/rtl872xd_evb/rtl872xd_evb.yaml | 16 ++++ .../rtl872xd_evb/rtl872xd_evb_defconfig | 19 +++++ 9 files changed, 179 insertions(+) create mode 100644 boards/realtek/rtl872xd_evb/Kconfig.rtl872xd_evb create mode 100644 boards/realtek/rtl872xd_evb/board.cmake create mode 100644 boards/realtek/rtl872xd_evb/board.yml create mode 100644 boards/realtek/rtl872xd_evb/doc/index.rst create mode 100644 boards/realtek/rtl872xd_evb/doc/rtl872xda_evb.webp create mode 100644 boards/realtek/rtl872xd_evb/rtl872xd_evb-pinctrl.dtsi create mode 100644 boards/realtek/rtl872xd_evb/rtl872xd_evb.dts create mode 100644 boards/realtek/rtl872xd_evb/rtl872xd_evb.yaml create mode 100644 boards/realtek/rtl872xd_evb/rtl872xd_evb_defconfig diff --git a/boards/realtek/rtl872xd_evb/Kconfig.rtl872xd_evb b/boards/realtek/rtl872xd_evb/Kconfig.rtl872xd_evb new file mode 100644 index 000000000000..a4b60a0b205a --- /dev/null +++ b/boards/realtek/rtl872xd_evb/Kconfig.rtl872xd_evb @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RTL872XD_EVB + select SOC_AMEBAD diff --git a/boards/realtek/rtl872xd_evb/board.cmake b/boards/realtek/rtl872xd_evb/board.cmake new file mode 100644 index 000000000000..79ab10f7e1d8 --- /dev/null +++ b/boards/realtek/rtl872xd_evb/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=Cortex-M33" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/realtek/rtl872xd_evb/board.yml b/boards/realtek/rtl872xd_evb/board.yml new file mode 100644 index 000000000000..3c261913f58e --- /dev/null +++ b/boards/realtek/rtl872xd_evb/board.yml @@ -0,0 +1,5 @@ +board: + name: rtl872xd_evb + vendor: realtek + socs: + - name: amebad diff --git a/boards/realtek/rtl872xd_evb/doc/index.rst b/boards/realtek/rtl872xd_evb/doc/index.rst new file mode 100644 index 000000000000..132bd21383c0 --- /dev/null +++ b/boards/realtek/rtl872xd_evb/doc/index.rst @@ -0,0 +1,77 @@ +.. zephyr:board:: rtl872xd_evb + +Overview +******** + +The Realtek RTL872xD Series is a Combo SoC that supports dual-band Wi-Fi 4 (2.4GHz + 5GHz) and +BLE 5.0 specifications. With ultra-low power consumption, complete encryption strategy and abundant +peripheral resources, it is widely in various products such as Home appliance control panel, +Smart door, Smart toy, Smart voice, Smart remote control, Bluetooth gateway, Headset, Wi-Fi gamepad, +Smart POS, etc. For more information, check `RTL872XD-EVB`_. + +The features include the following: + +- Dual cores: Real-M300 and Real-M200 +- 512KB + 64KB on-chip SRAM +- 802.11 a/b/g/n 1 x 1, 2.4GHz + 5GHz +- Supports BLE 5.0 +- Peripheral Interface: + + - Multi-communication interfaces: SPI x 2, UART x 4, I2C x 1 + - Hardware Key-scan interface supports up to 36 keys + - Hardware Quad-decoder supports statistical and comparison functions + - Hardware IR transceiver can easily adapt to various IR protocols + - SDIO/USB high speed interface (both host and slave) + - Supports real-time clock together with 18 channels of PWM output + - Supports 5 channels of touch pad and 6 channels of GDMA + - Supports 7 channels of normal 12-bit ADC and 1 channel of VBAT + - Integrated LCDC supports both RGB and I8080 interfaces + - Integrated hardware crypto engine supports AES256/192/128 and SHA256 + - Integrated audio codec + +For more information, Get application note and datasheet at `RTL872xCS/D Series`_ depending on chip you use. + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Building +******** + +Here is an example for building the :zephyr:code-sample:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: rtl872xd_evb + :goals: build + +Flashing +******** + +When the build finishes, downloading images into flash by `AmebaImageTool`_: + +See the ApplicationNote chapter Image Tool from documentation links for more details. + +#. Environment Requirements: EX. WinXP, Win 7 or later, Microsoft .NET Framework 4.0. +#. Connect chip and PC with USB wire. +#. Choose the Device profiles according to the chip you use. +#. Select the corresponding serial port and transmission baud rate. The default baud rate is 1500000. +#. Select the images to be programmed and set the start address and end address according to the flash layout, refer to [ameba_flashcfg.c/Flash_layout]. +#. Click the Download button and start. The progress bar will show the download progress of each image and the log window will show the operation status. + +.. note:: + + For an empty chip, the bootloader and app image shall be downloaded. + +Debugging +********* + +Using SWD through PB3(SWD_CLK) and PA27(SWD_DAT). + +References +********** + +.. _`RTL872XD-EVB`: https://www.realmcu.com/en/Home/Products/RTL872xCS-RTL872xD-Series# +.. _`RTL872xCS/D Series`: https://www.realmcu.com +.. _`AmebaImageTool`: https://github.com/Ameba-AIoT/ameba-rtos/tree/master/tools/ameba/ImageTool_Legacy/AmebaImageTool.exe diff --git a/boards/realtek/rtl872xd_evb/doc/rtl872xda_evb.webp b/boards/realtek/rtl872xd_evb/doc/rtl872xda_evb.webp new file mode 100644 index 0000000000000000000000000000000000000000..a50446aa08f89693b34d49086be5e218c5b3f67a GIT binary patch literal 81232 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%0DD-y$^L`fQ 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 S0000000000000000002l*Y1h{ literal 0 HcmV?d00001 diff --git a/boards/realtek/rtl872xd_evb/rtl872xd_evb-pinctrl.dtsi b/boards/realtek/rtl872xd_evb/rtl872xd_evb-pinctrl.dtsi new file mode 100644 index 000000000000..268edcab40bc --- /dev/null +++ b/boards/realtek/rtl872xd_evb/rtl872xd_evb-pinctrl.dtsi @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + compatible = "realtek,ameba-pinctrl"; + + /*PA30 is SWD_CLK, PA31 is SWD_DAT(both pull-up internally)*/ + loguart_default: loguart_default { + group1 { + pinmux = , /* RXD */ + ; /* TXD */ + bias-pull-up; + }; + }; +}; diff --git a/boards/realtek/rtl872xd_evb/rtl872xd_evb.dts b/boards/realtek/rtl872xd_evb/rtl872xd_evb.dts new file mode 100644 index 000000000000..b8819f262329 --- /dev/null +++ b/boards/realtek/rtl872xd_evb/rtl872xd_evb.dts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor Corp. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "rtl872xd_evb-pinctrl.dtsi" + +/ { + model = "RealTek AmebaD RTL872XD EVB"; + compatible = "realtek,rtl872xd_evb"; + + chosen { + zephyr,console = &loguart; + zephyr,shell-uart = &loguart; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; +}; + +/* 4MB flash */ +&flash0 { + reg = <0x0e000020 DT_SIZE_M(4)>; +}; + +&loguart { + status = "okay"; +}; diff --git a/boards/realtek/rtl872xd_evb/rtl872xd_evb.yaml b/boards/realtek/rtl872xd_evb/rtl872xd_evb.yaml new file mode 100644 index 000000000000..fa0b4d3cbe1b --- /dev/null +++ b/boards/realtek/rtl872xd_evb/rtl872xd_evb.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +identifier: rtl872xd_evb +name: Realtek rtl872xd evaluation board +vendor: realtek +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +ram: 512 +flash: 4096 +supported: + - pinctrl + - serial diff --git a/boards/realtek/rtl872xd_evb/rtl872xd_evb_defconfig b/boards/realtek/rtl872xd_evb/rtl872xd_evb_defconfig new file mode 100644 index 000000000000..1bc4e83ed3c7 --- /dev/null +++ b/boards/realtek/rtl872xd_evb/rtl872xd_evb_defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Realtek Semiconductor Corp. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_RUNTIME_NMI=y + +CONFIG_CORTEX_M_SYSTICK=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# This board implies building Non-Secure firmware +CONFIG_TRUSTED_EXECUTION_NONSECURE=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable LogUart +CONFIG_SERIAL=y From 55c477935073a9a6a3c25dd3b4d85f65a3e3ae09 Mon Sep 17 00:00:00 2001 From: zjian zhang Date: Thu, 19 Jun 2025 10:33:54 +0800 Subject: [PATCH 8/8] MAINTAINERS: Add hal_realtek as a new HAL module This commit adds maintainers for hal_realtek repository Signed-off-by: zjian zhang --- MAINTAINERS.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 8d7afd64b638..de90238cf76e 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3530,6 +3530,19 @@ Bouffalolab Platforms: labels: - "platform: bouffalolab" +realtek ameba Platforms: + status: maintained + maintainers: + - zjian-zhang + files: + - drivers/*/*ameba* + - boards/realtek/ + - soc/realtek/ + - dts/arm/realtek/ + - dts/bindings/*/*ameba* + labels: + - "platform: ameba" + Broadcom Platforms: status: odd fixes files: @@ -5000,6 +5013,14 @@ West: labels: - "platform: Ambiq" +"West project: hal_realtek": + status: maintained + maintainers: + - zjian-zhang + files: [] + labels: + - "platform: ameba" + "West project: hal_atmel": status: maintained maintainers: