4646
4747#include <zephyr/device.h>
4848#include <zephyr/drivers/dai.h>
49+ #ifdef CONFIG_DAI_INTEL_UAOL
50+ #include <zephyr/drivers/uaol.h>
51+ #include <sof/audio/uaol.h>
52+ #endif
4953
5054#include <sof/debug/telemetry/performance_monitor.h>
5155
@@ -344,8 +348,14 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
344348 }
345349 }
346350#endif
347- ret = dma_buffer_copy_to (dd -> local_buffer , dd -> dma_buffer ,
348- dd -> process , bytes , dd -> chmap );
351+
352+ #ifdef CONFIG_DAI_INTEL_UAOL
353+ if (dd -> uaol .feedback_drift )
354+ uaol_dma_buffer_copy_to (dd , bytes );
355+ else
356+ #endif /* CONFIG_DAI_INTEL_UAOL */
357+ ret = dma_buffer_copy_to (dd -> local_buffer , dd -> dma_buffer ,
358+ dd -> process , bytes , dd -> chmap );
349359 } else {
350360 audio_stream_invalidate (& dd -> dma_buffer -> stream , bytes );
351361 /*
@@ -427,6 +437,12 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
427437 /* update host position (in bytes offset) for drivers */
428438 dd -> total_data_processed += bytes ;
429439 }
440+
441+ #ifdef CONFIG_DAI_INTEL_UAOL
442+ if (dd -> uaol .fb_chan_idx >= 0 )
443+ process_uaol_feedback (dev , dd );
444+ #endif /* CONFIG_DAI_INTEL_UAOL */
445+
430446#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS
431447 /* Increment performance counters */
432448 io_perf_monitor_update_data (dd -> io_perf_dai_byte_count , bytes );
@@ -574,6 +590,75 @@ __cold int dai_common_new(struct dai_data *dd, struct comp_dev *dev,
574590 return 0 ;
575591}
576592
593+ static void dai_dma_release_channel (struct dai_data * dd )
594+ {
595+ if (dd -> chan_index >= 0 ) {
596+ sof_dma_release_channel (dd -> dma , dd -> chan_index );
597+ dd -> chan_index = - EINVAL ;
598+ }
599+
600+ #if CONFIG_UAOL_INTEL_ADSP
601+ if (dd -> uaol .fb_chan_idx >= 0 ) {
602+ sof_dma_release_channel (dd -> dma , dd -> uaol .fb_chan_idx );
603+ dd -> uaol .fb_chan_idx = - EINVAL ;
604+ }
605+ #endif
606+ }
607+
608+ static int dai_dma_config (struct dai_data * dd )
609+ {
610+ int ret = sof_dma_config (dd -> dma , dd -> chan_index , dd -> z_config );
611+ if (ret < 0 )
612+ return ret ;
613+
614+ #if CONFIG_UAOL_INTEL_ADSP
615+ if (dd -> uaol .fb_chan_idx >= 0 )
616+ ret = sof_dma_config (dd -> dma , dd -> uaol .fb_chan_idx , dd -> uaol .fb_z_config );
617+ #endif
618+
619+ return ret ;
620+ }
621+
622+ static int dai_dma_start (struct dai_data * dd )
623+ {
624+ int ret = sof_dma_start (dd -> dma , dd -> chan_index );
625+ if (ret < 0 )
626+ return ret ;
627+
628+ #if CONFIG_UAOL_INTEL_ADSP
629+ if (dd -> uaol .fb_chan_idx >= 0 )
630+ ret = sof_dma_start (dd -> dma , dd -> uaol .fb_chan_idx );
631+ #endif
632+
633+ return ret ;
634+ }
635+
636+ static int dai_dma_stop (struct dai_data * dd )
637+ {
638+ int ret = sof_dma_stop (dd -> dma , dd -> chan_index );
639+
640+ #if CONFIG_UAOL_INTEL_ADSP
641+ /* seems it's better to stop feedback even when the above fails */
642+ if (dd -> uaol .fb_chan_idx >= 0 )
643+ sof_dma_stop (dd -> dma , dd -> uaol .fb_chan_idx );
644+ #endif
645+
646+ return ret ;
647+ }
648+
649+ static int dai_dma_suspend (struct dai_data * dd )
650+ {
651+ int ret = sof_dma_suspend (dd -> dma , dd -> chan_index );
652+
653+ #if CONFIG_UAOL_INTEL_ADSP
654+ /* seems it's better to suspend feedback even when the above fails */
655+ if (dd -> uaol .fb_chan_idx >= 0 )
656+ sof_dma_suspend (dd -> dma , dd -> uaol .fb_chan_idx );
657+ #endif
658+
659+ return ret ;
660+ }
661+
577662__cold static struct comp_dev * dai_new (const struct comp_driver * drv ,
578663 const struct comp_ipc_config * config ,
579664 const void * spec )
@@ -627,18 +712,18 @@ __cold void dai_common_free(struct dai_data *dd)
627712 if (dd -> group )
628713 dai_group_put (dd -> group );
629714
630- if (dd -> chan_index >= 0 ) {
631- sof_dma_release_channel (dd -> dma , dd -> chan_index );
632- dd -> chan_index = - EINVAL ;
633- }
634-
715+ dai_dma_release_channel (dd );
635716 sof_dma_put (dd -> dma );
636717
637718 dai_release_llp_slot (dd );
638719
639720 dai_put (dd -> dai );
640721
641722 rfree (dd -> dai_spec_config );
723+
724+ #if CONFIG_UAOL_INTEL_ADSP
725+ uaol_free (dd );
726+ #endif
642727}
643728
644729__cold static void dai_free (struct comp_dev * dev )
@@ -1118,8 +1203,33 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev,
11181203 }
11191204
11201205 err = dai_set_dma_config (dd , dev );
1121- if (err < 0 )
1206+ if (err < 0 ) {
11221207 comp_err (dev , "set dma config failed." );
1208+ goto out ;
1209+ }
1210+
1211+ /* Ideally, this should be moved into setup_uaol_feedback_dma() in uaol.c, but
1212+ * there is no easy access to "params" there to set up the buffer format.
1213+ */
1214+ #ifdef CONFIG_DAI_INTEL_UAOL
1215+ /* create DSRC output buffer (if needed) */
1216+ if (dd -> ipc_config .type == SOF_DAI_INTEL_UAOL &&
1217+ dd -> ipc_config .direction == SOF_IPC_STREAM_PLAYBACK ) {
1218+ /* resampling might generate 1 extra frame; DSRC only works with 32-bit data */
1219+ size_t dsrc_buf_size = (dev -> frames + 1 ) * dd -> ipc_config .gtw_fmt -> channels_count * 4 ;
1220+ dd -> uaol .dsrc_buf = buffer_alloc_range (NULL , dsrc_buf_size , dsrc_buf_size ,
1221+ SOF_MEM_FLAG_USER , PLATFORM_DCACHE_ALIGN ,
1222+ BUFFER_USAGE_NOT_SHARED );
1223+ if (!dd -> uaol .dsrc_buf ) {
1224+ comp_err (dev , "failed to alloc dsrc buffer" );
1225+ goto out ;
1226+ }
1227+
1228+ /* params should be same as local_buffer's */
1229+ buffer_set_params (dd -> uaol .dsrc_buf , & params , BUFFER_UPDATE_FORCE );
1230+ }
1231+ #endif /* CONFIG_DAI_INTEL_UAOL */
1232+
11231233out :
11241234 /*
11251235 * Make sure to free all allocated items, all functions
@@ -1185,6 +1295,11 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev)
11851295 comp_dbg (dev , "new configured dma channel index %d" ,
11861296 dd -> chan_index );
11871297
1298+ #ifdef CONFIG_DAI_INTEL_UAOL
1299+ /* Does nothing if feedback DMA is not needed */
1300+ setup_uaol_feedback_dma (dd , dev );
1301+ #endif /* CONFIG_DAI_INTEL_UAOL */
1302+
11881303 return 0 ;
11891304}
11901305
@@ -1208,6 +1323,10 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev)
12081323
12091324 /* clear dma buffer to avoid pop noise */
12101325 buffer_zero (dd -> dma_buffer );
1326+ #ifdef CONFIG_DAI_INTEL_UAOL
1327+ if (dd -> uaol .fb_dma_buf )
1328+ memset (dd -> uaol .fb_dma_buf , 0 , dd -> uaol .fb_dma_buf_size );
1329+ #endif /* CONFIG_DAI_INTEL_UAOL */
12111330
12121331 /* dma reconfig not required if XRUN handling */
12131332 if (dd -> xrun ) {
@@ -1216,7 +1335,7 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev)
12161335 return 0 ;
12171336 }
12181337
1219- ret = sof_dma_config (dd -> dma , dd -> chan_index , dd -> z_config );
1338+ ret = dai_dma_config (dd );
12201339 if (ret < 0 )
12211340 comp_set_state (dev , COMP_TRIGGER_RESET );
12221341
@@ -1267,6 +1386,10 @@ void dai_common_reset(struct dai_data *dd, struct comp_dev *dev)
12671386 dd -> dma_buffer = NULL ;
12681387 }
12691388
1389+ #ifdef CONFIG_DAI_INTEL_UAOL
1390+ uaol_free (dd );
1391+ #endif /* CONFIG_DAI_INTEL_UAOL */
1392+
12701393 dd -> wallclock = 0 ;
12711394 dd -> total_data_processed = 0 ;
12721395 dd -> xrun = 0 ;
@@ -1303,7 +1426,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13031426
13041427 /* only start the DAI if we are not XRUN handling */
13051428 if (dd -> xrun == 0 ) {
1306- ret = sof_dma_start (dd -> dma , dd -> chan_index );
1429+ ret = dai_dma_start (dd );
13071430 if (ret < 0 )
13081431 return ret ;
13091432
@@ -1324,6 +1447,14 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13241447 buffer_zero (dd -> dma_buffer );
13251448 }
13261449
1450+ #ifdef CONFIG_DAI_INTEL_UAOL
1451+ /* It might be beneficial to clear any old obsolete feedback value to prevent
1452+ * it from being used to adjust the rate immediately after resume. A feedback
1453+ * value of 0 will be rejected by the sanity check. */
1454+ if (dd -> uaol .fb_dma_buf )
1455+ memset (dd -> uaol .fb_dma_buf , 0 , dd -> uaol .fb_dma_buf_size );
1456+ #endif /* CONFIG_DAI_INTEL_UAOL */
1457+
13271458 /* DMA driver and SOF's view of the DMA buffer's
13281459 * read and write cursors must be the same to
13291460 * avoid scenarios in which the DMA driver
@@ -1341,16 +1472,16 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13411472 /* only start the DAI if we are not XRUN handling */
13421473 if (dd -> xrun == 0 ) {
13431474 /* recover valid start position */
1344- ret = sof_dma_stop (dd -> dma , dd -> chan_index );
1475+ ret = dai_dma_stop (dd );
13451476 if (ret < 0 )
13461477 return ret ;
13471478
13481479 /* dma_config needed after stop */
1349- ret = sof_dma_config (dd -> dma , dd -> chan_index , dd -> z_config );
1480+ ret = dai_dma_config (dd );
13501481 if (ret < 0 )
13511482 return ret ;
13521483
1353- ret = sof_dma_start (dd -> dma , dd -> chan_index );
1484+ ret = dai_dma_start (dd );
13541485 if (ret < 0 )
13551486 return ret ;
13561487
@@ -1378,11 +1509,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13781509 * as soon as possible.
13791510 */
13801511#if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE
1381- ret = sof_dma_stop (dd -> dma , dd -> chan_index );
1512+ ret = dai_dma_stop (dd );
13821513 dai_trigger_op (dd -> dai , cmd , dev -> direction );
13831514#else
13841515 dai_trigger_op (dd -> dai , cmd , dev -> direction );
1385- ret = sof_dma_stop (dd -> dma , dd -> chan_index );
1516+ ret = dai_dma_stop (dd );
13861517 if (ret ) {
13871518 comp_warn (dev , "dma was stopped earlier" );
13881519 ret = 0 ;
@@ -1392,11 +1523,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13921523 case COMP_TRIGGER_PAUSE :
13931524 comp_dbg (dev , "PAUSE" );
13941525#if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE
1395- ret = sof_dma_suspend (dd -> dma , dd -> chan_index );
1526+ ret = dai_dma_suspend (dd );
13961527 dai_trigger_op (dd -> dai , cmd , dev -> direction );
13971528#else
13981529 dai_trigger_op (dd -> dai , cmd , dev -> direction );
1399- ret = sof_dma_suspend (dd -> dma , dd -> chan_index );
1530+ ret = dai_dma_suspend (dd );
14001531#endif
14011532 break ;
14021533 case COMP_TRIGGER_PRE_START :
@@ -1827,7 +1958,7 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun
18271958 comp_warn (dev , "dai trigger copy failed" );
18281959
18291960 if (dai_dma_cb (dd , dev , copy_bytes , converter ) == SOF_DMA_CB_STATUS_END )
1830- sof_dma_stop (dd -> dma , dd -> chan_index );
1961+ dai_dma_stop (dd );
18311962
18321963 ret = sof_dma_reload (dd -> dma , dd -> chan_index , copy_bytes );
18331964 if (ret < 0 ) {
0 commit comments