diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index 29e602871af7..2d917a072b1d 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -126,6 +126,9 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) if(CONFIG_COMP_TONE) add_subdirectory(tone) endif() + if(CONFIG_UAOL_INTEL_ADSP) + add_local_sources(sof uaol.c) + endif() if(CONFIG_ZEPHYR_NATIVE_DRIVERS) list(APPEND base_files host-zephyr.c) sof_list_append_ifdef(CONFIG_COMP_DAI base_files dai-zephyr.c) diff --git a/src/audio/base_fw_intel.c b/src/audio/base_fw_intel.c index 67b87a0afed4..57799f285f59 100644 --- a/src/audio/base_fw_intel.c +++ b/src/audio/base_fw_intel.c @@ -24,10 +24,6 @@ #include #include -#if CONFIG_UAOL_INTEL_ADSP -#include -#endif - #include #include #include @@ -37,6 +33,10 @@ #include #endif +#if CONFIG_UAOL_INTEL_ADSP +#include +#endif + struct ipc4_modules_info { uint32_t modules_count; struct sof_man_module modules[0]; @@ -46,22 +46,6 @@ struct ipc4_modules_info { STATIC_ASSERT(sizeof(struct ipc4_modules_info) < SOF_IPC_MSG_MAX_SIZE, invalid_modules_info_struct_size); -#if CONFIG_UAOL_INTEL_ADSP -struct ipc4_uaol_link_capabilities { - uint32_t input_streams_supported : 4; - uint32_t output_streams_supported : 4; - uint32_t bidirectional_streams_supported : 5; - uint32_t rsvd : 19; - uint32_t max_tx_fifo_size; - uint32_t max_rx_fifo_size; -} __packed __aligned(4); - -struct ipc4_uaol_capabilities { - uint32_t link_count; - struct ipc4_uaol_link_capabilities link_caps[]; -} __packed __aligned(4); -#endif /* CONFIG_UAOL_INTEL_ADSP */ - /* * TODO: default to value of ACE1.x platforms. This is defined * in multiple places in Zephyr, mm_drv_intel_adsp.h and @@ -103,61 +87,6 @@ __cold int basefw_vendor_fw_config(uint32_t *data_offset, char *data) return 0; } -#if CONFIG_UAOL_INTEL_ADSP -#define DEV_AND_COMMA(node) DEVICE_DT_GET(node), -static const struct device *uaol_devs[] = { - DT_FOREACH_STATUS_OKAY(intel_adsp_uaol, DEV_AND_COMMA) -}; - -#if !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY -__cold static void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type) -{ - const size_t dev_count = ARRAY_SIZE(uaol_devs); - struct uaol_capabilities dev_cap; - struct ipc4_uaol_capabilities *caps = (struct ipc4_uaol_capabilities *)tuple->value; - size_t caps_size = offsetof(struct ipc4_uaol_capabilities, link_caps[dev_count]); - size_t i; - int ret; - - assert_can_be_cold(); - - memset(caps, 0, caps_size); - - caps->link_count = dev_count; - for (i = 0; i < dev_count; i++) { - ret = uaol_get_capabilities(uaol_devs[i], &dev_cap); - if (ret) - continue; - - caps->link_caps[i].input_streams_supported = dev_cap.input_streams; - caps->link_caps[i].output_streams_supported = dev_cap.output_streams; - caps->link_caps[i].bidirectional_streams_supported = dev_cap.bidirectional_streams; - caps->link_caps[i].max_tx_fifo_size = dev_cap.max_tx_fifo_size; - caps->link_caps[i].max_rx_fifo_size = dev_cap.max_rx_fifo_size; - } - - tlv_value_set(tuple, type, caps_size, caps); -} -#endif /* CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY */ - -__cold static int uaol_stream_id_to_hda_link_stream_id(int uaol_stream_id) -{ - size_t dev_count = ARRAY_SIZE(uaol_devs); - size_t i; - - assert_can_be_cold(); - - for (i = 0; i < dev_count; i++) { - int hda_link_stream_id = uaol_get_mapped_hda_link_stream_id(uaol_devs[i], - uaol_stream_id); - if (hda_link_stream_id >= 0) - return hda_link_stream_id; - } - - return -1; -} -#endif /* CONFIG_UAOL_INTEL_ADSP */ - __cold int basefw_vendor_hw_config(uint32_t *data_offset, char *data) { struct sof_tlv *tuple = (struct sof_tlv *)data; diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index dfd2590c7108..3fcc790bc385 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -327,7 +327,7 @@ __cold int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, dai.type = SOF_DAI_INTEL_UAOL; dai.is_config_blob = true; cd->gtw_type = ipc4_gtw_alh; - ret = ipc4_find_dma_config(&dai, gtw_cfg_data, gtw_cfg_size); + ret = ipc4_find_dma_config_tlv(&dai, gtw_cfg_data, gtw_cfg_size); if (ret != IPC4_SUCCESS) { comp_err(dev, "No uaol dma_config found in blob!"); return -EINVAL; diff --git a/src/audio/mixin_mixout/mixin_mixout.h b/src/audio/mixin_mixout/mixin_mixout.h index 97aa0e12cdab..5cfb30f26c43 100644 --- a/src/audio/mixin_mixout/mixin_mixout.h +++ b/src/audio/mixin_mixout/mixin_mixout.h @@ -99,13 +99,6 @@ struct ipc4_mixer_mode_config { struct ipc4_mixer_mode_sink_config mixer_mode_sink_configs[1]; } __packed __aligned(4); -/* Pointer to data in circular buffer together with buffer boundaries */ -struct cir_buf_ptr { - void *buf_start; - void *buf_end; - void *ptr; -}; - /** * \brief mixin processing function interface */ diff --git a/src/audio/uaol.c b/src/audio/uaol.c new file mode 100644 index 000000000000..51e16aaab105 --- /dev/null +++ b/src/audio/uaol.c @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 Intel Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(uaol, CONFIG_SOF_LOG_LEVEL); + +struct ipc4_uaol_link_capabilities { + uint32_t input_streams_supported : 4; + uint32_t output_streams_supported : 4; + uint32_t bidirectional_streams_supported : 5; + uint32_t rsvd : 19; + uint32_t max_tx_fifo_size; + uint32_t max_rx_fifo_size; +} __packed __aligned(4); + +struct ipc4_uaol_capabilities { + uint32_t link_count; + struct ipc4_uaol_link_capabilities link_caps[]; +} __packed __aligned(4); + +#define DEV_AND_COMMA(node) DEVICE_DT_GET(node), +static const struct device *uaol_devs[] = { + DT_FOREACH_STATUS_OKAY(intel_adsp_uaol, DEV_AND_COMMA) +}; + +#if !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY +__cold void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type) +{ + const size_t dev_count = ARRAY_SIZE(uaol_devs); + struct uaol_capabilities dev_cap; + struct ipc4_uaol_capabilities *caps = (struct ipc4_uaol_capabilities *)tuple->value; + size_t caps_size = offsetof(struct ipc4_uaol_capabilities, link_caps[dev_count]); + size_t i; + int ret; + + assert_can_be_cold(); + + memset(caps, 0, caps_size); + + caps->link_count = dev_count; + for (i = 0; i < dev_count; i++) { + ret = uaol_get_capabilities(uaol_devs[i], &dev_cap); + if (ret) + continue; + + caps->link_caps[i].input_streams_supported = dev_cap.input_streams; + caps->link_caps[i].output_streams_supported = dev_cap.output_streams; + caps->link_caps[i].bidirectional_streams_supported = dev_cap.bidirectional_streams; + caps->link_caps[i].max_tx_fifo_size = dev_cap.max_tx_fifo_size; + caps->link_caps[i].max_rx_fifo_size = dev_cap.max_rx_fifo_size; + } + + tlv_value_set(tuple, type, caps_size, caps); +} +#endif /* !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY */ + +__cold int uaol_stream_id_to_hda_link_stream_id(int uaol_stream_id) +{ + size_t dev_count = ARRAY_SIZE(uaol_devs); + size_t i; + + assert_can_be_cold(); + + for (i = 0; i < dev_count; i++) { + int hda_link_stream_id = uaol_get_mapped_hda_link_stream_id(uaol_devs[i], + uaol_stream_id); + if (hda_link_stream_id >= 0) + return hda_link_stream_id; + } + + return -1; +} diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index dd81c157b8d8..5c6f15392800 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -66,6 +66,15 @@ struct audio_stream { struct sof_audio_stream_params runtime_stream_params; }; +/* A pointer to data in a ring buffer. Just for convenience to reduce the number of typical + * processing function parameters: e.g., just 3 parameters (in, out ptr, and size) instead of 7. + */ +struct cir_buf_ptr { + void *buf_start; + void *buf_end; + void *ptr; +}; + void audio_stream_recalc_align(struct audio_stream *stream); static inline void *audio_stream_get_rptr(const struct audio_stream *buf) diff --git a/src/include/sof/audio/uaol.h b/src/include/sof/audio/uaol.h new file mode 100644 index 000000000000..c12e373ea702 --- /dev/null +++ b/src/include/sof/audio/uaol.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 Intel Corporation. All rights reserved. + */ + +#ifndef __SOF_AUDIO_UAOL_H__ +#define __SOF_AUDIO_UAOL_H__ + +#include +#include + +struct sof_tlv; + +#if !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY +__cold void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type); +#endif /* !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY */ + +__cold int uaol_stream_id_to_hda_link_stream_id(int uaol_stream_id); + +#endif /* __SOF_AUDIO_UAOL_H__ */ diff --git a/src/include/sof/ipc/topology.h b/src/include/sof/ipc/topology.h index 3503c7a407d8..ecea8b96eeab 100644 --- a/src/include/sof/ipc/topology.h +++ b/src/include/sof/ipc/topology.h @@ -56,6 +56,7 @@ int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma, bool *d int ipc4_process_on_core(uint32_t core, bool blocking); int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id, uint32_t cmd); int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size); +int ipc4_find_dma_config_tlv(struct ipc_config_dai *dai, uint8_t *data_buffer, size_t size); int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd); int ipc4_pipeline_trigger(struct ipc_comp_dev *ppl_icd, uint32_t cmd, bool *delayed); int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buffer, diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index c13804c3e46e..3afd4d0f79ed 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -1299,6 +1299,43 @@ int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint3 return IPC4_SUCCESS; } +/* Unlike the above ipc4_find_dma_config(), this can find multiple DMA configs. + * For example, a UAOL copier may use two DMA channels: one for audio and one + * for clock feedback. This function can only work when all data in data_buffer + * is in TLV format; however, this is not always the case for all gateway types. + * Therefore, the above ipc4_find_dma_config() is still used as it can skip non-TLV + * blob data at the beginning of data_buffer. + */ +int ipc4_find_dma_config_tlv(struct ipc_config_dai *dai, uint8_t *data_buffer, size_t size) +{ + uint8_t *end_addr = data_buffer + size; + struct sof_tlv *tlvs; + struct ipc_dma_config *dma_cfg; + int count = 0; + + for (tlvs = (struct sof_tlv *)data_buffer; tlvs && (uint8_t *)tlvs < end_addr; + tlvs = tlv_next(tlvs)) { + dma_cfg = tlv_value_ptr_get(tlvs, GTW_DMA_CONFIG_ID); + if (!dma_cfg) + continue; + + if (count >= GTW_DMA_DEVICE_MAX_COUNT) { + tr_err(&ipc_tr, "Unexpected DMA config count %d, max %d", + count, GTW_DMA_DEVICE_MAX_COUNT); + return IPC4_INVALID_REQUEST; + } + + dai->host_dma_config[count++] = dma_cfg; + } + + if (count == 0) { + tr_err(&ipc_tr, "No DMA config found"); + return IPC4_INVALID_REQUEST; + } + + return IPC4_SUCCESS; +} + int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size, uint32_t device_id, int dma_cfg_idx) {