1 /*
2 * Copyright (c) 2018 Foundries.io
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8
9 #include <zephyr/device.h>
10 #include <zephyr/init.h>
11 #include <fsl_clock.h>
12 #include <zephyr/sys/util.h>
13
14 #if defined(CONFIG_MULTI_LEVEL_INTERRUPTS)
15 #include <errno.h>
16 #include <zephyr/irq_nextlevel.h>
17 #endif
18
19 #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(soc);
22
23 #define SCG_LPFLL_DISABLE 0U
24
25 static const struct device *dev_intmux;
26
27 /*
28 * Run-mode configuration for the fast internal reference clock (FIRC).
29 */
30 static const scg_firc_config_t rv32m1_firc_config = {
31 .enableMode = kSCG_FircEnable,
32 .div1 = kSCG_AsyncClkDivBy1,
33 .div2 = kSCG_AsyncClkDivBy1,
34 .div3 = kSCG_AsyncClkDivBy1,
35 .range = kSCG_FircRange48M,
36 .trimConfig = NULL,
37 };
38
39 /*
40 * FIRC-based system clock configuration.
41 */
42 static const scg_sys_clk_config_t rv32m1_sys_clk_config_firc = {
43 .divSlow = kSCG_SysClkDivBy2,
44 .divBus = kSCG_SysClkDivBy1,
45 .divExt = kSCG_SysClkDivBy1,
46 .divCore = kSCG_SysClkDivBy1,
47 .src = kSCG_SysClkSrcFirc,
48 };
49
50 /*
51 * LPFLL configuration.
52 */
53 static const scg_lpfll_config_t rv32m1_lpfll_cfg = {
54 .enableMode = SCG_LPFLL_DISABLE,
55 .div1 = kSCG_AsyncClkDivBy1,
56 .div2 = kSCG_AsyncClkDisable,
57 .div3 = kSCG_AsyncClkDisable,
58 .range = kSCG_LpFllRange48M,
59 .trimConfig = NULL,
60 };
61
sys_arch_reboot(int type)62 void sys_arch_reboot(int type)
63 {
64 ARG_UNUSED(type);
65
66 EVENT_UNIT->SLPCTRL |= EVENT_SLPCTRL_SYSRSTREQST_MASK;
67 }
68
arch_irq_enable(unsigned int irq)69 void arch_irq_enable(unsigned int irq)
70 {
71 if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) {
72 unsigned int level = rv32m1_irq_level(irq);
73
74 if (level == 1U) {
75 EVENT_UNIT->INTPTEN |= BIT(rv32m1_level1_irq(irq));
76 /* Ensures write has finished: */
77 (void)(EVENT_UNIT->INTPTEN);
78 } else {
79 irq_enable_next_level(dev_intmux, irq);
80 }
81 } else {
82 EVENT_UNIT->INTPTEN |= BIT(rv32m1_level1_irq(irq));
83 (void)(EVENT_UNIT->INTPTEN);
84 }
85 }
86
arch_irq_disable(unsigned int irq)87 void arch_irq_disable(unsigned int irq)
88 {
89 if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) {
90 unsigned int level = rv32m1_irq_level(irq);
91
92 if (level == 1U) {
93 EVENT_UNIT->INTPTEN &= ~BIT(rv32m1_level1_irq(irq));
94 /* Ensures write has finished: */
95 (void)(EVENT_UNIT->INTPTEN);
96 } else {
97 irq_disable_next_level(dev_intmux, irq);
98 }
99 } else {
100 EVENT_UNIT->INTPTEN &= ~BIT(rv32m1_level1_irq(irq));
101 (void)(EVENT_UNIT->INTPTEN);
102 }
103 }
104
arch_irq_is_enabled(unsigned int irq)105 int arch_irq_is_enabled(unsigned int irq)
106 {
107 if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) {
108 unsigned int level = rv32m1_irq_level(irq);
109
110 if (level == 1U) {
111 return (EVENT_UNIT->INTPTEN &
112 BIT(rv32m1_level1_irq(irq))) != 0;
113 } else {
114 uint32_t channel, line, ier;
115
116 /*
117 * Here we break the abstraction and look
118 * directly at the INTMUX registers. We can't
119 * use the irq_nextlevel.h API, as that only
120 * tells us whether some IRQ at the next level
121 * is enabled or not.
122 */
123 channel = rv32m1_intmux_channel(irq);
124 line = rv32m1_intmux_line(irq);
125 ier = INTMUX->CHANNEL[channel].CHn_IER_31_0 & BIT(line);
126
127 return ier != 0U;
128 }
129 } else {
130 return (EVENT_UNIT->INTPTEN & BIT(rv32m1_level1_irq(irq))) != 0;
131 }
132 }
133
134 /*
135 * SoC-level interrupt initialization. Clear any pending interrupts or
136 * events, and find the INTMUX device if necessary.
137 *
138 * This gets called as almost the first thing z_cstart() does, so it
139 * will happen before any calls to the _arch_irq_xxx() routines above.
140 */
soc_interrupt_init(void)141 void soc_interrupt_init(void)
142 {
143 EVENT_UNIT->INTPTPENDCLEAR = 0xFFFFFFFF;
144 (void)(EVENT_UNIT->INTPTPENDCLEAR); /* Ensures write has finished. */
145 EVENT_UNIT->EVTPENDCLEAR = 0xFFFFFFFF;
146 (void)(EVENT_UNIT->EVTPENDCLEAR); /* Ensures write has finished. */
147
148 if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) {
149 dev_intmux = DEVICE_DT_GET(DT_INST(0, openisa_rv32m1_intmux));
150 }
151 }
152
153 /**
154 * @brief Switch system clock configuration in run mode.
155 *
156 * Blocks until the updated configuration takes effect.
157 *
158 * @param cfg New system clock configuration
159 */
rv32m1_switch_sys_clk(const scg_sys_clk_config_t * cfg)160 static void rv32m1_switch_sys_clk(const scg_sys_clk_config_t *cfg)
161 {
162 scg_sys_clk_config_t cur_cfg;
163
164 CLOCK_SetRunModeSysClkConfig(cfg);
165 do {
166 CLOCK_GetCurSysClkConfig(&cur_cfg);
167 } while (cur_cfg.src != cfg->src);
168 }
169
170 /**
171 * @brief Initializes SIRC and switches system clock source to SIRC.
172 */
rv32m1_switch_to_sirc(void)173 static void rv32m1_switch_to_sirc(void)
174 {
175 const scg_sirc_config_t sirc_config = {
176 .enableMode = kSCG_SircEnable,
177 .div1 = kSCG_AsyncClkDisable,
178 .div2 = kSCG_AsyncClkDivBy2,
179 .range = kSCG_SircRangeHigh,
180 };
181 const scg_sys_clk_config_t sys_clk_config_sirc = {
182 .divSlow = kSCG_SysClkDivBy4,
183 .divCore = kSCG_SysClkDivBy1,
184 .src = kSCG_SysClkSrcSirc,
185 };
186
187 CLOCK_InitSirc(&sirc_config);
188 rv32m1_switch_sys_clk(&sys_clk_config_sirc);
189 }
190
191 /**
192 * @brief Setup peripheral clocks
193 *
194 * Setup the peripheral clock sources.
195 */
rv32m1_setup_peripheral_clocks(void)196 static void rv32m1_setup_peripheral_clocks(void)
197 {
198 #if DT_NODE_HAS_STATUS(DT_NODELABEL(tpm0), okay)
199 CLOCK_SetIpSrc(kCLOCK_Tpm0, kCLOCK_IpSrcFircAsync);
200 #endif
201 #if DT_NODE_HAS_STATUS(DT_NODELABEL(tpm1), okay)
202 CLOCK_SetIpSrc(kCLOCK_Tpm1, kCLOCK_IpSrcFircAsync);
203 #endif
204 #if DT_NODE_HAS_STATUS(DT_NODELABEL(tpm2), okay)
205 CLOCK_SetIpSrc(kCLOCK_Tpm2, kCLOCK_IpSrcFircAsync);
206 #endif
207 #if DT_NODE_HAS_STATUS(DT_NODELABEL(tpm3), okay)
208 CLOCK_SetIpSrc(kCLOCK_Tpm3, kCLOCK_IpSrcFircAsync);
209 #endif
210 }
211
212 /**
213 * @brief Perform basic hardware initialization
214 *
215 * Initializes the base clocks and LPFLL using helpers provided by the HAL.
216 *
217 * @return 0
218 */
soc_rv32m1_init(void)219 static int soc_rv32m1_init(void)
220 {
221 unsigned int key;
222
223
224 key = irq_lock();
225
226 /* Switch to SIRC so we can initialize the FIRC. */
227 rv32m1_switch_to_sirc();
228
229 /* Now that we're running off of SIRC, set up and switch to FIRC. */
230 CLOCK_InitFirc(&rv32m1_firc_config);
231 rv32m1_switch_sys_clk(&rv32m1_sys_clk_config_firc);
232
233 /* Initialize LPFLL */
234 CLOCK_InitLpFll(&rv32m1_lpfll_cfg);
235
236 /* Initialize peripheral clocks */
237 rv32m1_setup_peripheral_clocks();
238
239 irq_unlock(key);
240
241 return 0;
242 }
243
244 SYS_INIT(soc_rv32m1_init, PRE_KERNEL_1, 0);
245