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 <adrian.bonislawski@intel.com>
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
This commit is contained in:
Adrian Bonislawski 2023-07-18 11:59:49 +02:00 committed by Anas Nashif
parent b7e181c270
commit a026370461
9 changed files with 134 additions and 8 deletions

View file

@ -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.

View file

@ -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
}

View file

@ -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 <zephyr/drivers/dma.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
@ -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

View file

@ -7,6 +7,7 @@
#define DT_DRV_COMPAT intel_adsp_hda_host_in
#include <zephyr/drivers/dma.h>
#include <adsp_interrupt.h>
#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)

View file

@ -7,6 +7,7 @@
#define DT_DRV_COMPAT intel_adsp_hda_host_out
#include <zephyr/drivers/dma.h>
#include <adsp_interrupt.h>
#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)

View file

@ -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 = {}; \

View file

@ -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 = {}; \

View file

@ -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";
};

View file

@ -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)