diff --git a/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay b/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay index 6748b621985a..773fecc25bdb 100644 --- a/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay +++ b/app/boards/imx8mp_evk_mimx8ml8_adsp.overlay @@ -12,6 +12,10 @@ }; }; +&emul_dma { + status = "okay"; +}; + &sdma3 { status = "okay"; }; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 0512b92abc87..836763314601 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -194,6 +194,10 @@ __cold int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config, cfg.type = DAI_IMX_MICFIL; cfg_params = &sof_cfg->micfil; break; + case SOF_DAI_VIRTUAL: + cfg.type = DAI_VIRTUAL; + cfg_params = &sof_cfg->virtual_dai; + break; default: return -EINVAL; } @@ -492,8 +496,12 @@ __cold int dai_common_new(struct dai_data *dd, struct comp_dev *dev, dd->ipc_config = *dai_cfg; /* request GP LP DMA with shared access privilege */ +#if CONFIG_DAI_VIRTUAL + dir = SOF_DMA_DIR_MEM_TO_MEM; +#else dir = dai_cfg->direction == SOF_IPC_STREAM_PLAYBACK ? SOF_DMA_DIR_MEM_TO_DEV : SOF_DMA_DIR_DEV_TO_MEM; +#endif dd->dma = sof_dma_get(dir, dd->dai->dma_caps, dd->dai->dma_dev, SOF_DMA_ACCESS_SHARED); if (!dd->dma) { diff --git a/src/include/ipc/dai.h b/src/include/ipc/dai.h index b5b29316f9e6..1d86f8173962 100644 --- a/src/include/ipc/dai.h +++ b/src/include/ipc/dai.h @@ -94,9 +94,31 @@ enum sof_ipc_dai_type { SOF_DAI_AMD_SP_VIRTUAL, /**dai, dai->direction, dd->stream_id); + case SOF_DAI_VIRTUAL: + handshake = dai_get_handshake(dd->dai, dai->direction, + dd->stream_id); /* TODO: remove this when transition to native drivers is complete on all NXP platforms */ #ifndef CONFIG_ZEPHYR_NATIVE_DRIVERS channel = EDMA_HS_GET_CHAN(handshake); @@ -171,6 +174,7 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) case SOF_DAI_IMX_MICFIL: case SOF_DAI_IMX_SAI: case SOF_DAI_IMX_ESAI: + case SOF_DAI_VIRTUAL: dd->config.burst_elems = dai_get_fifo_depth(dd->dai, dai->direction); break; case SOF_DAI_AMD_BT: diff --git a/src/lib/dai.c b/src/lib/dai.c index c4daf2b06918..b90d1fe6c555 100644 --- a/src/lib/dai.c +++ b/src/lib/dai.c @@ -185,6 +185,9 @@ const struct device *zephyr_dev[] = { #if CONFIG_DAI_NXP_MICFIL DT_FOREACH_STATUS_OKAY(nxp_dai_micfil, GET_DEVICE_LIST) #endif +#if CONFIG_DAI_VIRTUAL + DT_FOREACH_STATUS_OKAY(virtual_dai, GET_DEVICE_LIST) +#endif }; /* convert sof_ipc_dai_type to Zephyr dai_type */ @@ -218,6 +221,8 @@ static int sof_dai_type_to_zephyr(uint32_t type) case SOF_DAI_AMD_HS_VIRTUAL: case SOF_DAI_AMD_SW_AUDIO: return -ENOTSUP; + case SOF_DAI_VIRTUAL: + return DAI_VIRTUAL; default: return -EINVAL; } diff --git a/tools/topology/topology1/CMakeLists.txt b/tools/topology/topology1/CMakeLists.txt index c6ae06d0be04..0c77ef6afbe5 100644 --- a/tools/topology/topology1/CMakeLists.txt +++ b/tools/topology/topology1/CMakeLists.txt @@ -71,6 +71,7 @@ set(TPLGS "sof-imx8mp-compr-pcm-cap-wm8960\;sof-imx8mp-compr-pcm-cap-wm8960" "sof-imx8mp-compr-wm8960\;sof-imx8mp-compr-wm8960\;-DCODEC=wm8960\;-DRATE=48000" "sof-imx8mp-compr-wm8960\;sof-imx8mp-compr-wm8962\;-DCODEC=wm8962\;-DRATE=48000" + "sof-imx8-virtual\;sof-imx8-virtual" ## end i.MX8MP topologies ## i.MX8ULP topologies diff --git a/tools/topology/topology1/m4/dai.m4 b/tools/topology/topology1/m4/dai.m4 index cd968c6c61fd..5ae7aac24f03 100644 --- a/tools/topology/topology1/m4/dai.m4 +++ b/tools/topology/topology1/m4/dai.m4 @@ -155,7 +155,7 @@ define(`DO_DAI_CONFIG', `' ` id "'$3`"' `' -` ifelse($1, `SSP', $5, $1, `HDA', $5, $1, `ALH', $5, $1, `ESAI', $5, $1, `SAI', $5, $1, `MICFIL', $5, $1, `AFE', $5, $1, `ACP', $5, $1, `ACPSP', $5, $1,`ACPSP_VIRTUAL', $5, $1, `ACPHS', $5, $1, `ACPHS_VIRTUAL', $5, $1, `ACP_SDW', $5, $1, `ACPDMIC', $5, `}')' +` ifelse($1, `SSP', $5, $1, `HDA', $5, $1, `ALH', $5, $1, `ESAI', $5, $1, `SAI', $5, $1, `MICFIL', $5, $1, `AFE', $5, $1, `ACP', $5, $1, `ACPSP', $5, $1,`ACPSP_VIRTUAL', $5, $1, `ACPHS', $5, $1, `ACPHS_VIRTUAL', $5, $1, `ACP_SDW', $5, $1, `ACPDMIC', $5, $1, `DAI_VIRTUAL', $5, `}')' `ifelse($1, `DMIC', $5, `')' `SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples_common" {' ` tokens "sof_dai_tokens"' diff --git a/tools/topology/topology1/platform/common/virtual-dai.m4 b/tools/topology/topology1/platform/common/virtual-dai.m4 new file mode 100644 index 000000000000..7c12f9a85f42 --- /dev/null +++ b/tools/topology/topology1/platform/common/virtual-dai.m4 @@ -0,0 +1,45 @@ +divert(-1) + +dnl Virtual DAI related macros + +dnl DAI_VIRTUAL_CLOCK(clock, freq, codec_provider, polarity) +dnl polarity is optional +define(`DAI_VIRTUAL_CLOCK', + $1 STR($3) + $1_freq STR($2)) + `ifelse($4, `inverted', `$1_invert "true"',`')') + +dnl DAI_VIRTUAL_TDM(slots, width, tx_mask, rx_mask) +define(`DAI_VIRTUAL_TDM', +` tdm_slots 'STR($1) +` tdm_slot_width 'STR($2) +` tx_slots 'STR($3) +` rx_slots 'STR($4) +) + +dnl DAI_VIRTUAL_CONFIG(format, mclk, bclk, fsync, tdm, config_data) +define(`DAI_VIRTUAL_CONFIG', +` format "'$1`"' +` '$2 +` '$3 +` '$4 +` '$5 +`}' +$6 +) + +dnl DAI_VIRTUAL_CONFIG_DATA(type, idx, dummy_id) +dnl dummy_id is optional +define(`DAI_VIRTUAL_CONFIG_DATA', +`SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples" {' +` tokens "sof_virtual_tokens"' +` tuples."short" {' +` SOF_TKN_DAI_VIRTUAL_MCLK_ID' ifelse($3, `', "0", STR($3)) +` }' +`}' +`SectionData."'N_DAI_CONFIG($1$2)`_data" {' +` tuples "'N_DAI_CONFIG($1$2)`_tuples"' +`}' +) + +divert(0)dnl diff --git a/tools/topology/topology1/sof-imx8-virtual.m4 b/tools/topology/topology1/sof-imx8-virtual.m4 new file mode 100644 index 000000000000..2cfbfd449c61 --- /dev/null +++ b/tools/topology/topology1/sof-imx8-virtual.m4 @@ -0,0 +1,71 @@ +# +# Topology for i.MX8 board using Virtual DAI (no physical codec) +# + +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`virtual-dai.m4') +include(`pcm.m4') +include(`buffer.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include DSP configuration +include(`platform/imx/imx8.m4') + +# +# Define the pipelines +# +# PCM0 ---> Volume ---> Virtual DAI0 (NoCodec) +# + +dnl PIPELINE_PCM_ADD(pipeline, +dnl pipe id, pcm, max channels, format, +dnl period, priority, core, +dnl pcm_min_rate, pcm_max_rate, pipeline_rate, +dnl time_domain, sched_comp) + +# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le +PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, + 1, 0, 2, s32le, + 1000, 0, 0, + 8000, 96000, 48000) + +# +# DAIs configuration +# + +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) + +DAI_ADD(sof/pipe-dai-playback.m4, + 1, DAI_VIRTUAL, 7, NoCodec-0, + PIPELINE_SOURCE_1, 2, s32le, + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +# +# PCM interface +# + +dnl PCM_PLAYBACK_ADD(name, pcm_id, playback) +PCM_PLAYBACK_ADD(Port0, 0, PIPELINE_PCM_1) + +# +# DAI Configuration +# + +dnl DAI_CONFIG(type, dai_index, link_id, name, config) +DAI_CONFIG(DAI_VIRTUAL, 7, 0, NoCodec-0, + DAI_VIRTUAL_CONFIG(I2S, DAI_VIRTUAL_CLOCK(mclk, 0, dai_provider), + DAI_VIRTUAL_CLOCK(bclk, 0, dai_provider), + DAI_VIRTUAL_CLOCK(fsync, 0, dai_provider), + DAI_VIRTUAL_TDM(2, 32, 3, 3), + DAI_VIRTUAL_CONFIG_DATA(DAI_VIRTUAL, 7, 0))) diff --git a/tools/topology/topology1/sof/tokens.m4 b/tools/topology/topology1/sof/tokens.m4 index b9748bb52fbc..6b2951934326 100644 --- a/tools/topology/topology1/sof/tokens.m4 +++ b/tools/topology/topology1/sof/tokens.m4 @@ -157,3 +157,7 @@ SectionVendorTokens."sof_acp_sdw_tokens" { SOF_TKN_AMD_ACP_SDW_SAMPLERATE "2100" SOF_TKN_AMD_ACP_SDW_CH "2101" } + +SectionVendorTokens."sof_virtual_tokens" { + SOF_TKN_DAI_VIRTUAL_MCLK_ID "2102" +} diff --git a/tools/topology/topology2/include/common/tokens.conf b/tools/topology/topology2/include/common/tokens.conf index d1b986ab01d4..80c907d84b5d 100644 --- a/tools/topology/topology2/include/common/tokens.conf +++ b/tools/topology/topology2/include/common/tokens.conf @@ -190,4 +190,9 @@ Object.Base.VendorToken { node_type 1980 deep_buffer_dma_ms 1981 } + + "19" { + name "dai_virtual" + mclk_id 2102 + } } diff --git a/zephyr/include/sof/lib/dma.h b/zephyr/include/sof/lib/dma.h index 1b384412b123..4e5b31d4ae7d 100644 --- a/zephyr/include/sof/lib/dma.h +++ b/zephyr/include/sof/lib/dma.h @@ -99,6 +99,7 @@ struct comp_dev; #define SOF_DMA_DEV_HS BIT(13) /**< connectable to ACP HS I2S */ #define SOF_DMA_DEV_MICFIL BIT(14) /**< connectable to MICFIL fifo */ #define SOF_DMA_DEV_SW BIT(15) /**< connectable to ACP SW */ +#define SOF_DMA_DEV_DAI_VIRTUAL BIT(16) /**< connectable to Virtual DAI */ /* DMA access privilege flag */ #define SOF_DMA_ACCESS_EXCLUSIVE 1 diff --git a/zephyr/lib/dma.c b/zephyr/lib/dma.c index c72e26cf57cf..4cb521bcf1dc 100644 --- a/zephyr/lib/dma.c +++ b/zephyr/lib/dma.c @@ -151,6 +151,17 @@ SHARED_DATA struct sof_dma dma[] = { }, #endif #if defined(CONFIG_SOC_MIMX8ML8_ADSP) +#if CONFIG_DAI_VIRTUAL +{ + .plat_data = { + .dir = SOF_DMA_DIR_MEM_TO_MEM, + .devs = SOF_DMA_DEV_DAI_VIRTUAL, + .channels = 32, + .period_count = 2, + }, + .z_dev = DEVICE_DT_GET(DT_NODELABEL(emul_dma)), +}, +#endif /* CONFIG_DAI_VIRTUAL */ { .plat_data = { .dir = SOF_DMA_DIR_MEM_TO_DEV | SOF_DMA_DIR_DEV_TO_MEM,