From 7f899a34463a233ec574c7a53a3674bcf7ef5899 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Fri, 8 Aug 2025 19:08:45 +0800 Subject: [PATCH] Add sys code from rt-thread --- .../board/ch569w/third_party_driver/Makefile | 2 + .../Peripheral/inc/CH56xSFR.h | 2 + .../third_party_driver/include/connect_soc.h | 98 +++++ .../third_party_driver/include/connect_sys.h | 396 ++++++++++++++++++ .../ch569w/third_party_driver/sys/Makefile | 3 + .../third_party_driver/sys/connect_sys.c | 280 +++++++++++++ 6 files changed, 781 insertions(+) create mode 100644 Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/include/connect_soc.h create mode 100644 Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/include/connect_sys.h create mode 100644 Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/sys/Makefile create mode 100644 Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/sys/connect_sys.c diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Makefile b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Makefile index 7b5f34c94..0bf187997 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Makefile @@ -1,5 +1,7 @@ SRC_DIR := Peripheral +SRC_DIR += sys + ifeq ($(CONFIG_BSP_USING_UART),y) SRC_DIR += uart endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Peripheral/inc/CH56xSFR.h b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Peripheral/inc/CH56xSFR.h index 8555a966d..6bbaf7021 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Peripheral/inc/CH56xSFR.h +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/Peripheral/inc/CH56xSFR.h @@ -1341,6 +1341,7 @@ extern "C" { #ifndef TABLE_IRQN typedef enum IRQn { + PWMX_OFFn = 0, Reset_IRQn = 1, NMI_IRQn = 2, /*!< Non Maskable Interrupt */ EXC_IRQn = 3, /*!< Exceptions Interrupt */ @@ -1367,6 +1368,7 @@ typedef enum IRQn ETH_IRQn = 34, PMT_IRQn = 35, ECDC_IRQn = 36, + END_OF_IRQn } IRQn_Type; #endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/include/connect_soc.h b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/include/connect_soc.h new file mode 100644 index 000000000..fde7751fb --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/include/connect_soc.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-07-15 Emuzit first version + */ +#ifndef __CONNECT_SOC_H__ +#define __CONNECT_SOC_H__ + +#include +#include +#include + +#if !defined(SOC_CH567) && \ + !defined(SOC_CH568) && \ + !defined(SOC_SERIES_CH569) +#define SOC_SERIES_CH569 +#endif + +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +//#define CHECK_STRUCT_SIZE(s, size) \ +// static_assert(sizeof(s) == size, #s " has wrong size") + +#define BITS_SET(x, bits) do x |= bits; while(0) +#define BITS_CLR(x, bits) do x &= ~bits; while(0) + +#define FLASH_BASE_ADDRESS 0x00000000 +#define RAMS_BASE_ADDRESS 0x20000000 +#define BUS8_BASE_ADDRESS 0x80000000 + +#ifdef SOC_SERIES_CH569 +#define RAMX_BASE_ADDRESS 0x20020000 +#define RAMS_SIZE 16 +#else +#define RAMS_SIZE 32 +#endif +#define RAMS_END (RAMS_BASE_ADDRESS + RAMS_SIZE * 1024) + +#define SYS_REG_BASE 0x40001000 +#define GPIO_REG_BASE 0x40001000 +#define GPIO_REG_BASE_PA 0x40001040 +#define GPIO_REG_BASE_PB 0x40001060 + +#define GPIO_PORTS 2 // 2 ports : PA & PB +#define GPIO_PA_PIN_START 0 // PA : pin number 0~31 +#define GPIO_PB_PIN_START 32 // PB : pin number 32~63 + +#ifdef SOC_SERIES_CH569 +#define GPIO_PA_PIN_MARK 0x00ffffff // PA : bits 0~23 +#define GPIO_PB_PIN_MARK 0x01ffffff // PB : bits 0~24 +#else +#define GPIO_PA_PIN_MARK 0x0000ffff // PA : bits 0~15 +#define GPIO_PB_PIN_MARK 0x00003fff // PB : bits 0~13 +#endif + +#define TMR0_REG_BASE 0x40002000 +#define TMR1_REG_BASE 0x40002400 +#define TMR2_REG_BASE 0x40002800 + +#define UART0_REG_BASE 0x40003000 +#define UART1_REG_BASE 0x40003400 +#define UART2_REG_BASE 0x40003800 +#define UART3_REG_BASE 0x40003c00 + +#define SPI0_REG_BASE 0x40004000 +#define SPI1_REG_BASE 0x40004400 + +#define PWMX_REG_BASE 0x40005000 + +#define PFIC_REG_BASE 0xe000e000 +#define SysTick_REG_BASE 0xe000f000 + +#ifdef SOC_SERIES_CH569 +#define HSPI_REG_BASE 0x40006000 // CH569W +#define ECDC_REG_BASE 0x40007000 +#define USBSS_REG_BASE 0x40008000 +#define USBHS_REG_BASE 0x40009000 +#define EMMC_REG_BASE 0x4000a000 +#define SERDES_REG_BASE 0x4000b000 +#define ETH_REG_BASE 0x4000c000 // CH565W/CH569W +#define DVP_REG_BASE 0x4000e000 // CH565W/CH565M +#else +#define LED_REG_BASE 0x40006000 +#define USB0_REG_BASE 0x40008000 // CH567 +#define USB1_REG_BASE 0x40009000 // CH567 +#define USB_REG_BASE 0x40009000 // CH568 +#define SDC_REG_BASE 0x4000a000 +#define SATA_REG_BASE 0x4000b000 // CH568 +#define ECDC_REG_BASE 0x4000c400 +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/include/connect_sys.h b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/include/connect_sys.h new file mode 100644 index 000000000..450e162f8 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/include/connect_sys.h @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-07-15 Emuzit first version + */ +#ifndef __CONNECT_SYS_H__ +#define __CONNECT_SYS_H__ + +#include "connect_soc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define sys_safe_access_enter(sys) \ + do { \ + sys->SAFE_ACCESS_SIG.reg = SAFE_ACCESS_SIG_1; \ + sys->SAFE_ACCESS_SIG.reg = SAFE_ACCESS_SIG_2; \ + } while(0) + +#define sys_safe_access_leave(sys) \ + do sys->SAFE_ACCESS_SIG.reg = 0; while(0) + +union _sys_safe_access_sig +{ + uint8_t reg; + struct + { + uint8_t safe_acc_mode : 2; // RO, current safe access, 11b => RWA ok + uint8_t resv_2 : 2; + uint8_t safe_acc_timer : 3; // RO, current safe access time count + uint8_t resv_7 : 1; + }; +}; +#define RB_SAFE_ACC_MODE 0x03 +#define RB_SAFE_ACC_TIMER 0x70 + +#define SAFE_ACCESS_SIG_1 0x57 +#define SAFE_ACCESS_SIG_2 0xa8 + +union _sys_glob_rom_cfg +{ + uint8_t reg; + struct + { + uint8_t rom_ext_re : 1; // RO, allow programmer to read FlashROM + uint8_t code_ram_we : 1; // RWA, code SRAM writaboe + uint8_t rom_data_we : 1; // RWA, FlashROM data erasable/writable + uint8_t rom_code_we : 1; // RWA, FlashROM code erasable/writable + uint8_t rom_code_ofs : 1; // RWA, FlashROM offset for user code + uint8_t resv_5 : 3; + }; +}; +#define RB_ROM_EXT_RE 0x01 +#define RB_CODE_RAM_WE 0x02 +#define RB_ROM_DATA_WE 0x04 +#define RB_ROM_CODE_WE 0x08 +#define RB_ROM_CODE_OFS 0x10 + +#define ROM_CODE_OFS_0x00000 0 +#define ROM_CODE_OFS_0x04000 1 + +union _sys_rst_boot_stat +{ + uint8_t reg; + struct + { + uint8_t reset_flag : 2; // RO, last reset cause + uint8_t cfg_reset_en : 1; // RO, external reset pin (#RST) status + uint8_t cfg_boot_en : 1; // RO, reset as 1 + uint8_t cfg_debug_en : 1; // RO + uint8_t boot_loader : 1; // RO + uint8_t resv_6 : 2; + }; +}; +#define RB_RESET_FLAG 0x03 +#define RB_CFG_RESET_EN 0x04 +#define RB_CFG_BOOT_EN 0x08 +#define RB_CFG_DEBUG_EN 0x10 +#define RB_BOOT_LOADER 0x20 + +#define RESET_FLAG_IS_SOFT 0 +#define RESET_FLAG_IS_POR 1 +#define RESET_FLAG_IS_WDOG 2 +#define RESET_FLAG_IS_RSTPIN 3 + +union _sys_rst_wdog_ctrl +{ + uint8_t reg; + struct + { + uint8_t software_reset : 1; // WA/WZ, system software reset, auto clear +#if defined(SOC_SERIES_CH569) + uint8_t wdog_rst_en : 1; // RWA, enable watchdog overflow to reset + uint8_t wdog_int_en : 1; // RWA, enable watchdog overflow interrupt + uint8_t wdog_int_flag : 1; // RW1, watchdog counter overflow +#else + uint8_t resv_2 : 3; +#endif + uint8_t resv_4 : 4; // RO, B.7-6 must write 01b + }; +}; +#define RB_SOFTWARE_RESET 0x01 +#ifdef SOC_SERIES_CH569 +#define RB_WDOG_RST_EN 0x02 +#define RB_WDOG_INT_EN 0x04 +#define RB_WDOG_INT_FLAG 0x08 +#endif +#define wdog_ctrl_wdat(v) (0x40 | (v)) + +union _sys_clk_pll_div +{ + uint8_t reg; + struct + { + uint8_t pll_div : 4; // RWA, min 2 + uint8_t resv_4 : 4; // RWA, B.7-6 must write 01b + }; +}; +#define clk_pll_div_wdat(div) (0x40 | (div)) + +union _sys_clk_cfg_ctrl +{ + uint8_t reg; + struct + { + uint8_t pll_sleep : 1; // RWA, PLL sleep control + uint8_t sel_pll : 1; // RWA, clock source select + uint8_t resv_6 : 6; // RWA, must write 10b + }; +}; +#define RB_CLK_PLL_SLEEP 0x01 +#define RB_CLK_SEL_PLL 0x02 + +#define CLK_PLL_SLEEP_DISABLE 0 +#define CLK_PLL_SLEEP_ENABLE 1 +#define CLK_SEL_PLL_HSE_30M 0 +#define CLK_SEL_PLL_USB_480M 1 +#define clk_cfg_ctrl_wdat(v) (0x80 | (v)) + +union _sys_clk_mod_aux +{ + uint8_t reg; + struct + { + uint8_t int_125m_en : 1; // RWA, USB PHY 125MHz to ETH + uint8_t ext_125m_en : 1; // RWA, external 125MHz to ETH + uint8_t mco_sel_msk : 2; // RWA, MCO output select + uint8_t mco_en : 1; // RWA, MCO output enable + uint8_t resv_5 : 3; + }; +}; +#define RB_INT_125M_EN 0x01 +#define RB_EXT_125M_EN 0x02 +#define RB_MCO_SEL_MSK 0x0C +#define RB_MCO_EN 0x10 + +#define MCO_SEL_MSK_125M 0 +#define MCO_SEL_MSK_25M 1 +#define MCO_SEL_MSK_2_5M 2 + +/* All bits are RWA (need safe_access_sig), 0/1 : clock on/off +*/ +union _sys_slp_clk_off0 +{ + uint8_t reg; + struct + { + uint8_t tmr0 : 1; + uint8_t tmr1 : 1; + uint8_t tmr2 : 1; + uint8_t pwmx : 1; + uint8_t uart0 : 1; + uint8_t uart1 : 1; + uint8_t uart2 : 1; + uint8_t uart3 : 1; + }; +}; +#define RB_SLP_CLK_TMR0 0x01 +#define RB_SLP_CLK_TMR1 0x02 +#define RB_SLP_CLK_TMR2 0x04 +#define RB_SLP_CLK_PWMX 0x08 +#define RB_SLP_CLK_UART0 0x10 +#define RB_SLP_CLK_UART1 0x20 +#define RB_SLP_CLK_UART2 0x40 +#define RB_SLP_CLK_UART3 0x80 + +#define SYS_SLP_CLK_ON 0 +#define SYS_SLP_CLK_OFF 1 + +/* All writable bits are RWA (need safe_access_sig), 0/1 : clock on/off +*/ +union _sys_slp_clk_off1 +{ + uint8_t reg; + struct + { + uint8_t spi0 : 1; + uint8_t spi1 : 1; +#if defined(SOC_CH567) + uint8_t sdc : 1; + uint8_t led : 1; + uint8_t usb0 : 1; + uint8_t usb1 : 1; + uint8_t resv_6 : 1; +#elif defined(SOC_CH568) + uint8_t sdc : 1; + uint8_t led : 1; + uint8_t resv_4 : 1; + uint8_t usb1 : 1; + uint8_t sata : 1; + uint8_t ecdc : 1; +#else + uint8_t emmc : 1; + uint8_t hspi : 1; + uint8_t usbhs : 1; + uint8_t usbss : 1; + uint8_t serd : 1; + uint8_t dvp : 1; +#endif + }; +}; +#define RB_SLP_CLK_SPI0 0x01 +#define RB_SLP_CLK_SPI1 0x02 +#if defined(SOC_WCH_CH567) +#define RB_SLP_CLK_SDC 0x04 +#define RB_SLP_CLK_LED 0x08 +#define RB_SLP_CLK_USB0 0x10 +#define RB_SLP_CLK_USB1 0x20 +#define RB_SLP_CLK_ECDC 0x80 +#elif defined(SOC_WCH_CH568) +#define RB_SLP_CLK_SDC 0x04 +#define RB_SLP_CLK_LED 0x08 +#define RB_SLP_CLK_USB1 0x20 +#define RB_SLP_CLK_SATA 0x40 +#define RB_SLP_CLK_ECDC 0x80 +#else +#define RB_SLP_CLK_EMMC 0x04 +#define RB_SLP_CLK_HSPI 0x08 +#define RB_SLP_CLK_USBHS 0x10 +#define RB_SLP_CLK_USBSS 0x20 +#define RB_SLP_CLK_SERD 0x40 +#define RB_SLP_CLK_DVP 0x80 +#endif + +/* All writable bits are RWA (need safe_access_sig) +*/ +union _sys_slp_wake_ctrl +{ + uint8_t reg; + struct + { +#if defined(SOC_WCH_CH567) + uint8_t usb0_wake : 1; + uint8_t usb1_wake : 1; + uint8_t resv_2 : 2; + uint8_t gpio_wake : 1; + uint8_t resv_5 : 3; +#elif defined(SOC_WCH_CH568) + uint8_t resv_0 : 1; + uint8_t usb1_wake : 1; + uint8_t sata_wake : 1; + uint8_t resv_3 : 1; + uint8_t gpio_wake : 1; + uint8_t resv_5 : 3; +#else + uint8_t usbhs_wake : 1; + uint8_t usbss_wake : 1; + uint8_t clk_eth : 1; + uint8_t clk_ecdc : 1; + uint8_t gpio_wake : 1; + uint8_t eth_wake : 1; + uint8_t resv_6 : 2; +#endif + }; +}; +#if defined(SOC_WCH_CH567) +#define RB_SLP_USB0_WAKE 0x01 +#define RB_SLP_USB1_WAKE 0x02 +#define RB_SLP_GPIO_WAKE 0x10 +#elif defined(SOC_WCH_CH568) +#define RB_SLP_USB1_WAKE 0x02 +#define RB_SLP_SATA_WAKE 0x04 +#define RB_SLP_GPIO_WAKE 0x10 +#else +#define RB_SLP_USBHS_WAKE 0x01 +#define RB_SLP_USBSS_WAKE 0x02 +#define RB_SLP_CLK_ETH 0x04 +#define RB_SLP_CLK_ECDC 0x08 +#define RB_SLP_GPIO_WAKE 0x10 +#define RB_SLP_ETH_WAKE 0x20 +#endif + +union _sys_slp_power_ctrl +{ + uint8_t reg; + struct + { + uint8_t usbhs_pwrdn : 1; // RWA, USBHS power down (0:PWRUP) + uint8_t resv_2 : 7; + }; +}; +#define RB_SLP_USBHS_PWRDN 0x01 + +union _sys_serd_ana_cfg1 +{ + uint16_t reg; + struct + { + uint8_t serd_pll_cfg; // RWA, reset as 0x5a + uint8_t serd_30m_sel : 1; // RWA + uint8_t serd_dn_tst : 1; // RWA + uint8_t resv_10 : 6; + }; +}; +#define RB_SERD_PLL_CFG 0x0ff +#define RB_SERD_30M_SEL 0x100 +#define RB_SERD_DN_TST 0x200 + +union _sys_serd_ana_cfg2 +{ + uint32_t reg; + struct + { + uint32_t serd_trx_cfg : 25; // RWA, reset as 423015h + uint32_t resv_25 : 7; + }; +}; +#define RB_SERD_TRX_CFG 0x1000000 + +/* + * 0x00 R8_SAFE_ACCESS_SIG: safe access signature register + * 0x01 R8_CHIP_ID: RF, chip ID register + * 0x02 R8_SAFE_ACCESS_ID: RF, read as 02h + * 0x03 R8_WDOG_COUNT RW, watchdog counter + * 0x04 R8_GLOB_ROM_CFG: ROM config register + * 0x05 R8_RST_BOOT_STAT: RO, boot state register + * 0x06 R8_RST_WDOG_CTRL: software reset & watchdog control register + * 0x07 R8_GLOB_RESET_KEEP: RW, only power-on-reset can clear this register + * 0x08 R8_CLK_PLL_DIV: RWA, PLL output divisor register + * 0x0a R8_CLK_CFG_CTRL: RWA, clock config register + * 0x0b R8_CLK_MOD_AUX: RWA, clock auxiliary register + * 0x0c R8_SLP_CLK_OFF0: RWA, sleep control register 0 + * 0x0d R8_SLP_CLK_OFF1: RWA, sleep control register 1 + * 0x0e R8_SLP_WAKE_CTRL: RWA, wakeup control register + * 0x0f R8_SLP_POWER_CTRL: RWA, low power management register + * 0x20 R16_SERD_ANA_CFG1: RWA, SerDes PHY analog param config register 1 + * 0x24 R32_SERD_ANA_CFG2: RWA, SerDes PHY analog param config register 2 + * + * CAVEAT: gcc (as of 8.2.0) tends to read 32-bit word for bit field test. + * Be careful for those with side effect for read. + */ +struct sys_registers +{ + union _sys_safe_access_sig SAFE_ACCESS_SIG; + uint8_t CHIP_ID; + uint8_t SAFE_ACCESS_ID; + uint8_t WDOG_COUNT; + union _sys_glob_rom_cfg GLOB_ROM_CFG; + union _sys_rst_boot_stat RST_BOOT_STAT; + union _sys_rst_wdog_ctrl RST_WDOG_CTRL; + uint8_t GLOB_RESET_KEEP; + union _sys_clk_pll_div CLK_PLL_DIV; + uint8_t resv_9; + union _sys_clk_cfg_ctrl CLK_CFG_CTRL; + union _sys_clk_mod_aux CLK_MOD_AUX; + union _sys_slp_clk_off0 SLP_CLK_OFF0; + union _sys_slp_clk_off1 SLP_CLK_OFF1; + union _sys_slp_wake_ctrl SLP_WAKE_CTRL; + union _sys_slp_power_ctrl SLP_POWER_CTRL; +#if defined(SOC_SERIES_CH569) + uint32_t resv_10[4]; + union _sys_serd_ana_cfg1 SERD_ANA_CFG1; + uint16_t resv_22; + union _sys_serd_ana_cfg2 SERD_ANA_CFG2; +#endif +} __packed; + +//CHECK_STRUCT_SIZE(struct sys_registers, 0x28); + +uint32_t sys_hclk_calc(void); +uint32_t sys_hclk_get(void); +int sys_hclk_set(uint32_t freq); +int sys_clk_off_by_irqn(uint8_t irqn, int off); +void sys_slp_clk_off0(uint8_t bits, int off); +void sys_slp_clk_off1(uint8_t bits, int off); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/sys/Makefile b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/sys/Makefile new file mode 100644 index 000000000..c56958110 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/sys/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := connect_sys.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/sys/connect_sys.c b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/sys/connect_sys.c new file mode 100644 index 000000000..c5d43e6db --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch569w/third_party_driver/sys/connect_sys.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-07-15 Emuzit first version + */ +#include +#include "xsconfig.h" +#include "board.h" +#include "xs_isr.h" +#include "CH56xSFR.h" +#include "connect_sys.h" + +static uint32_t hclk_freq; + +uint8_t _slp_clk_off0_irqn_bit(uint8_t irqn) +{ + uint8_t bitpos; + + switch (irqn) + { + case TMR0_IRQn: bitpos = RB_SLP_CLK_TMR0; break; + case TMR1_IRQn: bitpos = RB_SLP_CLK_TMR1; break; + case TMR2_IRQn: bitpos = RB_SLP_CLK_TMR2; break; + /* special case to control PWMX clock in irqn way */ + case PWMX_OFFn: bitpos = RB_SLP_CLK_PWMX; break; + case UART0_IRQn: bitpos = RB_SLP_CLK_UART0; break; + case UART1_IRQn: bitpos = RB_SLP_CLK_UART1; break; + case UART2_IRQn: bitpos = RB_SLP_CLK_UART2; break; + case UART3_IRQn: bitpos = RB_SLP_CLK_UART3; break; + default: + bitpos = 0; + } + + return bitpos; +} + +uint8_t _slp_clk_off1_irqn_bit(uint8_t irqn) +{ + uint8_t bitpos; + + switch (irqn) + { + case SPI0_IRQn: bitpos = RB_SLP_CLK_SPI0; break; + case SPI1_IRQn: bitpos = RB_SLP_CLK_SPI1; break; +#if defined(SOC_CH567) + case SDC_IRQn: bitpos = RB_SLP_CLK_SDC; break; + case LED_IRQn: bitpos = RB_SLP_CLK_LED; break; + case USB0_IRQn: bitpos = RB_SLP_CLK_USB0; break; + case USB1_IRQn: bitpos = RB_SLP_CLK_USB1; break; + case ECDC_IRQn: bitpos = RB_SLP_CLK_ECDC; break; +#elif defined(SOC_CH568) + case SDC_IRQn: bitpos = RB_SLP_CLK_SDC; break; + case LED_IRQn: bitpos = RB_SLP_CLK_LED; break; + case USB1_IRQn: bitpos = RB_SLP_CLK_USB1; break; + case USB0_IRQn: bitpos = RB_SLP_CLK_SATA; break; + case ECDC_IRQn: bitpos = RB_SLP_CLK_ECDC; break; +#else + case EMMC_IRQn: bitpos = RB_SLP_CLK_EMMC; break; + case HSPI_IRQn: bitpos = RB_SLP_CLK_HSPI; break; + case USBHS_IRQn: bitpos = RB_SLP_CLK_USBHS; break; + case USBSS_IRQn: bitpos = RB_SLP_CLK_USBSS; break; + case SERDES_IRQn: bitpos = RB_SLP_CLK_SERD; break; + case DVP_IRQn: bitpos = RB_SLP_CLK_DVP; break; +#endif + default: + bitpos = 0; + } + + return bitpos; +} + +#if defined(SOC_SERIES_CH569) +uint8_t _wake_clk_off_irqn_bit(uint8_t irqn) +{ + uint8_t bitpos; + + switch (irqn) + { + case ETH_IRQn: bitpos = RB_SLP_CLK_ETH; break; + case ECDC_IRQn: bitpos = RB_SLP_CLK_ECDC; break; + default: + bitpos = 0; + } + + return bitpos; +} +#endif + +/** + * @brief Turn on/off device clock for group clk_off0. + * + * @param bits is a bit mask to select corresponding devices. + * + * @param off is to turn off the clock (1) or trun on (0). + */ +void sys_slp_clk_off0(uint8_t bits, int off) +{ + volatile struct sys_registers *sys = (void *)SYS_REG_BASE; + x_base level; + uint8_t u8v; + + u8v = sys->SLP_CLK_OFF0.reg; + if ((u8v & bits) != (off ? bits : 0)) + { + u8v = off ? (u8v | bits) : (u8v & ~bits); + level = DisableLocalInterrupt(); + sys_safe_access_enter(sys); + sys->SLP_CLK_OFF0.reg = u8v; + sys_safe_access_leave(sys); + EnableLocalInterrupt(level); + } +} + +/** + * @brief Turn on/off device clock for group clk_off1. + * + * @param bits is a bit mask to select corresponding devices. + * + * @param off is to turn off the clock (1) or trun on (0). + */ +void sys_slp_clk_off1(uint8_t bits, int off) +{ + volatile struct sys_registers *sys = (void *)SYS_REG_BASE; + x_base level; + uint8_t u8v; + + u8v = sys->SLP_CLK_OFF1.reg; + if ((u8v & bits) != (off ? bits : 0)) + { + u8v = off ? (u8v | bits) : (u8v & ~bits); + level = DisableLocalInterrupt(); + sys_safe_access_enter(sys); + sys->SLP_CLK_OFF1.reg = u8v; + sys_safe_access_leave(sys); + EnableLocalInterrupt(level); + } +} + +/** + * @brief Turn on/off device clock, specified by its irq number. + * + * @param irqn is the irq number of the target device. + * PWMX does not have irqn, use special PWMX_OFFn number. + * + * @param off is to turn off the clock (1) or trun on (0). + * + * @return Returns if irqn-device has corresponding clk off bit : + * 0 if device not found; otherwise bit position of off0/off1. + */ +int sys_clk_off_by_irqn(uint8_t irqn, int off) +{ + volatile struct sys_registers *sys = (void *)SYS_REG_BASE; + uint8_t u8v; + size_t offset; + + uint8_t bitpos = 0; + + if (irqn < END_OF_IRQn) + { + if ((bitpos = _slp_clk_off0_irqn_bit(irqn)) != 0) + { + offset = offsetof(struct sys_registers, SLP_CLK_OFF0); + } + else if ((bitpos = _slp_clk_off1_irqn_bit(irqn)) != 0) + { + offset = offsetof(struct sys_registers, SLP_CLK_OFF1); + } +#if defined(SOC_SERIES_CH569) + else if ((bitpos = _wake_clk_off_irqn_bit(irqn)) != 0) + { + offset = offsetof(struct sys_registers, SLP_WAKE_CTRL); + } +#endif + if (bitpos) + { + volatile uint8_t *cxreg = (void *)sys; + x_base level; + u8v = cxreg[offset]; + if ((u8v & bitpos) != (off ? bitpos : 0)) + { + u8v = off ? (u8v | bitpos) : (u8v & ~bitpos); + level = DisableLocalInterrupt(); + sys_safe_access_enter(sys); + cxreg[offset] = u8v; + sys_safe_access_leave(sys); + EnableLocalInterrupt(level); + } + } + } + + return bitpos; +} + +/** + * @brief Setup HCLK frequency. + * + * @param freq is the desired hclk frequency. + * supported : 120/96/80/60/48/40/32/30/15/10/6/3/2 MHz + * + * @return Returns 0 if hclk is successfully set. + */ +int sys_hclk_set(uint32_t freq) +{ + volatile struct sys_registers *sys = (void *)SYS_REG_BASE; + + uint8_t plldiv; + + int clksel = -1; + + if (freq >= 30000000) + { + if (freq <= 120000000) + { + /* supported : 120/96/80/60/48/40/32/30 MHz */ + plldiv = 480000000 / freq; // 30M => 16 & 0xf => 0 + clksel = RB_CLK_SEL_PLL; + } + } + else if (freq >= 2000000) + { + /* supported : 15/10/6/3/2 MHz */ + plldiv = 30000000 / freq; + clksel = 0; + } + + if (clksel >= 0) + { + x_base level = DisableLocalInterrupt(); + sys_safe_access_enter(sys); + sys->CLK_PLL_DIV.reg = clk_pll_div_wdat(plldiv); + sys->CLK_CFG_CTRL.reg = clk_cfg_ctrl_wdat(clksel); + sys_safe_access_leave(sys); + EnableLocalInterrupt(level); + /* save to hclk_freq for quick report */ + sys_hclk_calc(); + clksel = 0; + } + + return clksel; +} + +/** + * @brief Get saved HCLK frequency. + * + * Valid only if HCLK is set strickly with sys_hclk_set(). + * Use sys_hclk_calc() otherwise. + * + * @return Returns saved HCLK frequency (Hz, 0 if not set yet). + */ +uint32_t sys_hclk_get(void) +{ + return hclk_freq; +} + +/** + * @brief Get current HCLK frequency, calculated from hw setting. + * + * @return Returns current HCLK frequency (Hz). + */ +uint32_t sys_hclk_calc(void) +{ + volatile struct sys_registers *sys = (void *)SYS_REG_BASE; + + uint8_t plldiv = sys->CLK_PLL_DIV.pll_div; + + if (sys->CLK_CFG_CTRL.sel_pll == CLK_SEL_PLL_USB_480M) + { + hclk_freq = plldiv ? 480000000 / plldiv : 30000000; + } + else + { + hclk_freq = plldiv ? 30000000 / plldiv : 2000000; + } + + return hclk_freq; +}