Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/audio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD)
add_subdirectory(tone)
endif()
if(CONFIG_UAOL_INTEL_ADSP)
add_local_sources(sof intel_uaol.c)
add_local_sources(sof intel_uaol.c dsrc.c)
endif()
if(CONFIG_ZEPHYR_NATIVE_DRIVERS)
list(APPEND base_files host-zephyr.c)
Expand Down
193 changes: 173 additions & 20 deletions src/audio/dai-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@

#include <zephyr/device.h>
#include <zephyr/drivers/dai.h>
#ifdef CONFIG_UAOL_INTEL_ADSP
#include <zephyr/drivers/uaol.h>
#include <sof/audio/intel_uaol.h>
#endif

#include <sof/debug/telemetry/performance_monitor.h>

Expand Down Expand Up @@ -204,6 +208,7 @@ __cold int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
cfg.type = DAI_AMD_TDM;
cfg_params = &sof_cfg->acptdm;
break;
#ifdef CONFIG_UAOL_INTEL_ADSP
case SOF_DAI_INTEL_UAOL:
cfg.type = DAI_INTEL_UAOL;
cfg.channels = common_config->gtw_fmt->channels_count;
Expand All @@ -215,7 +220,9 @@ __cold int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
cfg.word_size = common_config->gtw_fmt->valid_bit_depth;
cfg_params = spec_config;
dai_set_link_hda_config(&cfg.link_config, common_config, spec_config);
cfg.extra_link_config = dai_uaol_feedback_link_config(common_config);
break;
#endif /* CONFIG_UAOL_INTEL_ADSP */
case SOF_DAI_MEDIATEK_AFE:
cfg.type = DAI_MEDIATEK_AFE;
cfg_params = &sof_cfg->afe;
Expand All @@ -234,8 +241,8 @@ __cold int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
return dai_config_set(dev, &cfg, cfg_params, dai_cfg_size);
}

static int dai_get_properties_safe(struct dai *dai, int direction,
int stream_id, struct dai_properties *props)
int dai_get_properties_safe(struct dai *dai, int direction,
int stream_id, struct dai_properties *props)
{
const struct dai_properties *props_p;
int ret;
Expand Down Expand Up @@ -392,8 +399,14 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
}
}
#endif
ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer,
dd->process, bytes, dd->chmap);

#ifdef CONFIG_UAOL_INTEL_ADSP
if (dd->uaol.feedback_drift)
ret = uaol_dma_buffer_copy_to(dd, bytes);
else
#endif /* CONFIG_UAOL_INTEL_ADSP */
ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer,
dd->process, bytes, dd->chmap);
} else {
audio_stream_invalidate(&dd->dma_buffer->stream, bytes);
/*
Expand Down Expand Up @@ -475,6 +488,12 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
/* update host position (in bytes offset) for drivers */
dd->total_data_processed += bytes;
}

#ifdef CONFIG_UAOL_INTEL_ADSP
if (dd->uaol.fb_chan_idx >= 0)
process_uaol_feedback(dev, dd);
#endif /* CONFIG_UAOL_INTEL_ADSP */

