From 23cb2a6b0f86761d35c16f31433da5690ac3630a Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 11 Sep 2023 13:39:48 +0300 Subject: [PATCH] driver: imx: Add PDM MICFIL driver The Pulse Density Modulated Microphone Interface (MICFIL) is a popular way to deliver audio from microphones to the processor in several applications, such as mobile telephones. However, current digital-audio systems use multibit audio signal (also known as multibit PCM) to represent the signal. This block implements the required digital interface to provide a 24-bits audio signal from a PDM microphone bitstream in a configurable output sampling rate. This patch adds initial support for PDM MICFIL IP found on i.MX8MP board. Signed-off-by: Daniel Baluta --- src/drivers/imx/CMakeLists.txt | 4 + src/drivers/imx/Kconfig | 9 + src/drivers/imx/micfil.c | 336 ++++++++++++++++++ src/include/ipc/dai-imx.h | 7 + src/include/ipc/dai.h | 4 +- src/include/sof/drivers/micfil.h | 174 +++++++++ src/ipc/ipc3/dai.c | 6 + src/platform/Kconfig | 1 + .../imx8m/include/platform/lib/memory.h | 3 + src/platform/imx8m/lib/dai.c | 27 ++ src/platform/imx8m/lib/dma.c | 2 +- xtos/include/sof/lib/dma.h | 1 + 12 files changed, 572 insertions(+), 2 deletions(-) create mode 100644 src/drivers/imx/micfil.c create mode 100644 src/include/sof/drivers/micfil.h diff --git a/src/drivers/imx/CMakeLists.txt b/src/drivers/imx/CMakeLists.txt index 874e8c012190..5fdc480b76c2 100644 --- a/src/drivers/imx/CMakeLists.txt +++ b/src/drivers/imx/CMakeLists.txt @@ -22,6 +22,10 @@ if(CONFIG_IMX_SDMA) endif() endif() +if(CONFIG_IMX_MICFIL) + add_local_sources(sof micfil.c) +endif() + if(CONFIG_IMX_INTERRUPT_IRQSTEER) add_local_sources(sof interrupt-irqsteer.c) elseif(CONFIG_IMX_INTERRUPT_GENERIC) diff --git a/src/drivers/imx/Kconfig b/src/drivers/imx/Kconfig index 82d667a8275c..7874c72c096b 100644 --- a/src/drivers/imx/Kconfig +++ b/src/drivers/imx/Kconfig @@ -21,6 +21,15 @@ config IMX_ESAI help Select this to enable support for i.MX ESAI IP. +config IMX_MICFIL + bool "i.MX MICFIL PDM driver" + default n + depends on IMX + help + Select this to enable support for i.MX MICFIL PDM IP. This block implements + the required digital interface to provide a 24-bits audio signal from a PDM + microphone bitstream in a configurable output sampling rate + config IMX_INTERRUPT_IRQSTEER bool default n diff --git a/src/drivers/imx/micfil.c b/src/drivers/imx/micfil.c new file mode 100644 index 000000000000..adee0d2df0c8 --- /dev/null +++ b/src/drivers/imx/micfil.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright 2023 NXP +// +// Author: Daniel Baluta + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(micfil_dai, CONFIG_SOF_LOG_LEVEL); + +/* dd400475-35d7-4045-ab03-0c34957d7a08 */ +DECLARE_SOF_UUID("micfil-dai", micfil_uuid, 0xdd400475, 0x35d7, 0x4045, + 0xab, 0x03, 0x0c, 0x34, 0x95, 0x7d, 0x7a, 0x08); + +DECLARE_TR_CTX(micfil_tr, SOF_UUID(micfil_uuid), LOG_LEVEL_INFO); + +#define MICFIL_OSR_DEFAULT 16 +/* set default gain to 2 */ +#define MICFIL_DEFAULT_ADJ_RANGE 0x22222222 +#define MICFIL_CLK_ROOT 24576000 + +enum micfil_quality { + QUALITY_HIGH, + QUALITY_MEDIUM, + QUALITY_LOW, + QUALITY_VLOW0, + QUALITY_VLOW1, + QUALITY_VLOW2, +}; + +static int micfil_reset(struct dai *dai) +{ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_MDIS, 0); + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_SRES, MICFIL_CTRL1_SRES); + dai_update_bits(dai, REG_MICFIL_STAT, 0xff, 0xff); + + return 0; +} + +static int micfil_get_hw_params(struct dai *dai, + struct sof_ipc_stream_params *params, int dir) +{ + struct micfil_pdata *micfil = dai_get_drvdata(dai); + + dai_err(dai, "micfil_get_hw_params()"); + + params->rate = micfil->params.pdm_rate; + params->channels = micfil->params.pdm_ch; + params->buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; + params->frame_fmt = SOF_IPC_FRAME_S32_LE; + + return 0; +} + +static int micfil_set_quality(struct dai *dai) +{ + struct micfil_pdata *micfil = dai_get_drvdata(dai); + int qsel; + + switch (micfil->quality) { + case QUALITY_HIGH: + qsel = MICFIL_QSEL_HIGH_QUALITY; + break; + case QUALITY_MEDIUM: + qsel = MICFIL_QSEL_MEDIUM_QUALITY; + break; + case QUALITY_LOW: + qsel = MICFIL_QSEL_LOW_QUALITY; + break; + case QUALITY_VLOW0: + qsel = MICFIL_QSEL_VLOW0_QUALITY; + break; + case QUALITY_VLOW1: + qsel = MICFIL_QSEL_VLOW1_QUALITY; + break; + case QUALITY_VLOW2: + qsel = MICFIL_QSEL_VLOW2_QUALITY; + break; + default: + dai_err(dai, "MICFIL: invalid quality mode %d", micfil->quality); + return -EINVAL; + } + + dai_update_bits(dai, REG_MICFIL_CTRL2, MICFIL_CTRL2_QSEL, + MICFIL_CTRL2_QSEL_BITS(qsel)); + + return 0; +} + +/* get_pdm_clk - computes the product between k-factor and PDM_CLK rate + * @param dai, SOF DAI struct + * @param rate, output sampling rate + * + * PDM_CLK depends on Quality Mode, output sampling rate and quality + * mode + */ +static int micfil_get_pdm_clk(struct dai *dai, int rate) +{ + unsigned int osr; + unsigned int qsel; + unsigned int ctrl2_reg; + unsigned int pdm_clk = 0; + + ctrl2_reg = dai_read(dai, REG_MICFIL_CTRL2); + osr = 16 - ((ctrl2_reg & MICFIL_CTRL2_CICOSR) >> MICFIL_CTRL2_CICOSR_SHIFT); + qsel = (ctrl2_reg & MICFIL_CTRL2_QSEL) >> MICFIL_CTRL2_QSEL_SHIFT; + + switch (qsel) { + case MICFIL_QSEL_HIGH_QUALITY: + pdm_clk = rate * 8 * osr / 2; /* kfactor = 0.5 */ + break; + case MICFIL_QSEL_MEDIUM_QUALITY: + case MICFIL_QSEL_VLOW0_QUALITY: + pdm_clk = rate * 4 * osr; /* kfactor = 1 */ + break; + case MICFIL_QSEL_LOW_QUALITY: + case MICFIL_QSEL_VLOW1_QUALITY: + pdm_clk = rate * 2 * osr * 2; /* kfactor = 2 */ + break; + case MICFIL_QSEL_VLOW2_QUALITY: + pdm_clk = rate * osr; /* kfactor = 4 */ + break; + default: + break; + } + + return pdm_clk; +} + +static int micfil_get_clk_div(struct dai *dai, int rate) +{ + int pdm_clk; + + pdm_clk = micfil_get_pdm_clk(dai, rate); + if (pdm_clk <= 0) + return -EINVAL; + + return MICFIL_CLK_ROOT / (pdm_clk * 2); +} + +static int micfil_set_clock_params(struct dai *dai, int rate) +{ + int clk_div; + + dai_update_bits(dai, REG_MICFIL_CTRL2, MICFIL_CTRL2_CICOSR, + MICFIL_CTRL2_CICOSR_BITS(MICFIL_OSR_DEFAULT)); + + clk_div = micfil_get_clk_div(dai, rate); + if (clk_div < 0) + return -EINVAL; + + dai_update_bits(dai, REG_MICFIL_CTRL2, MICFIL_CTRL2_CLKDIV, + MICFIL_CTRL2_CLKDIV_BITS(clk_div)); + + return 0; +} + +static int micfil_set_config(struct dai *dai, struct ipc_config_dai *common_config, + const void *spec_config) +{ + int i, ret; + unsigned int val = 0; + struct micfil_pdata *micfil = dai_get_drvdata(dai); + const struct sof_ipc_dai_config *config = spec_config; + + micfil->params = config->micfil; + + dai_info(dai, "micfil_set_config() dai_idx %d channels %d sampling_freq %d", + common_config->dai_index, micfil->params.pdm_ch, micfil->params.pdm_rate); + + /* disable the module */ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_PDMIEN, 0); + + micfil_set_quality(dai); + + /* set default gain to 2 */ + dai_write(dai, REG_MICFIL_OUT_CTRL, MICFIL_DEFAULT_ADJ_RANGE); + + /* set DC Remover in bypass mode */ + for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) + val |= MICFIL_DC_BYPASS << MICFIL_DC_CHX_SHIFT(i); + dai_update_bits(dai, REG_MICFIL_DC_CTRL, MICFIL_DC_CTRL_CONFIG, val); + + /* FIFO WMK */ + dai_update_bits(dai, REG_MICFIL_FIFO_CTRL, MICFIL_FIFO_CTRL_FIFOWMK, + MICFIL_FIFO_CTRL_FIFOWMK_BITS(31)); + + /* enable channels */ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_CHNEN, + ((1 << micfil->params.pdm_ch) - 1)); + + ret = micfil_set_clock_params(dai, micfil->params.pdm_rate); + if (ret < 0) + return -EINVAL; + + return 0; +} + +static int micfil_get_handshake(struct dai *dai, int direction, int stream_id) +{ + return dai->plat_data.fifo[SOF_IPC_STREAM_CAPTURE].handshake; +} + +static int micfil_get_fifo(struct dai *dai, int direction, int stream_id) +{ + return dai->plat_data.fifo[SOF_IPC_STREAM_CAPTURE].offset; +} + +static int micfil_get_fifo_depth(struct dai *dai, int direction) +{ + return dai->plat_data.fifo[SOF_IPC_STREAM_CAPTURE].depth; +} + +static int micfil_start(struct dai *dai) +{ + int ret; + + dai_info(dai, "micfil_start()"); + + ret = micfil_reset(dai); + if (ret < 0) { + dai_err(dai, "micfil_start(): failed to reset micfil"); + return ret; + } + + /* DMA Interrupt Selection - DISEL bits + * 00 - DMA and IRQ disabled + * 01 - DMA req enabled + * 10 - IRQ enabled + * 11 - reserved + */ + dai_update_bits(dai, REG_MICFIL_CTRL1, + MICFIL_CTRL1_DISEL, + MICFIL_CTRL1_DISEL_BITS(MICFIL_CTRL1_DISEL_DMA)); + + /* Enable the module */ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_PDMIEN, MICFIL_CTRL1_PDMIEN); + + return 0; +} + +static int micfil_stop(struct dai *dai) +{ + dai_info(dai, "micfil_stop()"); + + /* Disable the module */ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_PDMIEN, 0); + + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_DISEL, + MICFIL_CTRL1_DISEL_BITS(MICFIL_CTRL1_DISEL_DISABLE)); + + return 0; +} + +static int micfil_trigger(struct dai *dai, int cmd, int direction) +{ + dai_info(dai, "micfil_trigger() cmd %d dir %d", cmd, direction); + + switch (cmd) { + case COMP_TRIGGER_START: + case COMP_TRIGGER_RELEASE: + micfil_start(dai); + break; + case COMP_TRIGGER_STOP: + case COMP_TRIGGER_PAUSE: + micfil_stop(dai); + case COMP_TRIGGER_PRE_START: + case COMP_TRIGGER_PRE_RELEASE: + break; + default: + dai_err(dai, "MICFIL: invalid trigger cmd %d", cmd); + return -EINVAL; + } + + return 0; +} + +static int micfil_probe(struct dai *dai) +{ + struct micfil_pdata *micfil; + + dai_info(dai, "micfil_probe()"); + + micfil = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*micfil)); + if (!micfil) { + dai_err(dai, "micfil probe failed"); + return -ENOMEM; + } + + micfil->quality = QUALITY_VLOW0; + + dai_set_drvdata(dai, micfil); + + return 0; +} + +static int micfil_remove(struct dai *dai) +{ + struct micfil_pdata *micfil = dai_get_drvdata(dai); + + dai_info(dai, "micfil_remove()"); + + rfree(micfil); + dai_set_drvdata(dai, NULL); + + return 0; +} + +const struct dai_driver micfil_driver = { + .type = SOF_DAI_IMX_MICFIL, + .uid = SOF_UUID(micfil_uuid), + .tctx = &micfil_tr, + .dma_dev = DMA_DEV_MICFIL, + .ops = { + .trigger = micfil_trigger, + .set_config = micfil_set_config, + .get_hw_params = micfil_get_hw_params, + .get_handshake = micfil_get_handshake, + .get_fifo = micfil_get_fifo, + .get_fifo_depth = micfil_get_fifo_depth, + .probe = micfil_probe, + .remove = micfil_remove, + }, +}; diff --git a/src/include/ipc/dai-imx.h b/src/include/ipc/dai-imx.h index bc478f0c97ad..5f9fc4dce837 100644 --- a/src/include/ipc/dai-imx.h +++ b/src/include/ipc/dai-imx.h @@ -54,4 +54,11 @@ struct sof_ipc_dai_sai_params { uint16_t reserved2; /* alignment */ } __attribute__((packed, aligned(4))); + +/* MICFIL Configuration Request - SOF_IPC_DAI_MICFIL_CONFIG */ +struct sof_ipc_dai_micfil_params { + uint32_t pdm_rate; + uint32_t pdm_ch; +} __attribute__((packed, aligned(4))); + #endif /* __IPC_DAI_IMX_H__ */ diff --git a/src/include/ipc/dai.h b/src/include/ipc/dai.h index b0ea6d7f6af5..37bd91fa6c29 100644 --- a/src/include/ipc/dai.h +++ b/src/include/ipc/dai.h @@ -92,7 +92,8 @@ enum sof_ipc_dai_type { SOF_DAI_MEDIATEK_AFE, /**< Mtk AFE */ SOF_DAI_AMD_HS, /**< Amd HS */ SOF_DAI_AMD_SP_VIRTUAL, /** + */ + +#ifndef __SOF_DRIVERS_MICFIL_H__ +#define __SOF_DRIVERS_MICFIL_H__ + +#include +#include +#include +#include +#include +#include + +extern const struct dai_driver micfil_driver; + +/* MICFIL private data */ +struct micfil_pdata { + int quality; + struct sof_ipc_dai_config config; + struct sof_ipc_dai_micfil_params params; +}; + +/* MICFIL Register Map */ +#define REG_MICFIL_CTRL1 0x00 +#define REG_MICFIL_CTRL2 0x04 +#define REG_MICFIL_STAT 0x08 +#define REG_MICFIL_FIFO_CTRL 0x10 +#define REG_MICFIL_FIFO_STAT 0x14 +#define REG_MICFIL_DATACH0 0x24 +#define REG_MICFIL_DATACH1 0x28 +#define REG_MICFIL_DATACH2 0x2C +#define REG_MICFIL_DATACH3 0x30 +#define REG_MICFIL_DATACH4 0x34 +#define REG_MICFIL_DATACH5 0x38 +#define REG_MICFIL_DATACH6 0x3C +#define REG_MICFIL_DATACH7 0x40 +#define REG_MICFIL_DC_CTRL 0x64 +#define REG_MICFIL_OUT_CTRL 0x74 +#define REG_MICFIL_OUT_STAT 0x7C +#define REG_MICFIL_VAD0_CTRL1 0x90 +#define REG_MICFIL_VAD0_CTRL2 0x94 + +#define REG_MICFIL_VAD0_STAT 0x98 +#define REG_MICFIL_VAD0_SCONFIG 0x9C +#define REG_MICFIL_VAD0_NCONFIG 0xA0 +#define REG_MICFIL_VAD0_NDATA 0xA4 +#define REG_MICFIL_VAD0_ZCD 0xA8 + +/* MICFIL Control Register 1 -- REG_MICFILL_CTRL1 0x00 */ +#define MICFIL_CTRL1_MDIS BIT(31) +#define MICFIL_CTRL1_DOZEN BIT(30) +#define MICFIL_CTRL1_PDMIEN BIT(29) +#define MICFIL_CTRL1_DBG BIT(28) +#define MICFIL_CTRL1_SRES BIT(27) +#define MICFIL_CTRL1_DBGE BIT(26) +#define MICFIL_CTRL1_CHNEN MASK(7, 0) + +#define MICFIL_CTRL1_DISEL_DISABLE 0 +#define MICFIL_CTRL1_DISEL_DMA 1 +#define MICFIL_CTRL1_DISEL_IRQ 2 +#define MICFIL_CTRL1_DISEL_BITS(x) SET_BITS(25, 24, x) +#define MICFIL_CTRL1_DISEL MASK(25, 24) +#define MICFIL_CTRL1_ERREN BIT(23) +#define MICFIL_CTRL1_CHEN(ch) BIT(ch) + +/* MICFIL Control Register 2 -- REG_MICFILL_CTRL2 0x04 */ +#define MICFIL_CTRL2_QSEL_SHIFT 25 +#define MICFIL_CTRL2_QSEL MASK(27, 25) +#define MICFIL_CTRL2_QSEL_BITS(x) SET_BITS(27, 25, x) +#define MICFIL_QSEL_MEDIUM_QUALITY 0 +#define MICFIL_QSEL_HIGH_QUALITY 1 +#define MICFIL_QSEL_LOW_QUALITY 7 +#define MICFIL_QSEL_VLOW0_QUALITY 6 +#define MICFIL_QSEL_VLOW1_QUALITY 5 +#define MICFIL_QSEL_VLOW2_QUALITY 4 + +#define MICFIL_CTRL2_CICOSR MASK(19, 16) +#define MICFIL_CTRL2_CICOSR_SHIFT 16 +#define MICFIL_CTRL2_CICOSR_BITS(x) SET_BITS(19, 16, x) +#define MICFIL_CTRL2_CLKDIV MASK(7, 0) +#define MICFIL_CTRL2_CLKDIV_BITS(x) SET_BITS(7, 0, x) + +/* MICFIL Status Register -- REG_MICFIL_STAT 0x08 */ +#define MICFIL_STAT_BSY_FIL BIT(31) +#define MICFIL_STAT_FIR_RDY BIT(30) +#define MICFIL_STAT_LOWFREQF BIT(29) +#define MICFIL_STAT_CHXF(ch) BIT(ch) + +/* MICFIL FIFO Control Register -- REG_MICFIL_FIFO_CTRL 0x10 */ +#define MICFIL_FIFO_CTRL_FIFOWMK MASK(2, 0) +#define MICFIL_FIFO_CTRL_FIFOWMK_BITS(x) SET_BITS(2, 0, x) + +/* MICFIL FIFO Status Register -- REG_MICFIL_FIFO_STAT 0x14 */ +#define MICFIL_FIFO_STAT_FIFOX_OVER(ch) BIT(ch) +#define MICFIL_FIFO_STAT_FIFOX_UNDER(ch) BIT((ch) + 8) + +/* MICFIL DC Remover Control Register -- REG_MICFIL_DC_CTRL */ +#define MICFIL_DC_CTRL_CONFIG MASK(15, 0) +#define MICFIL_DC_CHX_SHIFT(ch) ((ch) << 1) +#define MICFIL_DC_CHX(ch) MASK((((ch) << 1) + 1), ((ch) << 1)) +#define MICFIL_DC_CUTOFF_21HZ 0 +#define MICFIL_DC_CUTOFF_83HZ 1 +#define MICFIL_DC_CUTOFF_152Hz 2 +#define MICFIL_DC_BYPASS 3 + +/* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/ +#define MICFIL_VAD0_CTRL1_CHSEL MASK(26, 24) +#define MICFIL_VAD0_CTRL1_CICOSR MASK(19, 16) +#define MICFIL_VAD0_CTRL1_INITT MASK(12, 8) +#define MICFIL_VAD0_CTRL1_ST10 BIT(4) +#define MICFIL_VAD0_CTRL1_ERIE BIT(3) +#define MICFIL_VAD0_CTRL1_IE BIT(2) +#define MICFIL_VAD0_CTRL1_RST BIT(1) +#define MICFIL_VAD0_CTRL1_EN BIT(0) + +/* MICFIL HWVAD0 Control 2 Register -- REG_MICFIL_VAD0_CTRL2*/ +#define MICFIL_VAD0_CTRL2_FRENDIS BIT(31) +#define MICFIL_VAD0_CTRL2_PREFEN BIT(30) +#define MICFIL_VAD0_CTRL2_FOUTDIS BIT(28) +#define MICFIL_VAD0_CTRL2_FRAMET MASK(21, 16) +#define MICFIL_VAD0_CTRL2_INPGAIN MASK(11, 8) +#define MICFIL_VAD0_CTRL2_HPF MASK(1, 0) + +/* MICFIL HWVAD0 Signal CONFIG Register -- REG_MICFIL_VAD0_SCONFIG */ +#define MICFIL_VAD0_SCONFIG_SFILEN BIT(31) +#define MICFIL_VAD0_SCONFIG_SMAXEN BIT(30) +#define MICFIL_VAD0_SCONFIG_SGAIN MASK(3, 0) + +/* MICFIL HWVAD0 Noise CONFIG Register -- REG_MICFIL_VAD0_NCONFIG */ +#define MICFIL_VAD0_NCONFIG_NFILAUT BIT(31) +#define MICFIL_VAD0_NCONFIG_NMINEN BIT(30) +#define MICFIL_VAD0_NCONFIG_NDECEN BIT(29) +#define MICFIL_VAD0_NCONFIG_NOREN BIT(28) +#define MICFIL_VAD0_NCONFIG_NFILADJ MASK(12, 8) +#define MICFIL_VAD0_NCONFIG_NGAIN MASK(3, 0) + +/* MICFIL HWVAD0 Zero-Crossing Detector - REG_MICFIL_VAD0_ZCD */ +#define MICFIL_VAD0_ZCD_ZCDTH MASK(25, 16) +#define MICFIL_VAD0_ZCD_ZCDADJ MASK(11, 8) +#define MICFIL_VAD0_ZCD_ZCDAND BIT(4) +#define MICFIL_VAD0_ZCD_ZCDAUT BIT(2) +#define MICFIL_VAD0_ZCD_ZCDEN BIT(0) + +/* MICFIL HWVAD0 Status Register - REG_MICFIL_VAD0_STAT */ +#define MICFIL_VAD0_STAT_INITF BIT(31) +#define MICFIL_VAD0_STAT_INSATF BIT(16) +#define MICFIL_VAD0_STAT_EF BIT(15) +#define MICFIL_VAD0_STAT_IF BIT(0) + +/* MICFIL Output Control Register */ +#define MICFIL_OUTGAIN_CHX_SHIFT(v) (4 * (v)) + +/* Constants */ +#define MICFIL_OUTPUT_CHANNELS 8 +#define MICFIL_FIFO_NUM 8 + +#define FIFO_PTRWID 3 +#define FIFO_LEN BIT(FIFO_PTRWID) + +#define MICFIL_IRQ_LINES 4 +#define MICFIL_MAX_RETRY 25 +#define MICFIL_SLEEP_MIN 90000 /* in us */ +#define MICFIL_SLEEP_MAX 100000 /* in us */ +#define MICFIL_DMA_MAXBURST_RX 6 + +/* HWVAD Constants */ +#define MICFIL_HWVAD_ENVELOPE_MODE 0 +#define MICFIL_HWVAD_ENERGY_MODE 1 + +#endif /* __SOF_DRIVERS_MICFIL_H__ */ diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index ccc41524e002..9d2f5410c2a1 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -65,6 +65,10 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void dd->stream_id); channel = EDMA_HS_GET_CHAN(handshake); break; + case SOF_DAI_IMX_MICFIL: + channel = dai_get_handshake(dd->dai, dai->direction, + dd->stream_id); + break; case SOF_DAI_AMD_BT: channel = dai_get_handshake(dd->dai, dai->direction, dd->stream_id); @@ -156,6 +160,8 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) */ dd->stream_id = config->alh.stream_id; break; + case SOF_DAI_IMX_MICFIL: + COMPILER_FALLTHROUGH; case SOF_DAI_IMX_SAI: COMPILER_FALLTHROUGH; case SOF_DAI_IMX_ESAI: diff --git a/src/platform/Kconfig b/src/platform/Kconfig index f36c5ac2b7e4..d4787c140293 100644 --- a/src/platform/Kconfig +++ b/src/platform/Kconfig @@ -100,6 +100,7 @@ config IMX8M select XT_WAITI_DELAY select IMX select IMX_SDMA + select IMX_MICFIL select SCHEDULE_DMA_MULTI_CHANNEL select IMX_INTERRUPT_IRQSTEER help diff --git a/src/platform/imx8m/include/platform/lib/memory.h b/src/platform/imx8m/include/platform/lib/memory.h index 7d285dbfc463..6b2c00f89bad 100644 --- a/src/platform/imx8m/include/platform/lib/memory.h +++ b/src/platform/imx8m/include/platform/lib/memory.h @@ -59,6 +59,9 @@ #define SAI_7_BASE 0x30c80000 #define SAI_7_SIZE 0x00010000 +#define MICFIL_BASE 0x30ca0000 +#define MICFIL_SIZE 0x00010000 + #define UUID_ENTRY_ELF_BASE 0x1FFFA000 #define UUID_ENTRY_ELF_SIZE 0x6000 diff --git a/src/platform/imx8m/lib/dai.c b/src/platform/imx8m/lib/dai.c index 1096740e4f58..3c684d0c2c6e 100644 --- a/src/platform/imx8m/lib/dai.c +++ b/src/platform/imx8m/lib/dai.c @@ -6,6 +6,8 @@ #include #include +#include + #include #include #include @@ -142,12 +144,37 @@ static SHARED_DATA struct dai sai[] = { }; +static SHARED_DATA struct dai micfil[] = { +{ + .index = 2, + .plat_data = { + .base = MICFIL_BASE, + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = 0, /* No playback */ + .handshake = 0, + }, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = MICFIL_BASE + REG_MICFIL_DATACH0, + .handshake = 24, + }, + }, + + .drv = &micfil_driver, +}, +}; + const struct dai_type_info dti[] = { { .type = SOF_DAI_IMX_SAI, .dai_array = cache_to_uncache_init((struct dai *)sai), .num_dais = ARRAY_SIZE(sai) }, + { + .type = SOF_DAI_IMX_MICFIL, + .dai_array = cache_to_uncache_init((struct dai *)micfil), + .num_dais = ARRAY_SIZE(micfil) + }, + }; const struct dai_info lib_dai = { diff --git a/src/platform/imx8m/lib/dma.c b/src/platform/imx8m/lib/dma.c index 12403f92809e..ca02d52904ad 100644 --- a/src/platform/imx8m/lib/dma.c +++ b/src/platform/imx8m/lib/dma.c @@ -31,7 +31,7 @@ static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { * enabled as it is unneeded */ .dir = DMA_DIR_MEM_TO_DEV | DMA_DIR_DEV_TO_MEM, - .devs = DMA_DEV_SAI, + .devs = DMA_DEV_SAI | DMA_DEV_MICFIL, .base = SDMA3_BASE, .channels = 32, .irq = SDMA3_IRQ, diff --git a/xtos/include/sof/lib/dma.h b/xtos/include/sof/lib/dma.h index 82f4992cbe88..2f0bfe940dea 100644 --- a/xtos/include/sof/lib/dma.h +++ b/xtos/include/sof/lib/dma.h @@ -75,6 +75,7 @@ struct comp_buffer; #define DMA_DEV_SP_VIRTUAL BIT(11) /**< connectable to ACP SP VIRTUAL I2S */ #define DMA_DEV_HS_VIRTUAL BIT(12) /**< connectable to ACP HS VIRTUAL I2S */ #define DMA_DEV_HS BIT(13) /**< connectable to ACP HS I2S */ +#define DMA_DEV_MICFIL BIT(14) /**< connectable to MICFIL fifo */ /* DMA access privilege flag */ #define DMA_ACCESS_EXCLUSIVE 1