diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 9e07386e59e..e9b7488f05b 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -41,6 +41,7 @@ zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC intc_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_NXP_PINT intc_nxp_pint.c) zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_renesas_ra_icu.c) zephyr_library_sources_ifdef(CONFIG_NXP_IRQSTEER intc_nxp_irqsteer.c) +zephyr_library_sources_ifdef(CONFIG_INTC_MTK_ADSP intc_mtk_adsp.c) if(CONFIG_INTEL_VTD_ICTL) zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index d2bd166c96c..250309d2083 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -106,4 +106,6 @@ source "drivers/interrupt_controller/Kconfig.renesas_ra" source "drivers/interrupt_controller/Kconfig.nxp_irqsteer" +source "drivers/interrupt_controller/Kconfig.mtk_adsp" + endmenu diff --git a/drivers/interrupt_controller/Kconfig.mtk_adsp b/drivers/interrupt_controller/Kconfig.mtk_adsp new file mode 100644 index 00000000000..0c8875973e8 --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.mtk_adsp @@ -0,0 +1,9 @@ +# Copyright 2023 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 + +config INTC_MTK_ADSP + bool "MediaTek Audio DSP Interrupt Controller" + help + Very simple cascaded interrupt controller consisting of two + bitfield registers (status and enable) and one mask value + defining valid interrupts. diff --git a/drivers/interrupt_controller/intc_mtk_adsp.c b/drivers/interrupt_controller/intc_mtk_adsp.c new file mode 100644 index 00000000000..b562c9b501b --- /dev/null +++ b/drivers/interrupt_controller/intc_mtk_adsp.c @@ -0,0 +1,82 @@ +/* Copyright 2023 The ChromiumOS Authors + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#define DT_DRV_COMPAT mediatek_adsp_intc + +struct intc_mtk_cfg { + uint32_t xtensa_irq; + uint32_t irq_mask; + uint32_t sw_isr_off; + volatile uint32_t *enable_reg; + volatile uint32_t *status_reg; +}; + +bool intc_mtk_adsp_get_enable(const struct device *dev, int irq) +{ + const struct intc_mtk_cfg *cfg = dev->config; + + return (*cfg->enable_reg | (BIT(irq) & cfg->irq_mask)) != 0; +} + +void intc_mtk_adsp_set_enable(const struct device *dev, int irq, bool val) +{ + const struct intc_mtk_cfg *cfg = dev->config; + + irq_enable(cfg->xtensa_irq); + + if ((BIT(irq) & cfg->irq_mask) != 0) { + if (val) { + *cfg->enable_reg |= BIT(irq); + } else { + *cfg->enable_reg &= ~BIT(irq); + } + } +} + +static void intc_isr(const void *arg) +{ + const struct intc_mtk_cfg *cfg = ((struct device *)arg)->config; + uint32_t irqs = *cfg->status_reg & cfg->irq_mask; + + while (irqs != 0) { + uint32_t irq = find_msb_set(irqs) - 1; + uint32_t off = cfg->sw_isr_off + irq; + + _sw_isr_table[off].isr(_sw_isr_table[off].arg); + irqs &= ~BIT(irq); + } +} + +static void dev_init(const struct device *dev) +{ + const struct intc_mtk_cfg *cfg = dev->config; + + *cfg->enable_reg = 0; + irq_enable(cfg->xtensa_irq); +} + +#define DEV_INIT(N) \ + IRQ_CONNECT(DT_INST_IRQN(N), 0, intc_isr, DEVICE_DT_INST_GET(N), 0); \ + dev_init(DEVICE_DT_INST_GET(N)); + +static int intc_init(void) +{ + DT_INST_FOREACH_STATUS_OKAY(DEV_INIT); + return 0; +} + +SYS_INIT(intc_init, PRE_KERNEL_1, 0); + +#define DEF_DEV(N) \ +static const struct intc_mtk_cfg dev_cfg##N = { \ + .xtensa_irq = DT_INST_IRQN(N), \ + .irq_mask = DT_INST_PROP(N, mask), \ + .sw_isr_off = (N + 1) * 32, \ + .enable_reg = (void *)DT_INST_REG_ADDR(N), \ + .status_reg = (void *)DT_INST_PROP(N, status_reg) }; \ +DEVICE_DT_INST_DEFINE(N, NULL, NULL, NULL, &dev_cfg##N, PRE_KERNEL_1, 0, NULL); + +DT_INST_FOREACH_STATUS_OKAY(DEF_DEV); diff --git a/dts/bindings/interrupt-controller/mediatek,adsp_intc.yaml b/dts/bindings/interrupt-controller/mediatek,adsp_intc.yaml new file mode 100644 index 00000000000..03f5941d363 --- /dev/null +++ b/dts/bindings/interrupt-controller/mediatek,adsp_intc.yaml @@ -0,0 +1,33 @@ +# Copyright 2023 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 + +description: MediaTek MT8xxx Audio DSP Interrupt Controller + +compatible: "mediatek,adsp_intc" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + "#interrupt-cells": + const: 3 + + status-reg: + description: Register address of interrupt-is-signaled bits + type: int + required: true + + mask: + description: Mask of valid interrupt bits + type: int + required: true + +interrupt-cells: + - irq + - sense + - priority