#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS
/* Increment performance counters */
io_perf_monitor_update_data(dd->io_perf_dai_byte_count, bytes);
Expand Down Expand Up @@ -565,6 +584,10 @@ __cold int dai_common_new(struct dai_data *dd, struct comp_dev *dev,
SOF_DMA_DIR_MEM_TO_DEV : SOF_DMA_DIR_DEV_TO_MEM;

dd->chan_index = -EINVAL;
#ifdef CONFIG_UAOL_INTEL_ADSP
dd->uaol.fb_chan_idx = -EINVAL;
#endif

dd->dma = sof_dma_get(dir, dd->dai->dma_caps, dd->dai->dma_dev, SOF_DMA_ACCESS_SHARED);
if (!dd->dma) {
dai_put(dd->dai);
Expand Down Expand Up @@ -633,6 +656,78 @@ __cold int dai_common_new(struct dai_data *dd, struct comp_dev *dev,
return 0;
}

static void dai_dma_release_channel(struct dai_data *dd)
{
if (dd->chan_index >= 0) {
sof_dma_release_channel(dd->dma, dd->chan_index);
dd->chan_index = -EINVAL;
}

#if CONFIG_UAOL_INTEL_ADSP
if (dd->uaol.fb_chan_idx >= 0) {
sof_dma_release_channel(dd->uaol.fb_dma, dd->uaol.fb_chan_idx);
dd->uaol.fb_chan_idx = -EINVAL;
}
#endif
}

static int dai_dma_config(struct dai_data *dd)
{
int ret = sof_dma_config(dd->dma, dd->chan_index, dd->z_config);
if (ret < 0)
return ret;

#if CONFIG_UAOL_INTEL_ADSP
if (dd->uaol.fb_chan_idx >= 0)
ret = sof_dma_config(dd->uaol.fb_dma, dd->uaol.fb_chan_idx, dd->uaol.fb_z_config);
#endif

return ret;
}

static int dai_dma_start(struct dai_data *dd)
{
int ret = sof_dma_start(dd->dma, dd->chan_index);
if (ret < 0)
return ret;

#if CONFIG_UAOL_INTEL_ADSP
if (dd->uaol.fb_chan_idx >= 0) {
ret = sof_dma_start(dd->uaol.fb_dma, dd->uaol.fb_chan_idx);
if (ret < 0)
sof_dma_stop(dd->dma, dd->chan_index);
}
#endif

return ret;
}

static int dai_dma_stop(struct dai_data *dd)
{
int ret = sof_dma_stop(dd->dma, dd->chan_index);

#if CONFIG_UAOL_INTEL_ADSP
/* seems it's better to stop feedback even when the above fails */
if (dd->uaol.fb_chan_idx >= 0)
sof_dma_stop(dd->uaol.fb_dma, dd->uaol.fb_chan_idx);
#endif

return ret;
}

static int dai_dma_suspend(struct dai_data *dd)
{
int ret = sof_dma_suspend(dd->dma, dd->chan_index);

#if CONFIG_UAOL_INTEL_ADSP
/* seems it's better to suspend feedback even when the above fails */
if (dd->uaol.fb_chan_idx >= 0)
sof_dma_suspend(dd->uaol.fb_dma, dd->uaol.fb_chan_idx);
#endif

return ret;
}

__cold static struct comp_dev *dai_new(const struct comp_driver *drv,
const struct comp_ipc_config *config,
const void *spec)
Expand Down Expand Up @@ -689,18 +784,18 @@ __cold void dai_common_free(struct dai_data *dd)
if (dd->group)
dai_group_put(dd->group);

if (dd->chan_index >= 0) {
sof_dma_release_channel(dd->dma, dd->chan_index);
dd->chan_index = -EINVAL;
}

dai_dma_release_channel(dd);
sof_dma_put(dd->dma);

dai_release_llp_slot(dd);

dai_put(dd->dai);

sof_heap_free(dd->alloc_ctx.heap, dd->dai_spec_config);

#if CONFIG_UAOL_INTEL_ADSP
uaol_free(dd);
#endif
}

__cold static void dai_free(struct comp_dev *dev)
Expand Down Expand Up @@ -1183,8 +1278,35 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev,
}

err = dai_set_dma_config(dd, dev);
if (err < 0)
if (err < 0) {
comp_err(dev, "set dma config failed.");
goto out;
}

/* Ideally, this should be moved into setup_uaol_feedback_dma() in intel_uaol.c, but
* there is no easy access to "params" there to set up the buffer format.
*/
#ifdef CONFIG_UAOL_INTEL_ADSP
/* create DSRC output buffer (if needed) */
if (dd->ipc_config.type == SOF_DAI_INTEL_UAOL &&
dd->ipc_config.direction == SOF_IPC_STREAM_PLAYBACK) {
/* resampling might generate 1 extra frame; DSRC only works with 32-bit data */
size_t dsrc_buf_size = (dev->frames + 1) * dd->ipc_config.gtw_fmt->channels_count * 4;
dd->uaol.dsrc_buf = buffer_alloc_range(&dd->alloc_ctx, dsrc_buf_size,
Comment on lines +1291 to +1295
dsrc_buf_size,
SOF_MEM_FLAG_USER, PLATFORM_DCACHE_ALIGN,
BUFFER_USAGE_NOT_SHARED);
Comment on lines +1293 to +1298
if (!dd->uaol.dsrc_buf) {
comp_err(dev, "failed to alloc dsrc buffer");
err = -ENOMEM;
goto out;
}

/* params should be same as local_buffer's */
buffer_set_params(dd->uaol.dsrc_buf, &params, BUFFER_UPDATE_FORCE);
}
#endif /* CONFIG_UAOL_INTEL_ADSP */

out:
/*
* Make sure to free all allocated items, all functions
Expand Down Expand Up @@ -1250,6 +1372,11 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev)
comp_dbg(dev, "new configured dma channel index %d",
dd->chan_index);

#ifdef CONFIG_UAOL_INTEL_ADSP
/* Does nothing if feedback DMA is not needed */
setup_uaol_feedback_dma(dd, dev);
#endif /* CONFIG_UAOL_INTEL_ADSP */

return 0;
}

Expand All @@ -1273,6 +1400,10 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev)

/* clear dma buffer to avoid pop noise */
buffer_zero(dd->dma_buffer);
#ifdef CONFIG_UAOL_INTEL_ADSP
if (dd->uaol.fb_dma_buf)
memset(dd->uaol.fb_dma_buf, 0, dd->uaol.fb_dma_buf_size);
#endif /* CONFIG_UAOL_INTEL_ADSP */

