diff options
Diffstat (limited to 'sound/soc/intel/sst-baytrail-ipc.c')
-rw-r--r-- | sound/soc/intel/sst-baytrail-ipc.c | 132 |
1 files changed, 112 insertions, 20 deletions
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index d0eaeee21be4..7c1ec003d55d 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c | |||
@@ -173,6 +173,7 @@ struct sst_byt { | |||
173 | /* boot */ | 173 | /* boot */ |
174 | wait_queue_head_t boot_wait; | 174 | wait_queue_head_t boot_wait; |
175 | bool boot_complete; | 175 | bool boot_complete; |
176 | struct sst_fw *fw; | ||
176 | 177 | ||
177 | /* IPC messaging */ | 178 | /* IPC messaging */ |
178 | struct list_head tx_list; | 179 | struct list_head tx_list; |
@@ -299,6 +300,24 @@ static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt, | |||
299 | wake_up(&msg->waitq); | 300 | wake_up(&msg->waitq); |
300 | } | 301 | } |
301 | 302 | ||
303 | static void sst_byt_drop_all(struct sst_byt *byt) | ||
304 | { | ||
305 | struct ipc_message *msg, *tmp; | ||
306 | unsigned long flags; | ||
307 | |||
308 | /* drop all TX and Rx messages before we stall + reset DSP */ | ||
309 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
310 | list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) { | ||
311 | list_move(&msg->list, &byt->empty_list); | ||
312 | } | ||
313 | |||
314 | list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) { | ||
315 | list_move(&msg->list, &byt->empty_list); | ||
316 | } | ||
317 | |||
318 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
319 | } | ||
320 | |||
302 | static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg, | 321 | static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg, |
303 | void *rx_data) | 322 | void *rx_data) |
304 | { | 323 | { |
@@ -542,16 +561,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, | |||
542 | void *data) | 561 | void *data) |
543 | { | 562 | { |
544 | struct sst_byt_stream *stream; | 563 | struct sst_byt_stream *stream; |
564 | struct sst_dsp *sst = byt->dsp; | ||
565 | unsigned long flags; | ||
545 | 566 | ||
546 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | 567 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
547 | if (stream == NULL) | 568 | if (stream == NULL) |
548 | return NULL; | 569 | return NULL; |
549 | 570 | ||
571 | spin_lock_irqsave(&sst->spinlock, flags); | ||
550 | list_add(&stream->node, &byt->stream_list); | 572 | list_add(&stream->node, &byt->stream_list); |
551 | stream->notify_position = notify_position; | 573 | stream->notify_position = notify_position; |
552 | stream->pdata = data; | 574 | stream->pdata = data; |
553 | stream->byt = byt; | 575 | stream->byt = byt; |
554 | stream->str_id = id; | 576 | stream->str_id = id; |
577 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
555 | 578 | ||
556 | return stream; | 579 | return stream; |
557 | } | 580 | } |
@@ -630,6 +653,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
630 | { | 653 | { |
631 | u64 header; | 654 | u64 header; |
632 | int ret = 0; | 655 | int ret = 0; |
656 | struct sst_dsp *sst = byt->dsp; | ||
657 | unsigned long flags; | ||
633 | 658 | ||
634 | if (!stream->commited) | 659 | if (!stream->commited) |
635 | goto out; | 660 | goto out; |
@@ -644,8 +669,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
644 | 669 | ||
645 | stream->commited = false; | 670 | stream->commited = false; |
646 | out: | 671 | out: |
672 | spin_lock_irqsave(&sst->spinlock, flags); | ||
647 | list_del(&stream->node); | 673 | list_del(&stream->node); |
648 | kfree(stream); | 674 | kfree(stream); |
675 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
649 | 676 | ||
650 | return ret; | 677 | return ret; |
651 | } | 678 | } |
@@ -653,36 +680,33 @@ out: | |||
653 | static int sst_byt_stream_operations(struct sst_byt *byt, int type, | 680 | static int sst_byt_stream_operations(struct sst_byt *byt, int type, |
654 | int stream_id, int wait) | 681 | int stream_id, int wait) |
655 | { | 682 | { |
656 | struct sst_byt_start_stream_params start_stream; | ||
657 | u64 header; | 683 | u64 header; |
658 | void *tx_msg = NULL; | ||
659 | size_t size = 0; | ||
660 | |||
661 | if (type != IPC_IA_START_STREAM) { | ||
662 | header = sst_byt_header(type, 0, false, stream_id); | ||
663 | } else { | ||
664 | start_stream.byte_offset = 0; | ||
665 | header = sst_byt_header(IPC_IA_START_STREAM, | ||
666 | sizeof(start_stream) + sizeof(u32), | ||
667 | true, stream_id); | ||
668 | tx_msg = &start_stream; | ||
669 | size = sizeof(start_stream); | ||
670 | } | ||
671 | 684 | ||
685 | header = sst_byt_header(type, 0, false, stream_id); | ||
672 | if (wait) | 686 | if (wait) |
673 | return sst_byt_ipc_tx_msg_wait(byt, header, | 687 | return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); |
674 | tx_msg, size, NULL, 0); | ||
675 | else | 688 | else |
676 | return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size); | 689 | return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0); |
677 | } | 690 | } |
678 | 691 | ||
679 | /* stream ALSA trigger operations */ | 692 | /* stream ALSA trigger operations */ |
680 | int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream) | 693 | int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream, |
694 | u32 start_offset) | ||
681 | { | 695 | { |
696 | struct sst_byt_start_stream_params start_stream; | ||
697 | void *tx_msg; | ||
698 | size_t size; | ||
699 | u64 header; | ||
682 | int ret; | 700 | int ret; |
683 | 701 | ||
684 | ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM, | 702 | start_stream.byte_offset = start_offset; |
685 | stream->str_id, 0); | 703 | header = sst_byt_header(IPC_IA_START_STREAM, |
704 | sizeof(start_stream) + sizeof(u32), | ||
705 | true, stream->str_id); | ||
706 | tx_msg = &start_stream; | ||
707 | size = sizeof(start_stream); | ||
708 | |||
709 | ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size); | ||
686 | if (ret < 0) | 710 | if (ret < 0) |
687 | dev_err(byt->dev, "ipc: error failed to start stream %d\n", | 711 | dev_err(byt->dev, "ipc: error failed to start stream %d\n", |
688 | stream->str_id); | 712 | stream->str_id); |
@@ -774,6 +798,73 @@ static struct sst_dsp_device byt_dev = { | |||
774 | .ops = &sst_byt_ops, | 798 | .ops = &sst_byt_ops, |
775 | }; | 799 | }; |
776 | 800 | ||
801 | int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata) | ||
802 | { | ||
803 | struct sst_byt *byt = pdata->dsp; | ||
804 | |||
805 | dev_dbg(byt->dev, "dsp reset\n"); | ||
806 | sst_dsp_reset(byt->dsp); | ||
807 | sst_byt_drop_all(byt); | ||
808 | dev_dbg(byt->dev, "dsp in reset\n"); | ||
809 | |||
810 | return 0; | ||
811 | } | ||
812 | EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq); | ||
813 | |||
814 | int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata) | ||
815 | { | ||
816 | struct sst_byt *byt = pdata->dsp; | ||
817 | |||
818 | dev_dbg(byt->dev, "free all blocks and unload fw\n"); | ||
819 | sst_fw_unload(byt->fw); | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late); | ||
824 | |||
825 | int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata) | ||
826 | { | ||
827 | struct sst_byt *byt = pdata->dsp; | ||
828 | int ret; | ||
829 | |||
830 | dev_dbg(byt->dev, "reload dsp fw\n"); | ||
831 | |||
832 | sst_dsp_reset(byt->dsp); | ||
833 | |||
834 | ret = sst_fw_reload(byt->fw); | ||
835 | if (ret < 0) { | ||
836 | dev_err(dev, "error: failed to reload firmware\n"); | ||
837 | return ret; | ||
838 | } | ||
839 | |||
840 | /* wait for DSP boot completion */ | ||
841 | byt->boot_complete = false; | ||
842 | sst_dsp_boot(byt->dsp); | ||
843 | dev_dbg(byt->dev, "dsp booting...\n"); | ||
844 | |||
845 | return 0; | ||
846 | } | ||
847 | EXPORT_SYMBOL_GPL(sst_byt_dsp_boot); | ||
848 | |||
849 | int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata) | ||
850 | { | ||
851 | struct sst_byt *byt = pdata->dsp; | ||
852 | int err; | ||
853 | |||
854 | dev_dbg(byt->dev, "wait for dsp reboot\n"); | ||
855 | |||
856 | err = wait_event_timeout(byt->boot_wait, byt->boot_complete, | ||
857 | msecs_to_jiffies(IPC_BOOT_MSECS)); | ||
858 | if (err == 0) { | ||
859 | dev_err(byt->dev, "ipc: error DSP boot timeout\n"); | ||
860 | return -EIO; | ||
861 | } | ||
862 | |||
863 | dev_dbg(byt->dev, "dsp rebooted\n"); | ||
864 | return 0; | ||
865 | } | ||
866 | EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready); | ||
867 | |||
777 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | 868 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) |
778 | { | 869 | { |
779 | struct sst_byt *byt; | 870 | struct sst_byt *byt; |
@@ -840,6 +931,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
840 | } | 931 | } |
841 | 932 | ||
842 | pdata->dsp = byt; | 933 | pdata->dsp = byt; |
934 | byt->fw = byt_sst_fw; | ||
843 | 935 | ||
844 | return 0; | 936 | return 0; |
845 | 937 | ||