@@ -878,6 +878,78 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
878878 return snd_sof_dsp_set_power_state (sdev , & target_dsp_state );
879879}
880880
881+ static unsigned int hda_dsp_check_for_dma_streams (struct snd_sof_dev * sdev )
882+ {
883+ struct hdac_bus * bus = sof_to_bus (sdev );
884+ struct hdac_stream * s ;
885+ unsigned int active_streams = 0 ;
886+ int sd_offset ;
887+ u32 val ;
888+
889+ list_for_each_entry (s , & bus -> stream_list , list ) {
890+ sd_offset = SOF_STREAM_SD_OFFSET (s );
891+ val = snd_sof_dsp_read (sdev , HDA_DSP_HDA_BAR ,
892+ sd_offset );
893+ if (val & SOF_HDA_SD_CTL_DMA_START )
894+ active_streams |= BIT (s -> index );
895+ }
896+
897+ return active_streams ;
898+ }
899+
900+ static int hda_dsp_s5_quirk (struct snd_sof_dev * sdev )
901+ {
902+ int ret ;
903+
904+ /*
905+ * Do not assume a certain timing between the prior
906+ * suspend flow, and running of this quirk function.
907+ * This is needed if the controller was just put
908+ * to reset before calling this function.
909+ */
910+ usleep_range (500 , 1000 );
911+
912+ /*
913+ * Take controller out of reset to flush DMA
914+ * transactions.
915+ */
916+ ret = hda_dsp_ctrl_link_reset (sdev , false);
917+ if (ret < 0 )
918+ return ret ;
919+
920+ usleep_range (500 , 1000 );
921+
922+ /* Restore state for shutdown, back to reset */
923+ ret = hda_dsp_ctrl_link_reset (sdev , true);
924+ if (ret < 0 )
925+ return ret ;
926+
927+ return ret ;
928+ }
929+
930+ int hda_dsp_shutdown_dma_flush (struct snd_sof_dev * sdev )
931+ {
932+ unsigned int active_streams ;
933+ int ret , ret2 ;
934+
935+ /* check if DMA cleanup has been successful */
936+ active_streams = hda_dsp_check_for_dma_streams (sdev );
937+
938+ sdev -> system_suspend_target = SOF_SUSPEND_S3 ;
939+ ret = snd_sof_suspend (sdev -> dev );
940+
941+ if (active_streams ) {
942+ dev_warn (sdev -> dev ,
943+ "There were active DSP streams (%#x) at shutdown, trying to recover\n" ,
944+ active_streams );
945+ ret2 = hda_dsp_s5_quirk (sdev );
946+ if (ret2 < 0 )
947+ dev_err (sdev -> dev , "shutdown recovery failed (%d)\n" , ret2 );
948+ }
949+
950+ return ret ;
951+ }
952+
881953int hda_dsp_shutdown (struct snd_sof_dev * sdev )
882954{
883955 sdev -> system_suspend_target = SOF_SUSPEND_S3 ;
0 commit comments