diff options
| author | Mark Brown <broonie@linaro.org> | 2014-05-13 13:23:56 -0400 |
|---|---|---|
| committer | Mark Brown <broonie@linaro.org> | 2014-05-13 13:23:56 -0400 |
| commit | 8bee1fd482622718fcc1a537db1d7ca48d7f52f8 (patch) | |
| tree | 8b40cf912a942771b0b22f2aa0ac20d5af256010 | |
| parent | dfe1951b0c1c6a80b8ad8702eb93f8a4dffa31f1 (diff) | |
| parent | cffd6665f57ed18f4be9185c4330c8c98c22e201 (diff) | |
Merge branch 'fix/intel' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-intel
Conflicts:
sound/soc/intel/sst-baytrail-dsp.c
| -rw-r--r-- | sound/soc/intel/sst-acpi.c | 1 | ||||
| -rw-r--r-- | sound/soc/intel/sst-baytrail-dsp.c | 2 | ||||
| -rw-r--r-- | sound/soc/intel/sst-baytrail-ipc.c | 8 | ||||
| -rw-r--r-- | sound/soc/intel/sst-dsp-priv.h | 3 | ||||
| -rw-r--r-- | sound/soc/intel/sst-dsp.c | 1 | ||||
| -rw-r--r-- | sound/soc/intel/sst-dsp.h | 1 | ||||
| -rw-r--r-- | sound/soc/intel/sst-firmware.c | 25 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-dsp.c | 4 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-ipc.c | 35 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-ipc.h | 4 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-pcm.c | 107 |
11 files changed, 129 insertions, 62 deletions
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c index 5d06eecb6198..18aee77f8d4a 100644 --- a/sound/soc/intel/sst-acpi.c +++ b/sound/soc/intel/sst-acpi.c | |||
| @@ -138,6 +138,7 @@ static int sst_acpi_probe(struct platform_device *pdev) | |||
| 138 | 138 | ||
| 139 | sst_pdata = &sst_acpi->sst_pdata; | 139 | sst_pdata = &sst_acpi->sst_pdata; |
| 140 | sst_pdata->id = desc->sst_id; | 140 | sst_pdata->id = desc->sst_id; |
| 141 | sst_pdata->dma_dev = dev; | ||
| 141 | sst_acpi->desc = desc; | 142 | sst_acpi->desc = desc; |
| 142 | sst_acpi->mach = mach; | 143 | sst_acpi->mach = mach; |
| 143 | 144 | ||
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c index 4a5d489e520b..fc588764ffa3 100644 --- a/sound/soc/intel/sst-baytrail-dsp.c +++ b/sound/soc/intel/sst-baytrail-dsp.c | |||
| @@ -324,7 +324,7 @@ static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
| 324 | return ret; | 324 | return ret; |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); | 327 | ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32)); |
| 328 | if (ret) | 328 | if (ret) |
| 329 | return ret; | 329 | return ret; |
| 330 | 330 | ||
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index 3e1dad3449bd..7c1ec003d55d 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c | |||
| @@ -561,16 +561,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, | |||
| 561 | void *data) | 561 | void *data) |
| 562 | { | 562 | { |
| 563 | struct sst_byt_stream *stream; | 563 | struct sst_byt_stream *stream; |
| 564 | struct sst_dsp *sst = byt->dsp; | ||
| 565 | unsigned long flags; | ||
| 564 | 566 | ||
| 565 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | 567 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
| 566 | if (stream == NULL) | 568 | if (stream == NULL) |
| 567 | return NULL; | 569 | return NULL; |
| 568 | 570 | ||
| 571 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 569 | list_add(&stream->node, &byt->stream_list); | 572 | list_add(&stream->node, &byt->stream_list); |
| 570 | stream->notify_position = notify_position; | 573 | stream->notify_position = notify_position; |
| 571 | stream->pdata = data; | 574 | stream->pdata = data; |
| 572 | stream->byt = byt; | 575 | stream->byt = byt; |
| 573 | stream->str_id = id; | 576 | stream->str_id = id; |
| 577 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 574 | 578 | ||
| 575 | return stream; | 579 | return stream; |
| 576 | } | 580 | } |
| @@ -649,6 +653,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
| 649 | { | 653 | { |
| 650 | u64 header; | 654 | u64 header; |
| 651 | int ret = 0; | 655 | int ret = 0; |
| 656 | struct sst_dsp *sst = byt->dsp; | ||
| 657 | unsigned long flags; | ||
| 652 | 658 | ||
| 653 | if (!stream->commited) | 659 | if (!stream->commited) |
| 654 | goto out; | 660 | goto out; |
| @@ -663,8 +669,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
| 663 | 669 | ||
| 664 | stream->commited = false; | 670 | stream->commited = false; |
| 665 | out: | 671 | out: |
| 672 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 666 | list_del(&stream->node); | 673 | list_del(&stream->node); |
| 667 | kfree(stream); | 674 | kfree(stream); |
| 675 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 668 | 676 | ||
| 669 | return ret; | 677 | return ret; |
| 670 | } | 678 | } |
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h index cd4a3ca25ce4..ffb308bd81ce 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/sst-dsp-priv.h | |||
| @@ -136,7 +136,7 @@ struct sst_module_data { | |||
| 136 | enum sst_data_type data_type; /* type of module data */ | 136 | enum sst_data_type data_type; /* type of module data */ |
| 137 | 137 | ||
| 138 | u32 size; /* size in bytes */ | 138 | u32 size; /* size in bytes */ |
| 139 | u32 offset; /* offset in FW file */ | 139 | int32_t offset; /* offset in FW file */ |
| 140 | u32 data_offset; /* offset in ADSP memory space */ | 140 | u32 data_offset; /* offset in ADSP memory space */ |
| 141 | void *data; /* module data */ | 141 | void *data; /* module data */ |
| 142 | }; | 142 | }; |
| @@ -228,6 +228,7 @@ struct sst_dsp { | |||
| 228 | spinlock_t spinlock; /* IPC locking */ | 228 | spinlock_t spinlock; /* IPC locking */ |
| 229 | struct mutex mutex; /* DSP FW lock */ | 229 | struct mutex mutex; /* DSP FW lock */ |
| 230 | struct device *dev; | 230 | struct device *dev; |
| 231 | struct device *dma_dev; | ||
| 231 | void *thread_context; | 232 | void *thread_context; |
| 232 | int irq; | 233 | int irq; |
| 233 | u32 id; | 234 | u32 id; |
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index 0c129fd85ecf..0b715b20a2d7 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c | |||
| @@ -337,6 +337,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev, | |||
| 337 | spin_lock_init(&sst->spinlock); | 337 | spin_lock_init(&sst->spinlock); |
| 338 | mutex_init(&sst->mutex); | 338 | mutex_init(&sst->mutex); |
| 339 | sst->dev = dev; | 339 | sst->dev = dev; |
| 340 | sst->dma_dev = pdata->dma_dev; | ||
| 340 | sst->thread_context = sst_dev->thread_context; | 341 | sst->thread_context = sst_dev->thread_context; |
| 341 | sst->sst_dev = sst_dev; | 342 | sst->sst_dev = sst_dev; |
| 342 | sst->id = pdata->id; | 343 | sst->id = pdata->id; |
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index 74052b59485c..e44423be66c4 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h | |||
| @@ -169,6 +169,7 @@ struct sst_pdata { | |||
| 169 | u32 dma_base; | 169 | u32 dma_base; |
| 170 | u32 dma_size; | 170 | u32 dma_size; |
| 171 | int dma_engine; | 171 | int dma_engine; |
| 172 | struct device *dma_dev; | ||
| 172 | 173 | ||
| 173 | /* DSP */ | 174 | /* DSP */ |
| 174 | u32 id; | 175 | u32 id; |
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 0c74bf1d2021..3bb43dac892d 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c | |||
| @@ -59,14 +59,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | |||
| 59 | sst_fw->private = private; | 59 | sst_fw->private = private; |
| 60 | sst_fw->size = fw->size; | 60 | sst_fw->size = fw->size; |
| 61 | 61 | ||
| 62 | err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32)); | ||
| 63 | if (err < 0) { | ||
| 64 | kfree(sst_fw); | ||
| 65 | return NULL; | ||
| 66 | } | ||
| 67 | |||
| 68 | /* allocate DMA buffer to store FW data */ | 62 | /* allocate DMA buffer to store FW data */ |
| 69 | sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size, | 63 | sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size, |
| 70 | &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); | 64 | &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); |
| 71 | if (!sst_fw->dma_buf) { | 65 | if (!sst_fw->dma_buf) { |
| 72 | dev_err(dsp->dev, "error: DMA alloc failed\n"); | 66 | dev_err(dsp->dev, "error: DMA alloc failed\n"); |
| @@ -144,7 +138,7 @@ void sst_fw_free(struct sst_fw *sst_fw) | |||
| 144 | list_del(&sst_fw->list); | 138 | list_del(&sst_fw->list); |
| 145 | mutex_unlock(&dsp->mutex); | 139 | mutex_unlock(&dsp->mutex); |
| 146 | 140 | ||
| 147 | dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf, | 141 | dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf, |
| 148 | sst_fw->dmable_fw_paddr); | 142 | sst_fw->dmable_fw_paddr); |
| 149 | kfree(sst_fw); | 143 | kfree(sst_fw); |
| 150 | } | 144 | } |
| @@ -240,6 +234,9 @@ static int block_alloc_contiguous(struct sst_module *module, | |||
| 240 | size -= block->size; | 234 | size -= block->size; |
| 241 | } | 235 | } |
| 242 | 236 | ||
| 237 | list_for_each_entry(block, &tmp, list) | ||
| 238 | list_add(&block->module_list, &module->block_list); | ||
| 239 | |||
| 243 | list_splice(&tmp, &dsp->used_block_list); | 240 | list_splice(&tmp, &dsp->used_block_list); |
| 244 | return 0; | 241 | return 0; |
| 245 | } | 242 | } |
| @@ -285,8 +282,7 @@ static int block_alloc(struct sst_module *module, | |||
| 285 | /* do we span > 1 blocks */ | 282 | /* do we span > 1 blocks */ |
| 286 | if (data->size > block->size) { | 283 | if (data->size > block->size) { |
| 287 | ret = block_alloc_contiguous(module, data, | 284 | ret = block_alloc_contiguous(module, data, |
| 288 | block->offset + block->size, | 285 | block->offset, data->size); |
| 289 | data->size - block->size); | ||
| 290 | if (ret == 0) | 286 | if (ret == 0) |
| 291 | return ret; | 287 | return ret; |
| 292 | } | 288 | } |
| @@ -382,7 +378,7 @@ static int block_alloc_fixed(struct sst_module *module, | |||
| 382 | 378 | ||
| 383 | err = block_alloc_contiguous(module, data, | 379 | err = block_alloc_contiguous(module, data, |
| 384 | block->offset + block->size, | 380 | block->offset + block->size, |
| 385 | data->size - block->size + data->offset - block->offset); | 381 | data->size - block->size); |
| 386 | if (err < 0) | 382 | if (err < 0) |
| 387 | return -ENOMEM; | 383 | return -ENOMEM; |
| 388 | 384 | ||
| @@ -409,15 +405,10 @@ static int block_alloc_fixed(struct sst_module *module, | |||
| 409 | if (data->offset >= block->offset && data->offset < block_end) { | 405 | if (data->offset >= block->offset && data->offset < block_end) { |
| 410 | 406 | ||
| 411 | err = block_alloc_contiguous(module, data, | 407 | err = block_alloc_contiguous(module, data, |
| 412 | block->offset + block->size, | 408 | block->offset, data->size); |
| 413 | data->size - block->size); | ||
| 414 | if (err < 0) | 409 | if (err < 0) |
| 415 | return -ENOMEM; | 410 | return -ENOMEM; |
| 416 | 411 | ||
| 417 | /* add block */ | ||
| 418 | block->data_type = data->data_type; | ||
| 419 | list_move(&block->list, &dsp->used_block_list); | ||
| 420 | list_add(&block->module_list, &module->block_list); | ||
| 421 | return 0; | 412 | return 0; |
| 422 | } | 413 | } |
| 423 | 414 | ||
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index f5ebf36af889..535f517629fd 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c | |||
| @@ -433,7 +433,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
| 433 | int ret = -ENODEV, i, j, region_count; | 433 | int ret = -ENODEV, i, j, region_count; |
| 434 | u32 offset, size; | 434 | u32 offset, size; |
| 435 | 435 | ||
| 436 | dev = sst->dev; | 436 | dev = sst->dma_dev; |
| 437 | 437 | ||
| 438 | switch (sst->id) { | 438 | switch (sst->id) { |
| 439 | case SST_DEV_ID_LYNX_POINT: | 439 | case SST_DEV_ID_LYNX_POINT: |
| @@ -466,7 +466,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
| 466 | return ret; | 466 | return ret; |
| 467 | } | 467 | } |
| 468 | 468 | ||
| 469 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); | 469 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31)); |
| 470 | if (ret) | 470 | if (ret) |
| 471 | return ret; | 471 | return ret; |
| 472 | 472 | ||
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 455a1857c441..e7996b39a484 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
| @@ -617,7 +617,7 @@ static void hsw_notification_work(struct work_struct *work) | |||
| 617 | case IPC_POSITION_CHANGED: | 617 | case IPC_POSITION_CHANGED: |
| 618 | trace_ipc_notification("DSP stream position changed for", | 618 | trace_ipc_notification("DSP stream position changed for", |
| 619 | stream->reply.stream_hw_id); | 619 | stream->reply.stream_hw_id); |
| 620 | sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos)); | 620 | sst_dsp_inbox_read(hsw->dsp, pos, sizeof(*pos)); |
| 621 | 621 | ||
| 622 | if (stream->notify_position) | 622 | if (stream->notify_position) |
| 623 | stream->notify_position(stream, stream->pdata); | 623 | stream->notify_position(stream, stream->pdata); |
| @@ -1159,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | |||
| 1159 | void *data) | 1159 | void *data) |
| 1160 | { | 1160 | { |
| 1161 | struct sst_hsw_stream *stream; | 1161 | struct sst_hsw_stream *stream; |
| 1162 | struct sst_dsp *sst = hsw->dsp; | ||
| 1163 | unsigned long flags; | ||
| 1162 | 1164 | ||
| 1163 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | 1165 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
| 1164 | if (stream == NULL) | 1166 | if (stream == NULL) |
| 1165 | return NULL; | 1167 | return NULL; |
| 1166 | 1168 | ||
| 1169 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 1167 | list_add(&stream->node, &hsw->stream_list); | 1170 | list_add(&stream->node, &hsw->stream_list); |
| 1168 | stream->notify_position = notify_position; | 1171 | stream->notify_position = notify_position; |
| 1169 | stream->pdata = data; | 1172 | stream->pdata = data; |
| @@ -1172,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | |||
| 1172 | 1175 | ||
| 1173 | /* work to process notification messages */ | 1176 | /* work to process notification messages */ |
| 1174 | INIT_WORK(&stream->notify_work, hsw_notification_work); | 1177 | INIT_WORK(&stream->notify_work, hsw_notification_work); |
| 1178 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 1175 | 1179 | ||
| 1176 | return stream; | 1180 | return stream; |
| 1177 | } | 1181 | } |
| @@ -1180,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
| 1180 | { | 1184 | { |
| 1181 | u32 header; | 1185 | u32 header; |
| 1182 | int ret = 0; | 1186 | int ret = 0; |
| 1187 | struct sst_dsp *sst = hsw->dsp; | ||
| 1188 | unsigned long flags; | ||
| 1183 | 1189 | ||
| 1184 | /* dont free DSP streams that are not commited */ | 1190 | /* dont free DSP streams that are not commited */ |
| 1185 | if (!stream->commited) | 1191 | if (!stream->commited) |
| @@ -1201,8 +1207,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
| 1201 | trace_hsw_stream_free_req(stream, &stream->free_req); | 1207 | trace_hsw_stream_free_req(stream, &stream->free_req); |
| 1202 | 1208 | ||
| 1203 | out: | 1209 | out: |
| 1210 | cancel_work_sync(&stream->notify_work); | ||
| 1211 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 1204 | list_del(&stream->node); | 1212 | list_del(&stream->node); |
| 1205 | kfree(stream); | 1213 | kfree(stream); |
| 1214 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 1206 | 1215 | ||
| 1207 | return ret; | 1216 | return ret; |
| 1208 | } | 1217 | } |
| @@ -1538,10 +1547,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
| 1538 | } | 1547 | } |
| 1539 | 1548 | ||
| 1540 | /* Stream pointer positions */ | 1549 | /* Stream pointer positions */ |
| 1541 | int sst_hsw_get_dsp_position(struct sst_hsw *hsw, | 1550 | u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, |
| 1542 | struct sst_hsw_stream *stream) | 1551 | struct sst_hsw_stream *stream) |
| 1543 | { | 1552 | { |
| 1544 | return stream->rpos.position; | 1553 | u32 rpos; |
| 1554 | |||
| 1555 | sst_dsp_read(hsw->dsp, &rpos, | ||
| 1556 | stream->reply.read_position_register_address, sizeof(rpos)); | ||
| 1557 | |||
| 1558 | return rpos; | ||
| 1559 | } | ||
| 1560 | |||
| 1561 | /* Stream presentation (monotonic) positions */ | ||
| 1562 | u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, | ||
| 1563 | struct sst_hsw_stream *stream) | ||
| 1564 | { | ||
| 1565 | u64 ppos; | ||
| 1566 | |||
| 1567 | sst_dsp_read(hsw->dsp, &ppos, | ||
| 1568 | stream->reply.presentation_position_register_address, | ||
| 1569 | sizeof(ppos)); | ||
| 1570 | |||
| 1571 | return ppos; | ||
| 1545 | } | 1572 | } |
| 1546 | 1573 | ||
| 1547 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, | 1574 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, |
| @@ -1610,7 +1637,7 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
| 1610 | trace_ipc_request("PM enter Dx state", state); | 1637 | trace_ipc_request("PM enter Dx state", state); |
| 1611 | 1638 | ||
| 1612 | ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), | 1639 | ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), |
| 1613 | dx, sizeof(dx)); | 1640 | dx, sizeof(*dx)); |
| 1614 | if (ret < 0) { | 1641 | if (ret < 0) { |
| 1615 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); | 1642 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); |
| 1616 | return ret; | 1643 | return ret; |
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index d517929ccc38..2ac194a6d04b 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h | |||
| @@ -464,7 +464,9 @@ int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, | |||
| 464 | struct sst_hsw_stream *stream, u32 *position); | 464 | struct sst_hsw_stream *stream, u32 *position); |
| 465 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, | 465 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, |
| 466 | struct sst_hsw_stream *stream, u32 stage_id, u32 position); | 466 | struct sst_hsw_stream *stream, u32 stage_id, u32 position); |
| 467 | int sst_hsw_get_dsp_position(struct sst_hsw *hsw, | 467 | u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, |
| 468 | struct sst_hsw_stream *stream); | ||
| 469 | u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, | ||
| 468 | struct sst_hsw_stream *stream); | 470 | struct sst_hsw_stream *stream); |
| 469 | 471 | ||
| 470 | /* HW port config */ | 472 | /* HW port config */ |
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; |
