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:
parent
b7e181c270
commit
a026370461
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = {}; \
|
||||
|
|
|
@ -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 = {}; \
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue