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
@@ -352,8 +356,14 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
352356 }
353357 }
354358#endif
355- ret = dma_buffer_copy_to (dd -> local_buffer , dd -> dma_buffer ,
356- dd -> process , bytes , dd -> chmap );
359+
360+ #ifdef CONFIG_DAI_INTEL_UAOL
361+ if (dd -> uaol .feedback_drift )
362+ uaol_dma_buffer_copy_to (dd , bytes );
363+ else
364+ #endif /* CONFIG_DAI_INTEL_UAOL */
365+ ret = dma_buffer_copy_to (dd -> local_buffer , dd -> dma_buffer ,
366+ dd -> process , bytes , dd -> chmap );
357367 } else {
358368 audio_stream_invalidate (& dd -> dma_buffer -> stream , bytes );
359369 /*
@@ -435,6 +445,12 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
435445 /* update host position (in bytes offset) for drivers */
436446 dd -> total_data_processed += bytes ;
437447 }
448+
449+ #ifdef CONFIG_DAI_INTEL_UAOL
450+ if (dd -> uaol .fb_chan_idx >= 0 )
451+ process_uaol_feedback (dev , dd );
452+ #endif /* CONFIG_DAI_INTEL_UAOL */
453+
438454#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS
439455 /* Increment performance counters */
440456 io_perf_monitor_update_data (dd -> io_perf_dai_byte_count , bytes );
@@ -593,6 +609,75 @@ __cold int dai_common_new(struct dai_data *dd, struct comp_dev *dev,
593609 return 0 ;
594610}
595611
612+ static void dai_dma_release_channel (struct dai_data * dd )
613+ {
614+ if (dd -> chan_index >= 0 ) {
615+ sof_dma_release_channel (dd -> dma , dd -> chan_index );
616+ dd -> chan_index = - EINVAL ;
617+ }
618+
619+ #if CONFIG_UAOL_INTEL_ADSP
620+ if (dd -> uaol .fb_chan_idx >= 0 ) {
621+ sof_dma_release_channel (dd -> dma , dd -> uaol .fb_chan_idx );
622+ dd -> uaol .fb_chan_idx = - EINVAL ;
623+ }
624+ #endif
625+ }
626+
627+ static int dai_dma_config (struct dai_data * dd )
628+ {
629+ int ret = sof_dma_config (dd -> dma , dd -> chan_index , dd -> z_config );
630+ if (ret < 0 )
631+ return ret ;
632+
633+ #if CONFIG_UAOL_INTEL_ADSP
634+ if (dd -> uaol .fb_chan_idx >= 0 )
635+ ret = sof_dma_config (dd -> dma , dd -> uaol .fb_chan_idx , dd -> uaol .fb_z_config );
636+ #endif
637+
638+ return ret ;
639+ }
640+
641+ static int dai_dma_start (struct dai_data * dd )
642+ {
643+ int ret = sof_dma_start (dd -> dma , dd -> chan_index );
644+ if (ret < 0 )
645+ return ret ;
646+
647+ #if CONFIG_UAOL_INTEL_ADSP
648+ if (dd -> uaol .fb_chan_idx >= 0 )
649+ ret = sof_dma_start (dd -> dma , dd -> uaol .fb_chan_idx );
650+ #endif
651+
652+ return ret ;
653+ }
654+
655+ static int dai_dma_stop (struct dai_data * dd )
656+ {
657+ int ret = sof_dma_stop (dd -> dma , dd -> chan_index );
658+
659+ #if CONFIG_UAOL_INTEL_ADSP
660+ /* seems it's better to stop feedback even when the above fails */
661+ if (dd -> uaol .fb_chan_idx >= 0 )
662+ sof_dma_stop (dd -> dma , dd -> uaol .fb_chan_idx );
663+ #endif
664+
665+ return ret ;
666+ }
667+
668+ static int dai_dma_suspend (struct dai_data * dd )
669+ {
670+ int ret = sof_dma_suspend (dd -> dma , dd -> chan_index );
671+
672+ #if CONFIG_UAOL_INTEL_ADSP
673+ /* seems it's better to suspend feedback even when the above fails */
674+ if (dd -> uaol .fb_chan_idx >= 0 )
675+ sof_dma_suspend (dd -> dma , dd -> uaol .fb_chan_idx );
676+ #endif
677+
678+ return ret ;
679+ }
680+
596681__cold static struct comp_dev * dai_new (const struct comp_driver * drv ,
597682 const struct comp_ipc_config * config ,
598683 const void * spec )
@@ -649,18 +734,18 @@ __cold void dai_common_free(struct dai_data *dd)
649734 if (dd -> group )
650735 dai_group_put (dd -> group );
651736
652- if (dd -> chan_index >= 0 ) {
653- sof_dma_release_channel (dd -> dma , dd -> chan_index );
654- dd -> chan_index = - EINVAL ;
655- }
656-
737+ dai_dma_release_channel (dd );
657738 sof_dma_put (dd -> dma );
658739
659740 dai_release_llp_slot (dd );
660741
661742 dai_put (dd -> dai );
662743
663744 sof_heap_free (dd -> alloc_ctx .heap , dd -> dai_spec_config );
745+
746+ #if CONFIG_UAOL_INTEL_ADSP
747+ uaol_free (dd );
748+ #endif
664749}
665750
666751__cold static void dai_free (struct comp_dev * dev )
@@ -1143,8 +1228,33 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev,
11431228 }
11441229
11451230 err = dai_set_dma_config (dd , dev );
1146- if (err < 0 )
1231+ if (err < 0 ) {
11471232 comp_err (dev , "set dma config failed." );
1233+ goto out ;
1234+ }
1235+
1236+ /* Ideally, this should be moved into setup_uaol_feedback_dma() in uaol.c, but
1237+ * there is no easy access to "params" there to set up the buffer format.
1238+ */
1239+ #ifdef CONFIG_DAI_INTEL_UAOL
1240+ /* create DSRC output buffer (if needed) */
1241+ if (dd -> ipc_config .type == SOF_DAI_INTEL_UAOL &&
1242+ dd -> ipc_config .direction == SOF_IPC_STREAM_PLAYBACK ) {
1243+ /* resampling might generate 1 extra frame; DSRC only works with 32-bit data */
1244+ size_t dsrc_buf_size = (dev -> frames + 1 ) * dd -> ipc_config .gtw_fmt -> channels_count * 4 ;
1245+ dd -> uaol .dsrc_buf = buffer_alloc_range (NULL , dsrc_buf_size , dsrc_buf_size ,
1246+ SOF_MEM_FLAG_USER , PLATFORM_DCACHE_ALIGN ,
1247+ BUFFER_USAGE_NOT_SHARED );
1248+ if (!dd -> uaol .dsrc_buf ) {
1249+ comp_err (dev , "failed to alloc dsrc buffer" );
1250+ goto out ;
1251+ }
1252+
1253+ /* params should be same as local_buffer's */
1254+ buffer_set_params (dd -> uaol .dsrc_buf , & params , BUFFER_UPDATE_FORCE );
1255+ }
1256+ #endif /* CONFIG_DAI_INTEL_UAOL */
1257+
11481258out :
11491259 /*
11501260 * Make sure to free all allocated items, all functions
@@ -1210,6 +1320,11 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev)
12101320 comp_dbg (dev , "new configured dma channel index %d" ,
12111321 dd -> chan_index );
12121322
1323+ #ifdef CONFIG_DAI_INTEL_UAOL
1324+ /* Does nothing if feedback DMA is not needed */
1325+ setup_uaol_feedback_dma (dd , dev );
1326+ #endif /* CONFIG_DAI_INTEL_UAOL */
1327+
12131328 return 0 ;
12141329}
12151330
@@ -1233,6 +1348,10 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev)
12331348
12341349 /* clear dma buffer to avoid pop noise */
12351350 buffer_zero (dd -> dma_buffer );
1351+ #ifdef CONFIG_DAI_INTEL_UAOL
1352+ if (dd -> uaol .fb_dma_buf )
1353+ memset (dd -> uaol .fb_dma_buf , 0 , dd -> uaol .fb_dma_buf_size );
1354+ #endif /* CONFIG_DAI_INTEL_UAOL */
12361355
12371356 /* dma reconfig not required if XRUN handling */
12381357 if (dd -> xrun ) {
@@ -1241,7 +1360,7 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev)
12411360 return 0 ;
12421361 }
12431362
1244- ret = sof_dma_config (dd -> dma , dd -> chan_index , dd -> z_config );
1363+ ret = dai_dma_config (dd );
12451364 if (ret < 0 )
12461365 comp_set_state (dev , COMP_TRIGGER_RESET );
12471366
@@ -1292,6 +1411,10 @@ void dai_common_reset(struct dai_data *dd, struct comp_dev *dev)
12921411 dd -> dma_buffer = NULL ;
12931412 }
12941413
1414+ #ifdef CONFIG_DAI_INTEL_UAOL
1415+ uaol_free (dd );
1416+ #endif /* CONFIG_DAI_INTEL_UAOL */
1417+
12951418 dd -> wallclock = 0 ;
12961419 dd -> total_data_processed = 0 ;
12971420 dd -> xrun = 0 ;
@@ -1328,7 +1451,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13281451
13291452 /* only start the DAI if we are not XRUN handling */
13301453 if (dd -> xrun == 0 ) {
1331- ret = sof_dma_start (dd -> dma , dd -> chan_index );
1454+ ret = dai_dma_start (dd );
13321455 if (ret < 0 )
13331456 return ret ;
13341457
@@ -1349,6 +1472,14 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13491472 buffer_zero (dd -> dma_buffer );
13501473 }
13511474
1475+ #ifdef CONFIG_DAI_INTEL_UAOL
1476+ /* It might be beneficial to clear any old obsolete feedback value to prevent
1477+ * it from being used to adjust the rate immediately after resume. A feedback
1478+ * value of 0 will be rejected by the sanity check. */
1479+ if (dd -> uaol .fb_dma_buf )
1480+ memset (dd -> uaol .fb_dma_buf , 0 , dd -> uaol .fb_dma_buf_size );
1481+ #endif /* CONFIG_DAI_INTEL_UAOL */
1482+
13521483 /* DMA driver and SOF's view of the DMA buffer's
13531484 * read and write cursors must be the same to
13541485 * avoid scenarios in which the DMA driver
@@ -1366,16 +1497,16 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13661497 /* only start the DAI if we are not XRUN handling */
13671498 if (dd -> xrun == 0 ) {
13681499 /* recover valid start position */
1369- ret = sof_dma_stop (dd -> dma , dd -> chan_index );
1500+ ret = dai_dma_stop (dd );
13701501 if (ret < 0 )
13711502 return ret ;
13721503
13731504 /* dma_config needed after stop */
1374- ret = sof_dma_config (dd -> dma , dd -> chan_index , dd -> z_config );
1505+ ret = dai_dma_config (dd );
13751506 if (ret < 0 )
13761507 return ret ;
13771508
1378- ret = sof_dma_start (dd -> dma , dd -> chan_index );
1509+ ret = dai_dma_start (dd );
13791510 if (ret < 0 )
13801511 return ret ;
13811512
@@ -1403,11 +1534,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
14031534 * as soon as possible.
14041535 */
14051536#if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE
1406- ret = sof_dma_stop (dd -> dma , dd -> chan_index );
1537+ ret = dai_dma_stop (dd );
14071538 dai_trigger_op (dd -> dai , cmd , dev -> direction );
14081539#else
14091540 dai_trigger_op (dd -> dai , cmd , dev -> direction );
1410- ret = sof_dma_stop (dd -> dma , dd -> chan_index );
1541+ ret = dai_dma_stop (dd );
14111542 if (ret ) {
14121543 comp_warn (dev , "dma was stopped earlier" );
14131544 ret = 0 ;
@@ -1417,11 +1548,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
14171548 case COMP_TRIGGER_PAUSE :
14181549 comp_dbg (dev , "PAUSE" );
14191550#if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE
1420- ret = sof_dma_suspend (dd -> dma , dd -> chan_index );
1551+ ret = dai_dma_suspend (dd );
14211552 dai_trigger_op (dd -> dai , cmd , dev -> direction );
14221553#else
14231554 dai_trigger_op (dd -> dai , cmd , dev -> direction );
1424- ret = sof_dma_suspend (dd -> dma , dd -> chan_index );
1555+ ret = dai_dma_suspend (dd );
14251556#endif
14261557 break ;
14271558 case COMP_TRIGGER_PRE_START :
@@ -1852,7 +1983,7 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun
18521983 comp_warn (dev , "dai trigger copy failed" );
18531984
18541985 if (dai_dma_cb (dd , dev , copy_bytes , converter ) == SOF_DMA_CB_STATUS_END )
1855- sof_dma_stop (dd -> dma , dd -> chan_index );
1986+ dai_dma_stop (dd );
18561987
18571988 ret = sof_dma_reload (dd -> dma , dd -> chan_index , copy_bytes );
18581989 if (ret < 0 ) {
0 commit comments