diff --git a/drivers/dma/Kconfig.intel_adsp_hda b/drivers/dma/Kconfig.intel_adsp_hda index d219595458a..20ced567cb0 100644 --- a/drivers/dma/Kconfig.intel_adsp_hda +++ b/drivers/dma/Kconfig.intel_adsp_hda @@ -41,3 +41,10 @@ config DMA_INTEL_ADSP_HDA depends on DMA_INTEL_ADSP_HDA_LINK_OUT || DMA_INTEL_ADSP_HDA_LINK_IN || DMA_INTEL_ADSP_HDA_HOST_OUT || DMA_INTEL_ADSP_HDA_HOST_IN help Intel ADSP HDA DMA driver. + +config DMA_INTEL_ADSP_HDA_TIMING_L1_EXIT + bool "Intel ADSP HDA Host L1 Exit Interrupt" + default y if SOC_INTEL_ACE15_MTPM + depends on DMA_INTEL_ADSP_HDA_HOST_IN || DMA_INTEL_ADSP_HDA_HOST_OUT + help + Intel ADSP HDA Host Interrupt for L1 exit. diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 3189f774e71..14768e7531a 100644 --- a/drivers/dma/dma_intel_adsp_hda.c +++ b/drivers/dma/dma_intel_adsp_hda.c @@ -181,6 +181,34 @@ int intel_adsp_hda_dma_host_reload(const struct device *dev, uint32_t channel, __ASSERT(channel < cfg->dma_channels, "Channel does not exist"); +#if CONFIG_DMA_INTEL_ADSP_HDA_TIMING_L1_EXIT +#if CONFIG_SOC_SERIES_INTEL_ACE + ACE_DfPMCCH.svcfg |= ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT; +#endif + switch (cfg->direction) { + case HOST_TO_MEMORY: + uint32_t rp = *DGBRP(cfg->base, cfg->regblock_size, channel); + uint32_t next_rp = (rp + INTEL_HDA_MIN_FPI_INCREMENT_FOR_INTERRUPT) % + intel_adsp_hda_get_buffer_size(cfg->base, cfg->regblock_size, channel); + + intel_adsp_hda_set_buffer_segment_ptr(cfg->base, cfg->regblock_size, + channel, next_rp); + intel_adsp_hda_enable_buffer_interrupt(cfg->base, cfg->regblock_size, channel); + break; + case MEMORY_TO_HOST: + uint32_t wp = *DGBWP(cfg->base, cfg->regblock_size, channel); + uint32_t next_wp = (wp + INTEL_HDA_MIN_FPI_INCREMENT_FOR_INTERRUPT) % + intel_adsp_hda_get_buffer_size(cfg->base, cfg->regblock_size, channel); + + intel_adsp_hda_set_buffer_segment_ptr(cfg->base, cfg->regblock_size, + channel, next_wp); + intel_adsp_hda_enable_buffer_interrupt(cfg->base, cfg->regblock_size, channel); + break; + default: + break; + } +#endif + intel_adsp_hda_host_commit(cfg->base, cfg->regblock_size, channel, size); return 0; @@ -322,6 +350,13 @@ static void intel_adsp_hda_channels_init(const struct device *dev) intel_adsp_hda_link_commit(cfg->base, cfg->regblock_size, i, size); } } + +#if CONFIG_DMA_INTEL_ADSP_HDA_TIMING_L1_EXIT + /* Configure interrupts */ + if (cfg->irq_config) { + cfg->irq_config(); + } +#endif } int intel_adsp_hda_dma_init(const struct device *dev) @@ -389,3 +424,47 @@ int intel_adsp_hda_dma_pm_action(const struct device *dev, enum pm_device_action return 0; } #endif + +#define DEVICE_DT_GET_AND_COMMA(node_id) DEVICE_DT_GET(node_id), + +void intel_adsp_hda_dma_isr(void) +{ +#if CONFIG_DMA_INTEL_ADSP_HDA_TIMING_L1_EXIT + struct dma_context *dma_ctx; + const struct intel_adsp_hda_dma_cfg *cfg; + bool clear_l1_exit = false; + int i, j; + const struct device *host_dev[] = { +#if CONFIG_DMA_INTEL_ADSP_HDA_HOST_OUT + DT_FOREACH_STATUS_OKAY(intel_adsp_hda_host_out, DEVICE_DT_GET_AND_COMMA) +#endif +#if CONFIG_DMA_INTEL_ADSP_HDA_HOST_IN + DT_FOREACH_STATUS_OKAY(intel_adsp_hda_host_in, DEVICE_DT_GET_AND_COMMA) +#endif + }; + + for (i = 0; i < ARRAY_SIZE(host_dev); i++) { + dma_ctx = (struct dma_context *)host_dev[i]->data; + cfg = host_dev[i]->config; + + for (j = 0; j < dma_ctx->dma_channels; j++) { + if (atomic_test_bit(dma_ctx->atomic, j)) { + clear_l1_exit |= + intel_adsp_hda_check_buffer_interrupt(cfg->base, + cfg->regblock_size, + j); + intel_adsp_hda_disable_buffer_interrupt(cfg->base, + cfg->regblock_size, j); + intel_adsp_hda_clear_buffer_interrupt(cfg->base, + cfg->regblock_size, j); + } + } + } + + if (clear_l1_exit) { +#if CONFIG_SOC_SERIES_INTEL_ACE + ACE_DfPMCCH.svcfg &= ~(ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT); +#endif + } +#endif +} diff --git a/drivers/dma/dma_intel_adsp_hda.h b/drivers/dma/dma_intel_adsp_hda.h index 4638732a8ac..d9937a52a93 100644 --- a/drivers/dma/dma_intel_adsp_hda.h +++ b/drivers/dma/dma_intel_adsp_hda.h @@ -9,6 +9,9 @@ #define INTEL_ADSP_HDA_MAX_CHANNELS DT_PROP(DT_NODELABEL(hda_host_out), dma_channels) +/* Minimum recommended FPI increment */ +#define INTEL_HDA_MIN_FPI_INCREMENT_FOR_INTERRUPT 32 + #include #include #include @@ -24,6 +27,7 @@ struct intel_adsp_hda_dma_cfg { uint32_t regblock_size; uint32_t dma_channels; enum dma_channel_direction direction; + void (*irq_config)(void); }; int intel_adsp_hda_dma_host_in_config(const struct device *dev, @@ -62,6 +66,8 @@ int intel_adsp_hda_dma_init(const struct device *dev); int intel_adsp_hda_dma_get_attribute(const struct device *dev, uint32_t type, uint32_t *value); +void intel_adsp_hda_dma_isr(void); + #ifdef CONFIG_PM_DEVICE int intel_adsp_hda_dma_pm_action(const struct device *dev, enum pm_device_action action); #endif diff --git a/drivers/dma/dma_intel_adsp_hda_host_in.c b/drivers/dma/dma_intel_adsp_hda_host_in.c index 4fbf42e5328..a999c7fbba6 100644 --- a/drivers/dma/dma_intel_adsp_hda_host_in.c +++ b/drivers/dma/dma_intel_adsp_hda_host_in.c @@ -7,6 +7,7 @@ #define DT_DRV_COMPAT intel_adsp_hda_host_in #include +#include #include "dma_intel_adsp_hda.h" static const struct dma_driver_api intel_adsp_hda_dma_host_in_api = { @@ -20,11 +21,14 @@ static const struct dma_driver_api intel_adsp_hda_dma_host_in_api = { }; #define INTEL_ADSP_HDA_DMA_HOST_IN_INIT(inst) \ + static void intel_adsp_hda_dma##inst##_irq_config(void); \ + \ static const struct intel_adsp_hda_dma_cfg intel_adsp_hda_dma##inst##_config = { \ .base = DT_INST_REG_ADDR(inst), \ .regblock_size = DT_INST_REG_SIZE(inst), \ .dma_channels = DT_INST_PROP(inst, dma_channels), \ - .direction = MEMORY_TO_HOST \ + .direction = MEMORY_TO_HOST, \ + .irq_config = intel_adsp_hda_dma##inst##_irq_config \ }; \ \ static struct intel_adsp_hda_dma_data intel_adsp_hda_dma##inst##_data = {}; \ @@ -36,6 +40,16 @@ static const struct dma_driver_api intel_adsp_hda_dma_host_in_api = { &intel_adsp_hda_dma##inst##_data, \ &intel_adsp_hda_dma##inst##_config, POST_KERNEL, \ CONFIG_DMA_INIT_PRIORITY, \ - &intel_adsp_hda_dma_host_in_api); + &intel_adsp_hda_dma_host_in_api); \ + \ + static void intel_adsp_hda_dma##inst##_irq_config(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), intel_adsp_hda_dma_isr, \ + DEVICE_DT_INST_GET(inst), \ + DT_INST_IRQ(inst, sense)); \ + irq_enable(DT_INST_IRQN(inst)); \ + IF_ENABLED(CONFIG_SOC_SERIES_INTEL_ACE, (ACE_DINT[0].ie[ACE_INTL_HDAHIDMA] = 1;)) \ + } DT_INST_FOREACH_STATUS_OKAY(INTEL_ADSP_HDA_DMA_HOST_IN_INIT) diff --git a/drivers/dma/dma_intel_adsp_hda_host_out.c b/drivers/dma/dma_intel_adsp_hda_host_out.c index efd85e93fe8..cb7d9137a1a 100644 --- a/drivers/dma/dma_intel_adsp_hda_host_out.c +++ b/drivers/dma/dma_intel_adsp_hda_host_out.c @@ -7,6 +7,7 @@ #define DT_DRV_COMPAT intel_adsp_hda_host_out #include +#include #include "dma_intel_adsp_hda.h" #define LOG_LEVEL CONFIG_DMA_LOG_LEVEL @@ -24,11 +25,14 @@ static const struct dma_driver_api intel_adsp_hda_dma_host_out_api = { }; #define INTEL_ADSP_HDA_DMA_HOST_OUT_INIT(inst) \ + static void intel_adsp_hda_dma##inst##_irq_config(void); \ + \ static const struct intel_adsp_hda_dma_cfg intel_adsp_hda_dma##inst##_config = { \ .base = DT_INST_REG_ADDR(inst), \ .regblock_size = DT_INST_REG_SIZE(inst), \ .dma_channels = DT_INST_PROP(inst, dma_channels), \ - .direction = HOST_TO_MEMORY \ + .direction = HOST_TO_MEMORY, \ + .irq_config = intel_adsp_hda_dma##inst##_irq_config, \ }; \ \ static struct intel_adsp_hda_dma_data intel_adsp_hda_dma##inst##_data = {}; \ @@ -40,6 +44,16 @@ static const struct dma_driver_api intel_adsp_hda_dma_host_out_api = { &intel_adsp_hda_dma##inst##_data, \ &intel_adsp_hda_dma##inst##_config, POST_KERNEL, \ CONFIG_DMA_INIT_PRIORITY, \ - &intel_adsp_hda_dma_host_out_api); + &intel_adsp_hda_dma_host_out_api); \ + \ + static void intel_adsp_hda_dma##inst##_irq_config(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), intel_adsp_hda_dma_isr, \ + DEVICE_DT_INST_GET(inst), \ + DT_INST_IRQ(inst, sense)); \ + irq_enable(DT_INST_IRQN(inst)); \ + IF_ENABLED(CONFIG_SOC_SERIES_INTEL_ACE, (ACE_DINT[0].ie[ACE_INTL_HDAHODMA] = 1;)) \ + } DT_INST_FOREACH_STATUS_OKAY(INTEL_ADSP_HDA_DMA_HOST_OUT_INIT) diff --git a/drivers/dma/dma_intel_adsp_hda_link_in.c b/drivers/dma/dma_intel_adsp_hda_link_in.c index 8f415d6e57e..fc631d136f0 100644 --- a/drivers/dma/dma_intel_adsp_hda_link_in.c +++ b/drivers/dma/dma_intel_adsp_hda_link_in.c @@ -29,7 +29,8 @@ static const struct dma_driver_api intel_adsp_hda_dma_link_in_api = { .base = DT_INST_REG_ADDR(inst), \ .regblock_size = DT_INST_REG_SIZE(inst), \ .dma_channels = DT_INST_PROP(inst, dma_channels), \ - .direction = PERIPHERAL_TO_MEMORY \ + .direction = PERIPHERAL_TO_MEMORY, \ + .irq_config = NULL \ }; \ \ static struct intel_adsp_hda_dma_data intel_adsp_hda_dma##inst##_data = {}; \ diff --git a/drivers/dma/dma_intel_adsp_hda_link_out.c b/drivers/dma/dma_intel_adsp_hda_link_out.c index 03200539a56..eefa50189f0 100644 --- a/drivers/dma/dma_intel_adsp_hda_link_out.c +++ b/drivers/dma/dma_intel_adsp_hda_link_out.c @@ -29,7 +29,8 @@ static const struct dma_driver_api intel_adsp_hda_dma_link_out_api = { .base = DT_INST_REG_ADDR(inst), \ .regblock_size = DT_INST_REG_SIZE(inst), \ .dma_channels = DT_INST_PROP(inst, dma_channels), \ - .direction = MEMORY_TO_PERIPHERAL \ + .direction = MEMORY_TO_PERIPHERAL, \ + .irq_config = NULL \ }; \ \ static struct intel_adsp_hda_dma_data intel_adsp_hda_dma##inst##_data = {}; \ diff --git a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi index 0c2711e0920..f68c745f45d 100644 --- a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi @@ -487,6 +487,8 @@ dma-buf-size-alignment = <32>; dma-copy-alignment = <32>; power-domain = <&hst_domain>; + interrupts = <13 0 0>; + interrupt-parent = <&ace_intc>; status = "okay"; }; @@ -499,6 +501,8 @@ dma-buf-size-alignment = <32>; dma-copy-alignment = <32>; power-domain = <&hst_domain>; + interrupts = <12 0 0>; + interrupt-parent = <&ace_intc>; status = "okay"; }; diff --git a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h index 791b52bf6de..2d166d8950a 100644 --- a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h +++ b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h @@ -392,7 +392,7 @@ static inline void intel_adsp_hda_underrun_clear(uint32_t base, uint32_t regbloc * @param base Base address of the IP register block * @param regblock_size Register block size * @param sid Stream ID - * @param size size + * @param size */ static inline void intel_adsp_hda_set_buffer_segment_ptr(uint32_t base, uint32_t regblock_size, uint32_t sid, uint32_t size) @@ -461,7 +461,7 @@ static inline void intel_adsp_hda_clear_buffer_interrupt(uint32_t base, uint32_t * @param regblock_size Register block size * @param sid Stream ID * - * @retval buffer segment ptr + * @retval interrupt status */ static inline uint32_t intel_adsp_hda_check_buffer_interrupt(uint32_t base, uint32_t regblock_size, uint32_t sid)