diff options
Diffstat (limited to 'sound/soc/intel/sst-haswell-pcm.c')
-rw-r--r-- | sound/soc/intel/sst-haswell-pcm.c | 107 |
1 files changed, 71 insertions, 36 deletions
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 0a32dd13a23d..9d5f64a583a3 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
@@ -99,6 +99,7 @@ struct hsw_pcm_data { | |||
99 | struct snd_compr_stream *cstream; | 99 | struct snd_compr_stream *cstream; |
100 | unsigned int wpos; | 100 | unsigned int wpos; |
101 | struct mutex mutex; | 101 | struct mutex mutex; |
102 | bool allocated; | ||
102 | }; | 103 | }; |
103 | 104 | ||
104 | /* private data for the driver */ | 105 | /* private data for the driver */ |
@@ -107,12 +108,14 @@ struct hsw_priv_data { | |||
107 | struct sst_hsw *hsw; | 108 | struct sst_hsw *hsw; |
108 | 109 | ||
109 | /* page tables */ | 110 | /* page tables */ |
110 | unsigned char *pcm_pg[HSW_PCM_COUNT][2]; | 111 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; |
111 | 112 | ||
112 | /* DAI data */ | 113 | /* DAI data */ |
113 | struct hsw_pcm_data pcm[HSW_PCM_COUNT]; | 114 | struct hsw_pcm_data pcm[HSW_PCM_COUNT]; |
114 | }; | 115 | }; |
115 | 116 | ||
117 | static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data); | ||
118 | |||
116 | static inline u32 hsw_mixer_to_ipc(unsigned int value) | 119 | static inline u32 hsw_mixer_to_ipc(unsigned int value) |
117 | { | 120 | { |
118 | if (value >= ARRAY_SIZE(volume_map)) | 121 | if (value >= ARRAY_SIZE(volume_map)) |
@@ -273,28 +276,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { | |||
273 | }; | 276 | }; |
274 | 277 | ||
275 | /* Create DMA buffer page table for DSP */ | 278 | /* Create DMA buffer page table for DSP */ |
276 | static int create_adsp_page_table(struct hsw_priv_data *pdata, | 279 | static int create_adsp_page_table(struct snd_pcm_substream *substream, |
277 | struct snd_soc_pcm_runtime *rtd, | 280 | struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd, |
278 | unsigned char *dma_area, size_t size, int pcm, int stream) | 281 | unsigned char *dma_area, size_t size, int pcm) |
279 | { | 282 | { |
280 | int i, pages; | 283 | struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); |
284 | int i, pages, stream = substream->stream; | ||
281 | 285 | ||
282 | if (size % PAGE_SIZE) | 286 | pages = snd_sgbuf_aligned_pages(size); |
283 | pages = (size / PAGE_SIZE) + 1; | ||
284 | else | ||
285 | pages = size / PAGE_SIZE; | ||
286 | 287 | ||
287 | dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", | 288 | dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", |
288 | dma_area, size, pages); | 289 | dma_area, size, pages); |
289 | 290 | ||
290 | for (i = 0; i < pages; i++) { | 291 | for (i = 0; i < pages; i++) { |
291 | u32 idx = (((i << 2) + i)) >> 1; | 292 | u32 idx = (((i << 2) + i)) >> 1; |
292 | u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT; | 293 | u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; |
293 | u32 *pg_table; | 294 | u32 *pg_table; |
294 | 295 | ||
295 | dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); | 296 | dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); |
296 | 297 | ||
297 | pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx); | 298 | pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx); |
298 | 299 | ||
299 | if (i & 1) | 300 | if (i & 1) |
300 | *pg_table |= (pfn << 4); | 301 | *pg_table |= (pfn << 4); |
@@ -317,12 +318,36 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
317 | struct sst_hsw *hsw = pdata->hsw; | 318 | struct sst_hsw *hsw = pdata->hsw; |
318 | struct sst_module *module_data; | 319 | struct sst_module *module_data; |
319 | struct sst_dsp *dsp; | 320 | struct sst_dsp *dsp; |
321 | struct snd_dma_buffer *dmab; | ||
320 | enum sst_hsw_stream_type stream_type; | 322 | enum sst_hsw_stream_type stream_type; |
321 | enum sst_hsw_stream_path_id path_id; | 323 | enum sst_hsw_stream_path_id path_id; |
322 | u32 rate, bits, map, pages, module_id; | 324 | u32 rate, bits, map, pages, module_id; |
323 | u8 channels; | 325 | u8 channels; |
324 | int ret; | 326 | int ret; |
325 | 327 | ||
328 | /* check if we are being called a subsequent time */ | ||
329 | if (pcm_data->allocated) { | ||
330 | ret = sst_hsw_stream_reset(hsw, pcm_data->stream); | ||
331 | if (ret < 0) | ||
332 | dev_dbg(rtd->dev, "error: reset stream failed %d\n", | ||
333 | ret); | ||
334 | |||
335 | ret = sst_hsw_stream_free(hsw, pcm_data->stream); | ||
336 | if (ret < 0) { | ||
337 | dev_dbg(rtd->dev, "error: free stream failed %d\n", | ||
338 | ret); | ||
339 | return ret; | ||
340 | } | ||
341 | pcm_data->allocated = false; | ||
342 | |||
343 | pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id, | ||
344 | hsw_notify_pointer, pcm_data); | ||
345 | if (pcm_data->stream == NULL) { | ||
346 | dev_err(rtd->dev, "error: failed to create stream\n"); | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | } | ||
350 | |||
326 | /* stream direction */ | 351 | /* stream direction */ |
327 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 352 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
328 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; | 353 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; |
@@ -416,8 +441,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
416 | return ret; | 441 | return ret; |
417 | } | 442 | } |
418 | 443 | ||
419 | ret = create_adsp_page_table(pdata, rtd, runtime->dma_area, | 444 | dmab = snd_pcm_get_dma_buf(substream); |
420 | runtime->dma_bytes, rtd->cpu_dai->id, substream->stream); | 445 | |
446 | ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area, | ||
447 | runtime->dma_bytes, rtd->cpu_dai->id); | ||
421 | if (ret < 0) | 448 | if (ret < 0) |
422 | return ret; | 449 | return ret; |
423 | 450 | ||
@@ -430,9 +457,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
430 | pages = runtime->dma_bytes / PAGE_SIZE; | 457 | pages = runtime->dma_bytes / PAGE_SIZE; |
431 | 458 | ||
432 | ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, | 459 | ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, |
433 | virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]), | 460 | pdata->dmab[rtd->cpu_dai->id][substream->stream].addr, |
434 | pages, runtime->dma_bytes, 0, | 461 | pages, runtime->dma_bytes, 0, |
435 | (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT)); | 462 | snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT); |
436 | if (ret < 0) { | 463 | if (ret < 0) { |
437 | dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret); | 464 | dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret); |
438 | return ret; | 465 | return ret; |
@@ -474,6 +501,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
474 | dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); | 501 | dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); |
475 | return ret; | 502 | return ret; |
476 | } | 503 | } |
504 | pcm_data->allocated = true; | ||
477 | 505 | ||
478 | ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); | 506 | ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); |
479 | if (ret < 0) | 507 | if (ret < 0) |
@@ -541,12 +569,14 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) | |||
541 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | 569 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); |
542 | struct sst_hsw *hsw = pdata->hsw; | 570 | struct sst_hsw *hsw = pdata->hsw; |
543 | snd_pcm_uframes_t offset; | 571 | snd_pcm_uframes_t offset; |
572 | uint64_t ppos; | ||
573 | u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); | ||
544 | 574 | ||
545 | offset = bytes_to_frames(runtime, | 575 | offset = bytes_to_frames(runtime, position); |
546 | sst_hsw_get_dsp_position(hsw, pcm_data->stream)); | 576 | ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); |
547 | 577 | ||
548 | dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", | 578 | dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n", |
549 | frames_to_bytes(runtime, (u32)offset)); | 579 | position, ppos); |
550 | return offset; | 580 | return offset; |
551 | } | 581 | } |
552 | 582 | ||
@@ -606,6 +636,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) | |||
606 | dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); | 636 | dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); |
607 | goto out; | 637 | goto out; |
608 | } | 638 | } |
639 | pcm_data->allocated = 0; | ||
609 | pcm_data->stream = NULL; | 640 | pcm_data->stream = NULL; |
610 | 641 | ||
611 | out: | 642 | out: |
@@ -621,7 +652,7 @@ static struct snd_pcm_ops hsw_pcm_ops = { | |||
621 | .hw_free = hsw_pcm_hw_free, | 652 | .hw_free = hsw_pcm_hw_free, |
622 | .trigger = hsw_pcm_trigger, | 653 | .trigger = hsw_pcm_trigger, |
623 | .pointer = hsw_pcm_pointer, | 654 | .pointer = hsw_pcm_pointer, |
624 | .mmap = snd_pcm_lib_default_mmap, | 655 | .page = snd_pcm_sgbuf_ops_page, |
625 | }; | 656 | }; |
626 | 657 | ||
627 | static void hsw_pcm_free(struct snd_pcm *pcm) | 658 | static void hsw_pcm_free(struct snd_pcm *pcm) |
@@ -632,17 +663,16 @@ static void hsw_pcm_free(struct snd_pcm *pcm) | |||
632 | static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | 663 | static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) |
633 | { | 664 | { |
634 | struct snd_pcm *pcm = rtd->pcm; | 665 | struct snd_pcm *pcm = rtd->pcm; |
666 | struct snd_soc_platform *platform = rtd->platform; | ||
667 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | ||
668 | struct device *dev = pdata->dma_dev; | ||
635 | int ret = 0; | 669 | int ret = 0; |
636 | 670 | ||
637 | ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32)); | ||
638 | if (ret) | ||
639 | return ret; | ||
640 | |||
641 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || | 671 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || |
642 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | 672 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { |
643 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, | 673 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, |
644 | SNDRV_DMA_TYPE_DEV, | 674 | SNDRV_DMA_TYPE_DEV_SG, |
645 | rtd->card->dev, | 675 | dev, |
646 | hsw_pcm_hardware.buffer_bytes_max, | 676 | hsw_pcm_hardware.buffer_bytes_max, |
647 | hsw_pcm_hardware.buffer_bytes_max); | 677 | hsw_pcm_hardware.buffer_bytes_max); |
648 | if (ret) { | 678 | if (ret) { |
@@ -742,11 +772,14 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
742 | { | 772 | { |
743 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | 773 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); |
744 | struct hsw_priv_data *priv_data; | 774 | struct hsw_priv_data *priv_data; |
745 | int i; | 775 | struct device *dma_dev; |
776 | int i, ret = 0; | ||
746 | 777 | ||
747 | if (!pdata) | 778 | if (!pdata) |
748 | return -ENODEV; | 779 | return -ENODEV; |
749 | 780 | ||
781 | dma_dev = pdata->dma_dev; | ||
782 | |||
750 | priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); | 783 | priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); |
751 | priv_data->hsw = pdata->dsp; | 784 | priv_data->hsw = pdata->dsp; |
752 | snd_soc_platform_set_drvdata(platform, priv_data); | 785 | snd_soc_platform_set_drvdata(platform, priv_data); |
@@ -758,15 +791,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
758 | 791 | ||
759 | /* playback */ | 792 | /* playback */ |
760 | if (hsw_dais[i].playback.channels_min) { | 793 | if (hsw_dais[i].playback.channels_min) { |
761 | priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA); | 794 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, |
762 | if (priv_data->pcm_pg[i][0] == NULL) | 795 | PAGE_SIZE, &priv_data->dmab[i][0]); |
796 | if (ret < 0) | ||
763 | goto err; | 797 | goto err; |
764 | } | 798 | } |
765 | 799 | ||
766 | /* capture */ | 800 | /* capture */ |
767 | if (hsw_dais[i].capture.channels_min) { | 801 | if (hsw_dais[i].capture.channels_min) { |
768 | priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA); | 802 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, |
769 | if (priv_data->pcm_pg[i][1] == NULL) | 803 | PAGE_SIZE, &priv_data->dmab[i][1]); |
804 | if (ret < 0) | ||
770 | goto err; | 805 | goto err; |
771 | } | 806 | } |
772 | } | 807 | } |
@@ -776,11 +811,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
776 | err: | 811 | err: |
777 | for (;i >= 0; i--) { | 812 | for (;i >= 0; i--) { |
778 | if (hsw_dais[i].playback.channels_min) | 813 | if (hsw_dais[i].playback.channels_min) |
779 | kfree(priv_data->pcm_pg[i][0]); | 814 | snd_dma_free_pages(&priv_data->dmab[i][0]); |
780 | if (hsw_dais[i].capture.channels_min) | 815 | if (hsw_dais[i].capture.channels_min) |
781 | kfree(priv_data->pcm_pg[i][1]); | 816 | snd_dma_free_pages(&priv_data->dmab[i][1]); |
782 | } | 817 | } |
783 | return -ENOMEM; | 818 | return ret; |
784 | } | 819 | } |
785 | 820 | ||
786 | static int hsw_pcm_remove(struct snd_soc_platform *platform) | 821 | static int hsw_pcm_remove(struct snd_soc_platform *platform) |
@@ -791,9 +826,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform) | |||
791 | 826 | ||
792 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | 827 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { |
793 | if (hsw_dais[i].playback.channels_min) | 828 | if (hsw_dais[i].playback.channels_min) |
794 | kfree(priv_data->pcm_pg[i][0]); | 829 | snd_dma_free_pages(&priv_data->dmab[i][0]); |
795 | if (hsw_dais[i].capture.channels_min) | 830 | if (hsw_dais[i].capture.channels_min) |
796 | kfree(priv_data->pcm_pg[i][1]); | 831 | snd_dma_free_pages(&priv_data->dmab[i][1]); |
797 | } | 832 | } |
798 | 833 | ||
799 | return 0; | 834 | return 0; |