From 22ad526c2691ff53d4e0479b8cd391d975d433f7 Mon Sep 17 00:00:00 2001 From: Jaroslaw Stelter Date: Fri, 25 Nov 2022 12:17:17 +0100 Subject: [PATCH] LNL: Add hda_dma_config for interfaces In LNL the GPDMA engine was removed. Instead HD Audio Link DMA is used to transport data over audio interfaces. Since HD Audio is a Host managed engine, the link configuration is passed through IPCv4. The configuration must be forwarded to appropriate interface driver to configure HW. Signed-off-by: Jaroslaw Stelter --- src/audio/copier/copier.c | 22 ++++++++++++---- src/audio/dai-zephyr.c | 4 +++ src/include/ipc4/alh.h | 4 +++ src/include/sof/audio/ipc-config.h | 40 ++++++++++++++++++++++++++++++ src/include/sof/ipc/topology.h | 1 + src/include/sof/lib/dai-legacy.h | 7 ++++++ src/include/sof/lib/dai-zephyr.h | 16 ++++++++++++ src/ipc/ipc3/dai.c | 5 ++++ src/ipc/ipc4/dai.c | 40 ++++++++++++++++++++++++++++++ src/ipc/ipc4/helper.c | 14 +++++++++++ src/lib/dai.c | 12 +++++++++ 11 files changed, 160 insertions(+), 5 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 4962d8532cad..f051780614fb 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -385,7 +385,7 @@ static int create_dai(struct comp_dev *parent_dev, struct copier_data *cd, const struct comp_driver *drv; struct ipc_config_dai dai; int dai_count; - int i; + int i, ret; drv = ipc4_get_drv((uint8_t *)&id); if (!drv) @@ -415,6 +415,13 @@ static int create_dai(struct comp_dev *parent_dev, struct copier_data *cd, dai.type = SOF_DAI_INTEL_SSP; dai.is_config_blob = true; type = ipc4_gtw_ssp; + ret = ipc4_find_dma_config(&dai, (uint8_t *)copier->gtw_cfg.config_data, + copier->gtw_cfg.config_length * 4); + if (ret != 0) { + comp_err(parent_dev, "No ssp dma_config found in blob!"); + return -EINVAL; + } + dai.out_fmt = &copier->out_fmt; break; case ipc4_alh_link_output_class: case ipc4_alh_link_input_class: @@ -467,14 +474,20 @@ static int create_dai(struct comp_dev *parent_dev, struct copier_data *cd, dai.type = SOF_DAI_INTEL_DMIC; dai.is_config_blob = true; type = ipc4_gtw_dmic; + + ret = ipc4_find_dma_config(&dai, (uint8_t *)copier->gtw_cfg.config_data, + copier->gtw_cfg.config_length * 4); + if (ret != 0) { + comp_err(parent_dev, "No dmic dma_config found in blob!"); + return -EINVAL; + } + dai.out_fmt = &copier->out_fmt; break; default: return -EINVAL; } for (i = 0; i < dai_count; i++) { - int ret; - dai.dai_index = dai_index[i]; ret = init_dai(parent_dev, drv, config, copier, pipeline, &dai, type, i, dai_count); @@ -495,8 +508,7 @@ static int create_dai(struct comp_dev *parent_dev, struct copier_data *cd, /* create multi_endpoint_buffer for ALH multi-gateway case */ if (dai_count > 1) { - int ret = create_endpoint_buffer(parent_dev, cd, config, copier, type, true, 0); - + ret = create_endpoint_buffer(parent_dev, cd, config, copier, type, true, 0); if (ret < 0) return ret; } diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 2b70c2fddc8e..db6301ad361c 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -143,6 +143,8 @@ int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config, case SOF_DAI_INTEL_SSP: cfg.type = is_blob ? DAI_INTEL_SSP_NHLT : DAI_INTEL_SSP; cfg_params = is_blob ? spec_config : &sof_cfg->ssp; + dai_set_link_hda_config(&cfg.link_config, + common_config, cfg_params); break; case SOF_DAI_INTEL_ALH: cfg.type = is_blob ? DAI_INTEL_ALH_NHLT : DAI_INTEL_ALH; @@ -151,6 +153,8 @@ int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config, case SOF_DAI_INTEL_DMIC: cfg.type = is_blob ? DAI_INTEL_DMIC_NHLT : DAI_INTEL_DMIC; cfg_params = is_blob ? spec_config : &sof_cfg->dmic; + dai_set_link_hda_config(&cfg.link_config, + common_config, cfg_params); break; case SOF_DAI_INTEL_HDA: cfg.type = is_blob ? DAI_INTEL_HDA_NHLT : DAI_INTEL_HDA; diff --git a/src/include/ipc4/alh.h b/src/include/ipc4/alh.h index 8a296973cf32..af30a2a36723 100644 --- a/src/include/ipc4/alh.h +++ b/src/include/ipc4/alh.h @@ -29,7 +29,11 @@ #include #define IPC4_ALH_MAX_NUMBER_OF_GTW 16 +#ifdef CONFIG_DMA_INTEL_ADSP_GPDMA #define IPC4_ALH_DAI_INDEX_OFFSET 7 +#else +#define IPC4_ALH_DAI_INDEX_OFFSET 0 +#endif /* copier id = (group id << 4) + codec id + IPC4_ALH_DAI_INDEX_OFFSET * dai_index = (group id << 8) + codec id; diff --git a/src/include/sof/audio/ipc-config.h b/src/include/sof/audio/ipc-config.h index eb25e22b4782..8bedb7002e0c 100644 --- a/src/include/sof/audio/ipc-config.h +++ b/src/include/sof/audio/ipc-config.h @@ -9,6 +9,42 @@ #include #include +/* ACE 2.0 and newer */ +#define GTW_DMA_CONFIG_ID 0x1000 +#define GTW_DMA_INVALID_CHANNEL_ID 0xffffffff +/* Maximum number of devices */ +#define GTW_DMA_DEVICE_MAX_COUNT 16 + +struct dma_device_stream_channel_map { + uint32_t device_address; + uint32_t channel_map; +}; + +struct dma_stream_channel_map { + uint32_t device_count; + struct dma_device_stream_channel_map map[GTW_DMA_DEVICE_MAX_COUNT]; +}; + +struct ipc_dma_config { + uint8_t dma_method; /**< DMA method */ + uint8_t pre_allocated_by_host; /**< 1 - DMA pre-allocated by host, otherwise to be + * allocated by DSP + */ + uint16_t rsvd; + uint32_t dma_channel_id; /**< channel ID if DMA pre-allocated by host, otherwise + * invalid channel ID + */ + uint32_t stream_id; + /* DmaStreamChannelMap */ + struct dma_stream_channel_map channel_map; + uint32_t dma_priv_config_size; + uint8_t dma_priv_config[0]; +} __attribute__((packed, aligned(4))); + +#define GET_IPC_DMA_CONFIG(buffer, size) \ + ((struct ipc_dma_config *)((uint8_t *)(buffer) + (size) - sizeof(struct ipc_dma_config))) +#define GET_IPC_DMA_CONFIG_ID(buffer, size) ((uint32_t *)GET_IPC_DMA_CONFIG(buffer, size) - 2) + /* * Generic IPC information for base components. Fields can be added here with NO impact on * IPC ABI version. @@ -39,6 +75,10 @@ struct ipc_config_dai { uint32_t feature_mask; /**< copier feature mask (set directly from * ipc4_copier_module_cfg on init) */ + struct ipc_dma_config *host_dma_config; /**< DMA config - required for ACE 2.0 and newer */ + const struct ipc4_audio_format *out_fmt;/**< audio format for output pin 0 - required + * for ACE 2.0 and newer + */ }; /* generic volume component */ diff --git a/src/include/sof/ipc/topology.h b/src/include/sof/ipc/topology.h index 8ba06ac62fe0..fc42a7559f0a 100644 --- a/src/include/sof/ipc/topology.h +++ b/src/include/sof/ipc/topology.h @@ -56,6 +56,7 @@ int ipc4_create_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma); int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma, bool *delay); int ipc4_process_on_core(uint32_t core, bool blocking); int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id); +int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size); #else #error "No or invalid IPC MAJOR version selected." #endif diff --git a/src/include/sof/lib/dai-legacy.h b/src/include/sof/lib/dai-legacy.h index b72e176d10ac..c39219d66888 100644 --- a/src/include/sof/lib/dai-legacy.h +++ b/src/include/sof/lib/dai-legacy.h @@ -545,6 +545,13 @@ static inline const struct dai_info *dai_info_get(void) */ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void *config); +/** + * \brief Configure HD Audio DMA params for DAI + */ +void dai_set_link_hda_config(uint16_t *link_config, + struct ipc_config_dai *common_config, + const void *spec_config); + /** * \brief Reset DAI DMA config */ diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 639fdce5849f..412fe12e1cc7 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -76,6 +76,16 @@ struct timestamp_ops { struct timestamp_data *tsd); }; +union hdalink_cfg { + uint16_t full; + struct { + uint16_t lchan :4; + uint16_t hchan :4; + uint16_t stream :6; + uint16_t rsvd :1; + uint16_t dir :1; + } part; +}; /** * \brief DAI group information */ @@ -255,6 +265,12 @@ int dai_get_stream_id(struct dai *dai, int direction); */ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void *config); +/** + * \brief Configure HD Audio DMA params for DAI + */ +void dai_set_link_hda_config(uint16_t *link_config, + struct ipc_config_dai *common_config, + const void *spec_config); /** * \brief Reset DAI DMA config */ diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index 71b8ae614069..decee57299b9 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -29,6 +29,11 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); +void dai_set_link_hda_config(uint16_t *link_config, + struct ipc_config_dai *common_config, + const void *spec_config) +{ } + int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void *spec_config) { const struct sof_ipc_dai_config *config = spec_config; diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 4d3f871eac4b..9c30f55fa850 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -31,6 +31,42 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); +void dai_set_link_hda_config(uint16_t *link_config, + struct ipc_config_dai *common_config, + const void *spec_config) +{ +#if defined(CONFIG_ACE_VERSION_2_0) + const struct ipc4_audio_format *out_fmt = common_config->out_fmt; + const struct sof_ipc_dai_config *sof_cfg = spec_config; + union hdalink_cfg link_cfg; + + switch (common_config->type) { + case SOF_DAI_INTEL_SSP: + link_cfg.full = 0; + link_cfg.part.dir = common_config->direction; + link_cfg.part.stream = common_config->host_dma_config->stream_id; + break; + case SOF_DAI_INTEL_DMIC: + link_cfg.full = 0; + if (out_fmt->depth == IPC4_DEPTH_16BIT) { + /* 16bit dmic packs two 16bit samples into single 32bit word + * fw needs to adjust channel count to match final sample + * group size + */ + link_cfg.part.hchan = (out_fmt->channels_count - 1) / 2; + } else { + link_cfg.part.hchan = out_fmt->channels_count - 1; + } + link_cfg.part.stream = common_config->host_dma_config->stream_id; + break; + default: + /* other types of DAIs not need link_config */ + return; + } + *link_config = link_cfg.full; +#endif +} + int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void *spec_config) { const struct ipc4_copier_module_cfg *copier_cfg = spec_config; @@ -42,6 +78,10 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void COMPILER_FALLTHROUGH; case SOF_DAI_INTEL_DMIC: channel = 0; +#if defined(CONFIG_ACE_VERSION_2_0) + if (dai->host_dma_config->pre_allocated_by_host) + channel = dai->host_dma_config->dma_channel_id; +#endif break; case SOF_DAI_INTEL_HDA: channel = copier_cfg->gtw_cfg.node_id.f.v_index; diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index ac6c36571eef..00f1bf4f8866 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -789,3 +789,17 @@ int ipc4_add_comp_dev(struct comp_dev *dev) return IPC4_SUCCESS; }; + +int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size) +{ +#if defined(CONFIG_ACE_VERSION_2_0) + uint32_t *dma_config_id = GET_IPC_DMA_CONFIG_ID(data_buffer, size); + + if (*dma_config_id != GTW_DMA_CONFIG_ID) + return IPC4_INVALID_REQUEST; + + dai->host_dma_config = GET_IPC_DMA_CONFIG(data_buffer, size); +#endif + return IPC4_SUCCESS; +} + diff --git a/src/lib/dai.c b/src/lib/dai.c index b04c9d118832..2cdf0c9192a0 100644 --- a/src/lib/dai.c +++ b/src/lib/dai.c @@ -170,15 +170,27 @@ static void dai_set_device_params(struct dai *d) switch (d->type) { case SOF_DAI_INTEL_SSP: d->dma_dev = DMA_DEV_SSP; +#ifdef CONFIG_DMA_INTEL_ADSP_GPDMA d->dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP; +#else + d->dma_caps = DMA_CAP_HDA; +#endif break; case SOF_DAI_INTEL_DMIC: d->dma_dev = DMA_DEV_DMIC; +#ifdef CONFIG_DMA_INTEL_ADSP_GPDMA d->dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP; +#else + d->dma_caps = DMA_CAP_HDA; +#endif break; case SOF_DAI_INTEL_ALH: d->dma_dev = DMA_DEV_ALH; +#ifdef CONFIG_DMA_INTEL_ADSP_GPDMA d->dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP; +#else + d->dma_caps = DMA_CAP_HDA; +#endif break; case SOF_DAI_INTEL_HDA: d->dma_dev = DMA_DEV_HDA;