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