diff --git a/src/audio/base_fw_intel.c b/src/audio/base_fw_intel.c index d5ea9f8d4f89..a3bc5c967703 100644 --- a/src/audio/base_fw_intel.c +++ b/src/audio/base_fw_intel.c @@ -19,6 +19,10 @@ #include #endif +#if CONFIG_UAOL_INTEL_ADSP +#include +#endif + #include #include @@ -27,6 +31,20 @@ struct ipc4_modules_info { struct sof_man_module modules[0]; } __packed __aligned(4); +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); + LOG_MODULE_REGISTER(basefw_intel, CONFIG_SOF_LOG_LEVEL); int basefw_vendor_fw_config(uint32_t *data_offset, char *data) @@ -36,7 +54,7 @@ int basefw_vendor_fw_config(uint32_t *data_offset, char *data) tlv_value_uint32_set(tuple, IPC4_SLOW_CLOCK_FREQ_HZ_FW_CFG, IPC4_ALH_CAVS_1_8); tuple = tlv_next(tuple); - tlv_value_uint32_set(tuple, IPC4_UAOL_SUPPORT, 0); + tlv_value_uint32_set(tuple, IPC4_UAOL_SUPPORT, 1); tuple = tlv_next(tuple); tlv_value_uint32_set(tuple, IPC4_ALH_SUPPORT_LEVEL_FW_CFG, IPC4_ALH_CAVS_1_8); @@ -47,6 +65,41 @@ int basefw_vendor_fw_config(uint32_t *data_offset, char *data) return 0; } +#if CONFIG_UAOL_INTEL_ADSP + +#define UAOL_DEV(node) DEVICE_DT_GET(node), +static const struct device *uaol_devs[] = { + DT_FOREACH_STATUS_OKAY(intel_adsp_uaol, UAOL_DEV) +}; + +static void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type) +{ + unsigned int 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]); + unsigned int i; + int ret; + + 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 + int basefw_vendor_hw_config(uint32_t *data_offset, char *data) { struct sof_tlv *tuple = (struct sof_tlv *)data; @@ -63,6 +116,11 @@ int basefw_vendor_hw_config(uint32_t *data_offset, char *data) tuple = tlv_next(tuple); tlv_value_uint32_set(tuple, IPC4_LP_EBB_COUNT_HW_CFG, PLATFORM_LPSRAM_EBB_COUNT); +#if CONFIG_UAOL_INTEL_ADSP + tuple = tlv_next(tuple); + tlv_value_set_uaol_caps(tuple, IPC4_UAOL_CAPS_HW_CFG); +#endif + tuple = tlv_next(tuple); *data_offset = (int)((char *)tuple - data); @@ -298,6 +356,27 @@ static int basefw_set_fw_config(bool first_block, return 0; } +static int basefw_dma_control(bool first_block, bool last_block, + uint32_t data_size, const char *data) +{ + struct ipc4_dma_control *dma_control; + int ret; + + if (!(first_block && last_block)) + return IPC4_INVALID_REQUEST; + + dma_control = (struct ipc4_dma_control *)data; + + if (data_size < offsetof(struct ipc4_dma_control, config_data[dma_control->config_length])) + return IPC4_INVALID_CONFIG_DATA_STRUCT; + + ret = dai_control(dma_control->node_id, data); + if (ret) + return IPC4_INVALID_REQUEST; + + return IPC4_SUCCESS; +} + int basefw_vendor_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -308,6 +387,8 @@ int basefw_vendor_set_large_config(struct comp_dev *dev, switch (param_id) { case IPC4_FW_CONFIG: return basefw_set_fw_config(first_block, last_block, data_offset, data); + case IPC4_DMA_CONTROL: + return basefw_dma_control(first_block, last_block, data_offset, data); default: break; } diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 0d1f87de55c4..1160bde04a1c 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -142,6 +142,8 @@ static int copier_init(struct processing_module *mod) case ipc4_i2s_link_input_class: case ipc4_alh_link_output_class: case ipc4_alh_link_input_class: + case ipc4_alh_uaol_stream_link_output_class: + case ipc4_alh_uaol_stream_link_input_class: ret = copier_dai_create(dev, cd, copier, ipc_pipe->pipeline); if (ret < 0) { comp_err(dev, "unable to create dai"); diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index 74c6d62a4d6b..2b1fc7db4146 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -264,7 +264,7 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, type = ipc4_gtw_ssp; ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg, copier->gtw_cfg.config_length * 4); - if (ret != 0) { + if (ret != IPC4_SUCCESS) { comp_err(dev, "No ssp dma_config found in blob!"); return -EINVAL; } @@ -286,13 +286,26 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, if (ret) return ret; break; + case ipc4_alh_uaol_stream_link_output_class: + case ipc4_alh_uaol_stream_link_input_class: + dai.type = SOF_DAI_INTEL_UAOL; + dai.is_config_blob = true; + type = ipc4_gtw_alh; + ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg, + copier->gtw_cfg.config_length * 4); + if (ret != IPC4_SUCCESS) { + comp_err(dev, "No uaol dma_config found in blob!"); + return -EINVAL; + } + dai.out_fmt = &copier->out_fmt; + break; case ipc4_dmic_link_input_class: dai.type = SOF_DAI_INTEL_DMIC; dai.is_config_blob = true; type = ipc4_gtw_dmic; ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg, copier->gtw_cfg.config_length * 4); - if (ret != 0) { + if (ret != IPC4_SUCCESS) { comp_err(dev, "No dmic dma_config found in blob!"); return -EINVAL; } diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index ded21ef99bef..287a42001a7c 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -148,6 +148,8 @@ int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config, cfg.format = sof_cfg->format; cfg.options = sof_cfg->flags; cfg.rate = common_config->sampling_frequency; + cfg.channels = common_config->out_fmt->channels_count; + cfg.word_size = common_config->out_fmt->valid_bit_depth; switch (common_config->type) { case SOF_DAI_INTEL_SSP: @@ -178,6 +180,11 @@ int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config, cfg.type = DAI_IMX_ESAI; cfg_params = &sof_cfg->esai; break; + case SOF_DAI_INTEL_UAOL: + cfg.type = DAI_INTEL_UAOL; + cfg_params = gtw_cfg; + dai_set_link_hda_config(&cfg.link_config, common_config, >w_cfg->config_data); + break; default: return -EINVAL; } diff --git a/src/include/ipc/dai.h b/src/include/ipc/dai.h index b5b29316f9e6..14c49b75681b 100644 --- a/src/include/ipc/dai.h +++ b/src/include/ipc/dai.h @@ -94,7 +94,8 @@ enum sof_ipc_dai_type { SOF_DAI_AMD_SP_VIRTUAL, /**host_dma_config[0]->stream_id; break; + case SOF_DAI_INTEL_UAOL: + link_cfg.full = 0; + link_cfg.part.hchan = out_fmt->channels_count - 1; + link_cfg.part.dir = common_config->direction; + link_cfg.part.stream = common_config->host_dma_config[0]->stream_id; + break; default: /* other types of DAIs not need link_config */ return; @@ -115,6 +121,15 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void */ channel = 0; break; + case SOF_DAI_INTEL_UAOL: +#if defined(CONFIG_ACE_VERSION_2_0) || defined(CONFIG_ACE_VERSION_3_0) + channel = 0; + if (dai->host_dma_config[0]->pre_allocated_by_host) + channel = dai->host_dma_config[0]->dma_channel_id; +#else + channel = copier_cfg->gtw_cfg.node_id.f.v_index; +#endif + break; default: /* other types of DAIs not handled for now */ comp_err(dev, "dai_config_dma_channel(): Unknown dai type %d", dai->type); @@ -177,6 +192,16 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) dev->ipc_config.frame_fmt, dd->stream_id); break; + case SOF_DAI_INTEL_UAOL: +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS + dd->stream_id = dai_get_stream_id(dai_p, dai->direction); + dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S32_LE; + dd->config.burst_elems = dai_get_fifo_depth(dd->dai, dai->direction); + break; +#else + /* only native Zephyr driver supported */ + return -EINVAL; +#endif default: /* other types of DAIs not handled for now */ comp_warn(dev, "dai_data_config(): Unknown dai type %d", dai->type); diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 3774b4adca84..5dc264bfac3d 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -1076,6 +1076,18 @@ int ipc4_add_comp_dev(struct comp_dev *dev) int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size) { #if defined(CONFIG_ACE_VERSION_2_0) + if (dai->type == SOF_DAI_INTEL_UAOL) { + void *value_ptr = NULL; + uint32_t value_size; + + tlv_value_get(data_buffer, size, GTW_DMA_CONFIG_ID, &value_ptr, &value_size); + if (!value_ptr) + return IPC4_INVALID_REQUEST; + + dai->host_dma_config[0] = (struct ipc_dma_config *)value_ptr; + return IPC4_SUCCESS; + } + uint32_t *dma_config_id = GET_IPC_DMA_CONFIG_ID(data_buffer, size); if (*dma_config_id != GTW_DMA_CONFIG_ID) diff --git a/src/lib/dai.c b/src/lib/dai.c index 79266c93453d..e0a8f1ad97e0 100644 --- a/src/lib/dai.c +++ b/src/lib/dai.c @@ -151,6 +151,9 @@ const struct device *zephyr_dev[] = { #if CONFIG_DAI_NXP_ESAI DT_FOREACH_STATUS_OKAY(nxp_dai_esai, GET_DEVICE_LIST) #endif +#if CONFIG_DAI_INTEL_UAOL + DT_FOREACH_STATUS_OKAY(intel_uaol_dai, GET_DEVICE_LIST) +#endif }; static const struct device *dai_get_zephyr_device(uint32_t type, uint32_t index) @@ -202,6 +205,15 @@ static void dai_set_device_params(struct dai *d) d->dma_dev = DMA_DEV_HDA; d->dma_caps = DMA_CAP_HDA; break; + case SOF_DAI_INTEL_UAOL: +#ifdef CONFIG_DMA_INTEL_ADSP_GPDMA + d->dma_dev = DMA_DEV_ALH; + d->dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP; +#else + d->dma_dev = DMA_DEV_HDA; + d->dma_caps = DMA_CAP_HDA; +#endif + break; default: break; } @@ -245,6 +257,9 @@ struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags) case SOF_DAI_MEDIATEK_AFE: z_type = DAI_MEDIATEK_AFE; break; + case SOF_DAI_INTEL_UAOL: + z_type = DAI_INTEL_UAOL; + break; default: return NULL; } @@ -289,6 +304,29 @@ void dai_put(struct dai *dai) rfree(dai); } + +int dai_control(uint32_t node_id, const void *data) +{ + union ipc4_connector_node_id node = { .dw = node_id }; + const struct device *dev; + uint32_t z_type; + int ret; + + switch (node.f.dma_type) { + case ipc4_alh_uaol_stream_link_output_class: + case ipc4_alh_uaol_stream_link_input_class: + z_type = DAI_INTEL_UAOL; + break; + default: + return -EINVAL; + } + + dev = dai_get_zephyr_device(z_type, node.f.v_index); + if (dev == NULL) + return -ENODEV; + + return dai_config_set(dev, NULL, data); +} #else static inline const struct dai_type_info *dai_find_type(uint32_t type) {