From 41c6483ef5dc39d1991afad6451b8e1f3384f64e Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Fri, 6 Sep 2024 10:05:01 +0800 Subject: [PATCH 01/11] soc: add realtek RTS5817 Add support for the rts5817 MCU Signed-off-by: Darcy Lu --- soc/realtek/fingerprint/CMakeLists.txt | 4 +++ soc/realtek/fingerprint/Kconfig | 8 +++++ soc/realtek/fingerprint/Kconfig.defconfig | 8 +++++ soc/realtek/fingerprint/Kconfig.soc | 10 ++++++ .../fingerprint/rts5817/CMakeLists.txt | 8 +++++ soc/realtek/fingerprint/rts5817/Kconfig | 16 +++++++++ .../fingerprint/rts5817/Kconfig.defconfig | 12 +++++++ soc/realtek/fingerprint/rts5817/Kconfig.soc | 16 +++++++++ soc/realtek/fingerprint/rts5817/pinctrl_soc.h | 34 +++++++++++++++++++ soc/realtek/fingerprint/rts5817/soc.c | 33 ++++++++++++++++++ soc/realtek/fingerprint/rts5817/soc.h | 13 +++++++ soc/realtek/fingerprint/soc.yml | 4 +++ 12 files changed, 166 insertions(+) create mode 100644 soc/realtek/fingerprint/CMakeLists.txt create mode 100644 soc/realtek/fingerprint/Kconfig create mode 100644 soc/realtek/fingerprint/Kconfig.defconfig create mode 100644 soc/realtek/fingerprint/Kconfig.soc create mode 100644 soc/realtek/fingerprint/rts5817/CMakeLists.txt create mode 100644 soc/realtek/fingerprint/rts5817/Kconfig create mode 100644 soc/realtek/fingerprint/rts5817/Kconfig.defconfig create mode 100644 soc/realtek/fingerprint/rts5817/Kconfig.soc create mode 100644 soc/realtek/fingerprint/rts5817/pinctrl_soc.h create mode 100644 soc/realtek/fingerprint/rts5817/soc.c create mode 100644 soc/realtek/fingerprint/rts5817/soc.h create mode 100644 soc/realtek/fingerprint/soc.yml diff --git a/soc/realtek/fingerprint/CMakeLists.txt b/soc/realtek/fingerprint/CMakeLists.txt new file mode 100644 index 0000000000000..9ece0a95d678e --- /dev/null +++ b/soc/realtek/fingerprint/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/realtek/fingerprint/Kconfig b/soc/realtek/fingerprint/Kconfig new file mode 100644 index 0000000000000..1115379b858e8 --- /dev/null +++ b/soc/realtek/fingerprint/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_FINGERPRINT + +rsource "*/Kconfig" + +endif # SOC_FAMILY_FINGERPRINT diff --git a/soc/realtek/fingerprint/Kconfig.defconfig b/soc/realtek/fingerprint/Kconfig.defconfig new file mode 100644 index 0000000000000..6099c0fda301b --- /dev/null +++ b/soc/realtek/fingerprint/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_FINGERPRINT + +rsource "*/Kconfig.defconfig" + +endif # SOC_FAMILY_FINGERPRINT diff --git a/soc/realtek/fingerprint/Kconfig.soc b/soc/realtek/fingerprint/Kconfig.soc new file mode 100644 index 0000000000000..a8c804f20a142 --- /dev/null +++ b/soc/realtek/fingerprint/Kconfig.soc @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_FINGERPRINT + bool + +config SOC_FAMILY + default "fingerprint" if SOC_FAMILY_FINGERPRINT + +rsource "*/Kconfig.soc" diff --git a/soc/realtek/fingerprint/rts5817/CMakeLists.txt b/soc/realtek/fingerprint/rts5817/CMakeLists.txt new file mode 100644 index 0000000000000..281a5a12d6efa --- /dev/null +++ b/soc/realtek/fingerprint/rts5817/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# 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/realtek/fingerprint/rts5817/Kconfig b/soc/realtek/fingerprint/rts5817/Kconfig new file mode 100644 index 0000000000000..f5e69cb0a550e --- /dev/null +++ b/soc/realtek/fingerprint/rts5817/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RTS5817 + select ARM + select CPU_CORTEX_M33 + select CPU_HAS_FPU + select CPU_HAS_ARM_MPU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + select CACHE_MANAGEMENT + select ARMV8_M_DSP + select INIT_ARCH_HW_AT_BOOT + select XIP + select ARCH_HAS_EXTRA_EXCEPTION_INFO + select SOC_EARLY_INIT_HOOK diff --git a/soc/realtek/fingerprint/rts5817/Kconfig.defconfig b/soc/realtek/fingerprint/rts5817/Kconfig.defconfig new file mode 100644 index 0000000000000..d22b301d71e1b --- /dev/null +++ b/soc/realtek/fingerprint/rts5817/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RTS5817 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) + +config NUM_IRQS + default 32 + +endif # SOC_SERIES_RTS5817 diff --git a/soc/realtek/fingerprint/rts5817/Kconfig.soc b/soc/realtek/fingerprint/rts5817/Kconfig.soc new file mode 100644 index 0000000000000..34c7c144e2a43 --- /dev/null +++ b/soc/realtek/fingerprint/rts5817/Kconfig.soc @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RTS5817 + bool + select SOC_FAMILY_FINGERPRINT + +config SOC_RTS5817 + bool + select SOC_SERIES_RTS5817 + +config SOC + default "rts5817" if SOC_RTS5817 + +config SOC_SERIES + default "rts5817" if SOC_SERIES_RTS5817 diff --git a/soc/realtek/fingerprint/rts5817/pinctrl_soc.h b/soc/realtek/fingerprint/rts5817/pinctrl_soc.h new file mode 100644 index 0000000000000..1286dda78c7d8 --- /dev/null +++ b/soc/realtek/fingerprint/rts5817/pinctrl_soc.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_REALTEK_RTS5817_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_REALTEK_RTS5817_PINCTRL_SOC_H_ + +#include +#include + +typedef struct pinctrl_soc_pin { + uint8_t pin: 8; + uint8_t func: 3; + uint8_t pulldown: 1; + uint8_t pullup: 1; + uint8_t power_source: 2; +} pinctrl_soc_pin_t; + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + .pin = RTS_FP_PINMUX_PIN(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .func = RTS_FP_PINMUX_FUNC(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .pulldown = DT_PROP(node_id, bias_pull_down), \ + .pullup = DT_PROP(node_id, bias_pull_up), \ + .power_source = (DT_PROP_OR(node_id, power_source, IO_POWER_3V3)), \ + }, + +#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)} + +#endif /* ZEPHYR_SOC_ARM_REALTEK_RTS5817_PINCTRL_SOC_H_ */ diff --git a/soc/realtek/fingerprint/rts5817/soc.c b/soc/realtek/fingerprint/rts5817/soc.c new file mode 100644 index 0000000000000..fed999a48db97 --- /dev/null +++ b/soc/realtek/fingerprint/rts5817/soc.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include + +/** + * @brief Initialize cache + * + */ +static void cache_init(void) +{ + sys_cache_instr_enable(); + sys_cache_data_enable(); +} + +/** + * @brief Perform basic hardware initialization at boot. + * + * This needs to be run from the very beginning. + */ +void soc_early_init_hook(void) +{ + cache_init(); +} diff --git a/soc/realtek/fingerprint/rts5817/soc.h b/soc/realtek/fingerprint/rts5817/soc.h new file mode 100644 index 0000000000000..ce0159199ba5f --- /dev/null +++ b/soc/realtek/fingerprint/rts5817/soc.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOC_H_ +#define _SOC_H_ + +#include +#include + +#endif /* _SOC_H_ */ diff --git a/soc/realtek/fingerprint/soc.yml b/soc/realtek/fingerprint/soc.yml new file mode 100644 index 0000000000000..a5b868f865229 --- /dev/null +++ b/soc/realtek/fingerprint/soc.yml @@ -0,0 +1,4 @@ +family: +- name: fingerprint + socs: + - name: rts5817 From 6fc2eaba76bdc1321bc236789afc760d3e43accc Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Fri, 6 Sep 2024 10:53:28 +0800 Subject: [PATCH 02/11] include: dt-bindings: add headers for RTS5817 Add clock/interrupt/pinctrl/reset dt-bindings headers for RTS5817 Signed-off-by: Darcy Lu --- .../zephyr/dt-bindings/clock/rts5817_clock.h | 31 +++ .../interrupt-controller/rts5817_intc.h | 22 ++ .../dt-bindings/pinctrl/rts5817_pinctrl.h | 194 ++++++++++++++++++ .../zephyr/dt-bindings/reset/rts5817_reset.h | 36 ++++ 4 files changed, 283 insertions(+) create mode 100644 include/zephyr/dt-bindings/clock/rts5817_clock.h create mode 100644 include/zephyr/dt-bindings/interrupt-controller/rts5817_intc.h create mode 100644 include/zephyr/dt-bindings/pinctrl/rts5817_pinctrl.h create mode 100644 include/zephyr/dt-bindings/reset/rts5817_reset.h diff --git a/include/zephyr/dt-bindings/clock/rts5817_clock.h b/include/zephyr/dt-bindings/clock/rts5817_clock.h new file mode 100644 index 0000000000000..a090942a24be6 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/rts5817_clock.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RTS5817_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RTS5817_CLOCK_H_ + +#define RTS_FP_CLK_SYS_PLL 0 +#define RTS_FP_CLK_BUS 1 +#define RTS_FP_CLK_SPI_CACHE 2 +#define RTS_FP_CLK_SPI_SSOR 3 +#define RTS_FP_CLK_SPI_SSI_M 4 +#define RTS_FP_CLK_SPI_SSI_S 5 +#define RTS_FP_CLK_SHA 6 +#define RTS_FP_CLK_AES 7 +#define RTS_FP_CLK_PKE 8 +#define RTS_FP_CLK_I2C0 9 +#define RTS_FP_CLK_I2C1 10 +#define RTS_FP_CLK_TRNG 11 +#define RTS_FP_CLK_I2C_S 12 +#define RTS_FP_CLK_UART0 13 +#define RTS_FP_CLK_UART1 14 +#define RTS_FP_CLK_SIE 15 +#define RTS_FP_CLK_PUF 16 +#define RTS_FP_CLK_GE 17 + +#define RLX_CLK_NUM_SIZE (RTS_FP_CLK_GE + 1) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RTS5817_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/interrupt-controller/rts5817_intc.h b/include/zephyr/dt-bindings/interrupt-controller/rts5817_intc.h new file mode 100644 index 0000000000000..da0214eb15bb7 --- /dev/null +++ b/include/zephyr/dt-bindings/interrupt-controller/rts5817_intc.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INTERRUPT_CONTROLLER_RTS5817_INTC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_INTERRUPT_CONTROLLER_RTS5817_INTC_H_ + +#define IRQ_NUM_SIE 0 +#define IRQ_NUM_MC 1 +#define IRQ_NUM_SENSOR_SPI 4 +#define IRQ_NUM_SPI_MASTER 5 +#define IRQ_NUM_AES 6 +#define IRQ_NUM_SHA 7 +#define IRQ_NUM_GPIO 11 +#define IRQ_NUM_SP_GPIO 12 +#define IRQ_NUM_UART0 15 +#define IRQ_NUM_UART1 16 +#define IRQ_NUM_SPI_SLAVE 23 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INTERRUPT_CONTROLLER_RTS5817_INTC_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/rts5817_pinctrl.h b/include/zephyr/dt-bindings/pinctrl/rts5817_pinctrl.h new file mode 100644 index 0000000000000..3f2cae63a35e6 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/rts5817_pinctrl.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RTS5817_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RTS5817_PINCTRL_H_ + +/** + * Fields: + * + * - pin [ 7 : 0 ] + * - func [ 10 : 8 ] + */ +#define RTS_FP_PIN_SHIFT 0U +#define RTS_FP_PIN_MASK 0xFFU +#define RTS_FP_FUNC_SHIFT 8U +#define RTS_FP_FUNC_MASK 0x1FU + +#define RTS_FP_PINMUX(pin, func) \ + ((((RTS_FP_PIN_##pin) & RTS_FP_PIN_MASK) << RTS_FP_PIN_SHIFT) | \ + (((RTS_FP_PIN_##func) & RTS_FP_FUNC_MASK) << RTS_FP_FUNC_SHIFT)) + +#define RTS_FP_PINMUX_PIN(__pin) (((__pin) >> RTS_FP_PIN_SHIFT) & RTS_FP_PIN_MASK) +#define RTS_FP_PINMUX_FUNC(__pin) (((__pin) >> RTS_FP_FUNC_SHIFT) & RTS_FP_FUNC_MASK) + +#define IO_POWER_1V8 0 +#define IO_POWER_3V3 1 + +#define RTS_FP_PIN_FUNC0 0 +#define RTS_FP_PIN_FUNC1 1 +#define RTS_FP_PIN_FUNC2 2 +#define RTS_FP_PIN_FUNC3 3 +#define RTS_FP_PIN_FUNC4 4 +#define RTS_FP_PIN_FUNC5 5 +#define RTS_FP_PIN_FUNC6 6 +#define RTS_FP_PIN_FUNC7 7 + +#define RTS_FP_PIN_CACHE_CS1 0 +#define RTS_FP_PIN_CACHE_MISO 1 +#define RTS_FP_PIN_CACHE_MOSI 2 +#define RTS_FP_PIN_CACHE_SCK 3 +#define RTS_FP_PIN_CACHE_WP 4 +#define RTS_FP_PIN_CACHE_HOLD 5 +#define RTS_FP_PIN_CACHE_CS2 6 +#define RTS_FP_PIN_SNR_MISO 7 +#define RTS_FP_PIN_SNR_MOSI 8 +#define RTS_FP_PIN_SNR_CLK 9 +#define RTS_FP_PIN_SSI_M_MISO 10 +#define RTS_FP_PIN_SSI_M_MOSI 11 +#define RTS_FP_PIN_SSI_M_CS 12 +#define RTS_FP_PIN_SSI_M_SCK 13 +#define RTS_FP_PIN_SCL0 14 +#define RTS_FP_PIN_SDA0 15 +#define RTS_FP_PIN_SCL2 16 +#define RTS_FP_PIN_SDA2 17 +#define RTS_FP_PIN_SCL1 18 +#define RTS_FP_PIN_SDA1 19 +#define RTS_FP_PIN_SSI_S_MISO 20 +#define RTS_FP_PIN_SSI_S_MOSI 21 +#define RTS_FP_PIN_SSI_S_CS 22 +#define RTS_FP_PIN_SSI_S_SCK 23 +#define RTS_FP_PIN_GPIO14 24 +#define RTS_FP_PIN_GPIO15 25 +#define RTS_FP_PIN_AL0 26 +#define RTS_FP_PIN_AL1 27 +#define RTS_FP_PIN_AL2 28 +#define RTS_FP_PIN_SNR_RST 29 +#define RTS_FP_PIN_SNR_CS 30 +#define RTS_FP_PIN_SNR_GPIO 31 + +#define P_CACHE_CS2_F_CACHE_CS2 RTS_FP_PINMUX(CACHE_CS2, FUNC0) +#define P_CACHE_CS2_F_GPIO RTS_FP_PINMUX(CACHE_CS2, FUNC1) + +#define P_SNR_MISO_F_SNR_MISO RTS_FP_PINMUX(SNR_MISO, FUNC0) +#define P_SNR_MOSI_F_SNR_MOSI RTS_FP_PINMUX(SNR_MOSI, FUNC0) +#define P_SNR_CLK_F_SNR_CLK RTS_FP_PINMUX(SNR_CLK, FUNC0) + +#define P_SSI_M_MISO_F_GPIO RTS_FP_PINMUX(SSI_M_MISO, FUNC0) +#define P_SSI_M_MISO_F_PWM RTS_FP_PINMUX(SSI_M_MISO, FUNC1) +#define P_SSI_M_MISO_F_SSI_M_MISO RTS_FP_PINMUX(SSI_M_MISO, FUNC2) +#define P_SSI_M_MISO_F_SSI_S_MISO RTS_FP_PINMUX(SSI_M_MISO, FUNC3) +#define P_SSI_M_MISO_F_UART1_RX RTS_FP_PINMUX(SSI_M_MISO, FUNC4) +#define P_SSI_M_MISO_F_ASIC_DBG RTS_FP_PINMUX(SSI_M_MISO, FUNC5) + +#define P_SSI_M_MOSI_F_GPIO RTS_FP_PINMUX(SSI_M_MOSI, FUNC0) +#define P_SSI_M_MOSI_F_PWM RTS_FP_PINMUX(SSI_M_MOSI, FUNC1) +#define P_SSI_M_MOSI_F_SSI_M_MOSI RTS_FP_PINMUX(SSI_M_MOSI, FUNC2) +#define P_SSI_M_MOSI_F_SSI_S_MOSI RTS_FP_PINMUX(SSI_M_MOSI, FUNC3) +#define P_SSI_M_MOSI_F_UART1_TX RTS_FP_PINMUX(SSI_M_MOSI, FUNC4) +#define P_SSI_M_MOSI_F_ASIC_DBG RTS_FP_PINMUX(SSI_M_MOSI, FUNC5) + +#define P_SSI_M_CS_F_GPIO RTS_FP_PINMUX(SSI_M_CS, FUNC0) +#define P_SSI_M_CS_F_PWM RTS_FP_PINMUX(SSI_M_CS, FUNC1) +#define P_SSI_M_CS_F_SSI_M_CS RTS_FP_PINMUX(SSI_M_CS, FUNC2) +#define P_SSI_M_CS_F_SSI_S_CS RTS_FP_PINMUX(SSI_M_CS, FUNC3) +#define P_SSI_M_CS_F_UART1_RTS RTS_FP_PINMUX(SSI_M_CS, FUNC4) +#define P_SSI_M_CS_F_ASIC_DBG RTS_FP_PINMUX(SSI_M_CS, FUNC5) + +#define P_SSI_M_SCK_F_GPIO RTS_FP_PINMUX(SSI_M_SCK, FUNC0) +#define P_SSI_M_SCK_F_PWM RTS_FP_PINMUX(SSI_M_SCK, FUNC1) +#define P_SSI_M_SCK_F_SSI_M_CLK RTS_FP_PINMUX(SSI_M_SCK, FUNC2) +#define P_SSI_M_SCK_F_SSI_S_CLK RTS_FP_PINMUX(SSI_M_SCK, FUNC3) +#define P_SSI_M_SCK_F_UART1_CTS RTS_FP_PINMUX(SSI_M_SCK, FUNC4) +#define P_SSI_M_SCK_F_ASIC_DBG RTS_FP_PINMUX(SSI_M_SCK, FUNC5) + +#define P_SCL0_F_GPIO RTS_FP_PINMUX(SCL0, FUNC0) +#define P_SCL0_F_PWM RTS_FP_PINMUX(SCL0, FUNC1) +#define P_SCL0_F_I2C0_SCL RTS_FP_PINMUX(SCL0, FUNC2) +#define P_SCL0_F_UART0_RX RTS_FP_PINMUX(SCL0, FUNC3) +#define P_SCL0_F_SWD_CLK RTS_FP_PINMUX(SCL0, FUNC4) +#define P_SCL0_F_ASIC_DBG RTS_FP_PINMUX(SCL0, FUNC5) + +#define P_SDA0_F_GPIO RTS_FP_PINMUX(SDA0, FUNC0) +#define P_SDA0_F_PWM RTS_FP_PINMUX(SDA0, FUNC1) +#define P_SDA0_F_I2C0_SDA RTS_FP_PINMUX(SDA0, FUNC2) +#define P_SDA0_F_UART0_TX RTS_FP_PINMUX(SDA0, FUNC3) +#define P_SDA0_F_SWD_DAT RTS_FP_PINMUX(SDA0, FUNC4) +#define P_SDA0_F_ASIC_DBG RTS_FP_PINMUX(SDA0, FUNC5) + +#define P_SCL2_F_GPIO RTS_FP_PINMUX(SCL2, FUNC0) +#define P_SCL2_F_PWM RTS_FP_PINMUX(SCL2, FUNC1) +#define P_SCL2_F_I2C2_SCL RTS_FP_PINMUX(SCL2, FUNC2) +#define P_SCL2_F_UART0_RX RTS_FP_PINMUX(SCL2, FUNC3) +#define P_SCL2_F_SWD_CLK RTS_FP_PINMUX(SCL2, FUNC4) +#define P_SCL2_F_ASIC_DBG RTS_FP_PINMUX(SCL2, FUNC5) + +#define P_SDA2_F_GPIO RTS_FP_PINMUX(SDA2, FUNC0) +#define P_SDA2_F_PWM RTS_FP_PINMUX(SDA2, FUNC1) +#define P_SDA2_F_I2C2_SDA RTS_FP_PINMUX(SDA2, FUNC2) +#define P_SDA2_F_UART0_TX RTS_FP_PINMUX(SDA2, FUNC3) +#define P_SDA2_F_SWD_DAT RTS_FP_PINMUX(SDA2, FUNC4) +#define P_SDA2_F_ASIC_DBG RTS_FP_PINMUX(SDA2, FUNC5) + +#define P_SCL1_F_GPIO RTS_FP_PINMUX(SCL1, FUNC0) +#define P_SCL1_F_PWM RTS_FP_PINMUX(SCL1, FUNC1) +#define P_SCL1_F_I2C1_SCL RTS_FP_PINMUX(SCL1, FUNC2) +#define P_SCL1_F_JTAG_TCK RTS_FP_PINMUX(SCL1, FUNC4) + +#define P_SDA1_F_GPIO RTS_FP_PINMUX(SDA1, FUNC0) +#define P_SDA1_F_PWM RTS_FP_PINMUX(SDA1, FUNC1) +#define P_SDA1_F_I2C1_SDA RTS_FP_PINMUX(SDA1, FUNC2) +#define P_SDA1_F_JTAG_TMS RTS_FP_PINMUX(SDA1, FUNC4) + +#define P_SSI_S_MISO_F_GPIO RTS_FP_PINMUX(SSI_S_MISO, FUNC0) +#define P_SSI_S_MISO_F_PWM RTS_FP_PINMUX(SSI_S_MISO, FUNC1) +#define P_SSI_S_MISO_F_SSI_S_MISO RTS_FP_PINMUX(SSI_S_MISO, FUNC2) +#define P_SSI_S_MISO_F_UART1_RX RTS_FP_PINMUX(SSI_S_MISO, FUNC3) +#define P_SSI_S_MISO_F_JTAG_TDI RTS_FP_PINMUX(SSI_S_MISO, FUNC4) + +#define P_SSI_S_MOSI_F_GPIO RTS_FP_PINMUX(SSI_S_MOSI, FUNC0) +#define P_SSI_S_MOSI_F_PWM RTS_FP_PINMUX(SSI_S_MOSI, FUNC1) +#define P_SSI_S_MOSI_F_SSI_S_MOSI RTS_FP_PINMUX(SSI_S_MOSI, FUNC2) +#define P_SSI_S_MOSI_F_UART1_TX RTS_FP_PINMUX(SSI_S_MOSI, FUNC3) +#define P_SSI_S_MOSI_F_JTAG_TRST RTS_FP_PINMUX(SSI_S_MOSI, FUNC4) + +#define P_SSI_S_CS_F_GPIO RTS_FP_PINMUX(SSI_S_CS, FUNC0) +#define P_SSI_S_CS_F_PWM RTS_FP_PINMUX(SSI_S_CS, FUNC1) +#define P_SSI_S_CS_F_SSI_S_CS RTS_FP_PINMUX(SSI_S_CS, FUNC2) +#define P_SSI_S_CS_F_UART1_RTS RTS_FP_PINMUX(SSI_S_CS, FUNC3) +#define P_SSI_S_CS_F_JTAG_TDO RTS_FP_PINMUX(SSI_S_CS, FUNC4) + +#define P_SSI_S_SCK_F_GPIO RTS_FP_PINMUX(SSI_S_SCK, FUNC0) +#define P_SSI_S_SCK_F_PWM RTS_FP_PINMUX(SSI_S_SCK, FUNC1) +#define P_SSI_S_SCK_F_SSI_S_CLK RTS_FP_PINMUX(SSI_S_SCK, FUNC2) +#define P_SSI_S_SCK_F_UART1_CTS RTS_FP_PINMUX(SSI_S_SCK, FUNC3) + +#define P_GPIO14_F_GPIO RTS_FP_PINMUX(GPIO14, FUNC0) +#define P_GPIO14_F_PWM RTS_FP_PINMUX(GPIO14, FUNC1) +#define P_GPIO14_F_UART0_RX RTS_FP_PINMUX(GPIO14, FUNC2) + +#define P_GPIO15_F_GPIO RTS_FP_PINMUX(GPIO15, FUNC0) +#define P_GPIO15_F_PWM RTS_FP_PINMUX(GPIO15, FUNC1) +#define P_GPIO15_F_UART0_TX RTS_FP_PINMUX(GPIO15, FUNC2) + +#define P_AL0_F_GPIO RTS_FP_PINMUX(AL0, FUNC0) +#define P_AL0_F_PWM RTS_FP_PINMUX(AL0, FUNC1) +#define P_AL0_F_CS_BRIDGE RTS_FP_PINMUX(AL0, FUNC2) + +#define P_AL1_F_GPIO RTS_FP_PINMUX(AL1, FUNC0) +#define P_AL1_F_PWM RTS_FP_PINMUX(AL1, FUNC1) + +#define P_AL2_F_GPIO RTS_FP_PINMUX(AL2, FUNC0) +#define P_AL2_F_PWM RTS_FP_PINMUX(AL2, FUNC1) + +#define P_SNR_RST_F_SNR_RST RTS_FP_PINMUX(SNR_RST, FUNC0) + +#define P_SNR_CS_F_SNR_CS RTS_FP_PINMUX(SNR_CS, FUNC0) +#define P_SNR_CS_F_GPIO RTS_FP_PINMUX(SNR_CS, FUNC1) + +#define P_SNR_GPIO_F_GPIO RTS_FP_PINMUX(SNR_GPIO, FUNC0) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RTS5817_PINCTRL_H_ */ diff --git a/include/zephyr/dt-bindings/reset/rts5817_reset.h b/include/zephyr/dt-bindings/reset/rts5817_reset.h new file mode 100644 index 0000000000000..1a889f578cdab --- /dev/null +++ b/include/zephyr/dt-bindings/reset/rts5817_reset.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_RTS5817_RESET_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_RTS5817_RESET_H_ + +#define SYS_FORCE_RST_BUS 0 +#define SYS_FORCE_RST_AES 1 +#define SYS_FORCE_RST_GE 2 +#define SYS_FORCE_RST_SHA 3 +#define SYS_FORCE_RST_SPI_CACHE 4 +#define SYS_FORCE_RST_SPI_SSOR 5 +#define SYS_FORCE_RST_SPI_SSI_M 6 +#define SYS_FORCE_RST_SPI_SSI_S 7 +#define SYS_FORCE_RST_PKE 8 +#define SYS_FORCE_RST_I2C 9 +#define SYS_FORCE_RST_I2C0 10 +#define SYS_FORCE_RST_I2C1 11 +#define SYS_FORCE_RST_TRNG 12 +#define SYS_FORCE_RST_I2C_S 13 +#define SYS_FORCE_RST_UART0 14 +#define SYS_FORCE_RST_UART1 15 +#define SYS_FORCE_RST_PUF 16 +#define SYS_FORCE_RST_USB2 17 +#define SYS_FORCE_RST_CK30M 18 +#define SYS_FORCE_RST_CK60M 19 +#define SYS_FORCE_RST_CK120M 20 +#define SYS_FORCE_RST_USB2_PHY 21 +#define SYS_FORCE_RST_SYS 22 +#define SYS_FORCE_RST_DPHY 23 +#define SYS_FORCE_RST_SSI_S_BUS 24 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_RESET_RTS5817_RESET_H_ */ From 7716ff0af83811837f2334b033419d320b0a6304 Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Fri, 6 Sep 2024 10:25:41 +0800 Subject: [PATCH 03/11] dts: arm: add dtsi for RTS5817 Add Device Tree include files for RTS5817. Signed-off-by: Darcy Lu --- .../realtek/fingerprint/rts5817/rts5817.dtsi | 17 +++++++ .../fingerprint/rts5817/rts5817_base.dtsi | 47 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 dts/arm/realtek/fingerprint/rts5817/rts5817.dtsi create mode 100644 dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi diff --git a/dts/arm/realtek/fingerprint/rts5817/rts5817.dtsi b/dts/arm/realtek/fingerprint/rts5817/rts5817.dtsi new file mode 100644 index 0000000000000..d8a23002cae72 --- /dev/null +++ b/dts/arm/realtek/fingerprint/rts5817/rts5817.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + chosen { + zephyr,flash = &flash0; + }; + + flash0: memory@1800000 { + compatible = "soc-nv-flash"; + reg = <0x1800000 DT_SIZE_K(256)>; + }; +}; diff --git a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi new file mode 100644 index 0000000000000..42e72122891ba --- /dev/null +++ b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +/ { + chosen { + zephyr,sram = &sram0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m33"; + reg = <0>; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <1>; + }; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(256)>; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; From be0faafd1357a9add9f124da409fb052c6341e1e Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Fri, 13 Sep 2024 14:55:48 +0800 Subject: [PATCH 04/11] soc: realtek: Add image generate tool for RTS5817 Add tool to genarate images of RTS5817 after post build stage Signed-off-by: Darcy Lu --- soc/realtek/fingerprint/CMakeLists.txt | 1 + soc/realtek/fingerprint/common/CMakeLists.txt | 20 +++ .../common/tool/gen_download_bin.py | 164 ++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 soc/realtek/fingerprint/common/CMakeLists.txt create mode 100755 soc/realtek/fingerprint/common/tool/gen_download_bin.py diff --git a/soc/realtek/fingerprint/CMakeLists.txt b/soc/realtek/fingerprint/CMakeLists.txt index 9ece0a95d678e..9c70da2e9689c 100644 --- a/soc/realtek/fingerprint/CMakeLists.txt +++ b/soc/realtek/fingerprint/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright (c) 2024 Realtek Semiconductor, Inc. # SPDX-License-Identifier: Apache-2.0 +add_subdirectory(common) add_subdirectory(${SOC_SERIES}) diff --git a/soc/realtek/fingerprint/common/CMakeLists.txt b/soc/realtek/fingerprint/common/CMakeLists.txt new file mode 100644 index 0000000000000..5a2c49a163e4e --- /dev/null +++ b/soc/realtek/fingerprint/common/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +set(RTS_BIN_NAME ${CONFIG_KERNEL_BIN_NAME}.rts5817.bin) +string(TOUPPER "${SOC_NAME}" soc_name_upper) + +if(APPVERSION) + set(version ${APPVERSION}) +else() + set(version 0) +endif() + +set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND ${PYTHON_EXECUTABLE} ${SOC_${soc_name_upper}_DIR}/common/tool/gen_download_bin.py + -i ${KERNEL_BIN_NAME} + -o ${RTS_BIN_NAME} + -v ${version} +) diff --git a/soc/realtek/fingerprint/common/tool/gen_download_bin.py b/soc/realtek/fingerprint/common/tool/gen_download_bin.py new file mode 100755 index 0000000000000..e7e6dc8fa015f --- /dev/null +++ b/soc/realtek/fingerprint/common/tool/gen_download_bin.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import hashlib +import pathlib +import sys + +PATCH_FLAG = 0x3 +PATCH_FLAG_OFFSET = 0x0 +PATCH_FLAG_LEN = 0x4 +PATCH_IMG_SIZE_OFFSET = 0x4 +PATCH_IMG_SIZE_LEN = 0x2 + +PATCH_CONFIG_LEN = 0x50 +PATCH_RESERVED_LEN = 0xF70 +PATCH_SHA_LEN = 0x20 +PATCH_PADDING_LEN = 0x20 + +IMG_HEADER_FLAG = 0x2 +IMG_HEADER_FLAG_OFFSET = 0x0 +IMG_HEADER_FLAG_LEN = 0x4 +IMG_HEADER_VER_OFFSET = 0x4 +IMG_HEADER_VER_LEN = 0x4 +IMG_HEADER_RESERVED_LEN = 0xF8 + +IMG_SIZE_UNIT = 0x1000 +IMG_SHA_LEN = 0x20 +IMG_REAR_PADDING_LEN = 0x60 + + +def create_parser(arg_list): + """create argument parser according to pre-defined arguments + + :param arg_list: when empty, parses command line arguments, + else parses the given string + """ + parser = argparse.ArgumentParser(conflict_handler='resolve', allow_abbrev=False) + parser.add_argument("--input", "-i", nargs='?', dest="input") + parser.add_argument("--output", "-o", nargs='?', dest="output") + parser.add_argument("--version", "-v", type=lambda x: int(x, 16), dest="version") + + args = parser.parse_known_args(arg_list.split()) + + if arg_list == "": + args = parser.parse_known_args() + + return args + + +def file_check(input, output=None): + """check input and output files + If the input file is not exists or empty, raise error + + :param input: the input file object + :param output: the output file object + """ + if not input.exists(): + raise RuntimeError(f'Input file ({input}) is not exists') + elif input.stat().st_size == 0: + raise RuntimeError(f'Input file ({input}) is empty') + + if output is None: + output = ['out_', input] + + if output.exists(): + if output.samefile(input): + raise RuntimeError(f'Input file {input} should be different from Output file {output}') + output.unlink() + + output.touch() + return output + + +def gen_rompatch(img_len): + """generate rom patch for image + + :param img_len: the length of image + """ + patch_config = bytearray([0x0] * PATCH_CONFIG_LEN) + patch_config[PATCH_FLAG_OFFSET] = PATCH_FLAG + patch_config[PATCH_IMG_SIZE_OFFSET] = img_len + patch_reserved = bytearray([0xFF] * PATCH_RESERVED_LEN) + patch = patch_config + patch_reserved + patch_sha = hashlib.sha256(patch).digest() + patch += patch_sha + patch_padding = bytearray([0xFF] * PATCH_PADDING_LEN) + patch += patch_padding + return patch + + +def gen_img_header(img_version=0): + """generate rom patch for image + + :param img_version: the version of image + """ + img_header = IMG_HEADER_FLAG.to_bytes(IMG_HEADER_FLAG_LEN, "little") + img_header += img_version.to_bytes(IMG_HEADER_VER_LEN, "little") + img_header += bytearray([0xFF] * IMG_HEADER_RESERVED_LEN) + return img_header + + +def img_padding(img): + size = len(img) // IMG_SIZE_UNIT + rear = len(img) % IMG_SIZE_UNIT + + if rear <= IMG_SIZE_UNIT - IMG_SHA_LEN - IMG_REAR_PADDING_LEN: + size += 1 + padding_len = IMG_SIZE_UNIT - rear - IMG_SHA_LEN - IMG_REAR_PADDING_LEN + else: + size += 2 + padding_len = 2 * IMG_SIZE_UNIT - rear - IMG_SHA_LEN - IMG_REAR_PADDING_LEN + + img_with_padding = img + bytes([0xFF] * padding_len) + return size, img_with_padding + + +def main(): + """main of the application""" + + if len(sys.argv) < 3: + sys.exit() + + input_file = None + output_file = None + fw_version = 0x0 + + # parser input arguments + arguments = create_parser("") + for arg in vars(arguments[0]): + if (arg == "input") & (arguments[0].input is not None): + input_file = arguments[0].input + elif (arg == "output") & (arguments[0].output is not None): + output_file = arguments[0].output + elif (arg == "version") & (arguments[0].version is not None): + fw_version = arguments[0].version + + # check file + output_file = file_check(pathlib.Path(input_file), pathlib.Path(output_file)) + + # generate image header + header = gen_img_header(fw_version) + + with open(input_file, 'rb') as origin_img_file: + # start handling + origin_img = origin_img_file.read() + img_with_header = header + origin_img + img_size, img_with_padding = img_padding(img_with_header) + img_sha = hashlib.sha256(img_with_padding).digest() + img_with_sha = img_with_padding + img_sha + rompatch = gen_rompatch(img_size) + final_img = rompatch + img_with_sha + bytes([0xFF] * IMG_REAR_PADDING_LEN) + origin_img_file.close() + + with open(output_file, 'wb') as new_fw: + new_fw.write(final_img) + new_fw.close() + + +if __name__ == '__main__': + main() From 5a613ec9f61e49abb27b1a15a3a5df424a155164 Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Fri, 13 Sep 2024 14:57:12 +0800 Subject: [PATCH 05/11] script: Add flash runner for rts5817 Add flash runner script to support west flash for rts5817 Signed-off-by: Darcy Lu --- scripts/west_commands/runners/__init__.py | 1 + scripts/west_commands/runners/rtsflash.py | 174 ++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 scripts/west_commands/runners/rtsflash.py diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index fc318e3d6cc7e..5e81a8ed1b203 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -56,6 +56,7 @@ def _import_runner_module(runner_name): 'renode', 'renode-robot', 'rfp', + 'rtsflash', 'silabs_commander', 'spi_burn', 'spsdk', diff --git a/scripts/west_commands/runners/rtsflash.py b/scripts/west_commands/runners/rtsflash.py new file mode 100644 index 0000000000000..784a615fc40cc --- /dev/null +++ b/scripts/west_commands/runners/rtsflash.py @@ -0,0 +1,174 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Runner for flashing with rtsflash.""" + +import subprocess +import sys +import time + +import usb.core +import usb.util + +from runners.core import RunnerCaps, ZephyrBinaryRunner + +RTS_STANDARD_REQUEST = 0x0 + +RTS_STD_GET_STATUS = 0x1A +RTS_STD_SET_STATUS = 0x1B + +RTS_STD_DOWNLOAD_ENABLE = 0x1 +RTS_STD_DOWNLOAD_DISABLE = 0x1 + +RTS_VENDOR_REQUEST = 0x40 +RTS_VREQ_XMEM_WRITE = 0x40 +RTS_VREQ_XMEM_READ = 0x41 +RTS_VREQ_SF_ERASE_SECTOR = 0x33 + +RTS_SET_FW_VERSION = 0x01 +RTS_DOWNLOAD_IMAGE = 0x03 +RTS_RESET_APP = 0x06 +RTS_GET_UPDATE_RESULT = 0x07 +RTS_RESET_IAP = 0x08 + + +class RtsUsb: + def __init__(self, device=None): + if not device: + idvendor = 0x0BDA + idproduct = 0x5817 + else: + idvendor = int(device.split(':', 1)[0], 16) + idproduct = int(device.split(':', 1)[1], 16) + dev = usb.core.find(idVendor=idvendor, idProduct=idproduct) + if not dev: + raise RuntimeError("device not found") + self.dev = dev + self.mode = "" + self.get_mode() + + def __del__(self): + usb.util.dispose_resources(self.dev) + + def enable_download(self): + if self.mode == "ROM": + status = self.dev.ctrl_transfer( + RTS_STANDARD_REQUEST | 0x80, RTS_STD_GET_STATUS, 0, 0, 1 + ) + if int.from_bytes(status, byteorder="little") == 0: + self.dev.ctrl_transfer(RTS_STANDARD_REQUEST, RTS_STD_SET_STATUS, 1, 0, 0) + + def xmem_write(self, addr, data): + setup_value = addr & 0xFFFF + setup_index = (addr >> 16) & 0xFFFF + self.dev.ctrl_transfer( + RTS_VENDOR_REQUEST, RTS_VREQ_XMEM_WRITE, setup_value, setup_index, data + ) + + def xmem_read(self, addr): + setup_value = addr & 0xFFFF + setup_index = (addr >> 16) & 0xFFFF + ret = self.dev.ctrl_transfer( + RTS_VENDOR_REQUEST | 0x80, RTS_VREQ_XMEM_READ, setup_value, setup_index, 4 + ) + return int.from_bytes(ret, byteorder="little") + + def get_mode(self): + init_vector = self.xmem_read(0x401E2090) + if init_vector == 0: + self.mode = "ROM" + elif init_vector == 0x01800000: + self.mode = "IAP" + else: + raise ValueError("Unknown work mode") + + +class RtsflashBinaryRunner(ZephyrBinaryRunner): + """Runner front-end for rtsflash.""" + + def __init__(self, cfg, dev_id, alt, img, exe='dfu-util'): + super().__init__(cfg) + self.dev_id = dev_id + self.alt = alt + self.img = img + self.cmd = [exe, f'-d {dev_id}'] + try: + self.list_pattern = f', alt={int(self.alt)},' + except ValueError: + self.list_pattern = f', name="{self.alt}",' + self.reset = False + + @classmethod + def name(cls): + return "rtsflash" + + @classmethod + def capabilities(cls): + return RunnerCaps(commands={"flash"}, dev_id=True) + + @classmethod + def dev_id_help(cls) -> str: + return 'USB VID:PID of the connected device.' + + @classmethod + def do_add_parser(cls, parser): + parser.add_argument( + "--alt", required=True, help="interface alternate setting number or name" + ) + parser.add_argument("--pid", dest='dev_id', help=cls.dev_id_help()) + parser.add_argument("--img", help="binary to flash, default is --bin-file") + parser.add_argument( + '--dfu-util', default='dfu-util', help='dfu-util executable; defaults to "dfu-util"' + ) + + @classmethod + def do_create(cls, cfg, args): + if args.img is None: + args.img = cfg.bin_file + + ret = RtsflashBinaryRunner(cfg, args.dev_id, args.alt, args.img, exe=args.dfu_util) + + ret.ensure_device() + return ret + + def ensure_device(self): + if not self.find_device(): + self.reset = True + print('Please reset your board to switch to DFU mode...') + while not self.find_device(): + time.sleep(0.1) + + def find_device(self): + cmd = list(self.cmd) + ['-l'] + output = self.check_output(cmd) + output = output.decode(sys.getdefaultencoding()) + return self.list_pattern in output + + def do_run(self, command, **kwargs): + if not self.dev_id: + raise RuntimeError( + 'Please specify a USB VID:PID with the -i/--dev-id or --pid command-line switch.' + ) + + self.require(self.cmd[0]) + self.ensure_output('bin') + + if not self.find_device(): + raise RuntimeError('device not found') + + fpusb = RtsUsb(self.dev_id) + + fpusb.enable_download() + + try: + self.check_call(['dfu-suffix', '-c', self.img]) + except subprocess.CalledProcessError: + self.call(['dfu-suffix', '-a', self.img]) + + cmd = list(self.cmd) + cmd.extend(['-a', self.alt, '-D', self.img]) + self.check_call(cmd) + + if self.reset: + print('Now reset your board again to switch back to runtime mode.') From f456c1516eeab86defdbeeac4ce3b7dc7e205bb2 Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Mon, 4 Nov 2024 17:35:49 +0800 Subject: [PATCH 06/11] drivers: clock_control: add clock control for RTS5817 Add clock control driver for RTS5817 Signed-off-by: Darcy Lu --- drivers/clock_control/CMakeLists.txt | 2 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.rts5817 | 9 + drivers/clock_control/clock_control_rts5817.c | 1013 +++++++++++++++++ .../clock_control_rts5817_control.h | 503 ++++++++ .../clock_control_rts5817_gpll.h | 134 +++ .../fingerprint/rts5817/rts5817_base.dtsi | 9 + dts/bindings/clock/realtek,rts5817-clock.yaml | 18 + 8 files changed, 1690 insertions(+) create mode 100644 drivers/clock_control/Kconfig.rts5817 create mode 100644 drivers/clock_control/clock_control_rts5817.c create mode 100644 drivers/clock_control/clock_control_rts5817_control.h create mode 100644 drivers/clock_control/clock_control_rts5817_gpll.h create mode 100644 dts/bindings/clock/realtek,rts5817-clock.yaml diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 18b6025df6c7c..d063bb763fc76 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -122,3 +122,5 @@ endif() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MAX32 clock_control_max32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_WCH_RCC clock_control_wch_rcc.c) + +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RTS5817 clock_control_rts5817.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 05a2a7fb8fa67..9944444b175e2 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -114,4 +114,6 @@ source "drivers/clock_control/Kconfig.wch_rcc" source "drivers/clock_control/Kconfig.it51xxx" +source "drivers/clock_control/Kconfig.rts5817" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.rts5817 b/drivers/clock_control/Kconfig.rts5817 new file mode 100644 index 0000000000000..cc00f71094456 --- /dev/null +++ b/drivers/clock_control/Kconfig.rts5817 @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_RTS5817 + bool "RTS5817 clock control" + depends on DT_HAS_REALTEK_RTS5817_CLOCK_ENABLED + default y + help + Enable driver for RTS5817 Clock Control. diff --git a/drivers/clock_control/clock_control_rts5817.c b/drivers/clock_control/clock_control_rts5817.c new file mode 100644 index 0000000000000..d7b446ba02f23 --- /dev/null +++ b/drivers/clock_control/clock_control_rts5817.c @@ -0,0 +1,1013 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "zephyr/arch/common/sys_io.h" +#include "zephyr/device.h" +#include +#include +#include "clock_control_rts5817_control.h" +#include "clock_control_rts5817_gpll.h" + +#define DT_DRV_COMPAT realtek_rts5817_clock + +struct rts_fp_clock_data { + uint32_t syspll_frequency; + struct k_spinlock lock; +}; + +struct rts_fp_clock_config { + mem_addr_t base; + mem_addr_t syspll_base; + mem_addr_t sck_div_base; +}; + +struct clk_rlx { + uint16_t id; + const struct rlx_clk_ops *ops; + uint16_t clkreg; + uint16_t clk_change; +}; + +struct rlx_clk_ops { + int (*enable)(const struct device *dev, const struct clk_rlx *clk); + int (*disable)(const struct device *dev, const struct clk_rlx *clk); + enum clock_control_status (*get_status)(const struct device *dev, + const struct clk_rlx *clk); + uint32_t (*get_rate)(const struct device *dev, const struct clk_rlx *clk); + int (*set_rate)(const struct device *dev, const struct clk_rlx *clk, uint32_t rate); +}; + +static uint8_t m_div_array[] = {1, 2, 4, 6, 8, 10, 12, 14}; + +#define DEFINE_CLK_RLX(_name, _id, _ops, _clk_reg, _clk_change) \ + static const struct clk_rlx _name = { \ + .id = _id, \ + .ops = &_ops, \ + .clkreg = _clk_reg, \ + .clk_change = _clk_change, \ + } +#define CK_CHANGE_NULL 0 + +static inline uint32_t rts_fp_clk_read_reg(const struct device *dev, uint32_t offset) +{ + const struct rts_fp_clock_config *config = dev->config; + + return sys_read32(config->base + offset); +} + +static inline void rts_fp_clk_write_reg(const struct device *dev, uint32_t data, uint32_t offset) +{ + const struct rts_fp_clock_config *config = dev->config; + + sys_write32(data, config->base + offset); +} + +static inline uint32_t rts_fp_read_sck_div_reg(const struct device *dev) +{ + const struct rts_fp_clock_config *config = dev->config; + + return sys_read32(config->sck_div_base); +} + +static inline void rts_fp_write_sck_div_reg(const struct device *dev, uint32_t data) +{ + const struct rts_fp_clock_config *config = dev->config; + + sys_write32(data, config->sck_div_base); +} + +static void set_change_bit(const struct device *dev, uint32_t clk_change) +{ + const struct rts_fp_clock_config *config = dev->config; + + sys_set_bit(config->base + R_SYS_CLK_CHANGE, clk_change); +} + +static void clear_change_bit(const struct device *dev, uint32_t clk_change) +{ + const struct rts_fp_clock_config *config = dev->config; + + sys_clear_bit(config->base + R_SYS_CLK_CHANGE, clk_change); +} + +static int rlx_enable_syspll(const struct device *dev, const struct clk_rlx *clk) +{ + const struct rts_fp_clock_config *config = dev->config; + uint32_t timeout = 1000; + + sys_set_bits(config->syspll_base + R_SYSPLL_CTL, POW_SYSPLL); + k_busy_wait(20); + + sys_set_bits(config->syspll_base + R_SYSPLL_CTL, PLL_LOAD_EN); + k_busy_wait(10); + + sys_clear_bits(config->syspll_base + R_SYSPLL_CTL, PLL_LOAD_EN); + k_busy_wait(70); + + while (!(sys_read32(config->syspll_base + R_SYSPLL_STS) & PLL_CKUSABLE) && timeout--) { + k_busy_wait(10); + } + k_busy_wait(70); + if (timeout) { + return 0; + } else { + return -ETIMEDOUT; + } +} + +static int rlx_disable_syspll(const struct device *dev, const struct clk_rlx *clk) +{ + const struct rts_fp_clock_config *config = dev->config; + + sys_clear_bits(config->syspll_base + R_SYSPLL_CTL, POW_SYSPLL); + k_busy_wait(10); + + return 0; +} + +static enum clock_control_status rlx_syspll_status(const struct device *dev, + const struct clk_rlx *clk) +{ + const struct rts_fp_clock_config *config = dev->config; + + if (sys_read32(config->syspll_base + R_SYSPLL_STS) & PLL_CKUSABLE) { + return CLOCK_CONTROL_STATUS_ON; + } + return CLOCK_CONTROL_STATUS_OFF; +} + +static uint32_t rlx_syspll_get_rate(const struct device *dev, const struct clk_rlx *clk) +{ + ARG_UNUSED(clk); + const struct rts_fp_clock_config *config = dev->config; + struct rts_fp_clock_data *clk_data = dev->data; + uint32_t ssc_n, ssc_f; + uint32_t reg; + + reg = sys_read32(config->syspll_base + R_SYSPLL_NF_CODE); + ssc_n = reg & N_SSC_MASK; + ssc_f = reg & F_SSC_MASK; + clk_data->syspll_frequency = 4000000 * (ssc_n + 2 + ssc_f / 4096); /* Hz */ + + return clk_data->syspll_frequency; +} + +static int rlx_syspll_set_rate(const struct device *dev, const struct clk_rlx *clk, uint32_t rate) +{ + const struct rts_fp_clock_config *config = dev->config; + struct rts_fp_clock_data *clk_data = dev->data; + uint32_t ssc_n, ssc_f; + uint32_t reg; + + clk_data->syspll_frequency = rate; + ssc_n = (rate / 4000000) - 2; + ssc_f = 4096 * (rate % 4000000) / 4000000; + + /* PLL_REG_CCO_SEL=1: use CCO; PLL_REG_CCO_SEL=0: use VCO */ + sys_clear_bits(config->syspll_base + R_SYSPLL_CFG, PLL_REG_CCO_SEL); + if (ssc_f) { + sys_clear_bits(config->syspll_base + R_SYSPLL_CFG, PLL_REG_PI_SEL); + sys_clear_bits(config->syspll_base + R_SYSPLL_CFG, PLL_BYPASS_PI); + } else { + sys_set_bits(config->syspll_base + R_SYSPLL_CFG, PLL_REG_PI_SEL); + sys_set_bits(config->syspll_base + R_SYSPLL_CFG, PLL_BYPASS_PI); + } + sys_set_bits(config->syspll_base + R_SYSPLL_CFG, REG_SC_H); + reg = sys_read32(config->syspll_base + R_SYSPLL_NF_CODE); + reg = (reg & ~(F_SSC | N_SSC)) | (ssc_n << N_SSC_OFFSET) | (ssc_f << F_SSC_OFFSET); + sys_write32(reg, config->syspll_base + R_SYSPLL_NF_CODE); + + return 0; +} + +static const struct rlx_clk_ops rlx_clk_syspll_ops = { + .enable = rlx_enable_syspll, + .disable = rlx_disable_syspll, + .get_status = rlx_syspll_status, + .get_rate = rlx_syspll_get_rate, + .set_rate = rlx_syspll_set_rate, +}; + +static int rlx_enable_clk(const struct device *dev, const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t en_mask; + + if (clk->id == RTS_FP_CLK_GE) { + en_mask = (1 << GE_CLK_EN_OFFSET); + } else { + en_mask = (1 << 24); + } + + if (!(reg & en_mask)) { + rts_fp_clk_write_reg(dev, (reg | en_mask), clk->clkreg); + } + return 0; +} + +static int rlx_disable_clk(const struct device *dev, const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t en_mask; + + if (clk->id == RTS_FP_CLK_GE) { + en_mask = (1 << GE_CLK_EN_OFFSET); + } else { + en_mask = (1 << 24); + } + + if (reg & en_mask) { + rts_fp_clk_write_reg(dev, (reg & ~en_mask), clk->clkreg); + } + return 0; +} + +static enum clock_control_status rlx_get_status(const struct device *dev, const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t en_mask; + + if (clk->id == RTS_FP_CLK_GE) { + en_mask = (1 << GE_CLK_EN_OFFSET); + } else { + en_mask = (1 << 24); + } + + if (reg & en_mask) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } +} + +static uint32_t rlx_common_get_rate(const struct device *dev, const struct clk_rlx *clk) +{ + struct rts_fp_clock_data *clk_data = dev->data; + uint32_t src[] = {240000000, 160000000, 96000000, clk_data->syspll_frequency}; + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t divider, idx; + uint32_t rate; + + idx = reg & 0x3; + divider = (reg >> 2) & 0x7; + rate = src[idx] / m_div_array[divider]; + + return rate; +} + +static void __aligned(32) __noinline change_bus_clk_sub(const struct device *dev, + const struct clk_rlx *clk, uint32_t data) +{ + rts_fp_write_sck_div_reg(dev, 0x02); + set_change_bit(dev, clk->clk_change); + /* Assign writing R_SYS_BUS_CLK_CFG_REG to the next cache line */ + /* to ensure that it takes effect after reading the previous cacheline done */ + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + rts_fp_clk_write_reg(dev, data, clk->clkreg); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + clear_change_bit(dev, clk->clk_change); +} + +static void __aligned(32) __noinline change_cache_spi_clk_sub(const struct device *dev, + const struct clk_rlx *clk, + uint32_t data) +{ + set_change_bit(dev, clk->clk_change); + /* Assign writing R_SYS_SPI_CACHE_CLK_CFG_REG to the next cache line */ + /* to ensure that it takes effect after reading the previous cacheline done */ + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + rts_fp_clk_write_reg(dev, data, clk->clkreg); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + clear_change_bit(dev, clk->clk_change); +} + +static int rlx_common_set_rate(const struct device *dev, const struct clk_rlx *clk, uint32_t rate) +{ + struct rts_fp_clock_data *data = dev->data; + uint32_t divider, idx; + uint32_t reg; + k_spinlock_key_t key; + + if (clk->ops->get_rate(dev, clk) == rate) { + return 0; + } + + reg = rts_fp_clk_read_reg(dev, clk->clkreg); + switch (rate) { + case 240000000: + idx = 0; + divider = 0; + break; + case 120000000: + idx = 0; + divider = 1; + break; + case 60000000: + idx = 0; + divider = 2; + break; + case 30000000: + idx = 0; + divider = 4; + break; + case 160000000: + idx = 1; + divider = 0; + break; + case 80000000: + idx = 1; + divider = 1; + break; + case 40000000: + idx = 1; + divider = 2; + break; + case 20000000: + idx = 1; + divider = 4; + break; + case 96000000: + idx = 2; + divider = 0; + break; + case 48000000: + idx = 2; + divider = 1; + break; + case 24000000: + idx = 2; + divider = 2; + break; + case 16000000: + idx = 2; + divider = 3; + break; + default: + return -EINVAL; + } + + reg = (reg & ~0x3f) | idx | (divider << 2); + + if (clk->id == RTS_FP_CLK_BUS) { + uint8_t sck_div = rts_fp_read_sck_div_reg(dev); + + key = k_spin_lock(&data->lock); + change_bus_clk_sub(dev, clk, reg); + k_spin_unlock(&data->lock, key); + rts_fp_write_sck_div_reg(dev, sck_div); + } else if (clk->id == RTS_FP_CLK_SPI_CACHE) { + key = k_spin_lock(&data->lock); + change_cache_spi_clk_sub(dev, clk, reg); + k_spin_unlock(&data->lock, key); + } else { + key = k_spin_lock(&data->lock); + set_change_bit(dev, clk->clk_change); + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + clear_change_bit(dev, clk->clk_change); + + k_spin_unlock(&data->lock, key); + } + + return 0; +} + +static const struct rlx_clk_ops rlx_clk_bus_ops = { + .get_rate = rlx_common_get_rate, + .set_rate = rlx_common_set_rate, +}; + +static const struct rlx_clk_ops rlx_clk_common_ops = { + .enable = rlx_enable_clk, + .disable = rlx_disable_clk, + .get_status = rlx_get_status, + .get_rate = rlx_common_get_rate, + .set_rate = rlx_common_set_rate, +}; + +static uint32_t rlx_spi_get_rate(const struct device *dev, const struct clk_rlx *clk) +{ + struct rts_fp_clock_data *clk_data = dev->data; + uint32_t src[] = {240000000, 96000000, 80000000, clk_data->syspll_frequency}; + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t divider, idx; + uint32_t rate; + + idx = reg & 0x3; + divider = (reg >> 2) & 0x7; + rate = src[idx] / m_div_array[divider]; + + return rate; +} + +static int rlx_spi_set_rate(const struct device *dev, const struct clk_rlx *clk, uint32_t rate) +{ + struct rts_fp_clock_data *data = dev->data; + uint32_t divider, idx; + uint32_t reg; + k_spinlock_key_t key; + + if (clk->ops->get_rate(dev, clk) == rate) { + return 0; + } + + reg = rts_fp_clk_read_reg(dev, clk->clkreg); + switch (rate) { + case 240000000: + idx = 0; + divider = 0; + break; + case 120000000: + idx = 0; + divider = 1; + break; + case 60000000: + idx = 0; + divider = 2; + break; + case 30000000: + idx = 0; + divider = 4; + break; + case 80000000: + idx = 2; + divider = 0; + break; + case 40000000: + idx = 2; + divider = 1; + break; + case 20000000: + idx = 2; + divider = 2; + break; + case 96000000: + idx = 1; + divider = 0; + break; + case 48000000: + idx = 1; + divider = 1; + break; + case 24000000: + idx = 1; + divider = 2; + break; + case 16000000: + idx = 1; + divider = 3; + break; + default: + return -EINVAL; + } + + reg = (reg & ~0x3f) | idx | (divider << 2); + + key = k_spin_lock(&data->lock); + set_change_bit(dev, clk->clk_change); + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + clear_change_bit(dev, clk->clk_change); + + k_spin_unlock(&data->lock, key); + + return 0; +} + +static const struct rlx_clk_ops rlx_clk_spi_ops = { + .enable = rlx_enable_clk, + .disable = rlx_disable_clk, + .get_status = rlx_get_status, + .get_rate = rlx_spi_get_rate, + .set_rate = rlx_spi_set_rate, +}; + +static uint32_t rlx_uart_get_rate(const struct device *dev, const struct clk_rlx *clk) +{ + struct rts_fp_clock_data *clk_data = dev->data; + uint32_t src[] = {96000000, 120000000, 0, clk_data->syspll_frequency}; + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t divider, idx; + uint32_t rate; + + idx = reg & 0x3; + divider = (reg >> 2) & 0x7; + rate = src[idx] / m_div_array[divider]; + + return rate; +} + +static int rlx_uart_set_rate(const struct device *dev, const struct clk_rlx *clk, uint32_t rate) +{ + struct rts_fp_clock_data *data = dev->data; + uint32_t divider, idx; + uint32_t reg; + k_spinlock_key_t key; + + if (clk->ops->get_rate(dev, clk) == rate) { + return 0; + } + + reg = rts_fp_clk_read_reg(dev, clk->clkreg); + switch (rate) { + case 60000000: + idx = 1; + divider = 1; + break; + case 30000000: + idx = 1; + divider = 2; + break; + case 48000000: + idx = 0; + divider = 1; + break; + case 24000000: + idx = 0; + divider = 2; + break; + case 16000000: + idx = 0; + divider = 3; + break; + default: + return -EINVAL; + } + + reg = (reg & ~0x3f) | idx | (divider << 2); + key = k_spin_lock(&data->lock); + set_change_bit(dev, clk->clk_change); + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + clear_change_bit(dev, clk->clk_change); + + k_spin_unlock(&data->lock, key); + return 0; +} + +static const struct rlx_clk_ops rlx_clk_uart_ops = { + .enable = rlx_enable_clk, + .disable = rlx_disable_clk, + .get_status = rlx_get_status, + .get_rate = rlx_uart_get_rate, + .set_rate = rlx_uart_set_rate, +}; + +static uint32_t rlx_pke_get_rate(const struct device *dev, const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t src_clk_frq = 120000000; + uint32_t divider; + uint32_t rate; + + divider = (reg >> 2) & 0x7; + rate = src_clk_frq / m_div_array[divider]; + + return rate; +} + +static int rlx_pke_set_rate(const struct device *dev, const struct clk_rlx *clk, uint32_t rate) +{ + struct rts_fp_clock_data *data = dev->data; + uint32_t divider; + uint32_t reg; + k_spinlock_key_t key; + + if (clk->ops->get_rate(dev, clk) == rate) { + return 0; + } + + reg = rts_fp_clk_read_reg(dev, clk->clkreg); + switch (rate) { + case 120000000: + divider = 0; + break; + case 60000000: + divider = 1; + break; + case 30000000: + divider = 2; + break; + case 20000000: + divider = 3; + break; + default: + return -EINVAL; + } + + reg = (reg & ~0x1C) | (divider << 2); + key = k_spin_lock(&data->lock); + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + k_spin_unlock(&data->lock, key); + return 0; +} + +static const struct rlx_clk_ops rlx_clk_pke_ops = { + .enable = rlx_enable_clk, + .disable = rlx_disable_clk, + .get_status = rlx_get_status, + .get_rate = rlx_pke_get_rate, + .set_rate = rlx_pke_set_rate, +}; + +static int rlx_i2c_enable_clk(const struct device *dev, const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + + reg |= I2C_CLK_EN; + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + if (clk->id == RTS_FP_CLK_I2C0) { + reg |= I2C0_CLK_EN; + } else if (clk->id == RTS_FP_CLK_I2C1) { + reg |= I2C1_CLK_EN; + } else { + return -EINVAL; + } + + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + return 0; +} + +static int rlx_i2c_disable_clk(const struct device *dev, const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + + if (clk->id == RTS_FP_CLK_I2C0) { + reg &= ~I2C0_CLK_EN; + } else if (clk->id == RTS_FP_CLK_I2C1) { + reg &= ~I2C1_CLK_EN; + } else { + return -EINVAL; + } + + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + if (reg & (I2C0_CLK_EN | I2C1_CLK_EN)) { + return 0; + } + + reg &= ~I2C_CLK_EN; + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + + return 0; +} + +static enum clock_control_status rlx_i2c_get_status(const struct device *dev, + const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t en_mask; + + if (clk->id == RTS_FP_CLK_I2C0) { + en_mask = I2C0_CLK_EN; + } else if (clk->id == RTS_FP_CLK_I2C1) { + en_mask = I2C1_CLK_EN; + } else { + return -EINVAL; + } + + if (reg & en_mask) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } +} + +static uint32_t rlx_i2c_get_rate(const struct device *dev, const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t src_clk_frq = 240000000; + uint32_t divider; + uint32_t rate; + + divider = (reg >> 2) & 0x7; + rate = src_clk_frq / m_div_array[divider]; + + return rate; +} + +static int rlx_i2c_set_rate(const struct device *dev, const struct clk_rlx *clk, uint32_t rate) +{ + struct rts_fp_clock_data *data = dev->data; + uint32_t divider; + uint32_t reg; + k_spinlock_key_t key; + + if (clk->ops->get_rate(dev, clk) == rate) { + return 0; + } + + reg = rts_fp_clk_read_reg(dev, clk->clkreg); + switch (rate) { + case 240000000: + divider = 0; + break; + case 120000000: + divider = 1; + break; + case 60000000: + divider = 2; + break; + case 40000000: + divider = 3; + break; + default: + return -EINVAL; + } + + reg = (reg & ~0x1C) | (divider << 2); + key = k_spin_lock(&data->lock); + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + arch_nop(); + arch_nop(); + arch_nop(); + arch_nop(); + k_spin_unlock(&data->lock, key); + return 0; +} + +static const struct rlx_clk_ops rlx_clk_i2c_ops = { + .enable = rlx_i2c_enable_clk, + .disable = rlx_i2c_disable_clk, + .get_status = rlx_i2c_get_status, + .get_rate = rlx_i2c_get_rate, + .set_rate = rlx_i2c_set_rate, +}; + +static int rlx_ck60_enable_clk(const struct device *dev, const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + + if (clk->id == RTS_FP_CLK_TRNG) { + reg |= TRNG_CLK_EN; + } else if (clk->id == RTS_FP_CLK_I2C_S) { + reg |= I2C_S_CLK_EN; + } else { + return -EINVAL; + } + + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + return 0; +} + +static int rlx_ck60_disable_clk(const struct device *dev, const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + + if (clk->id == RTS_FP_CLK_TRNG) { + reg &= ~TRNG_CLK_EN; + } else if (clk->id == RTS_FP_CLK_I2C_S) { + reg &= ~I2C_S_CLK_EN; + } else { + return -EINVAL; + } + + rts_fp_clk_write_reg(dev, reg, clk->clkreg); + + return 0; +} + +static enum clock_control_status rlx_ck60_get_status(const struct device *dev, + const struct clk_rlx *clk) +{ + uint32_t reg = rts_fp_clk_read_reg(dev, clk->clkreg); + uint32_t en_mask; + + if (clk->id == RTS_FP_CLK_TRNG) { + en_mask = TRNG_CLK_EN_MASK; + } else if (clk->id == RTS_FP_CLK_I2C_S) { + en_mask = I2C_S_CLK_EN_MASK; + } else { + return -EINVAL; + } + + if (reg & en_mask) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } +} + +static const struct rlx_clk_ops rlx_clk_ck60_ops = { + .enable = rlx_ck60_enable_clk, + .disable = rlx_ck60_disable_clk, + .get_status = rlx_ck60_get_status, +}; + +static const struct rlx_clk_ops rlx_clk_gate_ops = { + .enable = rlx_enable_clk, + .disable = rlx_disable_clk, + .get_status = rlx_get_status, +}; + +DEFINE_CLK_RLX(syspll, RTS_FP_CLK_SYS_PLL, rlx_clk_syspll_ops, 0, 0); +DEFINE_CLK_RLX(bus_clk, RTS_FP_CLK_BUS, rlx_clk_bus_ops, R_SYS_BUS_CLK_CFG_REG, + CHANGE_BUS_CLK_PRE_OFFSET); +DEFINE_CLK_RLX(spi_cache_clk, RTS_FP_CLK_SPI_CACHE, rlx_clk_common_ops, R_SYS_SPI_CACHE_CLK_CFG_REG, + CHANGE_SPI_CACHE_CLK_OFFSET); +DEFINE_CLK_RLX(spi_ssor_clk, RTS_FP_CLK_SPI_SSOR, rlx_clk_spi_ops, R_SYS_SPI_SSOR_CLK_CFG_REG, + CHANGE_SPI_SSOR_CLK_OFFSET); +DEFINE_CLK_RLX(ssi_m_clk, RTS_FP_CLK_SPI_SSI_M, rlx_clk_spi_ops, R_SYS_SPI_SSI_M_CLK_CFG_REG, + CHANGE_SPI_SSI_M_CLK_OFFSET); +DEFINE_CLK_RLX(ssi_s_clk, RTS_FP_CLK_SPI_SSI_S, rlx_clk_spi_ops, R_SYS_SPI_SSI_S_CLK_CFG_REG, + CHANGE_SPI_SSI_S_CLK_OFFSET); +DEFINE_CLK_RLX(sha_clk, RTS_FP_CLK_SHA, rlx_clk_common_ops, R_SYS_SHA_CLK_CFG_REG, + CHANGE_SHA_CLK_OFFSET); +DEFINE_CLK_RLX(aes_clk, RTS_FP_CLK_AES, rlx_clk_common_ops, R_SYS_AES_CLK_CFG_REG, + CHANGE_AES_CLK_OFFSET); +DEFINE_CLK_RLX(pke_clk, RTS_FP_CLK_PKE, rlx_clk_pke_ops, R_SYS_PKE_CLK_CFG_REG, 0); +DEFINE_CLK_RLX(i2c0_clk, RTS_FP_CLK_I2C0, rlx_clk_i2c_ops, R_SYS_I2C_CLK_CFG_REG, 0); +DEFINE_CLK_RLX(i2c1_clk, RTS_FP_CLK_I2C1, rlx_clk_i2c_ops, R_SYS_I2C_CLK_CFG_REG, 0); +DEFINE_CLK_RLX(trng_clk, RTS_FP_CLK_TRNG, rlx_clk_ck60_ops, R_SYS_CK60_CFG_REG, 0); +DEFINE_CLK_RLX(i2c_s_clk, RTS_FP_CLK_I2C_S, rlx_clk_ck60_ops, R_SYS_CK60_CFG_REG, 0); +DEFINE_CLK_RLX(uart0_clk, RTS_FP_CLK_UART0, rlx_clk_uart_ops, R_SYS_UART0_CLK_CFG_REG, + CHANGE_UART0_CLK_OFFSET); +DEFINE_CLK_RLX(uart1_clk, RTS_FP_CLK_UART1, rlx_clk_uart_ops, R_SYS_UART1_CLK_CFG_REG, + CHANGE_UART1_CLK_OFFSET); +DEFINE_CLK_RLX(sie_clk, RTS_FP_CLK_SIE, rlx_clk_gate_ops, R_SYS_SIE_CLK_CFG_REG, 0); +DEFINE_CLK_RLX(puf_clk, RTS_FP_CLK_PUF, rlx_clk_gate_ops, R_SYS_PUF_CLK_CFG_REG, 0); +DEFINE_CLK_RLX(ge_clk, RTS_FP_CLK_GE, rlx_clk_gate_ops, R_SYS_BUS_CLK_CFG_REG, 0); + +static const struct clk_rlx *const m_clks[RLX_CLK_NUM_SIZE] = { + &syspll, &bus_clk, &spi_cache_clk, &spi_ssor_clk, &ssi_m_clk, &ssi_s_clk, + &sha_clk, &aes_clk, &pke_clk, &i2c0_clk, &i2c1_clk, &trng_clk, + &i2c_s_clk, &uart0_clk, &uart1_clk, &sie_clk, &puf_clk, &ge_clk, +}; +static int rts_fp_clk_on(const struct device *dev, clock_control_subsys_t sys) +{ + uint16_t clk_id = (uint32_t)sys; + const struct clk_rlx *clk; + + if (clk_id >= RLX_CLK_NUM_SIZE) { + return -EINVAL; + } + + clk = m_clks[clk_id]; + if (!clk->ops->enable) { + return -ENOSYS; + } + + return clk->ops->enable(dev, clk); +} + +static int rts_fp_clk_off(const struct device *dev, clock_control_subsys_t sys) +{ + uint16_t clk_id = (uint32_t)sys; + const struct clk_rlx *clk; + + if (clk_id >= RLX_CLK_NUM_SIZE) { + return -EINVAL; + } + + clk = m_clks[clk_id]; + if (!clk->ops->disable) { + return -ENOSYS; + } + + return clk->ops->disable(dev, clk); +} + +static enum clock_control_status rts_fp_clk_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + uint16_t clk_id = (uint32_t)sys; + const struct clk_rlx *clk; + + if (clk_id >= RLX_CLK_NUM_SIZE) { + return -EINVAL; + } + + clk = m_clks[clk_id]; + if (!clk->ops->get_status) { + return CLOCK_CONTROL_STATUS_UNKNOWN; + } + + return clk->ops->get_status(dev, clk); +} + +static int rts_fp_clk_get_rate(const struct device *dev, clock_control_subsys_t sys, uint32_t *rate) +{ + uint16_t clk_id = (uint32_t)sys; + const struct clk_rlx *clk; + + if (clk_id >= RLX_CLK_NUM_SIZE) { + return -EINVAL; + } + + clk = m_clks[clk_id]; + if (!clk->ops->get_rate) { + return -ENOSYS; + } + + *rate = clk->ops->get_rate(dev, clk); + return 0; +} + +static int rts_fp_clk_set_rate(const struct device *dev, clock_control_subsys_t sys, + clock_control_subsys_rate_t rate) +{ + uint16_t clk_id = (uint32_t)sys; + const struct clk_rlx *clk; + + if (clk_id >= RLX_CLK_NUM_SIZE) { + return -EINVAL; + } + + clk = m_clks[clk_id]; + if (!clk->ops->set_rate) { + return -ENOSYS; + } + + return clk->ops->set_rate(dev, clk, (uint32_t)rate); +} + +static const struct clock_control_driver_api rts_fp_clk_api = { + .on = rts_fp_clk_on, + .off = rts_fp_clk_off, + .get_status = rts_fp_clk_get_status, + .get_rate = rts_fp_clk_get_rate, + .set_rate = rts_fp_clk_set_rate, +}; + +/* HACK: enable uart clock for uart_ns16550.c driver */ +static void rts_fp_clk_enable_uart(const struct device *dev) +{ + /* set uart clock source to 120MHz */ + if (DT_NODE_HAS_STATUS(DT_INST(0, ns16550), okay)) { + rts_fp_clk_write_reg(dev, 1 | 1 << 24, R_SYS_UART0_CLK_CFG_REG); + } + + if (DT_NODE_HAS_STATUS(DT_INST(1, ns16550), okay)) { + rts_fp_clk_write_reg(dev, 1 | 1 << 24, R_SYS_UART1_CLK_CFG_REG); + } +} + +static int rts_fp_clk_init(const struct device *dev) +{ + struct rts_fp_clock_data *clk_data = dev->data; + + if (syspll.ops->get_status(dev, &syspll) == CLOCK_CONTROL_STATUS_ON) { + clk_data->syspll_frequency = syspll.ops->get_rate(dev, &syspll); + } + + /* HACK: enable uart clock for uart_ns16550.c driver */ + rts_fp_clk_enable_uart(dev); + + /* set bus rate according to clock-frequency in cpu node */ + clock_control_subsys_t sys = (clock_control_subsys_t)RTS_FP_CLK_BUS; + clock_control_subsys_rate_t rate = + (clock_control_subsys_t)DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency); + + rts_fp_clk_set_rate(dev, sys, rate); + + return 0; +} + +static struct rts_fp_clock_data rts_fp_clock_data = { + .syspll_frequency = 0, +}; + +static const struct rts_fp_clock_config rts_fp_clock_config = { + .base = DT_INST_REG_ADDR(0), + .syspll_base = DT_INST_REG_ADDR_BY_IDX(0, 1), + .sck_div_base = DT_INST_REG_ADDR_BY_IDX(0, 2), +}; + +DEVICE_DT_DEFINE(DT_DRV_INST(0), rts_fp_clk_init, NULL, &rts_fp_clock_data, &rts_fp_clock_config, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &rts_fp_clk_api); diff --git a/drivers/clock_control/clock_control_rts5817_control.h b/drivers/clock_control/clock_control_rts5817_control.h new file mode 100644 index 0000000000000..f71aba7624f57 --- /dev/null +++ b/drivers/clock_control/clock_control_rts5817_control.h @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_CLOCK_CONTROL_RTS5817_CONTROL_REG_H_ +#define ZEPHYR_DRIVERS_CLOCK_CONTROL_RTS5817_CONTROL_REG_H_ + +#define SYSCLK_BASE_ADDR 0 +#define R_SYS_CLK_CHANGE (SYSCLK_BASE_ADDR + 0X0000) +#define R_SYS_BUS_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0004) +#define R_SYS_SPI_CACHE_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0008) +#define R_SYS_SPI_SSOR_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X000C) +#define R_SYS_SPI_SSI_M_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0010) +#define R_SYS_SPI_SSI_S_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0014) +#define R_SYS_SHA_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0018) +#define R_SYS_AES_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X001C) +#define R_SYS_PKE_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0020) +#define R_SYS_I2C_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0024) +#define R_SYS_CK60_CFG_REG (SYSCLK_BASE_ADDR + 0X0028) +#define R_SYS_UART0_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X002C) +#define R_SYS_UART1_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0030) +#define R_SYS_SIE_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0034) +#define R_SYS_PUF_CLK_CFG_REG (SYSCLK_BASE_ADDR + 0X0038) + +/* Bits of R_SYS_CLK_CHANGE (0X0300) */ + +#define CHANGE_BUS_CLK_PRE_OFFSET 0 +#define CHANGE_BUS_CLK_PRE_BITS 1 +#define CHANGE_BUS_CLK_PRE_MASK (((1 << 1) - 1) << 0) +#define CHANGE_BUS_CLK_PRE (CHANGE_BUS_CLK_PRE_MASK) + +#define CHANGE_SPI_CACHE_CLK_OFFSET 1 +#define CHANGE_SPI_CACHE_CLK_BITS 1 +#define CHANGE_SPI_CACHE_CLK_MASK (((1 << 1) - 1) << 1) +#define CHANGE_SPI_CACHE_CLK (CHANGE_SPI_CACHE_CLK_MASK) + +#define CHANGE_SPI_SSOR_CLK_OFFSET 2 +#define CHANGE_SPI_SSOR_CLK_BITS 1 +#define CHANGE_SPI_SSOR_CLK_MASK (((1 << 1) - 1) << 2) +#define CHANGE_SPI_SSOR_CLK (CHANGE_SPI_SSOR_CLK_MASK) + +#define CHANGE_SPI_SSI_M_CLK_OFFSET 3 +#define CHANGE_SPI_SSI_M_CLK_BITS 1 +#define CHANGE_SPI_SSI_M_CLK_MASK (((1 << 1) - 1) << 3) +#define CHANGE_SPI_SSI_M_CLK (CHANGE_SPI_SSI_M_CLK_MASK) + +#define CHANGE_SPI_SSI_S_CLK_OFFSET 4 +#define CHANGE_SPI_SSI_S_CLK_BITS 1 +#define CHANGE_SPI_SSI_S_CLK_MASK (((1 << 1) - 1) << 4) +#define CHANGE_SPI_SSI_S_CLK (CHANGE_SPI_SSI_S_CLK_MASK) + +#define CHANGE_SHA_CLK_OFFSET 5 +#define CHANGE_SHA_CLK_BITS 1 +#define CHANGE_SHA_CLK_MASK (((1 << 1) - 1) << 5) +#define CHANGE_SHA_CLK (CHANGE_SHA_CLK_MASK) + +#define CHANGE_AES_CLK_OFFSET 6 +#define CHANGE_AES_CLK_BITS 1 +#define CHANGE_AES_CLK_MASK (((1 << 1) - 1) << 6) +#define CHANGE_AES_CLK (CHANGE_AES_CLK_MASK) + +#define CHANGE_UART0_CLK_OFFSET 7 +#define CHANGE_UART0_CLK_BITS 1 +#define CHANGE_UART0_CLK_MASK (((1 << 1) - 1) << 7) +#define CHANGE_UART0_CLK (CHANGE_UART0_CLK_MASK) + +#define CHANGE_UART1_CLK_OFFSET 8 +#define CHANGE_UART1_CLK_BITS 1 +#define CHANGE_UART1_CLK_MASK (((1 << 1) - 1) << 8) +#define CHANGE_UART1_CLK (CHANGE_UART1_CLK_MASK) + +/* Bits of R_SYS_BUS_CLK_CFG_REG (0X0304) */ + +#define BUS_CLK_SRC_SEL_OFFSET 0 +#define BUS_CLK_SRC_SEL_BITS 2 +#define BUS_CLK_SRC_SEL_MASK (((1 << 2) - 1) << 0) +#define BUS_CLK_SRC_SEL (BUS_CLK_SRC_SEL_MASK) + +#define BUS_CLK_DIV_OFFSET 2 +#define BUS_CLK_DIV_BITS 4 +#define BUS_CLK_DIV_MASK (((1 << 4) - 1) << 2) +#define BUS_CLK_DIV (BUS_CLK_DIV_MASK) + +#define BUS_CLK_NDIV_OFFSET 8 +#define BUS_CLK_NDIV_BITS 2 +#define BUS_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define BUS_CLK_NDIV (BUS_CLK_NDIV_MASK) + +#define BUS_CLK_FDIV_OFFSET 16 +#define BUS_CLK_FDIV_BITS 6 +#define BUS_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define BUS_CLK_FDIV (BUS_CLK_FDIV_MASK) + +#define GE_CLK_EN_OFFSET 25 +#define GE_CLK_EN_BITS 1 +#define GE_CLK_EN_MASK (((1 << 1) - 1) << 25) +#define GE_CLK_EN (GE_CLK_EN_MASK) + +/* Bits of R_SYS_SPI_CACHE_CLK_CFG_REG (0X0308) */ + +#define SPI_CACHE_CLK_SEL_OFFSET 0 +#define SPI_CACHE_CLK_SEL_BITS 2 +#define SPI_CACHE_CLK_SEL_MASK (((1 << 2) - 1) << 0) +#define SPI_CACHE_CLK_SEL (SPI_CACHE_CLK_SEL_MASK) + +#define SPI_CACHE_CLK_DIV_OFFSET 2 +#define SPI_CACHE_CLK_DIV_BITS 3 +#define SPI_CACHE_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define SPI_CACHE_CLK_DIV (SPI_CACHE_CLK_DIV_MASK) + +#define SPI_CACHE_CLK_NDIV_OFFSET 8 +#define SPI_CACHE_CLK_NDIV_BITS 2 +#define SPI_CACHE_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define SPI_CACHE_CLK_NDIV (SPI_CACHE_CLK_NDIV_MASK) + +#define SPI_CACHE_CLK_FDIV_OFFSET 16 +#define SPI_CACHE_CLK_FDIV_BITS 6 +#define SPI_CACHE_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define SPI_CACHE_CLK_FDIV (SPI_CACHE_CLK_FDIV_MASK) + +#define SPI_CACHE_CLK_EN_OFFSET 24 +#define SPI_CACHE_CLK_EN_BITS 1 +#define SPI_CACHE_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define SPI_CACHE_CLK_EN (SPI_CACHE_CLK_EN_MASK) + +/* Bits of R_SYS_SPI_SSOR_CLK_CFG_REG (0X030C) */ + +#define SPI_SSOR_CLK_SEL_OFFSET 0 +#define SPI_SSOR_CLK_SEL_BITS 2 +#define SPI_SSOR_CLK_SEL_MASK (((1 << 2) - 1) << 0) +#define SPI_SSOR_CLK_SEL (SPI_SSOR_CLK_SEL_MASK) + +#define SPI_SSOR_CLK_DIV_OFFSET 2 +#define SPI_SSOR_CLK_DIV_BITS 3 +#define SPI_SSOR_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define SPI_SSOR_CLK_DIV (SPI_SSOR_CLK_DIV_MASK) + +#define SPI_SSOR_CLK_NDIV_OFFSET 8 +#define SPI_SSOR_CLK_NDIV_BITS 2 +#define SPI_SSOR_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define SPI_SSOR_CLK_NDIV (SPI_SSOR_CLK_NDIV_MASK) + +#define SPI_SSOR_CLK_FDIV_OFFSET 16 +#define SPI_SSOR_CLK_FDIV_BITS 6 +#define SPI_SSOR_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define SPI_SSOR_CLK_FDIV (SPI_SSOR_CLK_FDIV_MASK) + +#define SPI_SSOR_CLK_EN_OFFSET 24 +#define SPI_SSOR_CLK_EN_BITS 1 +#define SPI_SSOR_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define SPI_SSOR_CLK_EN (SPI_SSOR_CLK_EN_MASK) + +/* Bits of R_SYS_SPI_SSI_M_CLK_CFG_REG (0X0310) */ + +#define SPI_SSI_M_CLK_SEL_OFFSET 0 +#define SPI_SSI_M_CLK_SEL_BITS 2 +#define SPI_SSI_M_CLK_SEL_MASK (((1 << 2) - 1) << 0) +#define SPI_SSI_M_CLK_SEL (SPI_SSI_M_CLK_SEL_MASK) + +#define SPI_SSI_M_CLK_DIV_OFFSET 2 +#define SPI_SSI_M_CLK_DIV_BITS 3 +#define SPI_SSI_M_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define SPI_SSI_M_CLK_DIV (SPI_SSI_M_CLK_DIV_MASK) + +#define SPI_SSI_M_CLK_NDIV_OFFSET 8 +#define SPI_SSI_M_CLK_NDIV_BITS 2 +#define SPI_SSI_M_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define SPI_SSI_M_CLK_NDIV (SPI_SSI_M_CLK_NDIV_MASK) + +#define SPI_SSI_M_CLK_FDIV_OFFSET 16 +#define SPI_SSI_M_CLK_FDIV_BITS 6 +#define SPI_SSI_M_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define SPI_SSI_M_CLK_FDIV (SPI_SSI_M_CLK_FDIV_MASK) + +#define SPI_SSI_M_CLK_EN_OFFSET 24 +#define SPI_SSI_M_CLK_EN_BITS 1 +#define SPI_SSI_M_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define SPI_SSI_M_CLK_EN (SPI_SSI_M_CLK_EN_MASK) + +/* Bits of R_SYS_SPI_SSI_S_CLK_CFG_REG (0X0314) */ + +#define SPI_SSI_S_CLK_SEL_OFFSET 0 +#define SPI_SSI_S_CLK_SEL_BITS 2 +#define SPI_SSI_S_CLK_SEL_MASK (((1 << 2) - 1) << 0) +#define SPI_SSI_S_CLK_SEL (SPI_SSI_S_CLK_SEL_MASK) + +#define SPI_SSI_S_CLK_DIV_OFFSET 2 +#define SPI_SSI_S_CLK_DIV_BITS 3 +#define SPI_SSI_S_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define SPI_SSI_S_CLK_DIV (SPI_SSI_S_CLK_DIV_MASK) + +#define SPI_SSI_S_CLK_NDIV_OFFSET 8 +#define SPI_SSI_S_CLK_NDIV_BITS 2 +#define SPI_SSI_S_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define SPI_SSI_S_CLK_NDIV (SPI_SSI_S_CLK_NDIV_MASK) + +#define SPI_SSI_S_CLK_FDIV_OFFSET 16 +#define SPI_SSI_S_CLK_FDIV_BITS 6 +#define SPI_SSI_S_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define SPI_SSI_S_CLK_FDIV (SPI_SSI_S_CLK_FDIV_MASK) + +#define SPI_SSI_S_CLK_EN_OFFSET 24 +#define SPI_SSI_S_CLK_EN_BITS 1 +#define SPI_SSI_S_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define SPI_SSI_S_CLK_EN (SPI_SSI_S_CLK_EN_MASK) + +/* Bits of R_SYS_SHA_CLK_CFG_REG (0X0318) */ + +#define SHA_CLK_SEL_OFFSET 0 +#define SHA_CLK_SEL_BITS 2 +#define SHA_CLK_SEL_MASK (((1 << 2) - 1) << 0) +#define SHA_CLK_SEL (SHA_CLK_SEL_MASK) + +#define SHA_CLK_DIV_OFFSET 2 +#define SHA_CLK_DIV_BITS 3 +#define SHA_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define SHA_CLK_DIV (SHA_CLK_DIV_MASK) + +#define SHA_CLK_NDIV_OFFSET 8 +#define SHA_CLK_NDIV_BITS 2 +#define SHA_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define SHA_CLK_NDIV (SHA_CLK_NDIV_MASK) + +#define SHA_CLK_FDIV_OFFSET 16 +#define SHA_CLK_FDIV_BITS 6 +#define SHA_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define SHA_CLK_FDIV (SHA_CLK_FDIV_MASK) + +#define SHA_CLK_EN_OFFSET 24 +#define SHA_CLK_EN_BITS 1 +#define SHA_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define SHA_CLK_EN (SHA_CLK_EN_MASK) + +/* Bits of R_SYS_AES_CLK_CFG_REG (0X031C) */ + +#define AES_CLK_SEL_OFFSET 0 +#define AES_CLK_SEL_BITS 2 +#define AES_CLK_SEL_MASK (((1 << 2) - 1) << 0) +#define AES_CLK_SEL (AES_CLK_SEL_MASK) + +#define AES_CLK_DIV_OFFSET 2 +#define AES_CLK_DIV_BITS 3 +#define AES_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define AES_CLK_DIV (AES_CLK_DIV_MASK) + +#define AES_CLK_NDIV_OFFSET 8 +#define AES_CLK_NDIV_BITS 2 +#define AES_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define AES_CLK_NDIV (AES_CLK_NDIV_MASK) + +#define AES_CLK_FDIV_OFFSET 16 +#define AES_CLK_FDIV_BITS 6 +#define AES_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define AES_CLK_FDIV (AES_CLK_FDIV_MASK) + +#define AES_CLK_EN_OFFSET 24 +#define AES_CLK_EN_BITS 1 +#define AES_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define AES_CLK_EN (AES_CLK_EN_MASK) + +/* Bits of R_SYS_PKE_CLK_CFG_REG (0X0320) */ + +#define PKE_CLK_DIV_OFFSET 2 +#define PKE_CLK_DIV_BITS 3 +#define PKE_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define PKE_CLK_DIV (PKE_CLK_DIV_MASK) + +#define PKE_CLK_NDIV_OFFSET 8 +#define PKE_CLK_NDIV_BITS 2 +#define PKE_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define PKE_CLK_NDIV (PKE_CLK_NDIV_MASK) + +#define PKE_CLK_FDIV_OFFSET 16 +#define PKE_CLK_FDIV_BITS 6 +#define PKE_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define PKE_CLK_FDIV (PKE_CLK_FDIV_MASK) + +#define PKE_CLK_EN_OFFSET 24 +#define PKE_CLK_EN_BITS 1 +#define PKE_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define PKE_CLK_EN (PKE_CLK_EN_MASK) + +/* Bits of R_SYS_I2C_CLK_CFG_REG (0X0324) */ + +#define I2C_CLK_DIV_OFFSET 2 +#define I2C_CLK_DIV_BITS 3 +#define I2C_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define I2C_CLK_DIV (I2C_CLK_DIV_MASK) + +#define I2C_CLK_NDIV_OFFSET 8 +#define I2C_CLK_NDIV_BITS 2 +#define I2C_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define I2C_CLK_NDIV (I2C_CLK_NDIV_MASK) + +#define I2C_CLK_FDIV_OFFSET 16 +#define I2C_CLK_FDIV_BITS 6 +#define I2C_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define I2C_CLK_FDIV (I2C_CLK_FDIV_MASK) + +#define I2C_CLK_EN_OFFSET 24 +#define I2C_CLK_EN_BITS 1 +#define I2C_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define I2C_CLK_EN (I2C_CLK_EN_MASK) + +#define I2C0_CLK_EN_OFFSET 25 +#define I2C0_CLK_EN_BITS 1 +#define I2C0_CLK_EN_MASK (((1 << 1) - 1) << 25) +#define I2C0_CLK_EN (I2C0_CLK_EN_MASK) + +#define I2C1_CLK_EN_OFFSET 26 +#define I2C1_CLK_EN_BITS 1 +#define I2C1_CLK_EN_MASK (((1 << 1) - 1) << 26) +#define I2C1_CLK_EN (I2C1_CLK_EN_MASK) + +/* Bits of R_SYS_CK60_CFG_REG (0X0328) */ + +#define I2C_S_CLK_EN_OFFSET 24 +#define I2C_S_CLK_EN_BITS 1 +#define I2C_S_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define I2C_S_CLK_EN (I2C_S_CLK_EN_MASK) + +#define TRNG_CLK_EN_OFFSET 25 +#define TRNG_CLK_EN_BITS 1 +#define TRNG_CLK_EN_MASK (((1 << 1) - 1) << 25) +#define TRNG_CLK_EN (TRNG_CLK_EN_MASK) + +/* Bits of R_SYS_UART0_CLK_CFG_REG (0X032C) */ + +#define UART0_CLK_SEL_OFFSET 0 +#define UART0_CLK_SEL_BITS 2 +#define UART0_CLK_SEL_MASK (((1 << 2) - 1) << 0) +#define UART0_CLK_SEL (UART0_CLK_SEL_MASK) + +#define UART0_CLK_DIV_OFFSET 2 +#define UART0_CLK_DIV_BITS 3 +#define UART0_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define UART0_CLK_DIV (UART0_CLK_DIV_MASK) + +#define UART0_CLK_NDIV_OFFSET 8 +#define UART0_CLK_NDIV_BITS 2 +#define UART0_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define UART0_CLK_NDIV (UART0_CLK_NDIV_MASK) + +#define UART0_CLK_FDIV_OFFSET 16 +#define UART0_CLK_FDIV_BITS 6 +#define UART0_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define UART0_CLK_FDIV (UART0_CLK_FDIV_MASK) + +#define UART0_CLK_EN_OFFSET 24 +#define UART0_CLK_EN_BITS 1 +#define UART0_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define UART0_CLK_EN (UART0_CLK_EN_MASK) + +/* Bits of R_SYS_UART1_CLK_CFG_REG (0X0330) */ + +#define UART1_CLK_SEL_OFFSET 0 +#define UART1_CLK_SEL_BITS 2 +#define UART1_CLK_SEL_MASK (((1 << 2) - 1) << 0) +#define UART1_CLK_SEL (UART1_CLK_SEL_MASK) + +#define UART1_CLK_DIV_OFFSET 2 +#define UART1_CLK_DIV_BITS 3 +#define UART1_CLK_DIV_MASK (((1 << 3) - 1) << 2) +#define UART1_CLK_DIV (UART1_CLK_DIV_MASK) + +#define UART1_CLK_NDIV_OFFSET 8 +#define UART1_CLK_NDIV_BITS 2 +#define UART1_CLK_NDIV_MASK (((1 << 2) - 1) << 8) +#define UART1_CLK_NDIV (UART1_CLK_NDIV_MASK) + +#define UART1_CLK_FDIV_OFFSET 16 +#define UART1_CLK_FDIV_BITS 6 +#define UART1_CLK_FDIV_MASK (((1 << 6) - 1) << 16) +#define UART1_CLK_FDIV (UART1_CLK_FDIV_MASK) + +#define UART1_CLK_EN_OFFSET 24 +#define UART1_CLK_EN_BITS 1 +#define UART1_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define UART1_CLK_EN (UART1_CLK_EN_MASK) + +/* Bits of R_SYS_SIE_CLK_CFG_REG (0X0334) */ + +#define SIE_CLK_EN_OFFSET 24 +#define SIE_CLK_EN_BITS 1 +#define SIE_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define SIE_CLK_EN (SIE_CLK_EN_MASK) + +/* Bits of R_SYS_PUF_CLK_CFG_REG (0X0338) */ + +#define PUF_CLK_EN_OFFSET 24 +#define PUF_CLK_EN_BITS 1 +#define PUF_CLK_EN_MASK (((1 << 1) - 1) << 24) +#define PUF_CLK_EN (PUF_CLK_EN_MASK) + +/* Parameters definition */ + +/* Parameters of R_SYS_BUS_CLK_CFG_REG (0x0304) */ +#define BUS_CLK_240M 0x0 +#define BUS_CLK_160M 0x1 +#define BUS_CLK_96M 0x2 +#define BUS_CLK_GPLL0 0x3 + +#define BUS_CLK_DIV_1 0x0 +#define BUS_CLK_DIV_2 0x1 +#define BUS_CLK_DIV_4 0x2 +#define BUS_CLK_DIV_6 0x3 + +/* Parameters of R_SYS_SPI_CACHE_CLK_CFG_REG (0X0308)*/ +#define SPI_CACHE_CLK_240M 0x0 +#define SPI_CACHE_CLK_160M 0x1 +#define SPI_CACHE_CLK_96M 0x2 +#define SPI_CACHE_CLK_GPLL0 0x3 + +#define SPI_CACHE_CLK_DIV_1 0x0 +#define SPI_CACHE_CLK_DIV_2 0x1 +#define SPI_CACHE_CLK_DIV_4 0x2 +#define SPI_CACHE_CLK_DIV_6 0x3 + +/* Parameters of R_SYS_SPI_SSOR_CLK_CFG_REG (0X030C) */ +#define SPI_SSOR_CLK_240M 0x0 +#define SPI_SSOR_CLK_96M 0x1 +#define SPI_SSOR_CLK_80M 0x2 +#define SPI_SSOR_CLK_GPLL0 0x3 + +#define SPI_SSOR_CLK_DIV_1 0x0 +#define SPI_SSOR_CLK_DIV_2 0x1 +#define SPI_SSOR_CLK_DIV_4 0x2 +#define SPI_SSOR_CLK_DIV_6 0x3 + +/* Parameters of R_SYS_SPI_SSI_M_CLK_CFG_REG (0X0310) */ +#define SPI_SSI_MST_CLK_240M 0x0 +#define SPI_SSI_MST_CLK_96M 0x1 +#define SPI_SSI_MST_CLK_80M 0x2 +#define SPI_SSI_MST_CLK_GPLL0 0x3 + +#define SPI_SSI_MST_CLK_DIV_1 0x0 +#define SPI_SSI_MST_CLK_DIV_2 0x1 +#define SPI_SSI_MST_CLK_DIV_4 0x2 +#define SPI_SSI_MST_CLK_DIV_6 0x3 + +/* Parameters of R_SYS_SPI_SSI_S_CLK_CFG_REG (0X0314) */ +#define SPI_SSI_SLV_CLK_240M 0x0 +#define SPI_SSI_SLV_CLK_96M 0x1 +#define SPI_SSI_SLV_CLK_80M 0x2 +#define SPI_SSI_SLV_CLK_GPLL0 0x3 + +#define SPI_SSI_SLV_CLK_DIV_1 0x0 +#define SPI_SSI_SLV_CLK_DIV_2 0x1 +#define SPI_SSI_SLV_CLK_DIV_4 0x2 +#define SPI_SSI_SLV_CLK_DIV_6 0x3 + +/* Parameters of R_SYS_SHA_CLK_CFG_REG (0X0318) */ +#define SHA_CLK_240M 0x0 +#define SHA_CLK_160M 0x1 +#define SHA_CLK_96M 0x2 +#define SHA_CLK_GPLL0 0x3 + +#define SHA_CLK_DIV_1 0x0 +#define SHA_CLK_DIV_2 0x1 +#define SHA_CLK_DIV_4 0x2 +#define SHA_CLK_DIV_6 0x3 + +/* Parameters of R_SYS_AES_CLK_CFG_REG (0X031C) */ +#define AES_CLK_240M 0x0 +#define AES_CLK_160M 0x1 +#define AES_CLK_96M 0x2 +#define AES_CLK_GPLL0 0x3 + +#define AES_CLK_DIV_1 0x0 +#define AES_CLK_DIV_2 0x1 +#define AES_CLK_DIV_4 0x2 +#define AES_CLK_DIV_6 0x3 + +/* Parameters of R_SYS_I2C_CLK_CFG_REG (0X0324) */ +#define I2C_CLK_DIV_1 0x0 +#define I2C_CLK_DIV_2 0x1 +#define I2C_CLK_DIV_4 0x2 +#define I2C_CLK_DIV_6 0x3 + +/* Parameters of R_SYS_UARTx_CLK_CFG_REG (0X032C 0X330) */ +#define UART_CLK_96M 0x0 +#define UART_CLK_120M 0x1 +#define UART_CLK_GPLL0 0x3 + +#define UART_CLK_DIV_1 0x0 +#define UART_CLK_DIV_2 0x1 +#define UART_CLK_DIV_4 0x2 +#define UART_CLK_DIV_6 0x3 + +/***********************Definition created by FW**********************/ +#define SENSOR_SPI_CLK_SEL_240M 0x00 +#define SENSOR_SPI_CLK_SEL_96M 0x01 +#define SENSOR_SPI_CLK_SEL_80M 0x02 +#define SENSOR_SPI_CLK_SEL_SYSPLL 0x03 + +#define SSI_SPI_MST_CLK_SEL_240M 0x00 +#define SSI_SPI_MST_CLK_SEL_96M 0x01 +#define SSI_SPI_MST_CLK_SEL_80M 0x02 +#define SSI_SPI_MST_CLK_SEL_SYSPLL 0x03 + +#endif /* ZEPHYR_DRIVERS_CLOCK_CONTROL_RTS5817_CONTROL_REG_H_ */ diff --git a/drivers/clock_control/clock_control_rts5817_gpll.h b/drivers/clock_control/clock_control_rts5817_gpll.h new file mode 100644 index 0000000000000..1c21d7bb446de --- /dev/null +++ b/drivers/clock_control/clock_control_rts5817_gpll.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_CLOCK_CONTROL_RTS5817_GPLL_REG_H_ +#define ZEPHYR_DRIVERS_CLOCK_CONTROL_RTS5817_GPLL_REG_H_ + +#define GPLL_SSCG_BASE_ADDR 0 +#define R_SYSPLL_CFG (GPLL_SSCG_BASE_ADDR + 0X0000) +#define R_SYSPLL_NF_CODE (GPLL_SSCG_BASE_ADDR + 0X0004) +#define R_SYSPLL_CTL (GPLL_SSCG_BASE_ADDR + 0X0008) +#define R_SYSPLL_STS (GPLL_SSCG_BASE_ADDR + 0X000C) + +/* Bits of R_SYSPLL_CFG (0X0000) */ + +#define PLL_ORDER_OFFSET 0 +#define PLL_ORDER_BITS 1 +#define PLL_ORDER_MASK (((1 << 1) - 1) << 0) +#define PLL_ORDER (PLL_ORDER_MASK) + +#define PLL_BYPASS_PI_OFFSET 1 +#define PLL_BYPASS_PI_BITS 1 +#define PLL_BYPASS_PI_MASK (((1 << 1) - 1) << 1) +#define PLL_BYPASS_PI (PLL_BYPASS_PI_MASK) + +#define PLL_REG_CCO_BIG_KVCO_OFFSET 2 +#define PLL_REG_CCO_BIG_KVCO_BITS 1 +#define PLL_REG_CCO_BIG_KVCO_MASK (((1 << 1) - 1) << 2) +#define PLL_REG_CCO_BIG_KVCO (PLL_REG_CCO_BIG_KVCO_MASK) + +#define PLL_REG_CCO_SEL_OFFSET 3 +#define PLL_REG_CCO_SEL_BITS 1 +#define PLL_REG_CCO_SEL_MASK (((1 << 1) - 1) << 3) +#define PLL_REG_CCO_SEL (PLL_REG_CCO_SEL_MASK) + +#define PLL_REG_CP_OFFSET 4 +#define PLL_REG_CP_BITS 3 +#define PLL_REG_CP_MASK (((1 << 3) - 1) << 4) +#define PLL_REG_CP (PLL_REG_CP_MASK) + +#define REG_EN_DCP_OFFSET 7 +#define REG_EN_DCP_BITS 1 +#define REG_EN_DCP_MASK (((1 << 1) - 1) << 7) +#define REG_EN_DCP (REG_EN_DCP_MASK) + +#define REG_PI_BIAS_OFFSET 8 +#define REG_PI_BIAS_BITS 2 +#define REG_PI_BIAS_MASK (((1 << 2) - 1) << 8) +#define REG_PI_BIAS (REG_PI_BIAS_MASK) + +#define PLL_REG_PI_CAP_OFFSET 10 +#define PLL_REG_PI_CAP_BITS 2 +#define PLL_REG_PI_CAP_MASK (((1 << 2) - 1) << 10) +#define PLL_REG_PI_CAP (PLL_REG_PI_CAP_MASK) + +#define REG_PI_EN_OFFSET 12 +#define REG_PI_EN_BITS 3 +#define REG_PI_EN_MASK (((1 << 3) - 1) << 12) +#define REG_PI_EN (REG_PI_EN_MASK) + +#define PLL_REG_PI_SEL_OFFSET 15 +#define PLL_REG_PI_SEL_BITS 1 +#define PLL_REG_PI_SEL_MASK (((1 << 1) - 1) << 15) +#define PLL_REG_PI_SEL (PLL_REG_PI_SEL_MASK) + +#define REG_SD_OFFSET 16 +#define REG_SD_BITS 2 +#define REG_SD_MASK (((1 << 2) - 1) << 16) +#define REG_SD (REG_SD_MASK) + +#define PLL_REG_SEL_VLDO_OFFSET 18 +#define PLL_REG_SEL_VLDO_BITS 2 +#define PLL_REG_SEL_VLDO_MASK (((1 << 2) - 1) << 18) +#define PLL_REG_SEL_VLDO (PLL_REG_SEL_VLDO_MASK) + +#define REG_SR_H_OFFSET 20 +#define REG_SR_H_BITS 3 +#define REG_SR_H_MASK (((1 << 3) - 1) << 20) +#define REG_SR_H (REG_SR_H_MASK) + +#define PLL_REG_EN_NEW_OFFSET 23 +#define PLL_REG_EN_NEW_BITS 1 +#define PLL_REG_EN_NEW_MASK (((1 << 1) - 1) << 23) +#define PLL_REG_EN_NEW (PLL_REG_EN_NEW_MASK) + +#define REG_SC_H_OFFSET 24 +#define REG_SC_H_BITS 1 +#define REG_SC_H_MASK (((1 << 1) - 1) << 24) +#define REG_SC_H (REG_SC_H_MASK) + +/* Bits of R_SYSPLL_NF_CODE (0X0004) */ + +#define N_SSC_OFFSET 0 +#define N_SSC_BITS 9 +#define N_SSC_MASK (((1 << 9) - 1) << 0) +#define N_SSC (N_SSC_MASK) + +#define F_SSC_OFFSET 16 +#define F_SSC_BITS 12 +#define F_SSC_MASK (((1 << 12) - 1) << 16) +#define F_SSC (F_SSC_MASK) + +/* Bits of R_SYSPLL_CTL (0X0008) */ + +#define POW_SYSPLL_OFFSET 0 +#define POW_SYSPLL_BITS 1 +#define POW_SYSPLL_MASK (((1 << 1) - 1) << 0) +#define POW_SYSPLL (POW_SYSPLL_MASK) + +#define PLL_LOAD_EN_OFFSET 1 +#define PLL_LOAD_EN_BITS 1 +#define PLL_LOAD_EN_MASK (((1 << 1) - 1) << 1) +#define PLL_LOAD_EN (PLL_LOAD_EN_MASK) + +#define SYSPLL_REF_SEL_OFFSET 2 +#define SYSPLL_REF_SEL_BITS 1 +#define SYSPLL_REF_SEL_MASK (((1 << 1) - 1) << 2) +#define SYSPLL_REF_SEL (SYSPLL_REF_SEL_MASK) + +/* Bits of R_SYSPLL_STS (0X000C) */ + +#define PLL_CLK_TFBAK_OFFSET 0 +#define PLL_CLK_TFBAK_BITS 1 +#define PLL_CLK_TFBAK_MASK (((1 << 1) - 1) << 0) +#define PLL_CLK_TFBAK (PLL_CLK_TFBAK_MASK) + +#define PLL_CKUSABLE_OFFSET 1 +#define PLL_CKUSABLE_BITS 1 +#define PLL_CKUSABLE_MASK (((1 << 1) - 1) << 1) +#define PLL_CKUSABLE (PLL_CKUSABLE_MASK) + +#endif /* ZEPHYR_DRIVERS_CLOCK_CONTROL_RTS5817_GPLL_REG_H_ */ diff --git a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi index 42e72122891ba..7edcb5ae581e8 100644 --- a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi +++ b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi @@ -39,6 +39,15 @@ #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; + + clks: clks@40100300 { + compatible = "realtek,rts5817-clock"; + reg = <0x40100300 0x100>, + <0x40150000 0x10>, + <0x40000018 0x4>; + #clock-cells = <1>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/clock/realtek,rts5817-clock.yaml b/dts/bindings/clock/realtek,rts5817-clock.yaml new file mode 100644 index 0000000000000..e341c8184ecc1 --- /dev/null +++ b/dts/bindings/clock/realtek,rts5817-clock.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Realtek RTS5817 clock + +compatible: "realtek,rts5817-clock" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#clock-cells": + const: 1 + +clock-cells: + - clkid From cd52378f477e4d1d72050b705ae74d19e46f90b7 Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Mon, 4 Nov 2024 17:45:52 +0800 Subject: [PATCH 07/11] drivers: reset: add reset driver for RTS5817 Add reset driver for RTS5817 Signed-off-by: Darcy Lu --- drivers/reset/CMakeLists.txt | 1 + drivers/reset/Kconfig | 1 + drivers/reset/Kconfig.rts5817 | 9 ++ drivers/reset/reset_rts5817.c | 66 +++++++++ drivers/reset/reset_rts5817.h | 140 ++++++++++++++++++ .../fingerprint/rts5817/rts5817_base.dtsi | 7 + dts/bindings/reset/realtek,rts5817-reset.yaml | 15 ++ 7 files changed, 239 insertions(+) create mode 100644 drivers/reset/Kconfig.rts5817 create mode 100644 drivers/reset/reset_rts5817.c create mode 100644 drivers/reset/reset_rts5817.h create mode 100644 dts/bindings/reset/realtek,rts5817-reset.yaml diff --git a/drivers/reset/CMakeLists.txt b/drivers/reset/CMakeLists.txt index 4ac4a77017d4d..a600b3350d834 100644 --- a/drivers/reset/CMakeLists.txt +++ b/drivers/reset/CMakeLists.txt @@ -14,3 +14,4 @@ zephyr_library_sources_ifdef(CONFIG_RESET_NXP_SYSCON reset_lpc_syscon.c) zephyr_library_sources_ifdef(CONFIG_RESET_NXP_RSTCTL reset_nxp_rstctl.c) zephyr_library_sources_ifdef(CONFIG_RESET_MMIO reset_mmio.c) zephyr_library_sources_ifdef(CONFIG_RESET_MCHP_MSS reset_mchp_mss.c) +zephyr_library_sources_ifdef(CONFIG_RESET_RTS5817 reset_rts5817.c) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 3646cf480666c..9841273b7c000 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -38,5 +38,6 @@ rsource "Kconfig.lpc_syscon" rsource "Kconfig.nxp_rstctl" rsource "Kconfig.mmio" rsource "Kconfig.mchp_mss" +rsource "Kconfig.rts5817" endif # RESET diff --git a/drivers/reset/Kconfig.rts5817 b/drivers/reset/Kconfig.rts5817 new file mode 100644 index 0000000000000..7e1d1057d0553 --- /dev/null +++ b/drivers/reset/Kconfig.rts5817 @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config RESET_RTS5817 + bool "RTS5817 Reset Controller Driver" + default y + depends on DT_HAS_REALTEK_RTS5817_RESET_ENABLED + help + This option enables the reset controller driver for RTS5817. diff --git a/drivers/reset/reset_rts5817.c b/drivers/reset/reset_rts5817.c new file mode 100644 index 0000000000000..fb0d337cea447 --- /dev/null +++ b/drivers/reset/reset_rts5817.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT realtek_rts5817_reset + +#include +#include +#include +#include +#include "reset_rts5817.h" + +struct reset_rts5817_config { + uintptr_t base; +}; + +static int reset_rts5817_status(const struct device *dev, uint32_t id, uint8_t *status) +{ + const struct reset_rts5817_config *config = dev->config; + + *status = !!sys_test_bit(config->base + R_SYS_FORCE_RST, id); + + return 0; +} + +static int reset_rts5817_line_assert(const struct device *dev, uint32_t id) +{ + const struct reset_rts5817_config *config = dev->config; + + sys_set_bit(config->base + R_SYS_FORCE_RST, id); + + return 0; +} + +static int reset_rts5817_line_deassert(const struct device *dev, uint32_t id) +{ + const struct reset_rts5817_config *config = dev->config; + + sys_clear_bit(config->base + R_SYS_FORCE_RST, id); + + return 0; +} + +static int reset_rts5817_line_toggle(const struct device *dev, uint32_t id) +{ + reset_rts5817_line_assert(dev, id); + reset_rts5817_line_deassert(dev, id); + + return 0; +} + +static const struct reset_driver_api reset_rts5817_driver_api = { + .status = reset_rts5817_status, + .line_assert = reset_rts5817_line_assert, + .line_deassert = reset_rts5817_line_deassert, + .line_toggle = reset_rts5817_line_toggle, +}; + +static const struct reset_rts5817_config reset_rts5817_config = { + .base = DT_INST_REG_ADDR(0), +}; + +DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, &reset_rts5817_config, PRE_KERNEL_1, + CONFIG_RESET_INIT_PRIORITY, &reset_rts5817_driver_api); diff --git a/drivers/reset/reset_rts5817.h b/drivers/reset/reset_rts5817.h new file mode 100644 index 0000000000000..6c32fef3400de --- /dev/null +++ b/drivers/reset/reset_rts5817.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_RESET_RESET_RTS5817_REG_H_ +#define ZEPHYR_DRIVERS_RESET_RESET_RTS5817_REG_H_ + +#define SYSRST_BASE_ADDR 0x0 +#define R_SYS_FORCE_RST (SYSRST_BASE_ADDR + 0X0000) + +/* Bits of R_SYS_FORCE_RST (0X0200) */ + +#define SYS_FORCE_RESET_BUS_OFFSET 0 +#define SYS_FORCE_RESET_BUS_BITS 1 +#define SYS_FORCE_RESET_BUS_MASK (((1 << 1) - 1) << 0) +#define SYS_FORCE_RESET_BUS (SYS_FORCE_RESET_BUS_MASK) + +#define SYS_FORCE_RESET_AES_OFFSET 1 +#define SYS_FORCE_RESET_AES_BITS 1 +#define SYS_FORCE_RESET_AES_MASK (((1 << 1) - 1) << 1) +#define SYS_FORCE_RESET_AES (SYS_FORCE_RESET_AES_MASK) + +#define SYS_FORCE_RESET_GE_OFFSET 2 +#define SYS_FORCE_RESET_GE_BITS 1 +#define SYS_FORCE_RESET_GE_MASK (((1 << 1) - 1) << 2) +#define SYS_FORCE_RESET_GE (SYS_FORCE_RESET_GE_MASK) + +#define SYS_FORCE_RESET_SHA_OFFSET 3 +#define SYS_FORCE_RESET_SHA_BITS 1 +#define SYS_FORCE_RESET_SHA_MASK (((1 << 1) - 1) << 3) +#define SYS_FORCE_RESET_SHA (SYS_FORCE_RESET_SHA_MASK) + +#define SYS_FORCE_RESET_SPI_CACHE_OFFSET 4 +#define SYS_FORCE_RESET_SPI_CACHE_BITS 1 +#define SYS_FORCE_RESET_SPI_CACHE_MASK (((1 << 1) - 1) << 4) +#define SYS_FORCE_RESET_SPI_CACHE (SYS_FORCE_RESET_SPI_CACHE_MASK) + +#define SYS_FORCE_RESET_SPI_SENSOR_OFFSET 5 +#define SYS_FORCE_RESET_SPI_SENSOR_BITS 1 +#define SYS_FORCE_RESET_SPI_SENSOR_MASK (((1 << 1) - 1) << 5) +#define SYS_FORCE_RESET_SPI_SENSOR (SYS_FORCE_RESET_SPI_SENSOR_MASK) + +#define SYS_FORCE_RESET_SPI_SSI_M_OFFSET 6 +#define SYS_FORCE_RESET_SPI_SSI_M_BITS 1 +#define SYS_FORCE_RESET_SPI_SSI_M_MASK (((1 << 1) - 1) << 6) +#define SYS_FORCE_RESET_SPI_SSI_M (SYS_FORCE_RESET_SPI_SSI_M_MASK) + +#define SYS_FORCE_RESET_SPI_SSI_S_OFFSET 7 +#define SYS_FORCE_RESET_SPI_SSI_S_BITS 1 +#define SYS_FORCE_RESET_SPI_SSI_S_MASK (((1 << 1) - 1) << 7) +#define SYS_FORCE_RESET_SPI_SSI_S (SYS_FORCE_RESET_SPI_SSI_S_MASK) + +#define SYS_FORCE_RESET_PKE_OFFSET 8 +#define SYS_FORCE_RESET_PKE_BITS 1 +#define SYS_FORCE_RESET_PKE_MASK (((1 << 1) - 1) << 8) +#define SYS_FORCE_RESET_PKE (SYS_FORCE_RESET_PKE_MASK) + +#define SYS_FORCE_RESET_I2C_OFFSET 9 +#define SYS_FORCE_RESET_I2C_BITS 1 +#define SYS_FORCE_RESET_I2C_MASK (((1 << 1) - 1) << 9) +#define SYS_FORCE_RESET_I2C (SYS_FORCE_RESET_I2C_MASK) + +#define SYS_FORCE_RESET_I2C0_OFFSET 10 +#define SYS_FORCE_RESET_I2C0_BITS 1 +#define SYS_FORCE_RESET_I2C0_MASK (((1 << 1) - 1) << 10) +#define SYS_FORCE_RESET_I2C0 (SYS_FORCE_RESET_I2C0_MASK) + +#define SYS_FORCE_RESET_I2C1_OFFSET 11 +#define SYS_FORCE_RESET_I2C1_BITS 1 +#define SYS_FORCE_RESET_I2C1_MASK (((1 << 1) - 1) << 11) +#define SYS_FORCE_RESET_I2C1 (SYS_FORCE_RESET_I2C1_MASK) + +#define SYS_FORCE_RESET_TRNG_OFFSET 12 +#define SYS_FORCE_RESET_TRNG_BITS 1 +#define SYS_FORCE_RESET_TRNG_MASK (((1 << 1) - 1) << 12) +#define SYS_FORCE_RESET_TRNG (SYS_FORCE_RESET_TRNG_MASK) + +#define SYS_FORCE_RESET_I2C_S_OFFSET 13 +#define SYS_FORCE_RESET_I2C_S_BITS 1 +#define SYS_FORCE_RESET_I2C_S_MASK (((1 << 1) - 1) << 13) +#define SYS_FORCE_RESET_I2C_S (SYS_FORCE_RESET_I2C_S_MASK) + +#define SYS_FORCE_RESET_UART0_OFFSET 14 +#define SYS_FORCE_RESET_UART0_BITS 1 +#define SYS_FORCE_RESET_UART0_MASK (((1 << 1) - 1) << 14) +#define SYS_FORCE_RESET_UART0 (SYS_FORCE_RESET_UART0_MASK) + +#define SYS_FORCE_RESET_UART1_OFFSET 15 +#define SYS_FORCE_RESET_UART1_BITS 1 +#define SYS_FORCE_RESET_UART1_MASK (((1 << 1) - 1) << 15) +#define SYS_FORCE_RESET_UART1 (SYS_FORCE_RESET_UART1_MASK) + +#define SYS_FORCE_RESET_PUF_OFFSET 16 +#define SYS_FORCE_RESET_PUF_BITS 1 +#define SYS_FORCE_RESET_PUF_MASK (((1 << 1) - 1) << 16) +#define SYS_FORCE_RESET_PUF (SYS_FORCE_RESET_PUF_MASK) + +#define SYS_FORCE_RESET_USB2_OFFSET 17 +#define SYS_FORCE_RESET_USB2_BITS 1 +#define SYS_FORCE_RESET_USB2_MASK (((1 << 1) - 1) << 17) +#define SYS_FORCE_RESET_USB2 (SYS_FORCE_RESET_USB2_MASK) + +#define SYS_FORCE_RESET_CK30M_OFFSET 18 +#define SYS_FORCE_RESET_CK30M_BITS 1 +#define SYS_FORCE_RESET_CK30M_MASK (((1 << 1) - 1) << 18) +#define SYS_FORCE_RESET_CK30M (SYS_FORCE_RESET_CK30M_MASK) + +#define SYS_FORCE_RESET_CK60M_OFFSET 19 +#define SYS_FORCE_RESET_CK60M_BITS 1 +#define SYS_FORCE_RESET_CK60M_MASK (((1 << 1) - 1) << 19) +#define SYS_FORCE_RESET_CK60M (SYS_FORCE_RESET_CK60M_MASK) + +#define SYS_FORCE_RESET_CK120M_OFFSET 20 +#define SYS_FORCE_RESET_CK120M_BITS 1 +#define SYS_FORCE_RESET_CK120M_MASK (((1 << 1) - 1) << 20) +#define SYS_FORCE_RESET_CK120M (SYS_FORCE_RESET_CK120M_MASK) + +#define USB2_PHY_FORCE_RESET_OFFSET 21 +#define USB2_PHY_FORCE_RESET_BITS 1 +#define USB2_PHY_FORCE_RESET_MASK (((1 << 1) - 1) << 21) +#define USB2_PHY_FORCE_RESET (USB2_PHY_FORCE_RESET_MASK) + +#define SYS_FORCE_RESET_SYS_OFFSET 22 +#define SYS_FORCE_RESET_SYS_BITS 1 +#define SYS_FORCE_RESET_SYS_MASK (((1 << 1) - 1) << 22) +#define SYS_FORCE_RESET_SYS (SYS_FORCE_RESET_SYS_MASK) + +#define SYS_FORCE_RESET_DPHY_OFFSET 23 +#define SYS_FORCE_RESET_DPHY_BITS 1 +#define SYS_FORCE_RESET_DPHY_MASK (((1 << 1) - 1) << 23) +#define SYS_FORCE_RESET_DPHY (SYS_FORCE_RESET_DPHY_MASK) + +#define SYS_FORCE_RESET_SPI_SSISLV_BUS_OFFSET 24 +#define SYS_FORCE_RESET_SPI_SSISLV_BUS_BITS 1 +#define SYS_FORCE_RESET_SPI_SSISLV_BUS_MASK (((1 << 1) - 1) << 24) +#define SYS_FORCE_RESET_SPI_SSISLV_BUS (SYS_FORCE_RESET_SPI_SSISLV_BUS_MASK) + +#endif /* ZEPHYR_DRIVERS_RESET_RESET_RTS5817_REG_H_ */ diff --git a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi index 7edcb5ae581e8..5950298e9455e 100644 --- a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi +++ b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi @@ -48,6 +48,13 @@ #clock-cells = <1>; status = "disabled"; }; + + reset: reset@40100200 { + compatible = "realtek,rts5817-reset"; + reg = <0x40100200 0x100>; + #reset-cells = <1>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/reset/realtek,rts5817-reset.yaml b/dts/bindings/reset/realtek,rts5817-reset.yaml new file mode 100644 index 0000000000000..6d9f8c980ed52 --- /dev/null +++ b/dts/bindings/reset/realtek,rts5817-reset.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Realtek RTS5817 Peripheral reset controller + +compatible: "realtek,rts5817-reset" + +include: [reset-controller.yaml, base.yaml] + +properties: + "#reset-cells": + const: 1 + +reset-cells: + - id From 7c9c007ae3aa37563f3b8937463cdc314bb8490a Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Tue, 5 Nov 2024 10:08:06 +0800 Subject: [PATCH 08/11] drivers: pinctrl: add pinctrl driver for RTS5817 Add pin controller driver for RTS5817 Signed-off-by: Darcy Lu --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.rts5817 | 9 + drivers/pinctrl/pinctrl_rts5817.c | 99 ++++ drivers/pinctrl/pinctrl_rts5817.h | 454 ++++++++++++++++++ .../fingerprint/rts5817/rts5817_base.dtsi | 10 + .../pinctrl/realtek,rts5817-pinctrl.yaml | 33 ++ 7 files changed, 607 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.rts5817 create mode 100644 drivers/pinctrl/pinctrl_rts5817.c create mode 100644 drivers/pinctrl/pinctrl_rts5817.h create mode 100644 dts/bindings/pinctrl/realtek,rts5817-pinctrl.yaml diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index bb302e9c94cfd..127fdb0b8f0cf 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -57,5 +57,6 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_SY1XX pinctrl_sy1xx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_REALTEK_RTS5912 pinctrl_realtek_rts5912.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_WCH_20X_30X_AFIO pinctrl_wch_20x_30x_afio.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_WCH_00X_AFIO pinctrl_wch_00x_afio.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_RTS5817 pinctrl_rts5817.c) add_subdirectory(renesas) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e13c4e427ff71..5a08cae192c0b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -82,6 +82,7 @@ source "drivers/pinctrl/Kconfig.sy1xx" source "drivers/pinctrl/Kconfig.realtek_rts5912" source "drivers/pinctrl/Kconfig.wch_20x_30x_afio" source "drivers/pinctrl/Kconfig.wch_00x_afio" +source "drivers/pinctrl/Kconfig.rts5817" rsource "renesas/Kconfig" diff --git a/drivers/pinctrl/Kconfig.rts5817 b/drivers/pinctrl/Kconfig.rts5817 new file mode 100644 index 0000000000000..a8087d57f005d --- /dev/null +++ b/drivers/pinctrl/Kconfig.rts5817 @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_RTS5817 + bool "RTS5817 pin controller driver" + default y + depends on DT_HAS_REALTEK_RTS5817_PINCTRL_ENABLED + help + Enable driver for RTS5817 pin controller. diff --git a/drivers/pinctrl/pinctrl_rts5817.c b/drivers/pinctrl/pinctrl_rts5817.c new file mode 100644 index 0000000000000..cffc257fa1ca6 --- /dev/null +++ b/drivers/pinctrl/pinctrl_rts5817.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "pinctrl_rts5817.h" + +#define PAD_CFG_SIZE 0x40 + +static void pinctrl_configure_pin(pinctrl_soc_pin_t pincfg) +{ + uint32_t base; + uint32_t value; + uint8_t h3l1 = pincfg.power_source & BIT(0); + uint8_t iev18 = (pincfg.power_source & BIT(1)) >> 1; + + if (pincfg.pin >= RTS_FP_PIN_AL0 && pincfg.pin <= RTS_FP_PIN_AL2) { + base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(pinctrl), 1); + + value = sys_read32(base); + + value &= ~((0x1 << (pincfg.pin - RTS_FP_PIN_AL0 + AL_GPIO_PU_CTRL_OFFSET)) | + (0x1 << (pincfg.pin - RTS_FP_PIN_AL0 + AL_GPIO_PD_CTRL_OFFSET)) | + (0x1 << (pincfg.pin - RTS_FP_PIN_AL0 + AL_GPIO_SEL_OFFSET))); + + if (pincfg.pin == RTS_FP_PIN_AL0) { + value &= ~(1 << CS1_BRIDGE_EN_OFFSET); + } + + if (pincfg.pin == RTS_FP_PIN_AL0 && pincfg.func == RTS_FP_PIN_FUNC2) { + value |= (1 << CS1_BRIDGE_EN_OFFSET); + } else { + value |= + (pincfg.func << (pincfg.pin - RTS_FP_PIN_AL0 + AL_GPIO_SEL_OFFSET)); + } + + value |= (pincfg.pulldown + << (pincfg.pin - RTS_FP_PIN_AL0 + AL_GPIO_PD_CTRL_OFFSET)) | + (pincfg.pullup << (pincfg.pin - RTS_FP_PIN_AL0 + AL_GPIO_PU_CTRL_OFFSET)); + + sys_write32(value, base); + } else if (pincfg.pin >= RTS_FP_PIN_SNR_RST && pincfg.pin <= RTS_FP_PIN_SNR_CS) { + base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(pinctrl), 2) + + (pincfg.pin - RTS_FP_PIN_SNR_RST) * 0x4; + + value = sys_read32(base); + + value &= ~(SENSOR_SCS_N_SEL_MASK | SENSOR_SCS_N_PDE_MASK | SENSOR_SCS_N_PUE_MASK | + SENSOR_SCS_N_H3L1_MASK | SENSOR_SCS_N_IEV18_MASK); + + value |= (pincfg.func << SENSOR_SCS_N_SEL_OFFSET) | + (pincfg.pulldown << SENSOR_SCS_N_PDE_OFFSET) | + (pincfg.pullup << SENSOR_SCS_N_PUE_OFFSET) | + (h3l1 << SENSOR_SCS_N_H3L1_OFFSET) | (iev18 << SENSOR_SCS_N_IEV18_OFFSET); + + sys_write32(value, base); + } else if (pincfg.pin == RTS_FP_PIN_SNR_GPIO) { + base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(pinctrl), 2) + 0xC; + + value = sys_read32(base); + + value &= ~(GPIO_SVIO_PULLCTL_MASK | GPIO_SVIO_IEV18_MASK | GPIO_SVIO_H3L1_MASK); + + value |= (pincfg.pulldown << GPIO_SVIO_PULLCTL_OFFSET) | + (pincfg.pullup << (GPIO_SVIO_PULLCTL_OFFSET + 1)) | + (iev18 << GPIO_SVIO_IEV18_OFFSET) | (h3l1 << GPIO_SVIO_H3L1_OFFSET); + + sys_write32(value, base); + } else { + base = DT_REG_ADDR(DT_NODELABEL(pinctrl)) + pincfg.pin * PAD_CFG_SIZE; + + value = sys_read32(base + PAD_CFG); + value &= ~(GPIO_FUNCTION_SEL_MASK | IEV18_MASK | H3L1_MASK | PU_MASK | PD_MASK); + value |= (((1 << pincfg.func) << GPIO_FUNCTION_SEL_OFFSET) | + (pincfg.pulldown << PD_OFFSET) | (pincfg.pullup << PU_OFFSET) | + (iev18 << IEV18_OFFSET) | (h3l1 << H3L1_OFFSET)); + + if (pincfg.pin == RTS_FP_PIN_CACHE_CS2) { + sys_write32(0x1, base + PAD_GPIO_INC); + } + + sys_write32(value, base); + } +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (int i = 0; i < pin_cnt; i++) { + pinctrl_configure_pin(pins[i]); + } + + return 0; +} diff --git a/drivers/pinctrl/pinctrl_rts5817.h b/drivers/pinctrl/pinctrl_rts5817.h new file mode 100644 index 0000000000000..4e10b4d2248eb --- /dev/null +++ b/drivers/pinctrl/pinctrl_rts5817.h @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_PINCTRL_RTS5817_REG_H_ +#define ZEPHYR_DRIVERS_PINCTRL_RTS5817_REG_H_ + +#define PAD_BASE_ADDR 0x0 + +#define PAD_CFG (PAD_BASE_ADDR + 0X0000) +#define PAD_GPIO_O (PAD_BASE_ADDR + 0X0004) +#define PAD_GPIO_OE (PAD_BASE_ADDR + 0X0008) +#define PAD_GPIO_I (PAD_BASE_ADDR + 0X000C) +#define PAD_GPIO_INC (PAD_BASE_ADDR + 0X0010) +#define PAD_GPIO_INT_EN (PAD_BASE_ADDR + 0X0010) +#define PAD_GPIO_INT (PAD_BASE_ADDR + 0X0014) + +#define SP_BASE0 0x0 +#define AL_GPIO_VALUE (SP_BASE0 + 0X0000) +#define AL_GPIO_CFG (SP_BASE0 + 0X0004) +#define AL_GPIO_IRQ_EN (SP_BASE0 + 0X0008) +#define AL_GPIO_IRQ (SP_BASE0 + 0X000C) +#define AL_SENSOR_RST_CTL (SP_BASE0 + 0X0010) +#define AL_SENSOR_SCS_N_CTL (SP_BASE0 + 0X0014) +#define FW_WAKEUP_TRIG (SP_BASE0 + 0X0018) +#define GPIO_SVIO_CFG (SP_BASE0 + 0X001C) + +#define SP_BASE1 0x0 +#define SENSOR_INT_CFG (SP_BASE1 + 0X0000) +#define SENSOR_INT_FLAG (SP_BASE1 + 0X0004) + +/* Bits of PAD_CFG (0X0000) */ + +#define PD_OFFSET 0 +#define PD_BITS 1 +#define PD_MASK (((1 << 1) - 1) << 0) +#define PD (PD_MASK) + +#define PU_OFFSET 1 +#define PU_BITS 1 +#define PU_MASK (((1 << 1) - 1) << 1) +#define PU (PU_MASK) + +#define H3L1_OFFSET 2 +#define H3L1_BITS 1 +#define H3L1_MASK (((1 << 1) - 1) << 2) +#define H3L1 (H3L1_MASK) + +#define DRIVING_OFFSET 3 +#define DRIVING_BITS 2 +#define DRIVING_MASK (((1 << 2) - 1) << 3) +#define DRIVING (DRIVING_MASK) + +#define SHDN_OFFSET 5 +#define SHDN_BITS 1 +#define SHDN_MASK (((1 << 1) - 1) << 5) +#define SHDN (SHDN_MASK) + +#define IEV18_OFFSET 6 +#define IEV18_BITS 1 +#define IEV18_MASK (((1 << 1) - 1) << 6) +#define IEV18 (IEV18_MASK) + +#define PAD_FUNCTION_SEL_OFFSET 8 +#define PAD_FUNCTION_SEL_BITS 2 +#define PAD_FUNCTION_SEL_MASK (((1 << 2) - 1) << 8) +#define PAD_FUNCTION_SEL (PAD_FUNCTION_SEL_MASK) + +#define GPIO_FUNCTION_SEL_OFFSET 8 +#define GPIO_FUNCTION_SEL_BITS 6 +#define GPIO_FUNCTION_SEL_MASK (((1 << 6) - 1) << 8) +#define GPIO_FUNCTION_SEL (GPIO_FUNCTION_SEL_MASK) + +/* Bits of PAD_GPIO_O (0X0004) */ + +#define GPIO_O_OFFSET 0 +#define GPIO_O_BITS 1 +#define GPIO_O_MASK (((1 << 1) - 1) << 0) +#define GPIO_O (GPIO_O_MASK) + +/* Bits of PAD_GPIO_OE (0X0008) */ + +#define GPIO_OE_OFFSET 0 +#define GPIO_OE_BITS 1 +#define GPIO_OE_MASK (((1 << 1) - 1) << 0) +#define GPIO_OE (GPIO_OE_MASK) + +/* Bits of PAD_GPIO_I (0X000C) */ + +#define GPIO_I_OFFSET 0 +#define GPIO_I_BITS 1 +#define GPIO_I_MASK (((1 << 1) - 1) << 0) +#define GPIO_I (GPIO_I_MASK) + +/* Bits of PAD_GPIO_INT_EN (0X0010) */ + +#define GPIO_FALLING_INT_EN_OFFSET 0 +#define GPIO_FALLING_INT_EN_BITS 1 +#define GPIO_FALLING_INT_EN_MASK (((1 << 1) - 1) << 0) +#define GPIO_FALLING_INT_EN (GPIO_FALLING_INT_EN_MASK) + +#define GPIO_RISING_INT_EN_OFFSET 1 +#define GPIO_RISING_INT_EN_BITS 1 +#define GPIO_RISING_INT_EN_MASK (((1 << 1) - 1) << 1) +#define GPIO_RISING_INT_EN (GPIO_RISING_INT_EN_MASK) + +/* Bits of PAD_GPIO_INT (0X0014) */ + +#define GPIO_FALLING_INT_OFFSET 0 +#define GPIO_FALLING_INT_BITS 1 +#define GPIO_FALLING_INT_MASK (((1 << 1) - 1) << 0) +#define GPIO_FALLING_INT (GPIO_FALLING_INT_MASK) + +#define GPIO_RISING_INT_OFFSET 1 +#define GPIO_RISING_INT_BITS 1 +#define GPIO_RISING_INT_MASK (((1 << 1) - 1) << 1) +#define GPIO_RISING_INT (GPIO_RISING_INT_MASK) + +/* Bits of R_SENSOR_INT_CFG (0X0024) */ + +#define IE_SENSOR_INT_OFFSET 0 +#define IE_SENSOR_INT_BITS 1 +#define IE_SENSOR_INT_MASK (((1 << 1) - 1) << 0) +#define IE_SENSOR_INT (IE_SENSOR_INT_MASK) + +#define I_SENSOR_PRIORITY_OFFSET 1 +#define I_SENSOR_PRIORITY_BITS 1 +#define I_SENSOR_PRIORITY_MASK (((1 << 1) - 1) << 1) +#define I_SENSOR_PRIORITY (I_SENSOR_PRIORITY_MASK) + +#define CFG_SENSOR_INT_POS_EN_OFFSET 2 +#define CFG_SENSOR_INT_POS_EN_BITS 2 +#define CFG_SENSOR_INT_POS_EN_MASK (((1 << 2) - 1) << 2) +#define CFG_SENSOR_INT_POS_EN (CFG_SENSOR_INT_POS_EN_MASK) + +#define CFG_SENSOR_INT_NEG_EN_OFFSET 4 +#define CFG_SENSOR_INT_NEG_EN_BITS 2 +#define CFG_SENSOR_INT_NEG_EN_MASK (((1 << 2) - 1) << 4) +#define CFG_SENSOR_INT_NEG_EN (CFG_SENSOR_INT_NEG_EN_MASK) + +/* Bits of R_SENSOR_INT_FLAG (0X0028) */ + +#define I_SENSOR_INTF_FALL_OFFSET 0 +#define I_SENSOR_INTF_FALL_BITS 2 +#define I_SENSOR_INTF_FALL_MASK (((1 << 2) - 1) << 0) +#define I_SENSOR_INTF_FALL (I_SENSOR_INTF_FALL_MASK) + +#define I_SENSOR_INTF_RISE_OFFSET 2 +#define I_SENSOR_INTF_RISE_BITS 2 +#define I_SENSOR_INTF_RISE_MASK (((1 << 2) - 1) << 2) +#define I_SENSOR_INTF_RISE (I_SENSOR_INTF_RISE_MASK) + +#define I_SENSOR_INTF_OFFSET 4 +#define I_SENSOR_INTF_BITS 2 +#define I_SENSOR_INTF_MASK (((1 << 2) - 1) << 4) +#define I_SENSOR_INTF (I_SENSOR_INTF_MASK) + +#define SENSOR_SCS_N_GPIO_INT_FALL_OFFSET 6 +#define SENSOR_SCS_N_GPIO_INT_FALL_BITS 1 +#define SENSOR_SCS_N_GPIO_INT_FALL_MASK (((1 << 1) - 1) << 6) +#define SENSOR_SCS_N_GPIO_INT_FALL (SENSOR_SCS_N_GPIO_INT_FALL_MASK) + +#define SENSOR_SCS_N_GPIO_INT_RISE_OFFSET 7 +#define SENSOR_SCS_N_GPIO_INT_RISE_BITS 1 +#define SENSOR_SCS_N_GPIO_INT_RISE_MASK (((1 << 1) - 1) << 7) +#define SENSOR_SCS_N_GPIO_INT_RISE (SENSOR_SCS_N_GPIO_INT_RISE_MASK) + +#define GPIO_SVIO_INT_FALL_OFFSET 8 +#define GPIO_SVIO_INT_FALL_BITS 1 +#define GPIO_SVIO_INT_FALL_MASK (((1 << 1) - 1) << 8) +#define GPIO_SVIO_INT_FALL (GPIO_SVIO_INT_FALL_MASK) + +#define GPIO_SVIO_INT_RISE_OFFSET 9 +#define GPIO_SVIO_INT_RISE_BITS 1 +#define GPIO_SVIO_INT_RISE_MASK (((1 << 1) - 1) << 9) +#define GPIO_SVIO_INT_RISE (GPIO_SVIO_INT_RISE_MASK) + +#define SENSOR_RSTN_GPIO_INT_FALL_OFFSET 10 +#define SENSOR_RSTN_GPIO_INT_FALL_BITS 1 +#define SENSOR_RSTN_GPIO_INT_FALL_MASK (((1 << 1) - 1) << 10) +#define SENSOR_RSTN_GPIO_INT_FALL (SENSOR_RSTN_GPIO_INT_FALL_MASK) + +#define SENSOR_RSTN_GPIO_INT_RISE_OFFSET 11 +#define SENSOR_RSTN_GPIO_INT_RISE_BITS 1 +#define SENSOR_RSTN_GPIO_INT_RISE_MASK (((1 << 1) - 1) << 11) +#define SENSOR_RSTN_GPIO_INT_RISE (SENSOR_RSTN_GPIO_INT_RISE_MASK) + +#define WAKE_UP_I_OFFSET 16 +#define WAKE_UP_I_BITS 2 +#define WAKE_UP_I_MASK (((1 << 2) - 1) << 16) +#define WAKE_UP_I (WAKE_UP_I_MASK) + +/* Bits of R_AL_GPIO_VALUE (0X0070) */ + +#define AL_GPIO_O_OFFSET 0 +#define AL_GPIO_O_BITS 3 +#define AL_GPIO_O_MASK (((1 << 3) - 1) << 0) +#define AL_GPIO_O (AL_GPIO_O_MASK) + +#define ASYNC_AL_GPIO_IN_OFFSET 3 +#define ASYNC_AL_GPIO_IN_BITS 3 +#define ASYNC_AL_GPIO_IN_MASK (((1 << 3) - 1) << 3) +#define ASYNC_AL_GPIO_IN (ASYNC_AL_GPIO_IN_MASK) + +#define AL_GPIO_I_OFFSET 6 +#define AL_GPIO_I_BITS 3 +#define AL_GPIO_I_MASK (((1 << 3) - 1) << 6) +#define AL_GPIO_I (AL_GPIO_I_MASK) + +/* Bits of R_AL_GPIO_CFG (0X0074) */ + +#define AL_GPIO_OE_OFFSET 0 +#define AL_GPIO_OE_BITS 3 +#define AL_GPIO_OE_MASK (((1 << 3) - 1) << 0) +#define AL_GPIO_OE (AL_GPIO_OE_MASK) + +#define AL_GPIO_OE2_OFFSET 3 +#define AL_GPIO_OE2_BITS 3 +#define AL_GPIO_OE2_MASK (((1 << 3) - 1) << 3) +#define AL_GPIO_OE2 (AL_GPIO_OE2_MASK) + +#define AL_GPIO_OE3_OFFSET 8 +#define AL_GPIO_OE3_BITS 3 +#define AL_GPIO_OE3_MASK (((1 << 3) - 1) << 8) +#define AL_GPIO_OE3 (AL_GPIO_OE3_MASK) + +#define AL_GPIO_SHDN_OFFSET 11 +#define AL_GPIO_SHDN_BITS 3 +#define AL_GPIO_SHDN_MASK (((1 << 3) - 1) << 11) +#define AL_GPIO_SHDN (AL_GPIO_SHDN_MASK) + +#define AL_GPIO_IEV18_OFFSET 16 +#define AL_GPIO_IEV18_BITS 3 +#define AL_GPIO_IEV18_MASK (((1 << 3) - 1) << 16) +#define AL_GPIO_IEV18 (AL_GPIO_IEV18_MASK) + +#define AL_GPIO_PU_CTRL_OFFSET 19 +#define AL_GPIO_PU_CTRL_BITS 3 +#define AL_GPIO_PU_CTRL_MASK (((1 << 3) - 1) << 19) +#define AL_GPIO_PU_CTRL (AL_GPIO_PU_CTRL_MASK) + +#define AL_GPIO_PD_CTRL_OFFSET 24 +#define AL_GPIO_PD_CTRL_BITS 3 +#define AL_GPIO_PD_CTRL_MASK (((1 << 3) - 1) << 24) +#define AL_GPIO_PD_CTRL (AL_GPIO_PD_CTRL_MASK) + +#define AL_GPIO_SEL_OFFSET 27 +#define AL_GPIO_SEL_BITS 3 +#define AL_GPIO_SEL_MASK (((1 << 3) - 1) << 27) +#define AL_GPIO_SEL (AL_GPIO_SEL_MASK) + +#define CS1_BRIDGE_EN_OFFSET 31 +#define CS1_BRIDGE_EN_BITS 1 +#define CS1_BRIDGE_EN_MASK (((1 << 1) - 1) << 31) +#define CS1_BRIDGE_EN (CS1_BRIDGE_EN_MASK) + +/* Bits of R_AL_GPIO_IRQ_EN (0X0078) */ + +#define AL_GPIO_INT_EN_FALL_OFFSET 0 +#define AL_GPIO_INT_EN_FALL_BITS 3 +#define AL_GPIO_INT_EN_FALL_MASK (((1 << 3) - 1) << 0) +#define AL_GPIO_INT_EN_FALL (AL_GPIO_INT_EN_FALL_MASK) + +#define AL_GPIO_INT_EN_RISE_OFFSET 3 +#define AL_GPIO_INT_EN_RISE_BITS 3 +#define AL_GPIO_INT_EN_RISE_MASK (((1 << 3) - 1) << 3) +#define AL_GPIO_INT_EN_RISE (AL_GPIO_INT_EN_RISE_MASK) + +/* Bits of R_AL_GPIO_IRQ (0X007C) */ + +#define AL_GPIO_INT_FALL_OFFSET 0 +#define AL_GPIO_INT_FALL_BITS 3 +#define AL_GPIO_INT_FALL_MASK (((1 << 3) - 1) << 0) +#define AL_GPIO_INT_FALL (AL_GPIO_INT_FALL_MASK) + +#define AL_GPIO_INT_RISE_OFFSET 3 +#define AL_GPIO_INT_RISE_BITS 3 +#define AL_GPIO_INT_RISE_MASK (((1 << 3) - 1) << 3) +#define AL_GPIO_INT_RISE (AL_GPIO_INT_RISE_MASK) + +/* Bits of R_AL_SENSOR_RST_CTL (0X0080) */ + +#define PAD_SENSOR_RSTN_I_OFFSET 0 +#define PAD_SENSOR_RSTN_I_BITS 1 +#define PAD_SENSOR_RSTN_I_MASK (((1 << 1) - 1) << 0) +#define PAD_SENSOR_RSTN_I (PAD_SENSOR_RSTN_I_MASK) + +#define SENSOR_RSTN_O_OFFSET 1 +#define SENSOR_RSTN_O_BITS 1 +#define SENSOR_RSTN_O_MASK (((1 << 1) - 1) << 1) +#define SENSOR_RSTN_O (SENSOR_RSTN_O_MASK) + +#define SENSOR_RSTN_OE0_OFFSET 2 +#define SENSOR_RSTN_OE0_BITS 1 +#define SENSOR_RSTN_OE0_MASK (((1 << 1) - 1) << 2) +#define SENSOR_RSTN_OE0 (SENSOR_RSTN_OE0_MASK) + +#define SENSOR_RSTN_OE2_OFFSET 3 +#define SENSOR_RSTN_OE2_BITS 1 +#define SENSOR_RSTN_OE2_MASK (((1 << 1) - 1) << 3) +#define SENSOR_RSTN_OE2 (SENSOR_RSTN_OE2_MASK) + +#define SENSOR_RSTN_OE3_OFFSET 4 +#define SENSOR_RSTN_OE3_BITS 1 +#define SENSOR_RSTN_OE3_MASK (((1 << 1) - 1) << 4) +#define SENSOR_RSTN_OE3 (SENSOR_RSTN_OE3_MASK) + +#define SENSOR_RSTN_IEV18_OFFSET 5 +#define SENSOR_RSTN_IEV18_BITS 1 +#define SENSOR_RSTN_IEV18_MASK (((1 << 1) - 1) << 5) +#define SENSOR_RSTN_IEV18 (SENSOR_RSTN_IEV18_MASK) + +#define SENSOR_RSTN_H3L1_OFFSET 6 +#define SENSOR_RSTN_H3L1_BITS 1 +#define SENSOR_RSTN_H3L1_MASK (((1 << 1) - 1) << 6) +#define SENSOR_RSTN_H3L1 (SENSOR_RSTN_H3L1_MASK) + +#define SENSOR_RSTN_PUE_OFFSET 7 +#define SENSOR_RSTN_PUE_BITS 1 +#define SENSOR_RSTN_PUE_MASK (((1 << 1) - 1) << 7) +#define SENSOR_RSTN_PUE (SENSOR_RSTN_PUE_MASK) + +#define SENSOR_RSTN_PDE_OFFSET 8 +#define SENSOR_RSTN_PDE_BITS 1 +#define SENSOR_RSTN_PDE_MASK (((1 << 1) - 1) << 8) +#define SENSOR_RSTN_PDE (SENSOR_RSTN_PDE_MASK) + +#define SENSOR_RSTN_GPIO_INT_EN_RISE_OFFSET 10 +#define SENSOR_RSTN_GPIO_INT_EN_RISE_BITS 1 +#define SENSOR_RSTN_GPIO_INT_EN_RISE_MASK (((1 << 1) - 1) << 10) +#define SENSOR_RSTN_GPIO_INT_EN_RISE (SENSOR_RSTN_GPIO_INT_EN_RISE_MASK) + +#define SENSOR_RSTN_GPIO_INT_EN_FALL_OFFSET 11 +#define SENSOR_RSTN_GPIO_INT_EN_FALL_BITS 1 +#define SENSOR_RSTN_GPIO_INT_EN_FALL_MASK (((1 << 1) - 1) << 11) +#define SENSOR_RSTN_GPIO_INT_EN_FALL (SENSOR_RSTN_GPIO_INT_EN_FALL_MASK) + +/* Bits of R_AL_SENSOR_SCS_N_CTL (0X0084) */ + +#define PAD_SENSOR_SCS_N_I_OFFSET 0 +#define PAD_SENSOR_SCS_N_I_BITS 1 +#define PAD_SENSOR_SCS_N_I_MASK (((1 << 1) - 1) << 0) +#define PAD_SENSOR_SCS_N_I (PAD_SENSOR_SCS_N_I_MASK) + +#define SENSOR_SCS_N_O_OFFSET 1 +#define SENSOR_SCS_N_O_BITS 1 +#define SENSOR_SCS_N_O_MASK (((1 << 1) - 1) << 1) +#define SENSOR_SCS_N_O (SENSOR_SCS_N_O_MASK) + +#define SENSOR_SCS_N_OE0_OFFSET 2 +#define SENSOR_SCS_N_OE0_BITS 1 +#define SENSOR_SCS_N_OE0_MASK (((1 << 1) - 1) << 2) +#define SENSOR_SCS_N_OE0 (SENSOR_SCS_N_OE0_MASK) + +#define SENSOR_SCS_N_OE2_OFFSET 3 +#define SENSOR_SCS_N_OE2_BITS 1 +#define SENSOR_SCS_N_OE2_MASK (((1 << 1) - 1) << 3) +#define SENSOR_SCS_N_OE2 (SENSOR_SCS_N_OE2_MASK) + +#define SENSOR_SCS_N_OE3_OFFSET 4 +#define SENSOR_SCS_N_OE3_BITS 1 +#define SENSOR_SCS_N_OE3_MASK (((1 << 1) - 1) << 4) +#define SENSOR_SCS_N_OE3 (SENSOR_SCS_N_OE3_MASK) + +#define SENSOR_SCS_N_IEV18_OFFSET 5 +#define SENSOR_SCS_N_IEV18_BITS 1 +#define SENSOR_SCS_N_IEV18_MASK (((1 << 1) - 1) << 5) +#define SENSOR_SCS_N_IEV18 (SENSOR_SCS_N_IEV18_MASK) + +#define SENSOR_SCS_N_H3L1_OFFSET 6 +#define SENSOR_SCS_N_H3L1_BITS 1 +#define SENSOR_SCS_N_H3L1_MASK (((1 << 1) - 1) << 6) +#define SENSOR_SCS_N_H3L1 (SENSOR_SCS_N_H3L1_MASK) + +#define SENSOR_SCS_N_PUE_OFFSET 7 +#define SENSOR_SCS_N_PUE_BITS 1 +#define SENSOR_SCS_N_PUE_MASK (((1 << 1) - 1) << 7) +#define SENSOR_SCS_N_PUE (SENSOR_SCS_N_PUE_MASK) + +#define SENSOR_SCS_N_PDE_OFFSET 8 +#define SENSOR_SCS_N_PDE_BITS 1 +#define SENSOR_SCS_N_PDE_MASK (((1 << 1) - 1) << 8) +#define SENSOR_SCS_N_PDE (SENSOR_SCS_N_PDE_MASK) + +#define SENSOR_SCS_N_SEL_OFFSET 9 +#define SENSOR_SCS_N_SEL_BITS 1 +#define SENSOR_SCS_N_SEL_MASK (((1 << 1) - 1) << 9) +#define SENSOR_SCS_N_SEL (SENSOR_SCS_N_SEL_MASK) + +#define SENSOR_SCS_N_GPIO_INT_EN_RISE_OFFSET 10 +#define SENSOR_SCS_N_GPIO_INT_EN_RISE_BITS 1 +#define SENSOR_SCS_N_GPIO_INT_EN_RISE_MASK (((1 << 1) - 1) << 10) +#define SENSOR_SCS_N_GPIO_INT_EN_RISE (SENSOR_SCS_N_GPIO_INT_EN_RISE_MASK) + +#define SENSOR_SCS_N_GPIO_INT_EN_FALL_OFFSET 11 +#define SENSOR_SCS_N_GPIO_INT_EN_FALL_BITS 1 +#define SENSOR_SCS_N_GPIO_INT_EN_FALL_MASK (((1 << 1) - 1) << 11) +#define SENSOR_SCS_N_GPIO_INT_EN_FALL (SENSOR_SCS_N_GPIO_INT_EN_FALL_MASK) + +/* Bits of R_GPIO_SVIO_CFG (0X008C) */ + +#define GPIO_SVIO_I_OFFSET 0 +#define GPIO_SVIO_I_BITS 1 +#define GPIO_SVIO_I_MASK (((1 << 1) - 1) << 0) +#define GPIO_SVIO_I (GPIO_SVIO_I_MASK) + +#define GPIO_SVIO_O_OFFSET 1 +#define GPIO_SVIO_O_BITS 1 +#define GPIO_SVIO_O_MASK (((1 << 1) - 1) << 1) +#define GPIO_SVIO_O (GPIO_SVIO_O_MASK) + +#define GPIO_SVIO_OE0_OFFSET 2 +#define GPIO_SVIO_OE0_BITS 1 +#define GPIO_SVIO_OE0_MASK (((1 << 1) - 1) << 2) +#define GPIO_SVIO_OE0 (GPIO_SVIO_OE0_MASK) + +#define GPIO_SVIO_OE2_OFFSET 3 +#define GPIO_SVIO_OE2_BITS 1 +#define GPIO_SVIO_OE2_MASK (((1 << 1) - 1) << 3) +#define GPIO_SVIO_OE2 (GPIO_SVIO_OE2_MASK) + +#define GPIO_SVIO_OE3_OFFSET 4 +#define GPIO_SVIO_OE3_BITS 1 +#define GPIO_SVIO_OE3_MASK (((1 << 1) - 1) << 4) +#define GPIO_SVIO_OE3 (GPIO_SVIO_OE3_MASK) + +#define GPIO_SVIO_H3L1_OFFSET 5 +#define GPIO_SVIO_H3L1_BITS 1 +#define GPIO_SVIO_H3L1_MASK (((1 << 1) - 1) << 5) +#define GPIO_SVIO_H3L1 (GPIO_SVIO_H3L1_MASK) + +#define GPIO_SVIO_IEV18_OFFSET 6 +#define GPIO_SVIO_IEV18_BITS 1 +#define GPIO_SVIO_IEV18_MASK (((1 << 1) - 1) << 6) +#define GPIO_SVIO_IEV18 (GPIO_SVIO_IEV18_MASK) + +#define GPIO_SVIO_PULLCTL_OFFSET 8 +#define GPIO_SVIO_PULLCTL_BITS 2 +#define GPIO_SVIO_PULLCTL_MASK (((1 << 2) - 1) << 8) +#define GPIO_SVIO_PULLCTL (GPIO_SVIO_PULLCTL_MASK) + +#define GPIO_SVIO_INT_EN_RISE_OFFSET 10 +#define GPIO_SVIO_INT_EN_RISE_BITS 1 +#define GPIO_SVIO_INT_EN_RISE_MASK (((1 << 1) - 1) << 10) +#define GPIO_SVIO_INT_EN_RISE (GPIO_SVIO_INT_EN_RISE_MASK) + +#define GPIO_SVIO_INT_EN_FALL_OFFSET 11 +#define GPIO_SVIO_INT_EN_FALL_BITS 1 +#define GPIO_SVIO_INT_EN_FALL_MASK (((1 << 1) - 1) << 11) +#define GPIO_SVIO_INT_EN_FALL (GPIO_SVIO_INT_EN_FALL_MASK) + +#endif /* ZEPHYR_DRIVERS_PINCTRL_RTS5817_REG_H_ */ diff --git a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi index 5950298e9455e..ad2cd5fc9acdb 100644 --- a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi +++ b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi @@ -55,6 +55,16 @@ #reset-cells = <1>; status = "disabled"; }; + + pinctrl: pinctrl@40110000 { + compatible = "realtek,rts5817-pinctrl"; + reg = <0x40110000 0x800>, + <0x401E2074 0x4>, + <0x401E2080 0xC>; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + }; }; }; diff --git a/dts/bindings/pinctrl/realtek,rts5817-pinctrl.yaml b/dts/bindings/pinctrl/realtek,rts5817-pinctrl.yaml new file mode 100644 index 0000000000000..1b7d53bdc8567 --- /dev/null +++ b/dts/bindings/pinctrl/realtek,rts5817-pinctrl.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Realtek RTS5817 series pin controller + +compatible: "realtek,rts5817-pinctrl" + +include: base.yaml + +child-binding: + description: RTS5817 pin controller pin group. + child-binding: + description: RTS5817 pin controller pin mux and configuration. + + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-disable + - bias-pull-down + - bias-pull-up + - input-enable + - output-enable + - drive-strength + - power-source + + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. Must + encode all the pin muxing information in a 32-bit value. From b8270de04e9a2eb800e2498ae6cb7160074e0da5 Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Tue, 5 Nov 2024 10:49:37 +0800 Subject: [PATCH 09/11] drivers: watchdog: add watchdog driver for RTS5817 Add watchdog driver for RTS5817 Signed-off-by: Darcy Lu --- drivers/watchdog/CMakeLists.txt | 1 + drivers/watchdog/Kconfig | 2 + drivers/watchdog/Kconfig.rts5817 | 10 ++ drivers/watchdog/wdt_rts5817.c | 151 ++++++++++++++++++ drivers/watchdog/wdt_rts5817.h | 62 +++++++ .../fingerprint/rts5817/rts5817_base.dtsi | 6 + .../watchdog/realtek,rts5817-watchdog.yaml | 13 ++ 7 files changed, 245 insertions(+) create mode 100644 drivers/watchdog/Kconfig.rts5817 create mode 100644 drivers/watchdog/wdt_rts5817.c create mode 100644 drivers/watchdog/wdt_rts5817.h create mode 100644 dts/bindings/watchdog/realtek,rts5817-watchdog.yaml diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index ab7dcabedc5fb..eb85a8237d800 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -54,6 +54,7 @@ zephyr_library_sources_ifdef(CONFIG_WWDT_NUMAKER wdt_wwdt_numaker.c) zephyr_library_sources_ifdef(CONFIG_WDT_ENE_KB106X wdt_ene_kb106x.c) zephyr_library_sources_ifdef(CONFIG_WDT_ENE_KB1200 wdt_ene_kb1200.c) zephyr_library_sources_ifdef(CONFIG_WDT_IWDG_WCH wdt_iwdg_wch.c) +zephyr_library_sources_ifdef(CONFIG_WDT_RTS5817 wdt_rts5817.c) zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c wdt_dw_common.c) zephyr_library_sources_ifdef(CONFIG_WDT_INTEL_ADSP wdt_intel_adsp.c wdt_dw_common.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 4fed392fd223c..70198746e1f85 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -157,4 +157,6 @@ source "drivers/watchdog/Kconfig.wch" source "drivers/watchdog/Kconfig.nxp_ewm" +source "drivers/watchdog/Kconfig.rts5817" + endif # WATCHDOG diff --git a/drivers/watchdog/Kconfig.rts5817 b/drivers/watchdog/Kconfig.rts5817 new file mode 100644 index 0000000000000..36ce4e0fc0431 --- /dev/null +++ b/drivers/watchdog/Kconfig.rts5817 @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config WDT_RTS5817 + bool "Realtek RTS5817 Watchdog driver" + default y + depends on DT_HAS_REALTEK_RTS5817_WATCHDOG_ENABLED + select HAS_WDT_DISABLE_AT_BOOT + help + Realtek RTS5817 watchdog driver. diff --git a/drivers/watchdog/wdt_rts5817.c b/drivers/watchdog/wdt_rts5817.c new file mode 100644 index 0000000000000..148840bf2cf5b --- /dev/null +++ b/drivers/watchdog/wdt_rts5817.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT realtek_rts5817_watchdog + +#include +#include +#include "wdt_rts5817.h" + +#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL +#include +LOG_MODULE_REGISTER(wdt_rts5817); + +#define WDOG_TIME_1S 0x0 +#define WDOG_TIME_2S 0x1 +#define WDOG_TIME_4S 0x2 +#define WDOG_TIME_8S 0x3 + +struct rts_fp_wdt_config { + mem_addr_t base; +}; + +static inline uint32_t rts_fp_read_reg(const struct device *dev) +{ + const struct rts_fp_wdt_config *config = dev->config; + + return sys_read32(config->base); +} + +static inline void rts_fp_write_reg(const struct device *dev, uint32_t value) +{ + const struct rts_fp_wdt_config *config = dev->config; + + sys_write32(value, config->base); +} + +static int rts_fp_wdt_setup(const struct device *dev, uint8_t options) +{ + uint32_t value; + + if ((options & WDT_OPT_PAUSE_IN_SLEEP) || (options & WDT_OPT_PAUSE_HALTED_BY_DBG)) { + LOG_ERR("Pause in sleep or halted by dbg is not supported"); + return -ENOTSUP; + } + + value = rts_fp_read_reg(dev); + value |= WDOG_EN; + rts_fp_write_reg(dev, value); + + return 0; +} + +static int rts_fp_wdt_disable(const struct device *dev) +{ + uint32_t value; + + value = rts_fp_read_reg(dev); + value &= ~WDOG_EN; + rts_fp_write_reg(dev, value); + + return 0; +} + +static int rts_fp_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg) +{ + uint32_t value; + + if (cfg->window.min > 0 || cfg->window.max > 8000) { + LOG_ERR("watchdog window.min should be equal to 0 and window.max should not exceed " + "8000"); + return -ENOTSUP; + } + + /* Set mode of watchdog and callback */ + switch (cfg->flags) { + case WDT_FLAG_RESET_NONE: + break; + + case WDT_FLAG_RESET_CPU_CORE: + case WDT_FLAG_RESET_SOC: + if (cfg->callback != NULL) { + LOG_ERR("watchdog callback is not supported"); + return -ENOTSUP; + } + + value = rts_fp_read_reg(dev); + value &= ~WDOG_TIME_MASK; + + if (cfg->window.max <= 1000) { + value |= WDOG_TIME_1S << WDOG_TIME_OFFSET; + } else if (cfg->window.max > 1000 && cfg->window.max <= 2000) { + value |= WDOG_TIME_2S << WDOG_TIME_OFFSET; + } else if (cfg->window.max > 2000 && cfg->window.max <= 4000) { + value |= WDOG_TIME_4S << WDOG_TIME_OFFSET; + } else if (cfg->window.max > 4000 && cfg->window.max <= 8000) { + value |= WDOG_TIME_8S << WDOG_TIME_OFFSET; + } else { + return -ENOTSUP; + } + + rts_fp_write_reg(dev, value); + + break; + + default: + LOG_ERR("unknown watchdog flags"); + return -EINVAL; + } + + return 0; +} + +static int rts_fp_wdt_feed(const struct device *dev, int channel_id) +{ + uint32_t value; + + value = rts_fp_read_reg(dev); + value |= WDOG_CLR; + rts_fp_write_reg(dev, value); + + return 0; +} + +static int rts_fp_wdt_init(const struct device *dev) +{ + /* Note: Watchdog is enabled by default for rts5817. + * so CONFIG_WDT_DISABLE_AT_BOOT needs to be selected by default + */ + + if (IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) { + rts_fp_wdt_disable(dev); + } + return 0; +} + +static const struct wdt_driver_api rts_fp_wdt_driver_api = { + .setup = rts_fp_wdt_setup, + .disable = rts_fp_wdt_disable, + .install_timeout = rts_fp_wdt_install_timeout, + .feed = rts_fp_wdt_feed, +}; + +const struct rts_fp_wdt_config rts_fp_config = { + .base = DT_INST_REG_ADDR(0), +}; + +DEVICE_DT_INST_DEFINE(0, &rts_fp_wdt_init, NULL, NULL, &rts_fp_config, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &rts_fp_wdt_driver_api); diff --git a/drivers/watchdog/wdt_rts5817.h b/drivers/watchdog/wdt_rts5817.h new file mode 100644 index 0000000000000..d15ae1874d067 --- /dev/null +++ b/drivers/watchdog/wdt_rts5817.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_WATCHDOG_WDT_RTS_RTS5817_H_ +#define ZEPHYR_DRIVERS_WATCHDOG_WDT_RTS_RTS5817_H_ + +/* Bits of R_WTDG_CTRL (0X0048) */ + +#define WDOG_EN_OFFSET 0 +#define WDOG_EN_BITS 1 +#define WDOG_EN_MASK (((1 << 1) - 1) << 0) +#define WDOG_EN (WDOG_EN_MASK) + +#define WDOG_CLR_OFFSET 1 +#define WDOG_CLR_BITS 1 +#define WDOG_CLR_MASK (((1 << 1) - 1) << 1) +#define WDOG_CLR (WDOG_CLR_MASK) + +#define WDOG_TIME_OFFSET 2 +#define WDOG_TIME_BITS 2 +#define WDOG_TIME_MASK (((1 << 2) - 1) << 2) +#define WDOG_TIME (WDOG_TIME_MASK) + +#define WDOG_REG_RST_EN_OFFSET 4 +#define WDOG_REG_RST_EN_BITS 1 +#define WDOG_REG_RST_EN_MASK (((1 << 1) - 1) << 4) +#define WDOG_REG_RST_EN (WDOG_REG_RST_EN_MASK) + +#define WDOG_BUS_RST_EN_OFFSET 5 +#define WDOG_BUS_RST_EN_BITS 1 +#define WDOG_BUS_RST_EN_MASK (((1 << 1) - 1) << 5) +#define WDOG_BUS_RST_EN (WDOG_BUS_RST_EN_MASK) + +#define WDOG_INT_EN_OFFSET 6 +#define WDOG_INT_EN_BITS 1 +#define WDOG_INT_EN_MASK (((1 << 1) - 1) << 6) +#define WDOG_INT_EN (WDOG_INT_EN_MASK) + +#define WDOG_INT_CLR_OFFSET 7 +#define WDOG_INT_CLR_BITS 1 +#define WDOG_INT_CLR_MASK (((1 << 1) - 1) << 7) +#define WDOG_INT_CLR (WDOG_INT_CLR_MASK) + +#define WDOG_INT_OFFSET 8 +#define WDOG_INT_BITS 1 +#define WDOG_INT_MASK (((1 << 1) - 1) << 8) +#define WDOG_INT (WDOG_INT_MASK) + +#define WDOG_INT_SEL_OFFSET 9 +#define WDOG_INT_SEL_BITS 1 +#define WDOG_INT_SEL_MASK (((1 << 1) - 1) << 9) +#define WDOG_INT_SEL (WDOG_INT_SEL_MASK) + +#define WDOG_CNT_OFFSET 16 +#define WDOG_CNT_BITS 16 +#define WDOG_CNT_MASK (((1 << 16) - 1) << 16) +#define WDOG_CNT (WDOG_CNT_MASK) + +#endif /* ZEPHYR_DRIVERS_WATCHDOG_WDT_RTS_RTS5817_H_ */ diff --git a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi index ad2cd5fc9acdb..0ea3baa876bca 100644 --- a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi +++ b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi @@ -65,6 +65,12 @@ #size-cells = <1>; status = "okay"; }; + + watchdog: watchdog@40100048 { + compatible = "realtek,rts5817-watchdog"; + reg = <0x40100048 0x4>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/watchdog/realtek,rts5817-watchdog.yaml b/dts/bindings/watchdog/realtek,rts5817-watchdog.yaml new file mode 100644 index 0000000000000..b440dea52b046 --- /dev/null +++ b/dts/bindings/watchdog/realtek,rts5817-watchdog.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Realtek RTS5817 Watchdog driver + +compatible: "realtek,rts5817-watchdog" + +include: base.yaml + +properties: + reg: + required: true From ffe45678387e2c577d8d4e1e5340f7ab2d31b70e Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Tue, 3 Jun 2025 15:40:47 +0800 Subject: [PATCH 10/11] boards: realtek: add rts5817_maa_evb board Add support for rts5817_maa_evb board Signed-off-by: Darcy Lu --- .../rts5817_maa_evb/Kconfig.rts5817_maa_evb | 5 ++ boards/realtek/rts5817_maa_evb/board.cmake | 7 ++ boards/realtek/rts5817_maa_evb/board.yml | 8 +++ .../doc/img/rts5817_maa_evb.webp | Bin 0 -> 57338 bytes boards/realtek/rts5817_maa_evb/doc/index.rst | 63 ++++++++++++++++++ .../rts5817_maa_evb-pinctrl.dtsi | 37 ++++++++++ .../rts5817_maa_evb/rts5817_maa_evb.dts | 43 ++++++++++++ .../rts5817_maa_evb/rts5817_maa_evb.yaml | 15 +++++ .../rts5817_maa_evb/rts5817_maa_evb_defconfig | 17 +++++ .../fingerprint/rts5817/rts5817_base.dtsi | 22 ++++++ 10 files changed, 217 insertions(+) create mode 100644 boards/realtek/rts5817_maa_evb/Kconfig.rts5817_maa_evb create mode 100644 boards/realtek/rts5817_maa_evb/board.cmake create mode 100644 boards/realtek/rts5817_maa_evb/board.yml create mode 100644 boards/realtek/rts5817_maa_evb/doc/img/rts5817_maa_evb.webp create mode 100644 boards/realtek/rts5817_maa_evb/doc/index.rst create mode 100644 boards/realtek/rts5817_maa_evb/rts5817_maa_evb-pinctrl.dtsi create mode 100644 boards/realtek/rts5817_maa_evb/rts5817_maa_evb.dts create mode 100644 boards/realtek/rts5817_maa_evb/rts5817_maa_evb.yaml create mode 100644 boards/realtek/rts5817_maa_evb/rts5817_maa_evb_defconfig diff --git a/boards/realtek/rts5817_maa_evb/Kconfig.rts5817_maa_evb b/boards/realtek/rts5817_maa_evb/Kconfig.rts5817_maa_evb new file mode 100644 index 0000000000000..59e334d3feef5 --- /dev/null +++ b/boards/realtek/rts5817_maa_evb/Kconfig.rts5817_maa_evb @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RTS5817_MAA_EVB + select SOC_RTS5817 diff --git a/boards/realtek/rts5817_maa_evb/board.cmake b/boards/realtek/rts5817_maa_evb/board.cmake new file mode 100644 index 0000000000000..99b2089132d16 --- /dev/null +++ b/boards/realtek/rts5817_maa_evb/board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 +set_property(TARGET runners_yaml_props_target PROPERTY bin_file zephyr.rts5817.bin) + +board_set_flasher_ifnset(rtsflash) +board_runner_args(rtsflash "--pid=0bda:5817" "--alt=0") +board_finalize_runner_args(rtsflash) diff --git a/boards/realtek/rts5817_maa_evb/board.yml b/boards/realtek/rts5817_maa_evb/board.yml new file mode 100644 index 0000000000000..5f40fd9adff0a --- /dev/null +++ b/boards/realtek/rts5817_maa_evb/board.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +board: + name: rts5817_maa_evb + vendor: realtek + socs: + - name: rts5817 diff --git a/boards/realtek/rts5817_maa_evb/doc/img/rts5817_maa_evb.webp b/boards/realtek/rts5817_maa_evb/doc/img/rts5817_maa_evb.webp new file mode 100644 index 0000000000000000000000000000000000000000..a4e48cc8d6fea474fadd2e9986e36c5231a864b1 GIT binary patch literal 57338 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 H2mk;8NFu}m literal 0 HcmV?d00001 diff --git a/boards/realtek/rts5817_maa_evb/doc/index.rst b/boards/realtek/rts5817_maa_evb/doc/index.rst new file mode 100644 index 0000000000000..905fda4a7bcc0 --- /dev/null +++ b/boards/realtek/rts5817_maa_evb/doc/index.rst @@ -0,0 +1,63 @@ +.. zephyr:board:: rts5817_maa_evb + +Overview +******** + +rts5817 is a high-performance MCU based on Realtek Real-M300 ARMv8-M architecture with Cortex-M33 instruction set compatible. + +.. figure:: img/rts5817_maa_evb.webp + :width: 400px + :align: center + :alt: rts5817_maa_evb + +Hardware +******** + +- 240MHz single-core 32-bit CPU with I-cache 32KB, D-cache 16KB +- 48KB boot ROM +- 256KB on-chip SRAM +- 1KB PUFrt OTP +- 2MB Flash +- USB2.0 full speed/high speed device +- Up to 11 GPIO +- 2 x UART +- 2 x Timer +- 2 x SPI, one can support slave mode +- Watchdog +- DMA +- Temperature sensor +- Cryptographic hardware acceleration (RNG, SHA, AES) +- Fingerprint mataching hardware acceleration (MAC, popcount, convolution, etc.) +- SWD for debug + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Programming and Debugging +************************* + +Building +======== + +#. Build :zephyr:code-sample:`hello_world` application as you would normally do. + +#. The file ``zephyr.rts5817.bin`` will be created if the build system can build successfully. + This binary image can be found under file "build/zephyr/". + +Flashing +======== + +#. Short the two pins of ``J6`` to enter force rom mode (see `RTS5817MAA_EVB_User_Guide`_). +#. Connect the board to your host computer using USB. +#. Use ``west flash`` command to flash the image. +#. Disconnect the two pins of ``J6`` and reboot, The :zephyr:code-sample:`hello_world` application is running. + +References +********** + +.. target-notes:: + +.. _RTS5817MAA_EVB_User_Guide: + https://github.com/RtkFP/Doc/blob/main/RTS5817MAA_EVB%20User%20Guide_V1.0.pdf diff --git a/boards/realtek/rts5817_maa_evb/rts5817_maa_evb-pinctrl.dtsi b/boards/realtek/rts5817_maa_evb/rts5817_maa_evb-pinctrl.dtsi new file mode 100644 index 0000000000000..552856f908859 --- /dev/null +++ b/boards/realtek/rts5817_maa_evb/rts5817_maa_evb-pinctrl.dtsi @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart0_default: uart0_default { + group0 { + pinmux = , ; + }; + }; + + /omit-if-no-ref/ sensor_spi_default: sensor_spi_default { + group0 { + pinmux = , , + ; + power-source = ; + bias-pull-down; + }; + + group1 { + pinmux = , ; + power-source = ; + bias-pull-up; + }; + }; + + /omit-if-no-ref/ ssi_master_default: ssi_master_default { + group0 { + pinmux = , , + , ; + bias-pull-down; + }; + }; +}; diff --git a/boards/realtek/rts5817_maa_evb/rts5817_maa_evb.dts b/boards/realtek/rts5817_maa_evb/rts5817_maa_evb.dts new file mode 100644 index 0000000000000..390f81ce11d3c --- /dev/null +++ b/boards/realtek/rts5817_maa_evb/rts5817_maa_evb.dts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Realtek Semiconductor, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "rts5817_maa_evb-pinctrl.dtsi" + +/ { + model = "Realtek rts5817_maa_evb"; + compatible = "realtek,rts5817_maa_evb"; + #address-cells = <1>; + #size-cells = <1>; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; +}; + +&clks { + status = "okay"; +}; + +&reset { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_default>; + current-speed = <57600>; + status = "okay"; +}; + +&uart1 { + status = "disabled"; +}; diff --git a/boards/realtek/rts5817_maa_evb/rts5817_maa_evb.yaml b/boards/realtek/rts5817_maa_evb/rts5817_maa_evb.yaml new file mode 100644 index 0000000000000..e33be64c4d61c --- /dev/null +++ b/boards/realtek/rts5817_maa_evb/rts5817_maa_evb.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +identifier: rts5817_maa_evb +name: RTS5817 Platform for fingerprint +type: mcu +arch: arm +ram: 256 +flash: 2048 +toolchain: + - zephyr + - gnuarmemb +testing: + default: true +vendor: realtek diff --git a/boards/realtek/rts5817_maa_evb/rts5817_maa_evb_defconfig b/boards/realtek/rts5817_maa_evb/rts5817_maa_evb_defconfig new file mode 100644 index 0000000000000..7d0bcb05f3744 --- /dev/null +++ b/boards/realtek/rts5817_maa_evb/rts5817_maa_evb_defconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2024 Realtek Semiconductor, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Enable clocks +CONFIG_CLOCK_CONTROL=y + +# Enable reset +CONFIG_RESET=y + +# Enable serial console +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable watchdog +CONFIG_WATCHDOG=y +CONFIG_WDT_DISABLE_AT_BOOT=y diff --git a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi index 0ea3baa876bca..d40be08377741 100644 --- a/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi +++ b/dts/arm/realtek/fingerprint/rts5817/rts5817_base.dtsi @@ -71,6 +71,28 @@ reg = <0x40100048 0x4>; status = "disabled"; }; + + uart0: dwapb@40120000 { + compatible = "ns16550"; + reg = <0x40120000 0x100>; + reg-shift = <2>; + interrupt-parent = <&nvic>; + interrupts = ; + clocks = <&clks RTS_FP_CLK_UART0>; + resets = <&reset SYS_FORCE_RST_UART0>; + status = "disabled"; + }; + + uart1: dwapb@40128000 { + compatible = "ns16550"; + reg = <0x40128000 0x100>; + reg-shift = <2>; + interrupt-parent = <&nvic>; + interrupts = ; + clocks = <&clks RTS_FP_CLK_UART1>; + resets = <&reset SYS_FORCE_RST_UART1>; + status = "disabled"; + }; }; }; From 867caa7c97872703c52c358eadb11694f0e4c825 Mon Sep 17 00:00:00 2001 From: Darcy Lu Date: Mon, 9 Jun 2025 13:55:32 +0800 Subject: [PATCH 11/11] MAINTAINERS: add maintainer for Realtek fingerprint SoC This commit adds maintainer of Realtek fingerprint SoC to maintainers.yml Signed-off-by: Darcy Lu --- MAINTAINERS.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 240b34c9a0d0e..1881e85171c95 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4169,6 +4169,19 @@ OpenTitan Platforms: description: >- OpenTitan boards, SOCs, dts files and related drivers. +Realtek Fingerprint Platforms: + status: maintained + maintainers: + - RtkFP + files: + - boards/realtek/rts5817_maa_evb/ + - drivers/*/*rts5817* + - dts/bindings/*/*rts5817* + - dts/arm/realtek/fingerprint/ + - soc/realtek/fingerprint/ + labels: + - "platform: Realtek Fingerprint" + Realtek EC Platforms: status: maintained maintainers: