4545
4646#include <zephyr/device.h>
4747#include <zephyr/drivers/dai.h>
48+ #ifdef CONFIG_UAOL_INTEL_ADSP
49+ #include <zephyr/drivers/uaol.h>
50+ #include <sof/audio/intel_uaol.h>
51+ #endif
4852
4953#include <sof/debug/telemetry/performance_monitor.h>
5054
@@ -204,6 +208,7 @@ __cold int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
204208 cfg .type = DAI_AMD_TDM ;
205209 cfg_params = & sof_cfg -> acptdm ;
206210 break ;
211+ #ifdef CONFIG_UAOL_INTEL_ADSP
207212 case SOF_DAI_INTEL_UAOL :
208213 cfg .type = DAI_INTEL_UAOL ;
209214 cfg .channels = common_config -> gtw_fmt -> channels_count ;
@@ -215,7 +220,9 @@ __cold int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
215220 cfg .word_size = common_config -> gtw_fmt -> valid_bit_depth ;
216221 cfg_params = spec_config ;
217222 dai_set_link_hda_config (& cfg .link_config , common_config , spec_config );
223+ cfg .extra_link_config = dai_uaol_feedback_link_config (common_config );
218224 break ;
225+ #endif /* CONFIG_UAOL_INTEL_ADSP */
219226 case SOF_DAI_MEDIATEK_AFE :
220227 cfg .type = DAI_MEDIATEK_AFE ;
221228 cfg_params = & sof_cfg -> afe ;
@@ -392,8 +399,14 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
392399 }
393400 }
394401#endif
395- ret = dma_buffer_copy_to (dd -> local_buffer , dd -> dma_buffer ,
396- dd -> process , bytes , dd -> chmap );
402+
403+ #ifdef CONFIG_UAOL_INTEL_ADSP
404+ if (dd -> uaol .feedback_drift )
405+ ret = uaol_dma_buffer_copy_to (dd , bytes );
406+ else
407+ #endif /* CONFIG_UAOL_INTEL_ADSP */
408+ ret = dma_buffer_copy_to (dd -> local_buffer , dd -> dma_buffer ,
409+ dd -> process , bytes , dd -> chmap );
397410 } else {
398411 audio_stream_invalidate (& dd -> dma_buffer -> stream , bytes );
399412 /*
@@ -475,6 +488,12 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
475488 /* update host position (in bytes offset) for drivers */
476489 dd -> total_data_processed += bytes ;
477490 }
491+
492+ #ifdef CONFIG_UAOL_INTEL_ADSP
493+ if (dd -> uaol .fb_chan_idx >= 0 )
494+ process_uaol_feedback (dev , dd );
495+ #endif /* CONFIG_UAOL_INTEL_ADSP */
496+
478497#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS
479498 /* Increment performance counters */
480499 io_perf_monitor_update_data (dd -> io_perf_dai_byte_count , bytes );
@@ -565,6 +584,10 @@ __cold int dai_common_new(struct dai_data *dd, struct comp_dev *dev,
565584 SOF_DMA_DIR_MEM_TO_DEV : SOF_DMA_DIR_DEV_TO_MEM ;
566585
567586 dd -> chan_index = - EINVAL ;
587+ #ifdef CONFIG_UAOL_INTEL_ADSP
588+ dd -> uaol .fb_chan_idx = - EINVAL ;
589+ #endif
590+
568591 dd -> dma = sof_dma_get (dir , dd -> dai -> dma_caps , dd -> dai -> dma_dev , SOF_DMA_ACCESS_SHARED );
569592 if (!dd -> dma ) {
570593 dai_put (dd -> dai );
@@ -633,6 +656,84 @@ __cold int dai_common_new(struct dai_data *dd, struct comp_dev *dev,
633656 return 0 ;
634657}
635658
659+ /* UAOL playback may own a 2nd DMA channel reading the USB feedback endpoint;
660+ * it follows the audio channel through config/start/stop/suspend/release.
661+ */
662+ static void dai_dma_release_channel (struct dai_data * dd )
663+ {
664+ if (dd -> chan_index >= 0 ) {
665+ sof_dma_release_channel (dd -> dma , dd -> chan_index );
666+ dd -> chan_index = - EINVAL ;
667+ }
668+
669+ #if CONFIG_UAOL_INTEL_ADSP
670+ /* also release the UAOL feedback DMA channel */
671+ if (dd -> uaol .fb_chan_idx >= 0 ) {
672+ sof_dma_release_channel (dd -> uaol .fb_dma , dd -> uaol .fb_chan_idx );
673+ dd -> uaol .fb_chan_idx = - EINVAL ;
674+ }
675+ #endif
676+ }
677+
678+ static int dai_dma_config (struct dai_data * dd )
679+ {
680+ int ret = sof_dma_config (dd -> dma , dd -> chan_index , dd -> z_config );
681+ if (ret < 0 )
682+ return ret ;
683+
684+ #if CONFIG_UAOL_INTEL_ADSP
685+ /* also config the UAOL feedback DMA channel */
686+ if (dd -> uaol .fb_chan_idx >= 0 )
687+ ret = sof_dma_config (dd -> uaol .fb_dma , dd -> uaol .fb_chan_idx , dd -> uaol .fb_z_config );
688+ #endif
689+
690+ return ret ;
691+ }
692+
693+ static int dai_dma_start (struct dai_data * dd )
694+ {
695+ int ret = sof_dma_start (dd -> dma , dd -> chan_index );
696+ if (ret < 0 )
697+ return ret ;
698+
699+ #if CONFIG_UAOL_INTEL_ADSP
700+ /* also start the UAOL feedback DMA channel; roll back audio DMA on failure */
701+ if (dd -> uaol .fb_chan_idx >= 0 ) {
702+ ret = sof_dma_start (dd -> uaol .fb_dma , dd -> uaol .fb_chan_idx );
703+ if (ret < 0 )
704+ sof_dma_stop (dd -> dma , dd -> chan_index );
705+ }
706+ #endif
707+
708+ return ret ;
709+ }
710+
711+ static int dai_dma_stop (struct dai_data * dd )
712+ {
713+ int ret = sof_dma_stop (dd -> dma , dd -> chan_index );
714+
715+ #if CONFIG_UAOL_INTEL_ADSP
716+ /* also stop the UAOL feedback DMA channel, even if the above fails */
717+ if (dd -> uaol .fb_chan_idx >= 0 )
718+ sof_dma_stop (dd -> uaol .fb_dma , dd -> uaol .fb_chan_idx );
719+ #endif
720+
721+ return ret ;
722+ }
723+
724+ static int dai_dma_suspend (struct dai_data * dd )
725+ {
726+ int ret = sof_dma_suspend (dd -> dma , dd -> chan_index );
727+
728+ #if CONFIG_UAOL_INTEL_ADSP
729+ /* also suspend the UAOL feedback DMA channel, even if the above fails */
730+ if (dd -> uaol .fb_chan_idx >= 0 )
731+ sof_dma_suspend (dd -> uaol .fb_dma , dd -> uaol .fb_chan_idx );
732+ #endif
733+
734+ return ret ;
735+ }
736+
636737__cold static struct comp_dev * dai_new (const struct comp_driver * drv ,
637738 const struct comp_ipc_config * config ,
638739 const void * spec )
@@ -689,18 +790,18 @@ __cold void dai_common_free(struct dai_data *dd)
689790 if (dd -> group )
690791 dai_group_put (dd -> group );
691792
692- if (dd -> chan_index >= 0 ) {
693- sof_dma_release_channel (dd -> dma , dd -> chan_index );
694- dd -> chan_index = - EINVAL ;
695- }
696-
793+ dai_dma_release_channel (dd );
697794 sof_dma_put (dd -> dma );
698795
699796 dai_release_llp_slot (dd );
700797
701798 dai_put (dd -> dai );
702799
703800 sof_heap_free (dd -> alloc_ctx .heap , dd -> dai_spec_config );
801+
802+ #if CONFIG_UAOL_INTEL_ADSP
803+ uaol_free (dd );
804+ #endif
704805}
705806
706807__cold static void dai_free (struct comp_dev * dev )
@@ -1183,8 +1284,11 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev,
11831284 }
11841285
11851286 err = dai_set_dma_config (dd , dev );
1186- if (err < 0 )
1287+ if (err < 0 ) {
11871288 comp_err (dev , "set dma config failed." );
1289+ goto out ;
1290+ }
1291+
11881292out :
11891293 /*
11901294 * Make sure to free all allocated items, all functions
@@ -1250,6 +1354,11 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev)
12501354 comp_dbg (dev , "new configured dma channel index %d" ,
12511355 dd -> chan_index );
12521356
1357+ #ifdef CONFIG_UAOL_INTEL_ADSP
1358+ /* Does nothing if feedback DMA is not needed */
1359+ setup_uaol_feedback_dma (dd , dev );
1360+ #endif /* CONFIG_UAOL_INTEL_ADSP */
1361+
12531362 return 0 ;
12541363}
12551364
@@ -1273,6 +1382,10 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev)
12731382
12741383 /* clear dma buffer to avoid pop noise */
12751384 buffer_zero (dd -> dma_buffer );
1385+ #ifdef CONFIG_UAOL_INTEL_ADSP
1386+ if (dd -> uaol .fb_dma_buf )
1387+ memset (dd -> uaol .fb_dma_buf , 0 , dd -> uaol .fb_dma_buf_size );
1388+ #endif /* CONFIG_UAOL_INTEL_ADSP */
12761389
12771390 /* dma reconfig not required if XRUN handling */
12781391 if (dd -> xrun ) {
@@ -1281,7 +1394,7 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev)
12811394 return 0 ;
12821395 }
12831396
1284- ret = sof_dma_config (dd -> dma , dd -> chan_index , dd -> z_config );
1397+ ret = dai_dma_config (dd );
12851398 if (ret < 0 )
12861399 comp_set_state (dev , COMP_TRIGGER_RESET );
12871400
@@ -1332,6 +1445,10 @@ void dai_common_reset(struct dai_data *dd, struct comp_dev *dev)
13321445 dd -> dma_buffer = NULL ;
13331446 }
13341447
1448+ #ifdef CONFIG_UAOL_INTEL_ADSP
1449+ uaol_free (dd );
1450+ #endif /* CONFIG_UAOL_INTEL_ADSP */
1451+
13351452 dd -> wallclock = 0 ;
13361453 dd -> total_data_processed = 0 ;
13371454 dd -> xrun = 0 ;
@@ -1368,7 +1485,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13681485
13691486 /* only start the DAI if we are not XRUN handling */
13701487 if (dd -> xrun == 0 ) {
1371- ret = sof_dma_start (dd -> dma , dd -> chan_index );
1488+ ret = dai_dma_start (dd );
13721489 if (ret < 0 )
13731490 return ret ;
13741491
@@ -1389,6 +1506,14 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
13891506 buffer_zero (dd -> dma_buffer );
13901507 }
13911508
1509+ #ifdef CONFIG_UAOL_INTEL_ADSP
1510+ /* It might be beneficial to clear any old obsolete feedback value to prevent
1511+ * it from being used to adjust the rate immediately after resume. A feedback
1512+ * value of 0 will be rejected by the sanity check. */
1513+ if (dd -> uaol .fb_dma_buf )
1514+ memset (dd -> uaol .fb_dma_buf , 0 , dd -> uaol .fb_dma_buf_size );
1515+ #endif /* CONFIG_UAOL_INTEL_ADSP */
1516+
13921517 /* DMA driver and SOF's view of the DMA buffer's
13931518 * read and write cursors must be the same to
13941519 * avoid scenarios in which the DMA driver
@@ -1406,16 +1531,16 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
14061531 /* only start the DAI if we are not XRUN handling */
14071532 if (dd -> xrun == 0 ) {
14081533 /* recover valid start position */
1409- ret = sof_dma_stop (dd -> dma , dd -> chan_index );
1534+ ret = dai_dma_stop (dd );
14101535 if (ret < 0 )
14111536 return ret ;
14121537
14131538 /* dma_config needed after stop */
1414- ret = sof_dma_config (dd -> dma , dd -> chan_index , dd -> z_config );
1539+ ret = dai_dma_config (dd );
14151540 if (ret < 0 )
14161541 return ret ;
14171542
1418- ret = sof_dma_start (dd -> dma , dd -> chan_index );
1543+ ret = dai_dma_start (dd );
14191544 if (ret < 0 )
14201545 return ret ;
14211546
@@ -1443,11 +1568,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
14431568 * as soon as possible.
14441569 */
14451570#if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE
1446- ret = sof_dma_stop (dd -> dma , dd -> chan_index );
1571+ ret = dai_dma_stop (dd );
14471572 dai_trigger_op (dd -> dai , cmd , dev -> direction );
14481573#else
14491574 dai_trigger_op (dd -> dai , cmd , dev -> direction );
1450- ret = sof_dma_stop (dd -> dma , dd -> chan_index );
1575+ ret = dai_dma_stop (dd );
14511576 if (ret ) {
14521577 comp_warn (dev , "dma was stopped earlier" );
14531578 ret = 0 ;
@@ -1457,11 +1582,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev,
14571582 case COMP_TRIGGER_PAUSE :
14581583 comp_dbg (dev , "PAUSE" );
14591584#if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE
1460- ret = sof_dma_suspend (dd -> dma , dd -> chan_index );
1585+ ret = dai_dma_suspend (dd );
14611586 dai_trigger_op (dd -> dai , cmd , dev -> direction );
14621587#else
14631588 dai_trigger_op (dd -> dai , cmd , dev -> direction );
1464- ret = sof_dma_suspend (dd -> dma , dd -> chan_index );
1589+ ret = dai_dma_suspend (dd );
14651590#endif
14661591 break ;
14671592 case COMP_TRIGGER_PRE_START :
@@ -1796,6 +1921,11 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun
17961921 if (dev -> direction == SOF_IPC_STREAM_PLAYBACK ) {
17971922 src_frames = audio_stream_get_avail_frames (& dd -> local_buffer -> stream );
17981923 sink_frames = free_bytes / audio_stream_frame_bytes (& dd -> dma_buffer -> stream );
1924+ #ifdef CONFIG_UAOL_INTEL_ADSP
1925+ /* DSRC may insert one frame on top of the copied ones */
1926+ if (dd -> uaol .feedback_drift > 0 && sink_frames )
1927+ sink_frames -- ;
1928+ #endif
17991929 frames = MIN (src_frames , sink_frames );
18001930
18011931 /*
@@ -1892,8 +2022,13 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun
18922022 comp_warn (dev , "dai trigger copy failed" );
18932023
18942024 if (dai_dma_cb (dd , dev , copy_bytes , converter ) == SOF_DMA_CB_STATUS_END )
1895- sof_dma_stop (dd -> dma , dd -> chan_index );
2025+ dai_dma_stop (dd );
18962026
2027+ #ifdef CONFIG_UAOL_INTEL_ADSP
2028+ /* adjust reload size as extra frame may be added by DSRC */
2029+ copy_bytes += dd -> uaol .dma_added_bytes ;
2030+ dd -> uaol .dma_added_bytes = 0 ;
2031+ #endif
18972032 ret = sof_dma_reload (dd -> dma , dd -> chan_index , copy_bytes );
18982033 if (ret < 0 ) {
18992034 dai_report_reload_xrun (dd , dev , copy_bytes );
0 commit comments