blob: d43a70d4529df6a3c2e73b4192b24cf83078b29b [file] [log] [blame]
/*
* 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 <stdbool.h>
#include <stdint.h>
#include <zephyr/devicetree.h>
#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_ */