From a0263704619c4b7c302711b0c2614b194fd8de7c Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 18 Jul 2023 11:59:49 +0200 Subject: [PATCH] drivers: hda: use interrupt for timing L1 exit on host DMA To properly setup L1 exit timing this patch will use buffer interrupt for HOST DMA and wait for Host HDA to actually start First interrupt will clear all others. Signed-off-by: Adrian Bonislawski Signed-off-by: Kai Vehmanen --- drivers/dma/Kconfig.intel_adsp_hda | 7 ++ drivers/dma/dma_intel_adsp_hda.c | 79 +++++++++++++++++++ drivers/dma/dma_intel_adsp_hda.h | 6 ++ drivers/dma/dma_intel_adsp_hda_host_in.c | 18 ++++- drivers/dma/dma_intel_adsp_hda_host_out.c | 18 ++++- drivers/dma/dma_intel_adsp_hda_link_in.c | 3 +- drivers/dma/dma_intel_adsp_hda_link_out.c | 3 +- dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi | 4 + .../common/include/intel_adsp_hda.h | 4 +- 9 files changed, 134 insertions(+), 8 deletions(-) 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)