diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 5e68b347ad9..3433fd33a4c 100644 --- a/drivers/dma/dma_intel_adsp_hda.c +++ b/drivers/dma/dma_intel_adsp_hda.c @@ -190,6 +190,7 @@ int intel_adsp_hda_dma_status(const struct device *dev, uint32_t channel, struct dma_status *stat) { const struct intel_adsp_hda_dma_cfg *const cfg = dev->config; + bool xrun_det; __ASSERT(channel < cfg->dma_channels, "Channel does not exist"); @@ -203,6 +204,25 @@ int intel_adsp_hda_dma_status(const struct device *dev, uint32_t channel, stat->pending_length = used; stat->free = unused; + switch (cfg->direction) { + case MEMORY_TO_PERIPHERAL: + xrun_det = intel_adsp_hda_is_buffer_underrun(cfg->base, cfg->regblock_size, + channel); + if (xrun_det) { + intel_adsp_hda_underrun_clear(cfg->base, cfg->regblock_size, channel); + return -EPIPE; + } + case PERIPHERAL_TO_MEMORY: + xrun_det = intel_adsp_hda_is_buffer_overrun(cfg->base, cfg->regblock_size, + channel); + if (xrun_det) { + intel_adsp_hda_overrun_clear(cfg->base, cfg->regblock_size, channel); + return -EPIPE; + } + default: + break; + } + return 0; } 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 258f9c58e23..4395a19ea94 100644 --- a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h +++ b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h @@ -346,4 +346,28 @@ static inline bool intel_adsp_hda_wp_rp_eq(uint32_t base, uint32_t regblock_size return *DGBWP(base, regblock_size, sid) == *DGBRP(base, regblock_size, sid); } +static inline bool intel_adsp_hda_is_buffer_overrun(uint32_t base, uint32_t regblock_size, + uint32_t sid) +{ + return (*DGCS(base, regblock_size, sid) & DGCS_BOR) == DGCS_BOR ? 1 : 0; +} + +static inline bool intel_adsp_hda_is_buffer_underrun(uint32_t base, uint32_t regblock_size, + uint32_t sid) +{ + return (*DGCS(base, regblock_size, sid) & DGCS_BUR) == DGCS_BUR ? 1 : 0; +} + +static inline void intel_adsp_hda_overrun_clear(uint32_t base, uint32_t regblock_size, + uint32_t sid) +{ + *DGCS(base, regblock_size, sid) |= DGCS_BOR; +} + +static inline void intel_adsp_hda_underrun_clear(uint32_t base, uint32_t regblock_size, + uint32_t sid) +{ + *DGCS(base, regblock_size, sid) |= DGCS_BUR; +} + #endif /* ZEPHYR_INCLUDE_INTEL_ADSP_HDA_H */