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