1 /*
2  * Copyright (c) 2020 Nuvoton Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef _NUVOTON_NPCX_SOC_CLOCK_H_
8 #define _NUVOTON_NPCX_SOC_CLOCK_H_
9 
10 #include <stdbool.h>
11 #include <stdint.h>
12 
13 #include <zephyr/devicetree.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /* Common clock control device node for all NPCX series */
20 #define NPCX_CLK_CTRL_NODE DT_NODELABEL(pcc)
21 
22 /**
23  * @brief NPCX clock configuration structure
24  *
25  * Used to indicate the device's clock bus type and corresponding PWDWN_CTL
26  * register/bit to turn on/off its source clock.
27  */
28 struct npcx_clk_cfg {
29 	uint16_t bus:8;
30 	uint16_t ctrl:5;
31 	uint16_t bit:3;
32 };
33 
34 /* Clock settings from pcc node */
35 /* Target OFMCLK freq */
36 #define OFMCLK DT_PROP(DT_NODELABEL(pcc), clock_frequency)
37 /* Core clock prescaler */
38 #define FPRED_VAL (DT_PROP(DT_NODELABEL(pcc), core_prescaler) - 1)
39 /* APB1 clock divider */
40 #define APB1DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb1_prescaler) - 1)
41 /* APB2 clock divider */
42 #define APB2DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb2_prescaler) - 1)
43 /* APB3 clock divider */
44 #define APB3DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb3_prescaler) - 1)
45 /* APB4 clock divider if supported */
46 #if DT_NODE_HAS_PROP(DT_NODELABEL(pcc), apb4_prescaler)
47 #if defined(CONFIG_CLOCK_CONTROL_NPCX_SUPP_APB4) /* Supported in NPCX9 and later series */
48 #define APB4DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb4_prescaler) - 1)
49 #else
50 #error "APB4 clock divider is not supported but defined in pcc node!"
51 #endif /* CONFIG_CLOCK_CONTROL_NPCX_SUPP_APB4 */
52 #endif
53 
54 /* Construct a uint8_t array from 'pwdwn-ctl-val' prop for PWDWN_CTL initialization. */
55 #define NPCX_PWDWN_CTL_ITEMS_INIT(node, prop, idx) DT_PROP_BY_IDX(node, prop, idx),
56 #define NPCX_PWDWN_CTL_INIT DT_FOREACH_PROP_ELEM(DT_NODELABEL(pcc), \
57 				pwdwn_ctl_val, NPCX_PWDWN_CTL_ITEMS_INIT)
58 
59 /*
60  * NPCX7 and later series clock tree macros:
61  * (Please refer Figure 58. for more information.)
62  *
63  * Maximum OFMCLK in npcx7/9 series is 100MHz,
64  * Maximum OFMCLK in npcx4 series is 120MHz,
65  *
66  * Suggestion for npcx series:
67  * - OFMCLK   > MAX_OFMCLK/2, XF_RANGE should be 1, else 0.
68  * - CORE_CLK > MAX_OFMCLK/2, AHB6DIV should be 1, else 0.
69  * - CORE_CLK > MAX_OFMCLK/2, FIUDIV should be 1, else 0.
70  */
71 /* Core domain clock */
72 #define CORE_CLK (OFMCLK / DT_PROP(DT_NODELABEL(pcc), core_prescaler))
73 /* Low Frequency clock */
74 #define LFCLK 32768
75 
76 /* FMUL clock */
77 #if (OFMCLK > (MAX_OFMCLK / 2))
78 #define FMCLK (OFMCLK / 2) /* FMUL clock = OFMCLK/2 */
79 #else
80 #define FMCLK OFMCLK /* FMUL clock = OFMCLK */
81 #endif
82 
83 /* APBs source clock */
84 #define APBSRC_CLK OFMCLK
85 
86 /* AHB6 clock */
87 #if (CORE_CLK > (MAX_OFMCLK / 2))
88 #define AHB6DIV_VAL 1 /* AHB6_CLK = CORE_CLK/2 */
89 #else
90 #define AHB6DIV_VAL 0 /* AHB6_CLK = CORE_CLK */
91 #endif
92 
93 /* FIU clock divider */
94 #if (CORE_CLK > (MAX_OFMCLK / 2))
95 #define FIUDIV_VAL 1 /* FIU_CLK = CORE_CLK/2 */
96 #else
97 #define FIUDIV_VAL 0 /* FIU_CLK = CORE_CLK */
98 #endif
99 
100 #if defined(CONFIG_CLOCK_CONTROL_NPCX_SUPP_FIU1)
101 #if (CORE_CLK > (MAX_OFMCLK / 2))
102 #define FIU1DIV_VAL 1 /* FIU1_CLK = CORE_CLK/2 */
103 #else
104 #define FIU1DIV_VAL 0 /* FIU1_CLK = CORE_CLK */
105 #endif
106 #endif /* CONFIG_CLOCK_CONTROL_NPCX_SUPP_FIU1 */
107 
108 /* I3C clock divider */
109 #if (OFMCLK == MHZ(120)) /* MCLkD must between 40 mhz to 50 mhz*/
110 #define MCLKD_SL 2    /* I3C_CLK = (MCLK / 3) */
111 #elif (OFMCLK <= MHZ(100) && OFMCLK >= MHZ(80))
112 #define MCLKD_SL 1    /* I3C_CLK = (MCLK / 2) */
113 #else
114 #define MCLKD_SL 0    /* I3C_CLK = MCLK */
115 #endif
116 
117 
118 /* Get APB clock freq */
119 #define NPCX_APB_CLOCK(no) (APBSRC_CLK / (APB##no##DIV_VAL + 1))
120 
121 /*
122  * Frequency multiplier M/N value definitions according to the requested
123  * OFMCLK (Unit:Hz).
124  */
125 #if (OFMCLK > (MAX_OFMCLK / 2))
126 #define HFCGN_VAL    0x82 /* Set XF_RANGE as 1 */
127 #else
128 #define HFCGN_VAL    0x02
129 #endif
130 #if   (OFMCLK == 120000000)
131 #define HFCGMH_VAL   0x0E
132 #define HFCGML_VAL   0x4E
133 #elif (OFMCLK == 100000000)
134 #define HFCGMH_VAL   0x0B
135 #define HFCGML_VAL   0xEC
136 #elif (OFMCLK == 96000000)
137 #define HFCGMH_VAL   0x0B
138 #define HFCGML_VAL   0x72
139 #elif (OFMCLK == 90000000)
140 #define HFCGMH_VAL   0x0A
141 #define HFCGML_VAL   0xBA
142 #elif (OFMCLK == 80000000)
143 #define HFCGMH_VAL   0x09
144 #define HFCGML_VAL   0x89
145 #elif (OFMCLK == 66000000)
146 #define HFCGMH_VAL   0x07
147 #define HFCGML_VAL   0xDE
148 #elif (OFMCLK == 50000000)
149 #define HFCGMH_VAL   0x0B
150 #define HFCGML_VAL   0xEC
151 #elif (OFMCLK == 48000000)
152 #define HFCGMH_VAL   0x0B
153 #define HFCGML_VAL   0x72
154 #else
155 #error "Unsupported OFMCLK Frequency"
156 #endif
157 
158 /* Clock prescaler configurations in different series */
159 #define VAL_HFCGP   ((FPRED_VAL << 4) | AHB6DIV_VAL)
160 #if defined(FIU1DIV_VAL)
161 #define VAL_HFCBCD  ((FIU1DIV_VAL << 4) | (FIUDIV_VAL << 2))
162 #else
163 #define VAL_HFCBCD  (FIUDIV_VAL << 4)
164 #endif /* FIU1DIV_VAL */
165 #define VAL_HFCBCD1 (APB1DIV_VAL | (APB2DIV_VAL << 4))
166 #if defined(APB4DIV_VAL)
167 #define VAL_HFCBCD2 (APB3DIV_VAL | (APB4DIV_VAL << 4))
168 #else
169 #define VAL_HFCBCD2 APB3DIV_VAL
170 #endif /* APB4DIV_VAL */
171 /* I3C1~I3C3 share the same configuration */
172 #define VAL_HFCBCD3 MCLKD_SL
173 
174 /**
175  * @brief Function to notify clock driver that backup the counter value of
176  *        low-frequency timer before ec entered deep idle state.
177  */
178 void npcx_clock_capture_low_freq_timer(void);
179 
180 /**
181  * @brief Function to notify clock driver that compensate the counter value of
182  *        system timer by low-frequency timer after ec left deep idle state.
183  *
184  */
185 void npcx_clock_compensate_system_timer(void);
186 
187 /**
188  * @brief Function to get time ticks in system sleep/deep sleep state. The unit
189  *        is ticks.
190  *
191  */
192 uint64_t npcx_clock_get_sleep_ticks(void);
193 
194 /**
195  * @brief Function to configure system sleep settings. After ec received "wfi"
196  *        instruction, ec will enter sleep/deep sleep state for better power
197  *        consumption.
198  *
199  * @param is_deep A boolean indicating ec enters deep sleep or sleep state
200  * @param is_instant A boolean indicating 'Instant Wake-up' from deep idle is
201  *                   enabled
202  */
203 void npcx_clock_control_turn_on_system_sleep(bool is_deep, bool is_instant);
204 
205 /**
206  * @brief Function to turn off system sleep mode.
207  */
208 void npcx_clock_control_turn_off_system_sleep(void);
209 
210 #ifdef __cplusplus
211 }
212 #endif
213 
214 #endif /* _NUVOTON_NPCX_SOC_CLOCK_H_ */
215