diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 447694038ffd55..4494b4b52218fc 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -207,3 +207,11 @@ void *xtensa_excint1_c(int *interrupted_stack) return z_get_next_switch_handle(interrupted_stack); } +int z_xtensa_irq_is_enabled(unsigned int irq) +{ + u32_t ie; + + __asm__ volatile("rsr.intenable %0" : "=r"(ie)); + + return (ie & (1 << irq)) != 0; +} diff --git a/drivers/interrupt_controller/cavs_ictl.c b/drivers/interrupt_controller/cavs_ictl.c index 9f057ab4f1db80..76c56ee312b73d 100644 --- a/drivers/interrupt_controller/cavs_ictl.c +++ b/drivers/interrupt_controller/cavs_ictl.c @@ -75,10 +75,25 @@ static inline unsigned int cavs_ictl_irq_get_state(struct device *dev) return 1; } +static int cavs_ictl_irq_get_line_state(struct device *dev, unsigned int irq) +{ + struct cavs_ictl_runtime *context = dev->driver_data; + + volatile struct cavs_registers * const regs = + (struct cavs_registers *)context->base_addr; + + if ((regs->disable_state_il & BIT(irq)) == 0) { + return 1; + } + + return 0; +} + static const struct irq_next_level_api cavs_apis = { .intr_enable = cavs_ictl_irq_enable, .intr_disable = cavs_ictl_irq_disable, .intr_get_state = cavs_ictl_irq_get_state, + .intr_get_line_state = cavs_ictl_irq_get_line_state, }; static int cavs_ictl_0_initialize(struct device *port) diff --git a/drivers/interrupt_controller/dw_ictl.c b/drivers/interrupt_controller/dw_ictl.c index 4738abc36520a7..faac1138883b8f 100644 --- a/drivers/interrupt_controller/dw_ictl.c +++ b/drivers/interrupt_controller/dw_ictl.c @@ -113,6 +113,28 @@ static inline unsigned int dw_ictl_intr_get_state(struct device *dev) return 0; } +static int dw_ictl_intr_get_line_state(struct device *dev, unsigned int irq) +{ + struct dw_ictl_runtime *context = dev->driver_data; + + const struct dw_ictl_config *config = dev->config->config_info; + + volatile struct dw_ictl_registers * const regs = + (struct dw_ictl_registers *)context->base_addr; + + if (config->numirqs > 32) { + if ((regs->irq_inten_h & BIT(irq - 32)) != 0) { + return 1; + } + } else { + if ((regs->irq_inten_l & BIT(irq)) != 0) { + return 1; + } + } + + return 0; +} + static void dw_ictl_config_irq(struct device *port); static const struct dw_ictl_config dw_config = { @@ -130,6 +152,7 @@ static const struct irq_next_level_api dw_ictl_apis = { .intr_enable = dw_ictl_intr_enable, .intr_disable = dw_ictl_intr_disable, .intr_get_state = dw_ictl_intr_get_state, + .intr_get_line_state = dw_ictl_intr_get_line_state, }; DEVICE_AND_API_INIT(dw_ictl, CONFIG_DW_ICTL_NAME, dw_ictl_initialize, diff --git a/drivers/interrupt_controller/rv32m1_intmux.c b/drivers/interrupt_controller/rv32m1_intmux.c index 057550cbf993d6..f6fad87772a4c9 100644 --- a/drivers/interrupt_controller/rv32m1_intmux.c +++ b/drivers/interrupt_controller/rv32m1_intmux.c @@ -86,6 +86,19 @@ static u32_t rv32m1_intmux_get_state(struct device *dev) return 0; } +static int rv32m1_intmux_get_line_state(struct device *dev, unsigned int irq) +{ + INTMUX_Type *regs = DEV_REGS(dev); + u32_t channel = rv32m1_intmux_channel(irq); + u32_t line = rv32m1_intmux_line(irq); + + if ((regs->CHANNEL[channel].CHn_IER_31_0 & BIT(line)) != 0) { + return 1; + } + + return 0; +} + /* * IRQ handling. */ @@ -113,6 +126,7 @@ static const struct irq_next_level_api rv32m1_intmux_apis = { .intr_enable = rv32m1_intmux_irq_enable, .intr_disable = rv32m1_intmux_irq_disable, .intr_get_state = rv32m1_intmux_get_state, + .intr_get_line_state = rv32m1_intmux_get_line_state, }; static const struct rv32m1_intmux_config rv32m1_intmux_cfg = { diff --git a/include/arch/xtensa/irq.h b/include/arch/xtensa/irq.h index d93efc06b144d6..4882eb67fbb66e 100644 --- a/include/arch/xtensa/irq.h +++ b/include/arch/xtensa/irq.h @@ -34,6 +34,8 @@ #define z_arch_irq_enable(irq) z_soc_irq_enable(irq) #define z_arch_irq_disable(irq) z_soc_irq_disable(irq) +#define z_arch_irq_is_enabled(irq) z_soc_irq_is_enabled(irq) + #ifdef CONFIG_DYNAMIC_INTERRUPTS extern int z_soc_irq_connect_dynamic(unsigned int irq, unsigned int priority, void (*routine)(void *parameter), @@ -47,6 +49,8 @@ extern int z_soc_irq_connect_dynamic(unsigned int irq, unsigned int priority, #define z_arch_irq_enable(irq) z_xtensa_irq_enable(irq) #define z_arch_irq_disable(irq) z_xtensa_irq_disable(irq) +#define z_arch_irq_is_enabled(irq) z_xtensa_irq_is_enabled(irq) + #endif /** @@ -98,6 +102,8 @@ static ALWAYS_INLINE bool z_arch_irq_unlocked(unsigned int key) return (key & 0xf) == 0; /* INTLEVEL field */ } +extern int z_xtensa_irq_is_enabled(unsigned int irq); + #include #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_IRQ_H_ */ diff --git a/include/irq_nextlevel.h b/include/irq_nextlevel.h index f8140861f234da..b7263136bb6a94 100644 --- a/include/irq_nextlevel.h +++ b/include/irq_nextlevel.h @@ -23,11 +23,14 @@ extern "C" { */ typedef void (*irq_next_level_func_t)(struct device *dev, unsigned int irq); typedef unsigned int (*irq_next_level_get_state_t)(struct device *dev); +typedef int (*irq_next_level_get_line_state_t)(struct device *dev, + unsigned int irq); struct irq_next_level_api { irq_next_level_func_t intr_enable; irq_next_level_func_t intr_disable; irq_next_level_get_state_t intr_get_state; + irq_next_level_get_line_state_t intr_get_line_state; }; /** * @endcond @@ -84,6 +87,24 @@ static inline unsigned int irq_is_enabled_next_level(struct device *dev) return api->intr_get_state(dev); } +/** + * @brief Get IRQ line enable state. + * + * Query if a particular IRQ line is enabled. + * + * @param dev Pointer to the device structure for the driver instance. + * @param irq IRQ line to be queried. + * + * @return interrupt enable state, true or false + */ +static inline unsigned int irq_line_is_enabled_next_level(struct device *dev, + unsigned int irq) +{ + const struct irq_next_level_api *api = dev->driver_api; + + return api->intr_get_line_state(dev, irq); +} + /** * @} */ diff --git a/soc/xtensa/intel_apl_adsp/soc.c b/soc/xtensa/intel_apl_adsp/soc.c index d8f07f441e74af..7ad9e970207ed8 100644 --- a/soc/xtensa/intel_apl_adsp/soc.c +++ b/soc/xtensa/intel_apl_adsp/soc.c @@ -101,6 +101,43 @@ void z_soc_irq_disable(u32_t irq) } } +int z_soc_irq_is_enabled(unsigned int irq) +{ + struct device *dev_cavs; + int ret = 0; + + switch (XTENSA_IRQ_NUMBER(irq)) { + case DT_CAVS_ICTL_0_IRQ: + dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_0_NAME); + break; + case DT_CAVS_ICTL_1_IRQ: + dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_1_NAME); + break; + case DT_CAVS_ICTL_2_IRQ: + dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_2_NAME); + break; + case DT_CAVS_ICTL_3_IRQ: + dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_3_NAME); + 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), diff --git a/soc/xtensa/intel_apl_adsp/soc.h b/soc/xtensa/intel_apl_adsp/soc.h index 096241f793e340..ae7a5ff25605c3 100644 --- a/soc/xtensa/intel_apl_adsp/soc.h +++ b/soc/xtensa/intel_apl_adsp/soc.h @@ -184,6 +184,7 @@ struct soc_dsp_shim_regs { extern void z_soc_irq_enable(u32_t irq); extern void z_soc_irq_disable(u32_t irq); +extern int z_soc_irq_is_enabled(unsigned int irq); extern u32_t soc_get_ref_clk_freq(void); diff --git a/soc/xtensa/intel_s1000/soc.c b/soc/xtensa/intel_s1000/soc.c index 7842fc26415cb5..f79a364c904a2c 100644 --- a/soc/xtensa/intel_s1000/soc.c +++ b/soc/xtensa/intel_s1000/soc.c @@ -147,6 +147,59 @@ void z_soc_irq_disable(u32_t irq) } } +int z_soc_irq_is_enabled(unsigned int irq) +{ + struct device *dev_cavs, *dev_ictl; + int ret = -EINVAL; + + switch (XTENSA_IRQ_NUMBER(irq)) { + case DT_CAVS_ICTL_0_IRQ: + dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_0_NAME); + break; + case DT_CAVS_ICTL_1_IRQ: + dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_1_NAME); + break; + case DT_CAVS_ICTL_2_IRQ: + dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_2_NAME); + break; + case DT_CAVS_ICTL_3_IRQ: + dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_3_NAME); + break; + default: + /* regular interrupt */ + ret = z_xtensa_is_irq_enabled(XTENSA_IRQ_NUMBER(irq)); + goto out; + } + + if (!dev_cavs) { + LOG_DBG("board: CAVS device binding failed"); + ret = -ENODEV; + goto out; + } + + switch (CAVS_IRQ_NUMBER(irq)) { + case DW_ICTL_IRQ_CAVS_OFFSET: + dev_ictl = device_get_binding(CONFIG_DW_ICTL_NAME); + break; + default: + /* The source of the interrupt is in CAVS interrupt logic */ + ret = irq_line_is_enabled_next_level(dev_cavs, + CAVS_IRQ_NUMBER(irq)); + goto out; + } + + if (!dev_ictl) { + LOG_DBG("board: DW intr_control device binding failed"); + ret = -NODEV; + goto out; + } + + ret = irq_line_is_enabled_next_level(dev_ictl, INTR_CNTL_IRQ_NUM(irq)); + +out: + return ret; +} + static inline void soc_set_resource_ownership(void) { volatile struct soc_resource_alloc_regs *regs = diff --git a/soc/xtensa/intel_s1000/soc.h b/soc/xtensa/intel_s1000/soc.h index 8e776caaa7df79..227b4b728e773c 100644 --- a/soc/xtensa/intel_s1000/soc.h +++ b/soc/xtensa/intel_s1000/soc.h @@ -212,6 +212,7 @@ struct soc_global_regs { extern void z_soc_irq_enable(u32_t irq); extern void z_soc_irq_disable(u32_t irq); +extern int z_soc_irq_is_enabled(unsigned int irq); extern u32_t soc_get_ref_clk_freq(void);