aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm_adsp.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2013-01-30 01:37:23 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-02-04 14:52:35 -0500
commitcf17c83c4ac2de13a7b158c1c27fffb30ce109c3 (patch)
tree7a617680ebf87bbc3a7f6435dad63205a050debb /sound/soc/codecs/wm_adsp.c
parent4c47c2b0f82c5ebe2187768b8ed05281d13b438e (diff)
ASoC: wm_adsp: Use asynchronous I/O to write firmware and coefficients
Allow the regmap API to use asynchronous I/O where supported to minimise the delay between transfers, reducing firmware download times. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r--sound/soc/codecs/wm_adsp.c82
1 files changed, 66 insertions, 16 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 5487a94f4595..be45e2b8b59e 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -15,6 +15,7 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/delay.h> 16#include <linux/delay.h>
17#include <linux/firmware.h> 17#include <linux/firmware.h>
18#include <linux/list.h>
18#include <linux/pm.h> 19#include <linux/pm.h>
19#include <linux/pm_runtime.h> 20#include <linux/pm_runtime.h>
20#include <linux/regmap.h> 21#include <linux/regmap.h>
@@ -153,6 +154,43 @@
153#define ADSP2_RAM_RDY_SHIFT 0 154#define ADSP2_RAM_RDY_SHIFT 0
154#define ADSP2_RAM_RDY_WIDTH 1 155#define ADSP2_RAM_RDY_WIDTH 1
155 156
157struct wm_adsp_buf {
158 struct list_head list;
159 void *buf;
160};
161
162static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
163 struct list_head *list)
164{
165 struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
166
167 if (buf == NULL)
168 return NULL;
169
170 buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA);
171 if (!buf->buf) {
172 kfree(buf);
173 return NULL;
174 }
175
176 if (list)
177 list_add_tail(&buf->list, list);
178
179 return buf;
180}
181
182static void wm_adsp_buf_free(struct list_head *list)
183{
184 while (!list_empty(list)) {
185 struct wm_adsp_buf *buf = list_first_entry(list,
186 struct wm_adsp_buf,
187 list);
188 list_del(&buf->list);
189 kfree(buf->buf);
190 kfree(buf);
191 }
192}
193
156#define WM_ADSP_NUM_FW 4 194#define WM_ADSP_NUM_FW 4
157 195
158static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { 196static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
@@ -254,6 +292,7 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
254 292
255static int wm_adsp_load(struct wm_adsp *dsp) 293static int wm_adsp_load(struct wm_adsp *dsp)
256{ 294{
295 LIST_HEAD(buf_list);
257 const struct firmware *firmware; 296 const struct firmware *firmware;
258 struct regmap *regmap = dsp->regmap; 297 struct regmap *regmap = dsp->regmap;
259 unsigned int pos = 0; 298 unsigned int pos = 0;
@@ -265,7 +304,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
265 const struct wm_adsp_region *mem; 304 const struct wm_adsp_region *mem;
266 const char *region_name; 305 const char *region_name;
267 char *file, *text; 306 char *file, *text;
268 void *buf; 307 struct wm_adsp_buf *buf;
269 unsigned int reg; 308 unsigned int reg;
270 int regions = 0; 309 int regions = 0;
271 int ret, offset, type, sizes; 310 int ret, offset, type, sizes;
@@ -420,18 +459,16 @@ static int wm_adsp_load(struct wm_adsp *dsp)
420 } 459 }
421 460
422 if (reg) { 461 if (reg) {
423 buf = kmemdup(region->data, le32_to_cpu(region->len), 462 buf = wm_adsp_buf_alloc(region->data,
424 GFP_KERNEL | GFP_DMA); 463 le32_to_cpu(region->len),
464 &buf_list);
425 if (!buf) { 465 if (!buf) {
426 adsp_err(dsp, "Out of memory\n"); 466 adsp_err(dsp, "Out of memory\n");
427 return -ENOMEM; 467 return -ENOMEM;
428 } 468 }
429 469
430 ret = regmap_raw_write(regmap, reg, buf, 470 ret = regmap_raw_write_async(regmap, reg, buf->buf,
431 le32_to_cpu(region->len)); 471 le32_to_cpu(region->len));
432
433 kfree(buf);
434
435 if (ret != 0) { 472 if (ret != 0) {
436 adsp_err(dsp, 473 adsp_err(dsp,
437 "%s.%d: Failed to write %d bytes at %d in %s: %d\n", 474 "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
@@ -445,12 +482,20 @@ static int wm_adsp_load(struct wm_adsp *dsp)
445 pos += le32_to_cpu(region->len) + sizeof(*region); 482 pos += le32_to_cpu(region->len) + sizeof(*region);
446 regions++; 483 regions++;
447 } 484 }
448 485
486 ret = regmap_async_complete(regmap);
487 if (ret != 0) {
488 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
489 goto out_fw;
490 }
491
449 if (pos > firmware->size) 492 if (pos > firmware->size)
450 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 493 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
451 file, regions, pos - firmware->size); 494 file, regions, pos - firmware->size);
452 495
453out_fw: 496out_fw:
497 regmap_async_complete(regmap);
498 wm_adsp_buf_free(&buf_list);
454 release_firmware(firmware); 499 release_firmware(firmware);
455out: 500out:
456 kfree(file); 501 kfree(file);
@@ -655,6 +700,7 @@ out:
655 700
656static int wm_adsp_load_coeff(struct wm_adsp *dsp) 701static int wm_adsp_load_coeff(struct wm_adsp *dsp)
657{ 702{
703 LIST_HEAD(buf_list);
658 struct regmap *regmap = dsp->regmap; 704 struct regmap *regmap = dsp->regmap;
659 struct wmfw_coeff_hdr *hdr; 705 struct wmfw_coeff_hdr *hdr;
660 struct wmfw_coeff_item *blk; 706 struct wmfw_coeff_item *blk;
@@ -664,7 +710,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
664 const char *region_name; 710 const char *region_name;
665 int ret, pos, blocks, type, offset, reg; 711 int ret, pos, blocks, type, offset, reg;
666 char *file; 712 char *file;
667 void *buf; 713 struct wm_adsp_buf *buf;
668 714
669 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 715 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
670 if (file == NULL) 716 if (file == NULL)
@@ -776,8 +822,9 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
776 } 822 }
777 823
778 if (reg) { 824 if (reg) {
779 buf = kmemdup(blk->data, le32_to_cpu(blk->len), 825 buf = wm_adsp_buf_alloc(blk->data,
780 GFP_KERNEL | GFP_DMA); 826 le32_to_cpu(blk->len),
827 &buf_list);
781 if (!buf) { 828 if (!buf) {
782 adsp_err(dsp, "Out of memory\n"); 829 adsp_err(dsp, "Out of memory\n");
783 return -ENOMEM; 830 return -ENOMEM;
@@ -786,27 +833,30 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
786 adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", 833 adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
787 file, blocks, le32_to_cpu(blk->len), 834 file, blocks, le32_to_cpu(blk->len),
788 reg); 835 reg);
789 ret = regmap_raw_write(regmap, reg, blk->data, 836 ret = regmap_raw_write_async(regmap, reg, buf->buf,
790 le32_to_cpu(blk->len)); 837 le32_to_cpu(blk->len));
791 if (ret != 0) { 838 if (ret != 0) {
792 adsp_err(dsp, 839 adsp_err(dsp,
793 "%s.%d: Failed to write to %x in %s\n", 840 "%s.%d: Failed to write to %x in %s\n",
794 file, blocks, reg, region_name); 841 file, blocks, reg, region_name);
795 } 842 }
796
797 kfree(buf);
798 } 843 }
799 844
800 pos += le32_to_cpu(blk->len) + sizeof(*blk); 845 pos += le32_to_cpu(blk->len) + sizeof(*blk);
801 blocks++; 846 blocks++;
802 } 847 }
803 848
849 ret = regmap_async_complete(regmap);
850 if (ret != 0)
851 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
852
804 if (pos > firmware->size) 853 if (pos > firmware->size)
805 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", 854 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
806 file, blocks, pos - firmware->size); 855 file, blocks, pos - firmware->size);
807 856
808out_fw: 857out_fw:
809 release_firmware(firmware); 858 release_firmware(firmware);
859 wm_adsp_buf_free(&buf_list);
810out: 860out:
811 kfree(file); 861 kfree(file);
812 return 0; 862 return 0;