/* dma reconfig not required if XRUN handling */
if (dd->xrun) {
Expand All @@ -1281,7 +1412,7 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev)
return 0;
}

ret = sof_dma_config(dd->dma, dd->chan_index, dd->z_config);
ret = dai_dma_config(dd);
if (ret < 0)
comp_set_state(dev, COMP_TRIGGER_RESET);

Expand Down Expand Up @@ -1332,6 +1463,10 @@ void dai_common_reset(struct dai_data *dd, struct comp_dev *dev)
dd->dma_buffer = NULL;
}

#ifdef CONFIG_UAOL_INTEL_ADSP
uaol_free(dd);
#endif /* CONFIG_UAOL_INTEL_ADSP */

dd->wallclock = 0;
dd->total_data_processed = 0;
dd->xrun = 0;
Expand Down Expand Up @@ -1368,7 +1503,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,

/* only start the DAI if we are not XRUN handling */
if (dd->xrun == 0) {
ret = sof_dma_start(dd->dma, dd->chan_index);
ret = dai_dma_start(dd);
if (ret < 0)
return ret;

Expand All @@ -1389,6 +1524,14 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
buffer_zero(dd->dma_buffer);
}

#ifdef CONFIG_UAOL_INTEL_ADSP
/* It might be beneficial to clear any old obsolete feedback value to prevent
* it from being used to adjust the rate immediately after resume. A feedback
* value of 0 will be rejected by the sanity check. */
if (dd->uaol.fb_dma_buf)
memset(dd->uaol.fb_dma_buf, 0, dd->uaol.fb_dma_buf_size);
#endif /* CONFIG_UAOL_INTEL_ADSP */

/* DMA driver and SOF's view of the DMA buffer's
* read and write cursors must be the same to
* avoid scenarios in which the DMA driver
Expand All @@ -1406,16 +1549,16 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
/* only start the DAI if we are not XRUN handling */
if (dd->xrun == 0) {
/* recover valid start position */
ret = sof_dma_stop(dd->dma, dd->chan_index);
ret = dai_dma_stop(dd);
if (ret < 0)
return ret;

/* dma_config needed after stop */
ret = sof_dma_config(dd->dma, dd->chan_index, dd->z_config);
ret = dai_dma_config(dd);
if (ret < 0)
return ret;

ret = sof_dma_start(dd->dma, dd->chan_index);
ret = dai_dma_start(dd);
if (ret < 0)
return ret;

Expand Down Expand Up @@ -1443,11 +1586,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
* as soon as possible.
*/
#if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE
ret = sof_dma_stop(dd->dma, dd->chan_index);
ret = dai_dma_stop(dd);
dai_trigger_op(dd->dai, cmd, dev->direction);
#else
dai_trigger_op(dd->dai, cmd, dev->direction);
ret = sof_dma_stop(dd->dma, dd->chan_index);
ret = dai_dma_stop(dd);
if (ret) {
comp_warn(dev, "dma was stopped earlier");
ret = 0;
Expand All @@ -1457,11 +1600,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
case COMP_TRIGGER_PAUSE:
comp_dbg(dev, "PAUSE");
#if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE
ret = sof_dma_suspend(dd->dma, dd->chan_index);
ret = dai_dma_suspend(dd);
dai_trigger_op(dd->dai, cmd, dev->direction);
#else
dai_trigger_op(dd->dai, cmd, dev->direction);
ret = sof_dma_suspend(dd->dma, dd->chan_index);
ret = dai_dma_suspend(dd);
#endif
break;
case COMP_TRIGGER_PRE_START:
Expand Down Expand Up @@ -1796,6 +1939,11 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun
if (dev->direction == SOF_IPC_STREAM_PLAYBACK) {
src_frames = audio_stream_get_avail_frames(&dd->local_buffer->stream);
sink_frames = free_bytes / audio_stream_frame_bytes(&dd->dma_buffer->stream);
#ifdef CONFIG_UAOL_INTEL_ADSP
/* DSRC may insert one frame on top of the copied ones */
if (dd->uaol.feedback_drift > 0 && sink_frames)
sink_frames--;
#endif
frames = MIN(src_frames, sink_frames);

/*
Expand Down Expand Up @@ -1892,8 +2040,13 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun
comp_warn(dev, "dai trigger copy failed");

if (dai_dma_cb(dd, dev, copy_bytes, converter) == SOF_DMA_CB_STATUS_END)
sof_dma_stop(dd->dma, dd->chan_index);
dai_dma_stop(dd);

#ifdef CONFIG_UAOL_INTEL_ADSP
/* adjust reload size as extra frame may be added by DSRC */
copy_bytes += dd->uaol.dma_added_bytes;
dd->uaol.dma_added_bytes = 0;
#endif
ret = sof_dma_reload(dd->dma, dd->chan_index, copy_bytes);
if (ret < 0) {
dai_report_reload_xrun(dd, dev, copy_bytes);
Expand Down
Loading
Loading