Skip to content

Commit

Permalink
dai: add support for Intel UAOL DAI
Browse files Browse the repository at this point in the history
This adds support for Intel USB Audio Offload Link (UAOL) DAI.

Signed-off-by: Tomasz Lissowski <[email protected]>
  • Loading branch information
tlissows committed Jun 14, 2024
1 parent 1470e6c commit b89f3e5
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 3 deletions.
83 changes: 82 additions & 1 deletion src/audio/base_fw_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include <zephyr/drivers/counter.h>
#endif

#if CONFIG_UAOL_INTEL_ADSP
#include <zephyr/drivers/uaol.h>
#endif

#include <ipc4/base_fw.h>
#include <rimage/sof/user/manifest.h>

Expand All @@ -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;
};

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)
Expand All @@ -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);
Expand All @@ -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)
{
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;

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;
Expand All @@ -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);

Expand Down Expand Up @@ -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 0;
}

int basefw_vendor_set_large_config(struct comp_dev *dev,
uint32_t param_id,
bool first_block,
Expand All @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions src/audio/copier/copier.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
13 changes: 13 additions & 0 deletions src/audio/copier/copier_dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,19 @@ 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 != 0) {
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;
Expand Down
8 changes: 8 additions & 0 deletions src/audio/dai-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,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:
Expand Down Expand Up @@ -177,6 +179,12 @@ 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 = container_of(spec_config,
struct ipc4_copier_gateway_cfg, config_data);
dai_set_link_hda_config(&cfg.link_config, common_config, spec_config);
break;
default:
return -EINVAL;
}
Expand Down
3 changes: 2 additions & 1 deletion src/include/ipc/dai.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ enum sof_ipc_dai_type {
SOF_DAI_AMD_SP_VIRTUAL, /**<Amd SP VIRTUAL */
SOF_DAI_AMD_HS_VIRTUAL, /**<Amd HS VIRTUAL */
SOF_DAI_IMX_MICFIL, /**< i.MX MICFIL */
SOF_DAI_AMD_SW_AUDIO /**<Amd SW AUDIO */
SOF_DAI_AMD_SW_AUDIO, /**<Amd SW AUDIO */
SOF_DAI_INTEL_UAOL, /**< Intel UAOL */
};

/* general purpose DAI configuration */
Expand Down
5 changes: 5 additions & 0 deletions src/include/sof/lib/dai-zephyr.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev);
* \brief release llp slot
*/
void dai_release_llp_slot(struct dai_data *dd);

/**
* \brief process ioctl request
*/
int dai_control(uint32_t node_id, const void *data);
/** @}*/

#endif /* __SOF_LIB_DAI_ZEPHYR_H__ */
25 changes: 25 additions & 0 deletions src/ipc/ipc4/dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ void dai_set_link_hda_config(uint16_t *link_config,
}
link_cfg.part.stream = common_config->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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions src/ipc/ipc4/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
76 changes: 75 additions & 1 deletion src/lib/dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
Expand All @@ -212,8 +224,47 @@ struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags)
{
const struct device *dev;
struct dai *d;
uint32_t z_type;

dev = dai_get_zephyr_device(type, index);
switch (type) {
case SOF_DAI_INTEL_SSP:
z_type = DAI_INTEL_SSP;
break;
case SOF_DAI_INTEL_DMIC:
z_type = DAI_INTEL_DMIC;
break;
case SOF_DAI_INTEL_HDA:
z_type = DAI_INTEL_HDA;
break;
case SOF_DAI_INTEL_ALH:
z_type = DAI_INTEL_ALH;
break;
case SOF_DAI_IMX_SAI:
z_type = DAI_IMX_SAI;
break;
case SOF_DAI_IMX_ESAI:
z_type = DAI_IMX_ESAI;
break;
case SOF_DAI_AMD_BT:
z_type = DAI_AMD_BT;
break;
case SOF_DAI_AMD_SP:
z_type = DAI_AMD_SP;
break;
case SOF_DAI_AMD_DMIC:
z_type = DAI_AMD_DMIC;
break;
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;
}

dev = dai_get_zephyr_device(z_type, index);
if (!dev) {
tr_err(&dai_tr, "dai_get: failed to get dai with index %d type %d",
index, type);
Expand Down Expand Up @@ -253,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)
{
Expand Down

0 comments on commit b89f3e5

Please sign in to comment.