1 /*
2 * Copyright (c) 2019 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <device.h>
8 #include <xtensa/xtruntime.h>
9 #include <irq_nextlevel.h>
10 #include <xtensa/hal.h>
11 #include <init.h>
12
13 #include "soc.h"
14
15 #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL
16 #include <logging/log.h>
17 LOG_MODULE_REGISTER(soc);
18
19 static uint32_t ref_clk_freq;
20
21 #define CAVS_INTC_NODE(n) DT_INST(n, intel_cavs_intc)
22
z_soc_irq_enable(uint32_t irq)23 void z_soc_irq_enable(uint32_t irq)
24 {
25 const struct device *dev_cavs, *dev_ictl;
26
27 switch (XTENSA_IRQ_NUMBER(irq)) {
28 case DT_IRQN(CAVS_INTC_NODE(0)):
29 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(0)));
30 break;
31 case DT_IRQN(CAVS_INTC_NODE(1)):
32 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(1)));
33 break;
34 case DT_IRQN(CAVS_INTC_NODE(2)):
35 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(2)));
36 break;
37 case DT_IRQN(CAVS_INTC_NODE(3)):
38 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(3)));
39 break;
40 default:
41 /* regular interrupt */
42 z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq));
43 return;
44 }
45
46 if (!dev_cavs) {
47 LOG_DBG("board: CAVS device binding failed");
48 return;
49 }
50
51 /* If the control comes here it means the specified interrupt
52 * is in either CAVS interrupt logic or DW interrupt controller
53 */
54 z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq));
55
56 switch (CAVS_IRQ_NUMBER(irq)) {
57 case DW_ICTL_IRQ_CAVS_OFFSET:
58 dev_ictl = device_get_binding(DT_LABEL(DT_INST(0, snps_designware_intc)));
59 break;
60 default:
61 /* The source of the interrupt is in CAVS interrupt logic */
62 irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
63 return;
64 }
65
66 if (!dev_ictl) {
67 LOG_DBG("board: DW intr_control device binding failed");
68 return;
69 }
70
71 /* If the control comes here it means the specified interrupt
72 * is in DW interrupt controller
73 */
74 irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
75
76 /* Manipulate the relevant bit in the interrupt controller
77 * register as needed
78 */
79 irq_enable_next_level(dev_ictl, INTR_CNTL_IRQ_NUM(irq));
80 }
81
z_soc_irq_disable(uint32_t irq)82 void z_soc_irq_disable(uint32_t irq)
83 {
84 const struct device *dev_cavs, *dev_ictl;
85
86 switch (XTENSA_IRQ_NUMBER(irq)) {
87 case DT_IRQN(CAVS_INTC_NODE(0)):
88 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(0)));
89 break;
90 case DT_IRQN(CAVS_INTC_NODE(1)):
91 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(1)));
92 break;
93 case DT_IRQN(CAVS_INTC_NODE(2)):
94 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(2)));
95 break;
96 case DT_IRQN(CAVS_INTC_NODE(3)):
97 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(3)));
98 break;
99 default:
100 /* regular interrupt */
101 z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
102 return;
103 }
104
105 if (!dev_cavs) {
106 LOG_DBG("board: CAVS device binding failed");
107 return;
108 }
109
110 /* If the control comes here it means the specified interrupt
111 * is in either CAVS interrupt logic or DW interrupt controller
112 */
113
114 switch (CAVS_IRQ_NUMBER(irq)) {
115 case DW_ICTL_IRQ_CAVS_OFFSET:
116 dev_ictl = device_get_binding(DT_LABEL(DT_INST(0, snps_designware_intc)));
117 break;
118 default:
119 /* The source of the interrupt is in CAVS interrupt logic */
120 irq_disable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
121
122 /* Disable the parent IRQ if all children are disabled */
123 if (!irq_is_enabled_next_level(dev_cavs)) {
124 z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
125 }
126 return;
127 }
128
129 if (!dev_ictl) {
130 LOG_DBG("board: DW intr_control device binding failed");
131 return;
132 }
133
134 /* If the control comes here it means the specified interrupt
135 * is in DW interrupt controller.
136 * Manipulate the relevant bit in the interrupt controller
137 * register as needed
138 */
139 irq_disable_next_level(dev_ictl, INTR_CNTL_IRQ_NUM(irq));
140
141 /* Disable the parent IRQ if all children are disabled */
142 if (!irq_is_enabled_next_level(dev_ictl)) {
143 irq_disable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
144
145 if (!irq_is_enabled_next_level(dev_cavs)) {
146 z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
147 }
148 }
149 }
150
z_soc_irq_is_enabled(unsigned int irq)151 int z_soc_irq_is_enabled(unsigned int irq)
152 {
153 const struct device *dev_cavs, *dev_ictl;
154 int ret = -EINVAL;
155
156 switch (XTENSA_IRQ_NUMBER(irq)) {
157 case DT_IRQN(CAVS_INTC_NODE(0)):
158 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(0)));
159 break;
160 case DT_IRQN(CAVS_INTC_NODE(1)):
161 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(1)));
162 break;
163 case DT_IRQN(CAVS_INTC_NODE(2)):
164 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(2)));
165 break;
166 case DT_IRQN(CAVS_INTC_NODE(3)):
167 dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(3)));
168 break;
169 default:
170 /* regular interrupt */
171 ret = z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq));
172 goto out;
173 }
174
175 if (!dev_cavs) {
176 LOG_DBG("board: CAVS device binding failed");
177 ret = -ENODEV;
178 goto out;
179 }
180
181 switch (CAVS_IRQ_NUMBER(irq)) {
182 case DW_ICTL_IRQ_CAVS_OFFSET:
183 dev_ictl = device_get_binding(DT_LABEL(DT_INST(0, snps_designware_intc)));
184 break;
185 default:
186 /* The source of the interrupt is in CAVS interrupt logic */
187 ret = irq_line_is_enabled_next_level(dev_cavs,
188 CAVS_IRQ_NUMBER(irq));
189 goto out;
190 }
191
192 if (!dev_ictl) {
193 LOG_DBG("board: DW intr_control device binding failed");
194 ret = -ENODEV;
195 goto out;
196 }
197
198 ret = irq_line_is_enabled_next_level(dev_ictl, INTR_CNTL_IRQ_NUM(irq));
199
200 out:
201 return ret;
202 }
203
soc_set_resource_ownership(void)204 static inline void soc_set_resource_ownership(void)
205 {
206 volatile struct soc_resource_alloc_regs *regs =
207 (volatile struct soc_resource_alloc_regs *)
208 SOC_RESOURCE_ALLOC_REG_BASE;
209 int index;
210
211
212 /* set ownership of DMA controllers and channels */
213 for (index = 0; index < SOC_NUM_LPGPDMAC; index++) {
214 regs->lpgpdmacxo[index] = SOC_LPGPDMAC_OWNER_DSP;
215 }
216
217 /* set ownership of I2S and DMIC controllers */
218 regs->dspiopo = SOC_DSPIOP_I2S_OWNSEL_DSP |
219 SOC_DSPIOP_DMIC_OWNSEL_DSP;
220
221 /* set ownership of timestamp and M/N dividers */
222 regs->geno = SOC_GENO_TIMESTAMP_OWNER_DSP |
223 SOC_GENO_MNDIV_OWNER_DSP;
224 }
225
soc_get_ref_clk_freq(void)226 uint32_t soc_get_ref_clk_freq(void)
227 {
228 return ref_clk_freq;
229 }
230
soc_set_audio_mclk(void)231 static inline void soc_set_audio_mclk(void)
232 {
233 #if (CONFIG_AUDIO)
234 int mclk;
235 volatile struct soc_mclk_control_regs *mclk_regs =
236 (volatile struct soc_mclk_control_regs *)SOC_MCLK_DIV_CTRL_BASE;
237
238 for (mclk = 0; mclk < SOC_NUM_MCLK_OUTPUTS; mclk++) {
239 /*
240 * set divider to bypass mode which makes MCLK output frequency
241 * to be the same as referece clock frequency
242 */
243 mclk_regs->mdivxr[mclk] = SOC_MDIVXR_SET_DIVIDER_BYPASS;
244 mclk_regs->mdivctrl |= SOC_MDIVCTRL_MCLK_OUT_EN(mclk);
245 }
246 #endif
247 }
248
soc_set_dmic_power(void)249 static inline void soc_set_dmic_power(void)
250 {
251 #if (CONFIG_AUDIO_INTEL_DMIC)
252 volatile struct soc_dmic_shim_regs *dmic_shim_regs =
253 (volatile struct soc_dmic_shim_regs *)SOC_DMIC_SHIM_REG_BASE;
254
255 /* enable power */
256 dmic_shim_regs->dmiclctl |= SOC_DMIC_SHIM_DMICLCTL_SPA;
257
258 while ((dmic_shim_regs->dmiclctl & SOC_DMIC_SHIM_DMICLCTL_CPA) == 0U) {
259 /* wait for power status */
260 }
261 #endif
262 }
263
soc_set_gna_power(void)264 static inline void soc_set_gna_power(void)
265 {
266 #if (CONFIG_INTEL_GNA)
267 volatile struct soc_global_regs *regs =
268 (volatile struct soc_global_regs *)SOC_S1000_GLB_CTRL_BASE;
269
270 /* power on GNA block */
271 regs->gna_power_control |= SOC_GNA_POWER_CONTROL_SPA;
272 while ((regs->gna_power_control & SOC_GNA_POWER_CONTROL_CPA) == 0U) {
273 /* wait for power status */
274 }
275
276 /* enable clock for GNA block */
277 regs->gna_power_control |= SOC_GNA_POWER_CONTROL_CLK_EN;
278 #endif
279 }
280
soc_set_power_and_clock(void)281 static inline void soc_set_power_and_clock(void)
282 {
283 volatile struct soc_dsp_shim_regs *dsp_shim_regs =
284 (volatile struct soc_dsp_shim_regs *)SOC_DSP_SHIM_REG_BASE;
285
286 dsp_shim_regs->clkctl |= SOC_CLKCTL_REQ_FAST_CLK |
287 SOC_CLKCTL_OCS_FAST_CLK;
288 dsp_shim_regs->pwrctl |= SOC_PWRCTL_DISABLE_PWR_GATING_DSP0;
289
290 soc_set_dmic_power();
291 soc_set_gna_power();
292 soc_set_audio_mclk();
293 }
294
soc_read_bootstraps(void)295 static inline void soc_read_bootstraps(void)
296 {
297 volatile struct soc_global_regs *regs =
298 (volatile struct soc_global_regs *)SOC_S1000_GLB_CTRL_BASE;
299 uint32_t bootstrap;
300
301 bootstrap = regs->straps;
302
303 bootstrap &= SOC_S1000_STRAP_REF_CLK;
304
305 switch (bootstrap) {
306 case SOC_S1000_STRAP_REF_CLK_19P2:
307 ref_clk_freq = 19200000U;
308 break;
309 case SOC_S1000_STRAP_REF_CLK_24P576:
310 ref_clk_freq = 24576000U;
311 break;
312 case SOC_S1000_STRAP_REF_CLK_38P4:
313 default:
314 ref_clk_freq = 38400000U;
315 break;
316 }
317 }
318
soc_init(const struct device * dev)319 static int soc_init(const struct device *dev)
320 {
321 soc_read_bootstraps();
322
323 LOG_INF("Reference clock frequency: %u Hz", ref_clk_freq);
324
325 soc_set_resource_ownership();
326 soc_set_power_and_clock();
327
328 return 0;
329 }
330
331 SYS_INIT(soc_init, PRE_KERNEL_1, 99);
332