/* * Copyright (c) 2019 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include "soc.h" #ifdef CONFIG_DYNAMIC_INTERRUPTS #include #endif #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL #include LOG_MODULE_REGISTER(soc); #define CAVS_INTC_NODE(n) DT_INST(n, intel_cavs_intc) void z_soc_irq_enable(u32_t irq) { struct device *dev_cavs; switch (XTENSA_IRQ_NUMBER(irq)) { case DT_IRQN(CAVS_INTC_NODE(0)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(0))); break; case DT_IRQN(CAVS_INTC_NODE(1)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(1))); break; case DT_IRQN(CAVS_INTC_NODE(2)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(2))); break; case DT_IRQN(CAVS_INTC_NODE(3)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(3))); break; default: /* regular interrupt */ z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); return; } if (!dev_cavs) { LOG_DBG("board: CAVS device binding failed"); return; } /* * The specified interrupt is in CAVS interrupt controller. * So enable core interrupt first. */ z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); /* Then enable the interrupt in CAVS interrupt controller */ irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq)); } void z_soc_irq_disable(u32_t irq) { struct device *dev_cavs; switch (XTENSA_IRQ_NUMBER(irq)) { case DT_IRQN(CAVS_INTC_NODE(0)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(0))); break; case DT_IRQN(CAVS_INTC_NODE(1)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(1))); break; case DT_IRQN(CAVS_INTC_NODE(2)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(2))); break; case DT_IRQN(CAVS_INTC_NODE(3)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(3))); break; default: /* regular interrupt */ z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); return; } if (!dev_cavs) { LOG_DBG("board: CAVS device binding failed"); return; } /* * The specified interrupt is in CAVS interrupt controller. * So disable the interrupt in CAVS interrupt controller. */ irq_disable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq)); /* Then disable the parent IRQ if all children are disabled */ if (!irq_is_enabled_next_level(dev_cavs)) { z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); } } int z_soc_irq_is_enabled(unsigned int irq) { struct device *dev_cavs; int ret = 0; switch (XTENSA_IRQ_NUMBER(irq)) { case DT_IRQN(CAVS_INTC_NODE(0)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(0))); break; case DT_IRQN(CAVS_INTC_NODE(1)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(1))); break; case DT_IRQN(CAVS_INTC_NODE(2)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(2))); break; case DT_IRQN(CAVS_INTC_NODE(3)): dev_cavs = device_get_binding(DT_LABEL(CAVS_INTC_NODE(3))); break; default: /* regular interrupt */ ret = z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); goto out; } if (!dev_cavs) { LOG_DBG("board: CAVS device binding failed"); ret = -ENODEV; goto out; } /* Then enable the interrupt in CAVS interrupt controller */ ret = irq_line_is_enabled_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq)); out: return ret; } #ifdef CONFIG_DYNAMIC_INTERRUPTS int z_soc_irq_connect_dynamic(unsigned int irq, unsigned int priority, void (*routine)(void *parameter), void *parameter, u32_t flags) { uint32_t table_idx; uint32_t cavs_irq, cavs_idx; int ret; ARG_UNUSED(flags); ARG_UNUSED(priority); /* extract 2nd level interrupt number */ cavs_irq = CAVS_IRQ_NUMBER(irq); ret = irq; if (cavs_irq == 0) { /* Not affecting 2nd level interrupts */ z_isr_install(irq, routine, parameter); goto irq_connect_out; } /* Figure out the base index. */ switch (XTENSA_IRQ_NUMBER(irq)) { case DT_IRQN(CAVS_INTC_NODE(0)): cavs_idx = 0; break; case DT_IRQN(CAVS_INTC_NODE(1)): cavs_idx = 1; break; case DT_IRQN(CAVS_INTC_NODE(2)): cavs_idx = 2; break; case DT_IRQN(CAVS_INTC_NODE(3)): cavs_idx = 3; break; default: ret = -EINVAL; goto irq_connect_out; } table_idx = CONFIG_CAVS_ISR_TBL_OFFSET + CONFIG_MAX_IRQ_PER_AGGREGATOR * cavs_idx; table_idx += cavs_irq; _sw_isr_table[table_idx].arg = parameter; _sw_isr_table[table_idx].isr = routine; irq_connect_out: return ret; } #endif static inline void soc_set_power_and_clock(void) { volatile struct soc_dsp_shim_regs *dsp_shim_regs = (volatile struct soc_dsp_shim_regs *)SOC_DSP_SHIM_REG_BASE; /* * DSP Core 0 PLL Clock Select divide by 1 * DSP Core 1 PLL Clock Select divide by 1 * Low Power Domain Clock Select depends on LMPCS bit * High Power Domain Clock Select depands on HMPCS bit * Low Power Domain PLL Clock Select device by 4 * High Power Domain PLL Clock Select device by 2 * Tensilica Core Prevent Audio PLL Shutdown (TCPAPLLS) * Tensilica Core Prevent Local Clock Gating (Core 0) * Tensilica Core Prevent Local Clock Gating (Core 1) */ dsp_shim_regs->clkctl = SOC_CLKCTL_DPCS_DIV1(0) | SOC_CLKCTL_DPCS_DIV1(1) | SOC_CLKCTL_LDCS_LMPCS | SOC_CLKCTL_HDCS_HMPCS | SOC_CLKCTL_LPMEM_PLL_CLK_SEL_DIV4 | SOC_CLKCTL_HPMEM_PLL_CLK_SEL_DIV2 | SOC_CLKCTL_TCPAPLLS | SOC_CLKCTL_TCPLCG_DIS(0) | SOC_CLKCTL_TCPLCG_DIS(1); /* Disable power gating for both cores */ dsp_shim_regs->pwrctl |= SOC_PWRCTL_DISABLE_PWR_GATING_DSP1 | SOC_PWRCTL_DISABLE_PWR_GATING_DSP0; /* Rewrite the low power sequencing control bits */ dsp_shim_regs->lpsctl = dsp_shim_regs->lpsctl; } static int soc_init(struct device *dev) { soc_set_power_and_clock(); return 0; } SYS_INIT(soc_init, PRE_KERNEL_1, 99);