/* * Copyright (c) 2020 Nuvoton Technology Corporation. * * SPDX-License-Identifier: Apache-2.0 */ #ifndef _NUVOTON_NPCX_SOC_CLOCK_H_ #define _NUVOTON_NPCX_SOC_CLOCK_H_ #include #include #include #ifdef __cplusplus extern "C" { #endif /* Common clock control device node for all NPCX series */ #define NPCX_CLK_CTRL_NODE DT_NODELABEL(pcc) /** * @brief NPCX clock configuration structure * * Used to indicate the device's clock bus type and corresponding PWDWN_CTL * register/bit to turn on/off its source clock. */ struct npcx_clk_cfg { uint16_t bus:8; uint16_t ctrl:5; uint16_t bit:3; }; /* Clock settings from pcc node */ /* Target OFMCLK freq */ #define OFMCLK DT_PROP(DT_NODELABEL(pcc), clock_frequency) /* Core clock prescaler */ #define FPRED_VAL (DT_PROP(DT_NODELABEL(pcc), core_prescaler) - 1) /* APB1 clock divider */ #define APB1DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb1_prescaler) - 1) /* APB2 clock divider */ #define APB2DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb2_prescaler) - 1) /* APB3 clock divider */ #define APB3DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb3_prescaler) - 1) /* APB4 clock divider if supported */ #if DT_NODE_HAS_PROP(DT_NODELABEL(pcc), apb4_prescaler) #if defined(CONFIG_CLOCK_CONTROL_NPCX_SUPP_APB4) /* Supported in NPCX9 and later series */ #define APB4DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb4_prescaler) - 1) #else #error "APB4 clock divider is not supported but defined in pcc node!" #endif /* CONFIG_CLOCK_CONTROL_NPCX_SUPP_APB4 */ #endif /* Construct a uint8_t array from 'pwdwn-ctl-val' prop for PWDWN_CTL initialization. */ #define NPCX_PWDWN_CTL_ITEMS_INIT(node, prop, idx) DT_PROP_BY_IDX(node, prop, idx), #define NPCX_PWDWN_CTL_INIT DT_FOREACH_PROP_ELEM(DT_NODELABEL(pcc), \ pwdwn_ctl_val, NPCX_PWDWN_CTL_ITEMS_INIT) /* * NPCX7 and later series clock tree macros: * (Please refer Figure 58. for more information.) * * Maximum OFMCLK in npcx7/9 series is 100MHz, * Maximum OFMCLK in npcx4 series is 120MHz, * * Suggestion for npcx series: * - OFMCLK > MAX_OFMCLK/2, XF_RANGE should be 1, else 0. * - CORE_CLK > MAX_OFMCLK/2, AHB6DIV should be 1, else 0. * - CORE_CLK > MAX_OFMCLK/2, FIUDIV should be 1, else 0. */ /* Core domain clock */ #define CORE_CLK (OFMCLK / DT_PROP(DT_NODELABEL(pcc), core_prescaler)) /* Low Frequency clock */ #define LFCLK 32768 /* FMUL clock */ #if (OFMCLK > (MAX_OFMCLK / 2)) #define FMCLK (OFMCLK / 2) /* FMUL clock = OFMCLK/2 */ #else #define FMCLK OFMCLK /* FMUL clock = OFMCLK */ #endif /* APBs source clock */ #define APBSRC_CLK OFMCLK /* AHB6 clock */ #if (CORE_CLK > (MAX_OFMCLK / 2)) #define AHB6DIV_VAL 1 /* AHB6_CLK = CORE_CLK/2 */ #else #define AHB6DIV_VAL 0 /* AHB6_CLK = CORE_CLK */ #endif /* FIU clock divider */ #if (CORE_CLK > (MAX_OFMCLK / 2)) #define FIUDIV_VAL 1 /* FIU_CLK = CORE_CLK/2 */ #else #define FIUDIV_VAL 0 /* FIU_CLK = CORE_CLK */ #endif #if defined(CONFIG_CLOCK_CONTROL_NPCX_SUPP_FIU1) #if (CORE_CLK > (MAX_OFMCLK / 2)) #define FIU1DIV_VAL 1 /* FIU1_CLK = CORE_CLK/2 */ #else #define FIU1DIV_VAL 0 /* FIU1_CLK = CORE_CLK */ #endif #endif /* CONFIG_CLOCK_CONTROL_NPCX_SUPP_FIU1 */ /* Get APB clock freq */ #define NPCX_APB_CLOCK(no) (APBSRC_CLK / (APB##no##DIV_VAL + 1)) /* * Frequency multiplier M/N value definitions according to the requested * OFMCLK (Unit:Hz). */ #if (OFMCLK > (MAX_OFMCLK / 2)) #define HFCGN_VAL 0x82 /* Set XF_RANGE as 1 */ #else #define HFCGN_VAL 0x02 #endif #if (OFMCLK == 120000000) #define HFCGMH_VAL 0x0E #define HFCGML_VAL 0x4E #elif (OFMCLK == 100000000) #define HFCGMH_VAL 0x0B #define HFCGML_VAL 0xEC #elif (OFMCLK == 96000000) #define HFCGMH_VAL 0x0B #define HFCGML_VAL 0x72 #elif (OFMCLK == 90000000) #define HFCGMH_VAL 0x0A #define HFCGML_VAL 0xBA #elif (OFMCLK == 80000000) #define HFCGMH_VAL 0x09 #define HFCGML_VAL 0x89 #elif (OFMCLK == 66000000) #define HFCGMH_VAL 0x07 #define HFCGML_VAL 0xDE #elif (OFMCLK == 50000000) #define HFCGMH_VAL 0x0B #define HFCGML_VAL 0xEC #elif (OFMCLK == 48000000) #define HFCGMH_VAL 0x0B #define HFCGML_VAL 0x72 #else #error "Unsupported OFMCLK Frequency" #endif /* Clock prescaler configurations in different series */ #define VAL_HFCGP ((FPRED_VAL << 4) | AHB6DIV_VAL) #if defined(FIU1DIV_VAL) #define VAL_HFCBCD ((FIU1DIV_VAL << 4) | (FIUDIV_VAL << 2)) #else #define VAL_HFCBCD (FIUDIV_VAL << 4) #endif /* FIU1DIV_VAL */ #define VAL_HFCBCD1 (APB1DIV_VAL | (APB2DIV_VAL << 4)) #if defined(APB4DIV_VAL) #define VAL_HFCBCD2 (APB3DIV_VAL | (APB4DIV_VAL << 4)) #else #define VAL_HFCBCD2 APB3DIV_VAL #endif /* APB4DIV_VAL */ /** * @brief Function to notify clock driver that backup the counter value of * low-frequency timer before ec entered deep idle state. */ void npcx_clock_capture_low_freq_timer(void); /** * @brief Function to notify clock driver that compensate the counter value of * system timer by low-frequency timer after ec left deep idle state. * */ void npcx_clock_compensate_system_timer(void); /** * @brief Function to get time ticks in system sleep/deep sleep state. The unit * is ticks. * */ uint64_t npcx_clock_get_sleep_ticks(void); /** * @brief Function to configure system sleep settings. After ec received "wfi" * instruction, ec will enter sleep/deep sleep state for better power * consumption. * * @param is_deep A boolean indicating ec enters deep sleep or sleep state * @param is_instant A boolean indicating 'Instant Wake-up' from deep idle is * enabled */ void npcx_clock_control_turn_on_system_sleep(bool is_deep, bool is_instant); /** * @brief Function to turn off system sleep mode. */ void npcx_clock_control_turn_off_system_sleep(void); #ifdef __cplusplus } #endif #endif /* _NUVOTON_NPCX_SOC_CLOCK_H_ */