Commit 95b9cff3 authored by Mark Brown's avatar Mark Brown

Merge tag 'asoc-v3.15-rc5-intel' into asoc-linus

ASoC: Intel fixes for v3.15

This is a relatively large batch of fixes for the newly added
Haswell/Baytrail drivers from Intel.  It's a bit larger than is good for
this point in the cycle but it's all for a newly added driver so not so
worrying as it might otherwise be.  Some of it's integration problems,
some of it's the sort of problem usually turned up in stress tests.

# gpg: Signature made Wed 14 May 2014 12:40:27 BST using RSA key ID 7EA229BD
# gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>"
# gpg:                 aka "Mark Brown <broonie@debian.org>"
# gpg:                 aka "Mark Brown <broonie@kernel.org>"
# gpg:                 aka "Mark Brown <broonie@tardis.ed.ac.uk>"
# gpg:                 aka "Mark Brown <broonie@linaro.org>"
# gpg:                 aka "Mark Brown <Mark.Brown@linaro.org>"
parents dd97254f cffd6665
...@@ -138,6 +138,7 @@ static int sst_acpi_probe(struct platform_device *pdev) ...@@ -138,6 +138,7 @@ static int sst_acpi_probe(struct platform_device *pdev)
sst_pdata = &sst_acpi->sst_pdata; sst_pdata = &sst_acpi->sst_pdata;
sst_pdata->id = desc->sst_id; sst_pdata->id = desc->sst_id;
sst_pdata->dma_dev = dev;
sst_acpi->desc = desc; sst_acpi->desc = desc;
sst_acpi->mach = mach; sst_acpi->mach = mach;
......
...@@ -324,7 +324,7 @@ static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata) ...@@ -324,7 +324,7 @@ static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET, memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
&pdata->fw_base, sizeof(u32)); &pdata->fw_base, sizeof(u32));
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));
if (ret) if (ret)
return ret; return ret;
......
...@@ -542,16 +542,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, ...@@ -542,16 +542,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
void *data) void *data)
{ {
struct sst_byt_stream *stream; struct sst_byt_stream *stream;
struct sst_dsp *sst = byt->dsp;
unsigned long flags;
stream = kzalloc(sizeof(*stream), GFP_KERNEL); stream = kzalloc(sizeof(*stream), GFP_KERNEL);
if (stream == NULL) if (stream == NULL)
return NULL; return NULL;
spin_lock_irqsave(&sst->spinlock, flags);
list_add(&stream->node, &byt->stream_list); list_add(&stream->node, &byt->stream_list);
stream->notify_position = notify_position; stream->notify_position = notify_position;
stream->pdata = data; stream->pdata = data;
stream->byt = byt; stream->byt = byt;
stream->str_id = id; stream->str_id = id;
spin_unlock_irqrestore(&sst->spinlock, flags);
return stream; return stream;
} }
...@@ -630,6 +634,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) ...@@ -630,6 +634,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
{ {
u64 header; u64 header;
int ret = 0; int ret = 0;
struct sst_dsp *sst = byt->dsp;
unsigned long flags;
if (!stream->commited) if (!stream->commited)
goto out; goto out;
...@@ -644,8 +650,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) ...@@ -644,8 +650,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
stream->commited = false; stream->commited = false;
out: out:
spin_lock_irqsave(&sst->spinlock, flags);
list_del(&stream->node); list_del(&stream->node);
kfree(stream); kfree(stream);
spin_unlock_irqrestore(&sst->spinlock, flags);
return ret; return ret;
} }
......
...@@ -228,6 +228,7 @@ struct sst_dsp { ...@@ -228,6 +228,7 @@ struct sst_dsp {
spinlock_t spinlock; /* IPC locking */ spinlock_t spinlock; /* IPC locking */
struct mutex mutex; /* DSP FW lock */ struct mutex mutex; /* DSP FW lock */
struct device *dev; struct device *dev;
struct device *dma_dev;
void *thread_context; void *thread_context;
int irq; int irq;
u32 id; u32 id;
......
...@@ -337,6 +337,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev, ...@@ -337,6 +337,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
spin_lock_init(&sst->spinlock); spin_lock_init(&sst->spinlock);
mutex_init(&sst->mutex); mutex_init(&sst->mutex);
sst->dev = dev; sst->dev = dev;
sst->dma_dev = pdata->dma_dev;
sst->thread_context = sst_dev->thread_context; sst->thread_context = sst_dev->thread_context;
sst->sst_dev = sst_dev; sst->sst_dev = sst_dev;
sst->id = pdata->id; sst->id = pdata->id;
......
...@@ -169,6 +169,7 @@ struct sst_pdata { ...@@ -169,6 +169,7 @@ struct sst_pdata {
u32 dma_base; u32 dma_base;
u32 dma_size; u32 dma_size;
int dma_engine; int dma_engine;
struct device *dma_dev;
/* DSP */ /* DSP */
u32 id; u32 id;
......
...@@ -57,14 +57,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, ...@@ -57,14 +57,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
sst_fw->private = private; sst_fw->private = private;
sst_fw->size = fw->size; sst_fw->size = fw->size;
err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32));
if (err < 0) {
kfree(sst_fw);
return NULL;
}
/* allocate DMA buffer to store FW data */ /* allocate DMA buffer to store FW data */
sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size,
&sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
if (!sst_fw->dma_buf) { if (!sst_fw->dma_buf) {
dev_err(dsp->dev, "error: DMA alloc failed\n"); dev_err(dsp->dev, "error: DMA alloc failed\n");
...@@ -106,7 +100,7 @@ void sst_fw_free(struct sst_fw *sst_fw) ...@@ -106,7 +100,7 @@ void sst_fw_free(struct sst_fw *sst_fw)
list_del(&sst_fw->list); list_del(&sst_fw->list);
mutex_unlock(&dsp->mutex); mutex_unlock(&dsp->mutex);
dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf, dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf,
sst_fw->dmable_fw_paddr); sst_fw->dmable_fw_paddr);
kfree(sst_fw); kfree(sst_fw);
} }
...@@ -202,6 +196,9 @@ static int block_alloc_contiguous(struct sst_module *module, ...@@ -202,6 +196,9 @@ static int block_alloc_contiguous(struct sst_module *module,
size -= block->size; size -= block->size;
} }
list_for_each_entry(block, &tmp, list)
list_add(&block->module_list, &module->block_list);
list_splice(&tmp, &dsp->used_block_list); list_splice(&tmp, &dsp->used_block_list);
return 0; return 0;
} }
...@@ -247,8 +244,7 @@ static int block_alloc(struct sst_module *module, ...@@ -247,8 +244,7 @@ static int block_alloc(struct sst_module *module,
/* do we span > 1 blocks */ /* do we span > 1 blocks */
if (data->size > block->size) { if (data->size > block->size) {
ret = block_alloc_contiguous(module, data, ret = block_alloc_contiguous(module, data,
block->offset + block->size, block->offset, data->size);
data->size - block->size);
if (ret == 0) if (ret == 0)
return ret; return ret;
} }
...@@ -344,7 +340,7 @@ static int block_alloc_fixed(struct sst_module *module, ...@@ -344,7 +340,7 @@ static int block_alloc_fixed(struct sst_module *module,
err = block_alloc_contiguous(module, data, err = block_alloc_contiguous(module, data,
block->offset + block->size, block->offset + block->size,
data->size - block->size + data->offset - block->offset); data->size - block->size);
if (err < 0) if (err < 0)
return -ENOMEM; return -ENOMEM;
...@@ -371,15 +367,10 @@ static int block_alloc_fixed(struct sst_module *module, ...@@ -371,15 +367,10 @@ static int block_alloc_fixed(struct sst_module *module,
if (data->offset >= block->offset && data->offset < block_end) { if (data->offset >= block->offset && data->offset < block_end) {
err = block_alloc_contiguous(module, data, err = block_alloc_contiguous(module, data,
block->offset + block->size, block->offset, data->size);
data->size - block->size);
if (err < 0) if (err < 0)
return -ENOMEM; return -ENOMEM;
/* add block */
block->data_type = data->data_type;
list_move(&block->list, &dsp->used_block_list);
list_add(&block->module_list, &module->block_list);
return 0; return 0;
} }
......
...@@ -433,7 +433,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) ...@@ -433,7 +433,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
int ret = -ENODEV, i, j, region_count; int ret = -ENODEV, i, j, region_count;
u32 offset, size; u32 offset, size;
dev = sst->dev; dev = sst->dma_dev;
switch (sst->id) { switch (sst->id) {
case SST_DEV_ID_LYNX_POINT: case SST_DEV_ID_LYNX_POINT:
...@@ -466,7 +466,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) ...@@ -466,7 +466,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
return ret; return ret;
} }
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));
if (ret) if (ret)
return ret; return ret;
......
...@@ -1159,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, ...@@ -1159,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
void *data) void *data)
{ {
struct sst_hsw_stream *stream; struct sst_hsw_stream *stream;
struct sst_dsp *sst = hsw->dsp;
unsigned long flags;
stream = kzalloc(sizeof(*stream), GFP_KERNEL); stream = kzalloc(sizeof(*stream), GFP_KERNEL);
if (stream == NULL) if (stream == NULL)
return NULL; return NULL;
spin_lock_irqsave(&sst->spinlock, flags);
list_add(&stream->node, &hsw->stream_list); list_add(&stream->node, &hsw->stream_list);
stream->notify_position = notify_position; stream->notify_position = notify_position;
stream->pdata = data; stream->pdata = data;
...@@ -1172,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, ...@@ -1172,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
/* work to process notification messages */ /* work to process notification messages */
INIT_WORK(&stream->notify_work, hsw_notification_work); INIT_WORK(&stream->notify_work, hsw_notification_work);
spin_unlock_irqrestore(&sst->spinlock, flags);
return stream; return stream;
} }
...@@ -1180,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) ...@@ -1180,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
{ {
u32 header; u32 header;
int ret = 0; int ret = 0;
struct sst_dsp *sst = hsw->dsp;
unsigned long flags;
/* dont free DSP streams that are not commited */ /* dont free DSP streams that are not commited */
if (!stream->commited) if (!stream->commited)
...@@ -1201,8 +1207,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) ...@@ -1201,8 +1207,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
trace_hsw_stream_free_req(stream, &stream->free_req); trace_hsw_stream_free_req(stream, &stream->free_req);
out: out:
cancel_work_sync(&stream->notify_work);
spin_lock_irqsave(&sst->spinlock, flags);
list_del(&stream->node); list_del(&stream->node);
kfree(stream); kfree(stream);
spin_unlock_irqrestore(&sst->spinlock, flags);
return ret; return ret;
} }
...@@ -1538,10 +1547,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream) ...@@ -1538,10 +1547,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
} }
/* Stream pointer positions */ /* Stream pointer positions */
int sst_hsw_get_dsp_position(struct sst_hsw *hsw, u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
struct sst_hsw_stream *stream) struct sst_hsw_stream *stream)
{ {
return stream->rpos.position; u32 rpos;
sst_dsp_read(hsw->dsp, &rpos,
stream->reply.read_position_register_address, sizeof(rpos));
return rpos;
}
/* Stream presentation (monotonic) positions */
u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
struct sst_hsw_stream *stream)
{
u64 ppos;
sst_dsp_read(hsw->dsp, &ppos,
stream->reply.presentation_position_register_address,
sizeof(ppos));
return ppos;
} }
int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
......
...@@ -464,7 +464,9 @@ int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, ...@@ -464,7 +464,9 @@ int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 *position); struct sst_hsw_stream *stream, u32 *position);
int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 stage_id, u32 position); struct sst_hsw_stream *stream, u32 stage_id, u32 position);
int sst_hsw_get_dsp_position(struct sst_hsw *hsw, u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
struct sst_hsw_stream *stream);
u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
struct sst_hsw_stream *stream); struct sst_hsw_stream *stream);
/* HW port config */ /* HW port config */
......
...@@ -99,6 +99,7 @@ struct hsw_pcm_data { ...@@ -99,6 +99,7 @@ struct hsw_pcm_data {
struct snd_compr_stream *cstream; struct snd_compr_stream *cstream;
unsigned int wpos; unsigned int wpos;
struct mutex mutex; struct mutex mutex;
bool allocated;
}; };
/* private data for the driver */ /* private data for the driver */
...@@ -107,12 +108,14 @@ struct hsw_priv_data { ...@@ -107,12 +108,14 @@ struct hsw_priv_data {
struct sst_hsw *hsw; struct sst_hsw *hsw;
/* page tables */ /* page tables */
unsigned char *pcm_pg[HSW_PCM_COUNT][2]; struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
/* DAI data */ /* DAI data */
struct hsw_pcm_data pcm[HSW_PCM_COUNT]; struct hsw_pcm_data pcm[HSW_PCM_COUNT];
}; };
static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
static inline u32 hsw_mixer_to_ipc(unsigned int value) static inline u32 hsw_mixer_to_ipc(unsigned int value)
{ {
if (value >= ARRAY_SIZE(volume_map)) if (value >= ARRAY_SIZE(volume_map))
...@@ -273,28 +276,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { ...@@ -273,28 +276,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {
}; };
/* Create DMA buffer page table for DSP */ /* Create DMA buffer page table for DSP */
static int create_adsp_page_table(struct hsw_priv_data *pdata, static int create_adsp_page_table(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd, struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd,
unsigned char *dma_area, size_t size, int pcm, int stream) unsigned char *dma_area, size_t size, int pcm)
{ {
int i, pages; struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
int i, pages, stream = substream->stream;
if (size % PAGE_SIZE) pages = snd_sgbuf_aligned_pages(size);
pages = (size / PAGE_SIZE) + 1;
else
pages = size / PAGE_SIZE;
dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
dma_area, size, pages); dma_area, size, pages);
for (i = 0; i < pages; i++) { for (i = 0; i < pages; i++) {
u32 idx = (((i << 2) + i)) >> 1; u32 idx = (((i << 2) + i)) >> 1;
u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT; u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
u32 *pg_table; u32 *pg_table;
dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx); pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx);
if (i & 1) if (i & 1)
*pg_table |= (pfn << 4); *pg_table |= (pfn << 4);
...@@ -317,12 +318,36 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -317,12 +318,36 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
struct sst_hsw *hsw = pdata->hsw; struct sst_hsw *hsw = pdata->hsw;
struct sst_module *module_data; struct sst_module *module_data;
struct sst_dsp *dsp; struct sst_dsp *dsp;
struct snd_dma_buffer *dmab;
enum sst_hsw_stream_type stream_type; enum sst_hsw_stream_type stream_type;
enum sst_hsw_stream_path_id path_id; enum sst_hsw_stream_path_id path_id;
u32 rate, bits, map, pages, module_id; u32 rate, bits, map, pages, module_id;
u8 channels; u8 channels;
int ret; int ret;
/* check if we are being called a subsequent time */
if (pcm_data->allocated) {
ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
if (ret < 0)
dev_dbg(rtd->dev, "error: reset stream failed %d\n",
ret);
ret = sst_hsw_stream_free(hsw, pcm_data->stream);
if (ret < 0) {
dev_dbg(rtd->dev, "error: free stream failed %d\n",
ret);
return ret;
}
pcm_data->allocated = false;
pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
hsw_notify_pointer, pcm_data);
if (pcm_data->stream == NULL) {
dev_err(rtd->dev, "error: failed to create stream\n");
return -EINVAL;
}
}
/* stream direction */ /* stream direction */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
path_id = SST_HSW_STREAM_PATH_SSP0_OUT; path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
...@@ -416,8 +441,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -416,8 +441,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
return ret; return ret;
} }
ret = create_adsp_page_table(pdata, rtd, runtime->dma_area, dmab = snd_pcm_get_dma_buf(substream);
runtime->dma_bytes, rtd->cpu_dai->id, substream->stream);
ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area,
runtime->dma_bytes, rtd->cpu_dai->id);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -430,9 +457,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -430,9 +457,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
pages = runtime->dma_bytes / PAGE_SIZE; pages = runtime->dma_bytes / PAGE_SIZE;
ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]), pdata->dmab[rtd->cpu_dai->id][substream->stream].addr,
pages, runtime->dma_bytes, 0, pages, runtime->dma_bytes, 0,
(u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT)); snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT);
if (ret < 0) { if (ret < 0) {
dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret); dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
return ret; return ret;
...@@ -474,6 +501,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -474,6 +501,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
return ret; return ret;
} }
pcm_data->allocated = true;
ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
if (ret < 0) if (ret < 0)
...@@ -541,12 +569,14 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) ...@@ -541,12 +569,14 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
struct sst_hsw *hsw = pdata->hsw; struct sst_hsw *hsw = pdata->hsw;
snd_pcm_uframes_t offset; snd_pcm_uframes_t offset;
uint64_t ppos;
u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
offset = bytes_to_frames(runtime, offset = bytes_to_frames(runtime, position);
sst_hsw_get_dsp_position(hsw, pcm_data->stream)); ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n",
frames_to_bytes(runtime, (u32)offset)); position, ppos);
return offset; return offset;
} }
...@@ -606,6 +636,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) ...@@ -606,6 +636,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
goto out; goto out;
} }
pcm_data->allocated = 0;
pcm_data->stream = NULL; pcm_data->stream = NULL;
out: out:
...@@ -621,7 +652,7 @@ static struct snd_pcm_ops hsw_pcm_ops = { ...@@ -621,7 +652,7 @@ static struct snd_pcm_ops hsw_pcm_ops = {
.hw_free = hsw_pcm_hw_free, .hw_free = hsw_pcm_hw_free,
.trigger = hsw_pcm_trigger, .trigger = hsw_pcm_trigger,
.pointer = hsw_pcm_pointer, .pointer = hsw_pcm_pointer,
.mmap = snd_pcm_lib_default_mmap, .page = snd_pcm_sgbuf_ops_page,
}; };
static void hsw_pcm_free(struct snd_pcm *pcm) static void hsw_pcm_free(struct snd_pcm *pcm)
...@@ -632,17 +663,16 @@ static void hsw_pcm_free(struct snd_pcm *pcm) ...@@ -632,17 +663,16 @@ static void hsw_pcm_free(struct snd_pcm *pcm)
static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_pcm *pcm = rtd->pcm; struct snd_pcm *pcm = rtd->pcm;
struct snd_soc_platform *platform = rtd->platform;
struct sst_pdata *pdata = dev_get_platdata(platform->dev);
struct device *dev = pdata->dma_dev;
int ret = 0; int ret = 0;
ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
if (ret)
return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = snd_pcm_lib_preallocate_pages_for_all(pcm, ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_DEV, SNDRV_DMA_TYPE_DEV_SG,
rtd->card->dev, dev,
hsw_pcm_hardware.buffer_bytes_max, hsw_pcm_hardware.buffer_bytes_max,
hsw_pcm_hardware.buffer_bytes_max); hsw_pcm_hardware.buffer_bytes_max);
if (ret) { if (ret) {
...@@ -742,11 +772,14 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) ...@@ -742,11 +772,14 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
{ {
struct sst_pdata *pdata = dev_get_platdata(platform->dev); struct sst_pdata *pdata = dev_get_platdata(platform->dev);
struct hsw_priv_data *priv_data; struct hsw_priv_data *priv_data;
int i; struct device *dma_dev;
int i, ret = 0;
if (!pdata) if (!pdata)
return -ENODEV; return -ENODEV;
dma_dev = pdata->dma_dev;
priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
priv_data->hsw = pdata->dsp; priv_data->hsw = pdata->dsp;
snd_soc_platform_set_drvdata(platform, priv_data); snd_soc_platform_set_drvdata(platform, priv_data);
...@@ -758,15 +791,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) ...@@ -758,15 +791,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
/* playback */ /* playback */
if (hsw_dais[i].playback.channels_min) { if (hsw_dais[i].playback.channels_min) {
priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA); ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
if (priv_data->pcm_pg[i][0] == NULL) PAGE_SIZE, &priv_data->dmab[i][0]);
if (ret < 0)
goto err; goto err;
} }
/* capture */ /* capture */
if (hsw_dais[i].capture.channels_min) { if (hsw_dais[i].capture.channels_min) {
priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA); ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
if (priv_data->pcm_pg[i][1] == NULL) PAGE_SIZE, &priv_data->dmab[i][1]);
if (ret < 0)
goto err; goto err;
} }
} }
...@@ -776,11 +811,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) ...@@ -776,11 +811,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
err: err:
for (;i >= 0; i--) { for (;i >= 0; i--) {
if (hsw_dais[i].playback.channels_min) if (hsw_dais[i].playback.channels_min)
kfree(priv_data->pcm_pg[i][0]); snd_dma_free_pages(&priv_data->dmab[i][0]);
if (hsw_dais[i].capture.channels_min) if (hsw_dais[i].capture.channels_min)
kfree(priv_data->pcm_pg[i][1]); snd_dma_free_pages(&priv_data->dmab[i][1]);
} }
return -ENOMEM; return ret;
} }
static int hsw_pcm_remove(struct snd_soc_platform *platform) 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,9 +826,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
if (hsw_dais[i].playback.channels_min) if (hsw_dais[i].playback.channels_min)
kfree(priv_data->pcm_pg[i][0]); snd_dma_free_pages(&priv_data->dmab[i][0]);
if (hsw_dais[i].capture.channels_min) if (hsw_dais[i].capture.channels_min)
kfree(priv_data->pcm_pg[i][1]); snd_dma_free_pages(&priv_data->dmab[i][1]);
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment