ASoC: wm_adsp: Add support for opening a compressed stream
[deliverable/linux.git] / sound / soc / codecs / wm_adsp.c
CommitLineData
2159ad93
MB
1/*
2 * wm_adsp.c -- Wolfson ADSP support
3 *
4 * Copyright 2012 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/init.h>
16#include <linux/delay.h>
17#include <linux/firmware.h>
cf17c83c 18#include <linux/list.h>
2159ad93
MB
19#include <linux/pm.h>
20#include <linux/pm_runtime.h>
21#include <linux/regmap.h>
973838a0 22#include <linux/regulator/consumer.h>
2159ad93 23#include <linux/slab.h>
cdcd7f72 24#include <linux/vmalloc.h>
6ab2b7b4 25#include <linux/workqueue.h>
f9f55e31 26#include <linux/debugfs.h>
2159ad93
MB
27#include <sound/core.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/soc.h>
31#include <sound/jack.h>
32#include <sound/initval.h>
33#include <sound/tlv.h>
34
35#include <linux/mfd/arizona/registers.h>
36
dc91428a 37#include "arizona.h"
2159ad93
MB
38#include "wm_adsp.h"
39
40#define adsp_crit(_dsp, fmt, ...) \
41 dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
42#define adsp_err(_dsp, fmt, ...) \
43 dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
44#define adsp_warn(_dsp, fmt, ...) \
45 dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
46#define adsp_info(_dsp, fmt, ...) \
47 dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
48#define adsp_dbg(_dsp, fmt, ...) \
49 dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
50
51#define ADSP1_CONTROL_1 0x00
52#define ADSP1_CONTROL_2 0x02
53#define ADSP1_CONTROL_3 0x03
54#define ADSP1_CONTROL_4 0x04
55#define ADSP1_CONTROL_5 0x06
56#define ADSP1_CONTROL_6 0x07
57#define ADSP1_CONTROL_7 0x08
58#define ADSP1_CONTROL_8 0x09
59#define ADSP1_CONTROL_9 0x0A
60#define ADSP1_CONTROL_10 0x0B
61#define ADSP1_CONTROL_11 0x0C
62#define ADSP1_CONTROL_12 0x0D
63#define ADSP1_CONTROL_13 0x0F
64#define ADSP1_CONTROL_14 0x10
65#define ADSP1_CONTROL_15 0x11
66#define ADSP1_CONTROL_16 0x12
67#define ADSP1_CONTROL_17 0x13
68#define ADSP1_CONTROL_18 0x14
69#define ADSP1_CONTROL_19 0x16
70#define ADSP1_CONTROL_20 0x17
71#define ADSP1_CONTROL_21 0x18
72#define ADSP1_CONTROL_22 0x1A
73#define ADSP1_CONTROL_23 0x1B
74#define ADSP1_CONTROL_24 0x1C
75#define ADSP1_CONTROL_25 0x1E
76#define ADSP1_CONTROL_26 0x20
77#define ADSP1_CONTROL_27 0x21
78#define ADSP1_CONTROL_28 0x22
79#define ADSP1_CONTROL_29 0x23
80#define ADSP1_CONTROL_30 0x24
81#define ADSP1_CONTROL_31 0x26
82
83/*
84 * ADSP1 Control 19
85 */
86#define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
87#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
88#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
89
90
91/*
92 * ADSP1 Control 30
93 */
94#define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */
95#define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */
96#define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */
97#define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */
98#define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
99#define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
100#define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
101#define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
102#define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
103#define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
104#define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
105#define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
106#define ADSP1_START 0x0001 /* DSP1_START */
107#define ADSP1_START_MASK 0x0001 /* DSP1_START */
108#define ADSP1_START_SHIFT 0 /* DSP1_START */
109#define ADSP1_START_WIDTH 1 /* DSP1_START */
110
94e205bf
CR
111/*
112 * ADSP1 Control 31
113 */
114#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
115#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
116#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
117
2d30b575
MB
118#define ADSP2_CONTROL 0x0
119#define ADSP2_CLOCKING 0x1
120#define ADSP2_STATUS1 0x4
121#define ADSP2_WDMA_CONFIG_1 0x30
122#define ADSP2_WDMA_CONFIG_2 0x31
123#define ADSP2_RDMA_CONFIG_1 0x34
2159ad93 124
10337b07
RF
125#define ADSP2_SCRATCH0 0x40
126#define ADSP2_SCRATCH1 0x41
127#define ADSP2_SCRATCH2 0x42
128#define ADSP2_SCRATCH3 0x43
129
2159ad93
MB
130/*
131 * ADSP2 Control
132 */
133
134#define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */
135#define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */
136#define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */
137#define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */
138#define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
139#define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
140#define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
141#define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
142#define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
143#define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
144#define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
145#define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
146#define ADSP2_START 0x0001 /* DSP1_START */
147#define ADSP2_START_MASK 0x0001 /* DSP1_START */
148#define ADSP2_START_SHIFT 0 /* DSP1_START */
149#define ADSP2_START_WIDTH 1 /* DSP1_START */
150
973838a0
MB
151/*
152 * ADSP2 clocking
153 */
154#define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
155#define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
156#define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
157
2159ad93
MB
158/*
159 * ADSP2 Status 1
160 */
161#define ADSP2_RAM_RDY 0x0001
162#define ADSP2_RAM_RDY_MASK 0x0001
163#define ADSP2_RAM_RDY_SHIFT 0
164#define ADSP2_RAM_RDY_WIDTH 1
165
cf17c83c
MB
166struct wm_adsp_buf {
167 struct list_head list;
168 void *buf;
169};
170
171static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
172 struct list_head *list)
173{
174 struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
175
176 if (buf == NULL)
177 return NULL;
178
cdcd7f72 179 buf->buf = vmalloc(len);
cf17c83c 180 if (!buf->buf) {
cdcd7f72 181 vfree(buf);
cf17c83c
MB
182 return NULL;
183 }
cdcd7f72 184 memcpy(buf->buf, src, len);
cf17c83c
MB
185
186 if (list)
187 list_add_tail(&buf->list, list);
188
189 return buf;
190}
191
192static void wm_adsp_buf_free(struct list_head *list)
193{
194 while (!list_empty(list)) {
195 struct wm_adsp_buf *buf = list_first_entry(list,
196 struct wm_adsp_buf,
197 list);
198 list_del(&buf->list);
cdcd7f72 199 vfree(buf->buf);
cf17c83c
MB
200 kfree(buf);
201 }
202}
203
04d1300f
CK
204#define WM_ADSP_FW_MBC_VSS 0
205#define WM_ADSP_FW_HIFI 1
206#define WM_ADSP_FW_TX 2
207#define WM_ADSP_FW_TX_SPK 3
208#define WM_ADSP_FW_RX 4
209#define WM_ADSP_FW_RX_ANC 5
210#define WM_ADSP_FW_CTRL 6
211#define WM_ADSP_FW_ASR 7
212#define WM_ADSP_FW_TRACE 8
213#define WM_ADSP_FW_SPK_PROT 9
214#define WM_ADSP_FW_MISC 10
215
216#define WM_ADSP_NUM_FW 11
dd84f925 217
1023dbd9 218static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
04d1300f
CK
219 [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
220 [WM_ADSP_FW_HIFI] = "MasterHiFi",
221 [WM_ADSP_FW_TX] = "Tx",
222 [WM_ADSP_FW_TX_SPK] = "Tx Speaker",
223 [WM_ADSP_FW_RX] = "Rx",
224 [WM_ADSP_FW_RX_ANC] = "Rx ANC",
225 [WM_ADSP_FW_CTRL] = "Voice Ctrl",
226 [WM_ADSP_FW_ASR] = "ASR Assist",
227 [WM_ADSP_FW_TRACE] = "Dbg Trace",
228 [WM_ADSP_FW_SPK_PROT] = "Protection",
229 [WM_ADSP_FW_MISC] = "Misc",
1023dbd9
MB
230};
231
406abc95
CK
232struct wm_adsp_compr {
233 struct wm_adsp *dsp;
234
235 struct snd_compr_stream *stream;
236 struct snd_compressed_buffer size;
237};
238
239#define WM_ADSP_DATA_WORD_SIZE 3
240
241#define WM_ADSP_MIN_FRAGMENTS 1
242#define WM_ADSP_MAX_FRAGMENTS 256
243#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * WM_ADSP_DATA_WORD_SIZE)
244#define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * WM_ADSP_DATA_WORD_SIZE)
245
246struct wm_adsp_fw_caps {
247 u32 id;
248 struct snd_codec_desc desc;
249};
250
251static const struct wm_adsp_fw_caps ez2control_caps[] = {
252 {
253 .id = SND_AUDIOCODEC_BESPOKE,
254 .desc = {
255 .max_ch = 1,
256 .sample_rates = { 16000 },
257 .num_sample_rates = 1,
258 .formats = SNDRV_PCM_FMTBIT_S16_LE,
259 },
260 },
261};
262
263static const struct {
1023dbd9 264 const char *file;
406abc95
CK
265 int compr_direction;
266 int num_caps;
267 const struct wm_adsp_fw_caps *caps;
1023dbd9 268} wm_adsp_fw[WM_ADSP_NUM_FW] = {
04d1300f
CK
269 [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
270 [WM_ADSP_FW_HIFI] = { .file = "hifi" },
271 [WM_ADSP_FW_TX] = { .file = "tx" },
272 [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" },
273 [WM_ADSP_FW_RX] = { .file = "rx" },
274 [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" },
406abc95
CK
275 [WM_ADSP_FW_CTRL] = {
276 .file = "ctrl",
277 .compr_direction = SND_COMPRESS_CAPTURE,
278 .num_caps = ARRAY_SIZE(ez2control_caps),
279 .caps = ez2control_caps,
280 },
04d1300f
CK
281 [WM_ADSP_FW_ASR] = { .file = "asr" },
282 [WM_ADSP_FW_TRACE] = { .file = "trace" },
283 [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
284 [WM_ADSP_FW_MISC] = { .file = "misc" },
1023dbd9
MB
285};
286
6ab2b7b4
DP
287struct wm_coeff_ctl_ops {
288 int (*xget)(struct snd_kcontrol *kcontrol,
289 struct snd_ctl_elem_value *ucontrol);
290 int (*xput)(struct snd_kcontrol *kcontrol,
291 struct snd_ctl_elem_value *ucontrol);
292 int (*xinfo)(struct snd_kcontrol *kcontrol,
293 struct snd_ctl_elem_info *uinfo);
294};
295
6ab2b7b4
DP
296struct wm_coeff_ctl {
297 const char *name;
2323736d 298 const char *fw_name;
3809f001 299 struct wm_adsp_alg_region alg_region;
6ab2b7b4 300 struct wm_coeff_ctl_ops ops;
3809f001 301 struct wm_adsp *dsp;
6ab2b7b4
DP
302 unsigned int enabled:1;
303 struct list_head list;
304 void *cache;
2323736d 305 unsigned int offset;
6ab2b7b4 306 size_t len;
0c2e3f34 307 unsigned int set:1;
6ab2b7b4 308 struct snd_kcontrol *kcontrol;
26c22a19 309 unsigned int flags;
6ab2b7b4
DP
310};
311
f9f55e31
RF
312#ifdef CONFIG_DEBUG_FS
313static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
314{
315 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
316
f9f55e31
RF
317 kfree(dsp->wmfw_file_name);
318 dsp->wmfw_file_name = tmp;
f9f55e31
RF
319}
320
321static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
322{
323 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
324
f9f55e31
RF
325 kfree(dsp->bin_file_name);
326 dsp->bin_file_name = tmp;
f9f55e31
RF
327}
328
329static void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
330{
f9f55e31
RF
331 kfree(dsp->wmfw_file_name);
332 kfree(dsp->bin_file_name);
333 dsp->wmfw_file_name = NULL;
334 dsp->bin_file_name = NULL;
f9f55e31
RF
335}
336
337static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
338 char __user *user_buf,
339 size_t count, loff_t *ppos)
340{
341 struct wm_adsp *dsp = file->private_data;
342 ssize_t ret;
343
078e7183 344 mutex_lock(&dsp->pwr_lock);
f9f55e31
RF
345
346 if (!dsp->wmfw_file_name || !dsp->running)
347 ret = 0;
348 else
349 ret = simple_read_from_buffer(user_buf, count, ppos,
350 dsp->wmfw_file_name,
351 strlen(dsp->wmfw_file_name));
352
078e7183 353 mutex_unlock(&dsp->pwr_lock);
f9f55e31
RF
354 return ret;
355}
356
357static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
358 char __user *user_buf,
359 size_t count, loff_t *ppos)
360{
361 struct wm_adsp *dsp = file->private_data;
362 ssize_t ret;
363
078e7183 364 mutex_lock(&dsp->pwr_lock);
f9f55e31
RF
365
366 if (!dsp->bin_file_name || !dsp->running)
367 ret = 0;
368 else
369 ret = simple_read_from_buffer(user_buf, count, ppos,
370 dsp->bin_file_name,
371 strlen(dsp->bin_file_name));
372
078e7183 373 mutex_unlock(&dsp->pwr_lock);
f9f55e31
RF
374 return ret;
375}
376
377static const struct {
378 const char *name;
379 const struct file_operations fops;
380} wm_adsp_debugfs_fops[] = {
381 {
382 .name = "wmfw_file_name",
383 .fops = {
384 .open = simple_open,
385 .read = wm_adsp_debugfs_wmfw_read,
386 },
387 },
388 {
389 .name = "bin_file_name",
390 .fops = {
391 .open = simple_open,
392 .read = wm_adsp_debugfs_bin_read,
393 },
394 },
395};
396
397static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
398 struct snd_soc_codec *codec)
399{
400 struct dentry *root = NULL;
401 char *root_name;
402 int i;
403
404 if (!codec->component.debugfs_root) {
405 adsp_err(dsp, "No codec debugfs root\n");
406 goto err;
407 }
408
409 root_name = kmalloc(PAGE_SIZE, GFP_KERNEL);
410 if (!root_name)
411 goto err;
412
413 snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num);
414 root = debugfs_create_dir(root_name, codec->component.debugfs_root);
415 kfree(root_name);
416
417 if (!root)
418 goto err;
419
420 if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running))
421 goto err;
422
423 if (!debugfs_create_x32("fw_id", S_IRUGO, root, &dsp->fw_id))
424 goto err;
425
426 if (!debugfs_create_x32("fw_version", S_IRUGO, root,
427 &dsp->fw_id_version))
428 goto err;
429
430 for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) {
431 if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name,
432 S_IRUGO, root, dsp,
433 &wm_adsp_debugfs_fops[i].fops))
434 goto err;
435 }
436
437 dsp->debugfs_root = root;
438 return;
439
440err:
441 debugfs_remove_recursive(root);
442 adsp_err(dsp, "Failed to create debugfs\n");
443}
444
445static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
446{
447 wm_adsp_debugfs_clear(dsp);
448 debugfs_remove_recursive(dsp->debugfs_root);
449}
450#else
451static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
452 struct snd_soc_codec *codec)
453{
454}
455
456static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
457{
458}
459
460static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp,
461 const char *s)
462{
463}
464
465static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp,
466 const char *s)
467{
468}
469
470static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
471{
472}
473#endif
474
1023dbd9
MB
475static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
476 struct snd_ctl_elem_value *ucontrol)
477{
ea53bf77 478 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
1023dbd9 479 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
3809f001 480 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
1023dbd9 481
3809f001 482 ucontrol->value.integer.value[0] = dsp[e->shift_l].fw;
1023dbd9
MB
483
484 return 0;
485}
486
487static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
488 struct snd_ctl_elem_value *ucontrol)
489{
ea53bf77 490 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
1023dbd9 491 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
3809f001 492 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
d27c5e15 493 int ret = 0;
1023dbd9 494
3809f001 495 if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
1023dbd9
MB
496 return 0;
497
498 if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
499 return -EINVAL;
500
d27c5e15
CK
501 mutex_lock(&dsp[e->shift_l].pwr_lock);
502
406abc95 503 if (dsp[e->shift_l].running || dsp[e->shift_l].compr)
d27c5e15
CK
504 ret = -EBUSY;
505 else
506 dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
1023dbd9 507
d27c5e15 508 mutex_unlock(&dsp[e->shift_l].pwr_lock);
1023dbd9 509
d27c5e15 510 return ret;
1023dbd9
MB
511}
512
513static const struct soc_enum wm_adsp_fw_enum[] = {
514 SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
515 SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
516 SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
517 SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
518};
519
336d0442 520const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
1023dbd9
MB
521 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
522 wm_adsp_fw_get, wm_adsp_fw_put),
523 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
524 wm_adsp_fw_get, wm_adsp_fw_put),
525 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
526 wm_adsp_fw_get, wm_adsp_fw_put),
336d0442
RF
527 SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
528 wm_adsp_fw_get, wm_adsp_fw_put),
b6ed61cf 529};
336d0442 530EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
2159ad93
MB
531
532static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
533 int type)
534{
535 int i;
536
537 for (i = 0; i < dsp->num_mems; i++)
538 if (dsp->mem[i].type == type)
539 return &dsp->mem[i];
540
541 return NULL;
542}
543
3809f001 544static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
45b9ee72
MB
545 unsigned int offset)
546{
3809f001 547 if (WARN_ON(!mem))
6c452bda 548 return offset;
3809f001 549 switch (mem->type) {
45b9ee72 550 case WMFW_ADSP1_PM:
3809f001 551 return mem->base + (offset * 3);
45b9ee72 552 case WMFW_ADSP1_DM:
3809f001 553 return mem->base + (offset * 2);
45b9ee72 554 case WMFW_ADSP2_XM:
3809f001 555 return mem->base + (offset * 2);
45b9ee72 556 case WMFW_ADSP2_YM:
3809f001 557 return mem->base + (offset * 2);
45b9ee72 558 case WMFW_ADSP1_ZM:
3809f001 559 return mem->base + (offset * 2);
45b9ee72 560 default:
6c452bda 561 WARN(1, "Unknown memory region type");
45b9ee72
MB
562 return offset;
563 }
564}
565
10337b07
RF
566static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
567{
568 u16 scratch[4];
569 int ret;
570
571 ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0,
572 scratch, sizeof(scratch));
573 if (ret) {
574 adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
575 return;
576 }
577
578 adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
579 be16_to_cpu(scratch[0]),
580 be16_to_cpu(scratch[1]),
581 be16_to_cpu(scratch[2]),
582 be16_to_cpu(scratch[3]));
583}
584
7585a5b0 585static int wm_coeff_info(struct snd_kcontrol *kctl,
6ab2b7b4
DP
586 struct snd_ctl_elem_info *uinfo)
587{
7585a5b0 588 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
6ab2b7b4
DP
589
590 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
591 uinfo->count = ctl->len;
592 return 0;
593}
594
c9f8dd71 595static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
6ab2b7b4
DP
596 const void *buf, size_t len)
597{
3809f001 598 struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
6ab2b7b4 599 const struct wm_adsp_region *mem;
3809f001 600 struct wm_adsp *dsp = ctl->dsp;
6ab2b7b4
DP
601 void *scratch;
602 int ret;
603 unsigned int reg;
604
3809f001 605 mem = wm_adsp_find_region(dsp, alg_region->type);
6ab2b7b4 606 if (!mem) {
3809f001
CK
607 adsp_err(dsp, "No base for region %x\n",
608 alg_region->type);
6ab2b7b4
DP
609 return -EINVAL;
610 }
611
2323736d 612 reg = ctl->alg_region.base + ctl->offset;
6ab2b7b4
DP
613 reg = wm_adsp_region_to_reg(mem, reg);
614
615 scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
616 if (!scratch)
617 return -ENOMEM;
618
3809f001 619 ret = regmap_raw_write(dsp->regmap, reg, scratch,
6ab2b7b4
DP
620 ctl->len);
621 if (ret) {
3809f001 622 adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
43bc3bf6 623 ctl->len, reg, ret);
6ab2b7b4
DP
624 kfree(scratch);
625 return ret;
626 }
3809f001 627 adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
6ab2b7b4
DP
628
629 kfree(scratch);
630
631 return 0;
632}
633
7585a5b0 634static int wm_coeff_put(struct snd_kcontrol *kctl,
6ab2b7b4
DP
635 struct snd_ctl_elem_value *ucontrol)
636{
7585a5b0 637 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
6ab2b7b4 638 char *p = ucontrol->value.bytes.data;
168d10e7
CK
639 int ret = 0;
640
641 mutex_lock(&ctl->dsp->pwr_lock);
6ab2b7b4
DP
642
643 memcpy(ctl->cache, p, ctl->len);
644
65d17a9c 645 ctl->set = 1;
168d10e7
CK
646 if (ctl->enabled)
647 ret = wm_coeff_write_control(ctl, p, ctl->len);
6ab2b7b4 648
168d10e7
CK
649 mutex_unlock(&ctl->dsp->pwr_lock);
650
651 return ret;
6ab2b7b4
DP
652}
653
c9f8dd71 654static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
6ab2b7b4
DP
655 void *buf, size_t len)
656{
3809f001 657 struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
6ab2b7b4 658 const struct wm_adsp_region *mem;
3809f001 659 struct wm_adsp *dsp = ctl->dsp;
6ab2b7b4
DP
660 void *scratch;
661 int ret;
662 unsigned int reg;
663
3809f001 664 mem = wm_adsp_find_region(dsp, alg_region->type);
6ab2b7b4 665 if (!mem) {
3809f001
CK
666 adsp_err(dsp, "No base for region %x\n",
667 alg_region->type);
6ab2b7b4
DP
668 return -EINVAL;
669 }
670
2323736d 671 reg = ctl->alg_region.base + ctl->offset;
6ab2b7b4
DP
672 reg = wm_adsp_region_to_reg(mem, reg);
673
674 scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
675 if (!scratch)
676 return -ENOMEM;
677
3809f001 678 ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len);
6ab2b7b4 679 if (ret) {
3809f001 680 adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
43bc3bf6 681 ctl->len, reg, ret);
6ab2b7b4
DP
682 kfree(scratch);
683 return ret;
684 }
3809f001 685 adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg);
6ab2b7b4
DP
686
687 memcpy(buf, scratch, ctl->len);
688 kfree(scratch);
689
690 return 0;
691}
692
7585a5b0 693static int wm_coeff_get(struct snd_kcontrol *kctl,
6ab2b7b4
DP
694 struct snd_ctl_elem_value *ucontrol)
695{
7585a5b0 696 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
6ab2b7b4 697 char *p = ucontrol->value.bytes.data;
168d10e7
CK
698 int ret = 0;
699
700 mutex_lock(&ctl->dsp->pwr_lock);
6ab2b7b4 701
26c22a19
CK
702 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
703 if (ctl->enabled)
168d10e7 704 ret = wm_coeff_read_control(ctl, p, ctl->len);
26c22a19 705 else
168d10e7
CK
706 ret = -EPERM;
707 } else {
bc1765d6
CK
708 if (!ctl->flags && ctl->enabled)
709 ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
710
168d10e7 711 memcpy(p, ctl->cache, ctl->len);
26c22a19
CK
712 }
713
168d10e7 714 mutex_unlock(&ctl->dsp->pwr_lock);
26c22a19 715
168d10e7 716 return ret;
6ab2b7b4
DP
717}
718
6ab2b7b4 719struct wmfw_ctl_work {
3809f001 720 struct wm_adsp *dsp;
6ab2b7b4
DP
721 struct wm_coeff_ctl *ctl;
722 struct work_struct work;
723};
724
3809f001 725static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
6ab2b7b4
DP
726{
727 struct snd_kcontrol_new *kcontrol;
728 int ret;
729
92bb4c32 730 if (!ctl || !ctl->name)
6ab2b7b4
DP
731 return -EINVAL;
732
733 kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
734 if (!kcontrol)
735 return -ENOMEM;
736 kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
737
738 kcontrol->name = ctl->name;
739 kcontrol->info = wm_coeff_info;
740 kcontrol->get = wm_coeff_get;
741 kcontrol->put = wm_coeff_put;
742 kcontrol->private_value = (unsigned long)ctl;
743
26c22a19
CK
744 if (ctl->flags) {
745 if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE)
746 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
747 if (ctl->flags & WMFW_CTL_FLAG_READABLE)
748 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
749 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
750 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
751 }
752
3809f001 753 ret = snd_soc_add_card_controls(dsp->card,
81ad93ec 754 kcontrol, 1);
6ab2b7b4
DP
755 if (ret < 0)
756 goto err_kcontrol;
757
758 kfree(kcontrol);
759
3809f001 760 ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card,
81ad93ec
DP
761 ctl->name);
762
6ab2b7b4
DP
763 return 0;
764
765err_kcontrol:
766 kfree(kcontrol);
767 return ret;
768}
769
b21acc1c
CK
770static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
771{
772 struct wm_coeff_ctl *ctl;
773 int ret;
774
775 list_for_each_entry(ctl, &dsp->ctl_list, list) {
776 if (!ctl->enabled || ctl->set)
777 continue;
26c22a19
CK
778 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
779 continue;
780
b21acc1c
CK
781 ret = wm_coeff_read_control(ctl,
782 ctl->cache,
783 ctl->len);
784 if (ret < 0)
785 return ret;
786 }
787
788 return 0;
789}
790
791static int wm_coeff_sync_controls(struct wm_adsp *dsp)
792{
793 struct wm_coeff_ctl *ctl;
794 int ret;
795
796 list_for_each_entry(ctl, &dsp->ctl_list, list) {
797 if (!ctl->enabled)
798 continue;
26c22a19 799 if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
b21acc1c
CK
800 ret = wm_coeff_write_control(ctl,
801 ctl->cache,
802 ctl->len);
803 if (ret < 0)
804 return ret;
805 }
806 }
807
808 return 0;
809}
810
811static void wm_adsp_ctl_work(struct work_struct *work)
812{
813 struct wmfw_ctl_work *ctl_work = container_of(work,
814 struct wmfw_ctl_work,
815 work);
816
817 wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
818 kfree(ctl_work);
819}
820
821static int wm_adsp_create_control(struct wm_adsp *dsp,
822 const struct wm_adsp_alg_region *alg_region,
2323736d 823 unsigned int offset, unsigned int len,
26c22a19
CK
824 const char *subname, unsigned int subname_len,
825 unsigned int flags)
b21acc1c
CK
826{
827 struct wm_coeff_ctl *ctl;
828 struct wmfw_ctl_work *ctl_work;
829 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
830 char *region_name;
831 int ret;
832
26c22a19
CK
833 if (flags & WMFW_CTL_FLAG_SYS)
834 return 0;
835
b21acc1c
CK
836 switch (alg_region->type) {
837 case WMFW_ADSP1_PM:
838 region_name = "PM";
839 break;
840 case WMFW_ADSP1_DM:
841 region_name = "DM";
842 break;
843 case WMFW_ADSP2_XM:
844 region_name = "XM";
845 break;
846 case WMFW_ADSP2_YM:
847 region_name = "YM";
848 break;
849 case WMFW_ADSP1_ZM:
850 region_name = "ZM";
851 break;
852 default:
2323736d 853 adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
b21acc1c
CK
854 return -EINVAL;
855 }
856
cb5b57a9
CK
857 switch (dsp->fw_ver) {
858 case 0:
859 case 1:
860 snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
861 dsp->num, region_name, alg_region->alg);
862 break;
863 default:
864 ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
865 "DSP%d%c %.12s %x", dsp->num, *region_name,
866 wm_adsp_fw_text[dsp->fw], alg_region->alg);
867
868 /* Truncate the subname from the start if it is too long */
869 if (subname) {
870 int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
871 int skip = 0;
872
873 if (subname_len > avail)
874 skip = subname_len - avail;
875
876 snprintf(name + ret,
877 SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s",
878 subname_len - skip, subname + skip);
879 }
880 break;
881 }
b21acc1c 882
7585a5b0 883 list_for_each_entry(ctl, &dsp->ctl_list, list) {
b21acc1c
CK
884 if (!strcmp(ctl->name, name)) {
885 if (!ctl->enabled)
886 ctl->enabled = 1;
887 return 0;
888 }
889 }
890
891 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
892 if (!ctl)
893 return -ENOMEM;
2323736d 894 ctl->fw_name = wm_adsp_fw_text[dsp->fw];
b21acc1c
CK
895 ctl->alg_region = *alg_region;
896 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
897 if (!ctl->name) {
898 ret = -ENOMEM;
899 goto err_ctl;
900 }
901 ctl->enabled = 1;
902 ctl->set = 0;
903 ctl->ops.xget = wm_coeff_get;
904 ctl->ops.xput = wm_coeff_put;
905 ctl->dsp = dsp;
906
26c22a19 907 ctl->flags = flags;
2323736d 908 ctl->offset = offset;
b21acc1c
CK
909 if (len > 512) {
910 adsp_warn(dsp, "Truncating control %s from %d\n",
911 ctl->name, len);
912 len = 512;
913 }
914 ctl->len = len;
915 ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
916 if (!ctl->cache) {
917 ret = -ENOMEM;
918 goto err_ctl_name;
919 }
920
2323736d
CK
921 list_add(&ctl->list, &dsp->ctl_list);
922
b21acc1c
CK
923 ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
924 if (!ctl_work) {
925 ret = -ENOMEM;
926 goto err_ctl_cache;
927 }
928
929 ctl_work->dsp = dsp;
930 ctl_work->ctl = ctl;
931 INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
932 schedule_work(&ctl_work->work);
933
934 return 0;
935
936err_ctl_cache:
937 kfree(ctl->cache);
938err_ctl_name:
939 kfree(ctl->name);
940err_ctl:
941 kfree(ctl);
942
943 return ret;
944}
945
2323736d
CK
946struct wm_coeff_parsed_alg {
947 int id;
948 const u8 *name;
949 int name_len;
950 int ncoeff;
951};
952
953struct wm_coeff_parsed_coeff {
954 int offset;
955 int mem_type;
956 const u8 *name;
957 int name_len;
958 int ctl_type;
959 int flags;
960 int len;
961};
962
cb5b57a9
CK
963static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
964{
965 int length;
966
967 switch (bytes) {
968 case 1:
969 length = **pos;
970 break;
971 case 2:
8299ee81 972 length = le16_to_cpu(*((__le16 *)*pos));
cb5b57a9
CK
973 break;
974 default:
975 return 0;
976 }
977
978 if (str)
979 *str = *pos + bytes;
980
981 *pos += ((length + bytes) + 3) & ~0x03;
982
983 return length;
984}
985
986static int wm_coeff_parse_int(int bytes, const u8 **pos)
987{
988 int val = 0;
989
990 switch (bytes) {
991 case 2:
8299ee81 992 val = le16_to_cpu(*((__le16 *)*pos));
cb5b57a9
CK
993 break;
994 case 4:
8299ee81 995 val = le32_to_cpu(*((__le32 *)*pos));
cb5b57a9
CK
996 break;
997 default:
998 break;
999 }
1000
1001 *pos += bytes;
1002
1003 return val;
1004}
1005
2323736d
CK
1006static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
1007 struct wm_coeff_parsed_alg *blk)
1008{
1009 const struct wmfw_adsp_alg_data *raw;
1010
cb5b57a9
CK
1011 switch (dsp->fw_ver) {
1012 case 0:
1013 case 1:
1014 raw = (const struct wmfw_adsp_alg_data *)*data;
1015 *data = raw->data;
2323736d 1016
cb5b57a9
CK
1017 blk->id = le32_to_cpu(raw->id);
1018 blk->name = raw->name;
1019 blk->name_len = strlen(raw->name);
1020 blk->ncoeff = le32_to_cpu(raw->ncoeff);
1021 break;
1022 default:
1023 blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
1024 blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
1025 &blk->name);
1026 wm_coeff_parse_string(sizeof(u16), data, NULL);
1027 blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
1028 break;
1029 }
2323736d
CK
1030
1031 adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
1032 adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
1033 adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
1034}
1035
1036static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
1037 struct wm_coeff_parsed_coeff *blk)
1038{
1039 const struct wmfw_adsp_coeff_data *raw;
cb5b57a9
CK
1040 const u8 *tmp;
1041 int length;
2323736d 1042
cb5b57a9
CK
1043 switch (dsp->fw_ver) {
1044 case 0:
1045 case 1:
1046 raw = (const struct wmfw_adsp_coeff_data *)*data;
1047 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
1048
1049 blk->offset = le16_to_cpu(raw->hdr.offset);
1050 blk->mem_type = le16_to_cpu(raw->hdr.type);
1051 blk->name = raw->name;
1052 blk->name_len = strlen(raw->name);
1053 blk->ctl_type = le16_to_cpu(raw->ctl_type);
1054 blk->flags = le16_to_cpu(raw->flags);
1055 blk->len = le32_to_cpu(raw->len);
1056 break;
1057 default:
1058 tmp = *data;
1059 blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
1060 blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
1061 length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
1062 blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
1063 &blk->name);
1064 wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
1065 wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
1066 blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
1067 blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
1068 blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
1069
1070 *data = *data + sizeof(raw->hdr) + length;
1071 break;
1072 }
2323736d
CK
1073
1074 adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
1075 adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
1076 adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
1077 adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
1078 adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
1079 adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
1080}
1081
1082static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
1083 const struct wmfw_region *region)
1084{
1085 struct wm_adsp_alg_region alg_region = {};
1086 struct wm_coeff_parsed_alg alg_blk;
1087 struct wm_coeff_parsed_coeff coeff_blk;
1088 const u8 *data = region->data;
1089 int i, ret;
1090
1091 wm_coeff_parse_alg(dsp, &data, &alg_blk);
1092 for (i = 0; i < alg_blk.ncoeff; i++) {
1093 wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
1094
1095 switch (coeff_blk.ctl_type) {
1096 case SNDRV_CTL_ELEM_TYPE_BYTES:
1097 break;
1098 default:
1099 adsp_err(dsp, "Unknown control type: %d\n",
1100 coeff_blk.ctl_type);
1101 return -EINVAL;
1102 }
1103
1104 alg_region.type = coeff_blk.mem_type;
1105 alg_region.alg = alg_blk.id;
1106
1107 ret = wm_adsp_create_control(dsp, &alg_region,
1108 coeff_blk.offset,
1109 coeff_blk.len,
1110 coeff_blk.name,
26c22a19
CK
1111 coeff_blk.name_len,
1112 coeff_blk.flags);
2323736d
CK
1113 if (ret < 0)
1114 adsp_err(dsp, "Failed to create control: %.*s, %d\n",
1115 coeff_blk.name_len, coeff_blk.name, ret);
1116 }
1117
1118 return 0;
1119}
1120
2159ad93
MB
1121static int wm_adsp_load(struct wm_adsp *dsp)
1122{
cf17c83c 1123 LIST_HEAD(buf_list);
2159ad93
MB
1124 const struct firmware *firmware;
1125 struct regmap *regmap = dsp->regmap;
1126 unsigned int pos = 0;
1127 const struct wmfw_header *header;
1128 const struct wmfw_adsp1_sizes *adsp1_sizes;
1129 const struct wmfw_adsp2_sizes *adsp2_sizes;
1130 const struct wmfw_footer *footer;
1131 const struct wmfw_region *region;
1132 const struct wm_adsp_region *mem;
1133 const char *region_name;
1134 char *file, *text;
cf17c83c 1135 struct wm_adsp_buf *buf;
2159ad93
MB
1136 unsigned int reg;
1137 int regions = 0;
1138 int ret, offset, type, sizes;
1139
1140 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
1141 if (file == NULL)
1142 return -ENOMEM;
1143
1023dbd9
MB
1144 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
1145 wm_adsp_fw[dsp->fw].file);
2159ad93
MB
1146 file[PAGE_SIZE - 1] = '\0';
1147
1148 ret = request_firmware(&firmware, file, dsp->dev);
1149 if (ret != 0) {
1150 adsp_err(dsp, "Failed to request '%s'\n", file);
1151 goto out;
1152 }
1153 ret = -EINVAL;
1154
1155 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1156 if (pos >= firmware->size) {
1157 adsp_err(dsp, "%s: file too short, %zu bytes\n",
1158 file, firmware->size);
1159 goto out_fw;
1160 }
1161
7585a5b0 1162 header = (void *)&firmware->data[0];
2159ad93
MB
1163
1164 if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
1165 adsp_err(dsp, "%s: invalid magic\n", file);
1166 goto out_fw;
1167 }
1168
2323736d
CK
1169 switch (header->ver) {
1170 case 0:
c61e59fe
CK
1171 adsp_warn(dsp, "%s: Depreciated file format %d\n",
1172 file, header->ver);
1173 break;
2323736d 1174 case 1:
cb5b57a9 1175 case 2:
2323736d
CK
1176 break;
1177 default:
2159ad93
MB
1178 adsp_err(dsp, "%s: unknown file format %d\n",
1179 file, header->ver);
1180 goto out_fw;
1181 }
2323736d 1182
3626992a 1183 adsp_info(dsp, "Firmware version: %d\n", header->ver);
2323736d 1184 dsp->fw_ver = header->ver;
2159ad93
MB
1185
1186 if (header->core != dsp->type) {
1187 adsp_err(dsp, "%s: invalid core %d != %d\n",
1188 file, header->core, dsp->type);
1189 goto out_fw;
1190 }
1191
1192 switch (dsp->type) {
1193 case WMFW_ADSP1:
1194 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1195 adsp1_sizes = (void *)&(header[1]);
1196 footer = (void *)&(adsp1_sizes[1]);
1197 sizes = sizeof(*adsp1_sizes);
1198
1199 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
1200 file, le32_to_cpu(adsp1_sizes->dm),
1201 le32_to_cpu(adsp1_sizes->pm),
1202 le32_to_cpu(adsp1_sizes->zm));
1203 break;
1204
1205 case WMFW_ADSP2:
1206 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
1207 adsp2_sizes = (void *)&(header[1]);
1208 footer = (void *)&(adsp2_sizes[1]);
1209 sizes = sizeof(*adsp2_sizes);
1210
1211 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
1212 file, le32_to_cpu(adsp2_sizes->xm),
1213 le32_to_cpu(adsp2_sizes->ym),
1214 le32_to_cpu(adsp2_sizes->pm),
1215 le32_to_cpu(adsp2_sizes->zm));
1216 break;
1217
1218 default:
6c452bda 1219 WARN(1, "Unknown DSP type");
2159ad93
MB
1220 goto out_fw;
1221 }
1222
1223 if (le32_to_cpu(header->len) != sizeof(*header) +
1224 sizes + sizeof(*footer)) {
1225 adsp_err(dsp, "%s: unexpected header length %d\n",
1226 file, le32_to_cpu(header->len));
1227 goto out_fw;
1228 }
1229
1230 adsp_dbg(dsp, "%s: timestamp %llu\n", file,
1231 le64_to_cpu(footer->timestamp));
1232
1233 while (pos < firmware->size &&
1234 pos - firmware->size > sizeof(*region)) {
1235 region = (void *)&(firmware->data[pos]);
1236 region_name = "Unknown";
1237 reg = 0;
1238 text = NULL;
1239 offset = le32_to_cpu(region->offset) & 0xffffff;
1240 type = be32_to_cpu(region->type) & 0xff;
1241 mem = wm_adsp_find_region(dsp, type);
7585a5b0 1242
2159ad93
MB
1243 switch (type) {
1244 case WMFW_NAME_TEXT:
1245 region_name = "Firmware name";
1246 text = kzalloc(le32_to_cpu(region->len) + 1,
1247 GFP_KERNEL);
1248 break;
2323736d
CK
1249 case WMFW_ALGORITHM_DATA:
1250 region_name = "Algorithm";
1251 ret = wm_adsp_parse_coeff(dsp, region);
1252 if (ret != 0)
1253 goto out_fw;
1254 break;
2159ad93
MB
1255 case WMFW_INFO_TEXT:
1256 region_name = "Information";
1257 text = kzalloc(le32_to_cpu(region->len) + 1,
1258 GFP_KERNEL);
1259 break;
1260 case WMFW_ABSOLUTE:
1261 region_name = "Absolute";
1262 reg = offset;
1263 break;
1264 case WMFW_ADSP1_PM:
2159ad93 1265 region_name = "PM";
45b9ee72 1266 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1267 break;
1268 case WMFW_ADSP1_DM:
2159ad93 1269 region_name = "DM";
45b9ee72 1270 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1271 break;
1272 case WMFW_ADSP2_XM:
2159ad93 1273 region_name = "XM";
45b9ee72 1274 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1275 break;
1276 case WMFW_ADSP2_YM:
2159ad93 1277 region_name = "YM";
45b9ee72 1278 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1279 break;
1280 case WMFW_ADSP1_ZM:
2159ad93 1281 region_name = "ZM";
45b9ee72 1282 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1283 break;
1284 default:
1285 adsp_warn(dsp,
1286 "%s.%d: Unknown region type %x at %d(%x)\n",
1287 file, regions, type, pos, pos);
1288 break;
1289 }
1290
1291 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
1292 regions, le32_to_cpu(region->len), offset,
1293 region_name);
1294
1295 if (text) {
1296 memcpy(text, region->data, le32_to_cpu(region->len));
1297 adsp_info(dsp, "%s: %s\n", file, text);
1298 kfree(text);
1299 }
1300
1301 if (reg) {
cdcd7f72
CK
1302 buf = wm_adsp_buf_alloc(region->data,
1303 le32_to_cpu(region->len),
1304 &buf_list);
1305 if (!buf) {
1306 adsp_err(dsp, "Out of memory\n");
1307 ret = -ENOMEM;
1308 goto out_fw;
1309 }
c1a7898d 1310
cdcd7f72
CK
1311 ret = regmap_raw_write_async(regmap, reg, buf->buf,
1312 le32_to_cpu(region->len));
1313 if (ret != 0) {
1314 adsp_err(dsp,
1315 "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
1316 file, regions,
1317 le32_to_cpu(region->len), offset,
1318 region_name, ret);
1319 goto out_fw;
2159ad93
MB
1320 }
1321 }
1322
1323 pos += le32_to_cpu(region->len) + sizeof(*region);
1324 regions++;
1325 }
cf17c83c
MB
1326
1327 ret = regmap_async_complete(regmap);
1328 if (ret != 0) {
1329 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
1330 goto out_fw;
1331 }
1332
2159ad93
MB
1333 if (pos > firmware->size)
1334 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
1335 file, regions, pos - firmware->size);
1336
f9f55e31
RF
1337 wm_adsp_debugfs_save_wmfwname(dsp, file);
1338
2159ad93 1339out_fw:
cf17c83c
MB
1340 regmap_async_complete(regmap);
1341 wm_adsp_buf_free(&buf_list);
2159ad93
MB
1342 release_firmware(firmware);
1343out:
1344 kfree(file);
1345
1346 return ret;
1347}
1348
2323736d
CK
1349static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
1350 const struct wm_adsp_alg_region *alg_region)
1351{
1352 struct wm_coeff_ctl *ctl;
1353
1354 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1355 if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
1356 alg_region->alg == ctl->alg_region.alg &&
1357 alg_region->type == ctl->alg_region.type) {
1358 ctl->alg_region.base = alg_region->base;
1359 }
1360 }
1361}
1362
3809f001 1363static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
b618a185 1364 unsigned int pos, unsigned int len)
db40517c 1365{
b618a185
CK
1366 void *alg;
1367 int ret;
db40517c 1368 __be32 val;
db40517c 1369
3809f001 1370 if (n_algs == 0) {
b618a185
CK
1371 adsp_err(dsp, "No algorithms\n");
1372 return ERR_PTR(-EINVAL);
db40517c
MB
1373 }
1374
3809f001
CK
1375 if (n_algs > 1024) {
1376 adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
b618a185
CK
1377 return ERR_PTR(-EINVAL);
1378 }
db40517c 1379
b618a185
CK
1380 /* Read the terminator first to validate the length */
1381 ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
1382 if (ret != 0) {
1383 adsp_err(dsp, "Failed to read algorithm list end: %d\n",
1384 ret);
1385 return ERR_PTR(ret);
1386 }
db40517c 1387
b618a185
CK
1388 if (be32_to_cpu(val) != 0xbedead)
1389 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
1390 pos + len, be32_to_cpu(val));
d62f4bc6 1391
b618a185
CK
1392 alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
1393 if (!alg)
1394 return ERR_PTR(-ENOMEM);
db40517c 1395
b618a185
CK
1396 ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
1397 if (ret != 0) {
1398 adsp_err(dsp, "Failed to read algorithm list: %d\n",
1399 ret);
1400 kfree(alg);
1401 return ERR_PTR(ret);
1402 }
ac50009f 1403
b618a185
CK
1404 return alg;
1405}
ac50009f 1406
14197095
CK
1407static struct wm_adsp_alg_region *
1408 wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id)
1409{
1410 struct wm_adsp_alg_region *alg_region;
1411
1412 list_for_each_entry(alg_region, &dsp->alg_regions, list) {
1413 if (id == alg_region->alg && type == alg_region->type)
1414 return alg_region;
1415 }
1416
1417 return NULL;
1418}
1419
d9d20e17
CK
1420static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
1421 int type, __be32 id,
1422 __be32 base)
1423{
1424 struct wm_adsp_alg_region *alg_region;
1425
1426 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1427 if (!alg_region)
1428 return ERR_PTR(-ENOMEM);
1429
1430 alg_region->type = type;
1431 alg_region->alg = be32_to_cpu(id);
1432 alg_region->base = be32_to_cpu(base);
1433
1434 list_add_tail(&alg_region->list, &dsp->alg_regions);
1435
2323736d
CK
1436 if (dsp->fw_ver > 0)
1437 wm_adsp_ctl_fixup_base(dsp, alg_region);
1438
d9d20e17
CK
1439 return alg_region;
1440}
1441
b618a185
CK
1442static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
1443{
1444 struct wmfw_adsp1_id_hdr adsp1_id;
1445 struct wmfw_adsp1_alg_hdr *adsp1_alg;
3809f001 1446 struct wm_adsp_alg_region *alg_region;
b618a185
CK
1447 const struct wm_adsp_region *mem;
1448 unsigned int pos, len;
3809f001 1449 size_t n_algs;
b618a185 1450 int i, ret;
db40517c 1451
b618a185
CK
1452 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
1453 if (WARN_ON(!mem))
1454 return -EINVAL;
1455
1456 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
1457 sizeof(adsp1_id));
1458 if (ret != 0) {
1459 adsp_err(dsp, "Failed to read algorithm info: %d\n",
1460 ret);
1461 return ret;
1462 }
db40517c 1463
3809f001 1464 n_algs = be32_to_cpu(adsp1_id.n_algs);
b618a185
CK
1465 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
1466 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
1467 dsp->fw_id,
1468 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
1469 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
1470 be32_to_cpu(adsp1_id.fw.ver) & 0xff,
3809f001 1471 n_algs);
b618a185 1472
d9d20e17
CK
1473 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
1474 adsp1_id.fw.id, adsp1_id.zm);
1475 if (IS_ERR(alg_region))
1476 return PTR_ERR(alg_region);
d62f4bc6 1477
d9d20e17
CK
1478 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
1479 adsp1_id.fw.id, adsp1_id.dm);
1480 if (IS_ERR(alg_region))
1481 return PTR_ERR(alg_region);
db40517c 1482
b618a185 1483 pos = sizeof(adsp1_id) / 2;
3809f001 1484 len = (sizeof(*adsp1_alg) * n_algs) / 2;
b618a185 1485
3809f001 1486 adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
b618a185
CK
1487 if (IS_ERR(adsp1_alg))
1488 return PTR_ERR(adsp1_alg);
1489
3809f001 1490 for (i = 0; i < n_algs; i++) {
b618a185
CK
1491 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
1492 i, be32_to_cpu(adsp1_alg[i].alg.id),
1493 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
1494 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
1495 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
1496 be32_to_cpu(adsp1_alg[i].dm),
1497 be32_to_cpu(adsp1_alg[i].zm));
ac50009f 1498
d9d20e17
CK
1499 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
1500 adsp1_alg[i].alg.id,
1501 adsp1_alg[i].dm);
1502 if (IS_ERR(alg_region)) {
1503 ret = PTR_ERR(alg_region);
b618a185
CK
1504 goto out;
1505 }
2323736d
CK
1506 if (dsp->fw_ver == 0) {
1507 if (i + 1 < n_algs) {
1508 len = be32_to_cpu(adsp1_alg[i + 1].dm);
1509 len -= be32_to_cpu(adsp1_alg[i].dm);
1510 len *= 4;
1511 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1512 len, NULL, 0, 0);
2323736d
CK
1513 } else {
1514 adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
1515 be32_to_cpu(adsp1_alg[i].alg.id));
1516 }
b618a185 1517 }
ac50009f 1518
d9d20e17
CK
1519 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
1520 adsp1_alg[i].alg.id,
1521 adsp1_alg[i].zm);
1522 if (IS_ERR(alg_region)) {
1523 ret = PTR_ERR(alg_region);
b618a185
CK
1524 goto out;
1525 }
2323736d
CK
1526 if (dsp->fw_ver == 0) {
1527 if (i + 1 < n_algs) {
1528 len = be32_to_cpu(adsp1_alg[i + 1].zm);
1529 len -= be32_to_cpu(adsp1_alg[i].zm);
1530 len *= 4;
1531 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1532 len, NULL, 0, 0);
2323736d
CK
1533 } else {
1534 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1535 be32_to_cpu(adsp1_alg[i].alg.id));
1536 }
b618a185 1537 }
db40517c
MB
1538 }
1539
b618a185
CK
1540out:
1541 kfree(adsp1_alg);
1542 return ret;
1543}
db40517c 1544
b618a185
CK
1545static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
1546{
1547 struct wmfw_adsp2_id_hdr adsp2_id;
1548 struct wmfw_adsp2_alg_hdr *adsp2_alg;
3809f001 1549 struct wm_adsp_alg_region *alg_region;
b618a185
CK
1550 const struct wm_adsp_region *mem;
1551 unsigned int pos, len;
3809f001 1552 size_t n_algs;
b618a185
CK
1553 int i, ret;
1554
1555 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
1556 if (WARN_ON(!mem))
d62f4bc6 1557 return -EINVAL;
d62f4bc6 1558
b618a185
CK
1559 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
1560 sizeof(adsp2_id));
db40517c 1561 if (ret != 0) {
b618a185
CK
1562 adsp_err(dsp, "Failed to read algorithm info: %d\n",
1563 ret);
db40517c
MB
1564 return ret;
1565 }
1566
3809f001 1567 n_algs = be32_to_cpu(adsp2_id.n_algs);
b618a185 1568 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
f9f55e31 1569 dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver);
b618a185
CK
1570 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
1571 dsp->fw_id,
f9f55e31
RF
1572 (dsp->fw_id_version & 0xff0000) >> 16,
1573 (dsp->fw_id_version & 0xff00) >> 8,
1574 dsp->fw_id_version & 0xff,
3809f001 1575 n_algs);
b618a185 1576
d9d20e17
CK
1577 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
1578 adsp2_id.fw.id, adsp2_id.xm);
1579 if (IS_ERR(alg_region))
1580 return PTR_ERR(alg_region);
db40517c 1581
d9d20e17
CK
1582 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
1583 adsp2_id.fw.id, adsp2_id.ym);
1584 if (IS_ERR(alg_region))
1585 return PTR_ERR(alg_region);
db40517c 1586
d9d20e17
CK
1587 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
1588 adsp2_id.fw.id, adsp2_id.zm);
1589 if (IS_ERR(alg_region))
1590 return PTR_ERR(alg_region);
db40517c 1591
b618a185 1592 pos = sizeof(adsp2_id) / 2;
3809f001 1593 len = (sizeof(*adsp2_alg) * n_algs) / 2;
db40517c 1594
3809f001 1595 adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
b618a185
CK
1596 if (IS_ERR(adsp2_alg))
1597 return PTR_ERR(adsp2_alg);
471f4885 1598
3809f001 1599 for (i = 0; i < n_algs; i++) {
b618a185
CK
1600 adsp_info(dsp,
1601 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
1602 i, be32_to_cpu(adsp2_alg[i].alg.id),
1603 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
1604 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
1605 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
1606 be32_to_cpu(adsp2_alg[i].xm),
1607 be32_to_cpu(adsp2_alg[i].ym),
1608 be32_to_cpu(adsp2_alg[i].zm));
db40517c 1609
d9d20e17
CK
1610 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
1611 adsp2_alg[i].alg.id,
1612 adsp2_alg[i].xm);
1613 if (IS_ERR(alg_region)) {
1614 ret = PTR_ERR(alg_region);
b618a185
CK
1615 goto out;
1616 }
2323736d
CK
1617 if (dsp->fw_ver == 0) {
1618 if (i + 1 < n_algs) {
1619 len = be32_to_cpu(adsp2_alg[i + 1].xm);
1620 len -= be32_to_cpu(adsp2_alg[i].xm);
1621 len *= 4;
1622 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1623 len, NULL, 0, 0);
2323736d
CK
1624 } else {
1625 adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
1626 be32_to_cpu(adsp2_alg[i].alg.id));
1627 }
b618a185 1628 }
471f4885 1629
d9d20e17
CK
1630 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
1631 adsp2_alg[i].alg.id,
1632 adsp2_alg[i].ym);
1633 if (IS_ERR(alg_region)) {
1634 ret = PTR_ERR(alg_region);
b618a185
CK
1635 goto out;
1636 }
2323736d
CK
1637 if (dsp->fw_ver == 0) {
1638 if (i + 1 < n_algs) {
1639 len = be32_to_cpu(adsp2_alg[i + 1].ym);
1640 len -= be32_to_cpu(adsp2_alg[i].ym);
1641 len *= 4;
1642 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1643 len, NULL, 0, 0);
2323736d
CK
1644 } else {
1645 adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
1646 be32_to_cpu(adsp2_alg[i].alg.id));
1647 }
b618a185 1648 }
471f4885 1649
d9d20e17
CK
1650 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
1651 adsp2_alg[i].alg.id,
1652 adsp2_alg[i].zm);
1653 if (IS_ERR(alg_region)) {
1654 ret = PTR_ERR(alg_region);
b618a185
CK
1655 goto out;
1656 }
2323736d
CK
1657 if (dsp->fw_ver == 0) {
1658 if (i + 1 < n_algs) {
1659 len = be32_to_cpu(adsp2_alg[i + 1].zm);
1660 len -= be32_to_cpu(adsp2_alg[i].zm);
1661 len *= 4;
1662 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1663 len, NULL, 0, 0);
2323736d
CK
1664 } else {
1665 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1666 be32_to_cpu(adsp2_alg[i].alg.id));
1667 }
db40517c
MB
1668 }
1669 }
1670
1671out:
b618a185 1672 kfree(adsp2_alg);
db40517c
MB
1673 return ret;
1674}
1675
2159ad93
MB
1676static int wm_adsp_load_coeff(struct wm_adsp *dsp)
1677{
cf17c83c 1678 LIST_HEAD(buf_list);
2159ad93
MB
1679 struct regmap *regmap = dsp->regmap;
1680 struct wmfw_coeff_hdr *hdr;
1681 struct wmfw_coeff_item *blk;
1682 const struct firmware *firmware;
471f4885
MB
1683 const struct wm_adsp_region *mem;
1684 struct wm_adsp_alg_region *alg_region;
2159ad93
MB
1685 const char *region_name;
1686 int ret, pos, blocks, type, offset, reg;
1687 char *file;
cf17c83c 1688 struct wm_adsp_buf *buf;
2159ad93
MB
1689
1690 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
1691 if (file == NULL)
1692 return -ENOMEM;
1693
1023dbd9
MB
1694 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
1695 wm_adsp_fw[dsp->fw].file);
2159ad93
MB
1696 file[PAGE_SIZE - 1] = '\0';
1697
1698 ret = request_firmware(&firmware, file, dsp->dev);
1699 if (ret != 0) {
1700 adsp_warn(dsp, "Failed to request '%s'\n", file);
1701 ret = 0;
1702 goto out;
1703 }
1704 ret = -EINVAL;
1705
1706 if (sizeof(*hdr) >= firmware->size) {
1707 adsp_err(dsp, "%s: file too short, %zu bytes\n",
1708 file, firmware->size);
1709 goto out_fw;
1710 }
1711
7585a5b0 1712 hdr = (void *)&firmware->data[0];
2159ad93
MB
1713 if (memcmp(hdr->magic, "WMDR", 4) != 0) {
1714 adsp_err(dsp, "%s: invalid magic\n", file);
a4cdbec7 1715 goto out_fw;
2159ad93
MB
1716 }
1717
c712326d
MB
1718 switch (be32_to_cpu(hdr->rev) & 0xff) {
1719 case 1:
1720 break;
1721 default:
1722 adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
1723 file, be32_to_cpu(hdr->rev) & 0xff);
1724 ret = -EINVAL;
1725 goto out_fw;
1726 }
1727
2159ad93
MB
1728 adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
1729 (le32_to_cpu(hdr->ver) >> 16) & 0xff,
1730 (le32_to_cpu(hdr->ver) >> 8) & 0xff,
1731 le32_to_cpu(hdr->ver) & 0xff);
1732
1733 pos = le32_to_cpu(hdr->len);
1734
1735 blocks = 0;
1736 while (pos < firmware->size &&
1737 pos - firmware->size > sizeof(*blk)) {
7585a5b0 1738 blk = (void *)(&firmware->data[pos]);
2159ad93 1739
c712326d
MB
1740 type = le16_to_cpu(blk->type);
1741 offset = le16_to_cpu(blk->offset);
2159ad93
MB
1742
1743 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
1744 file, blocks, le32_to_cpu(blk->id),
1745 (le32_to_cpu(blk->ver) >> 16) & 0xff,
1746 (le32_to_cpu(blk->ver) >> 8) & 0xff,
1747 le32_to_cpu(blk->ver) & 0xff);
1748 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
1749 file, blocks, le32_to_cpu(blk->len), offset, type);
1750
1751 reg = 0;
1752 region_name = "Unknown";
1753 switch (type) {
c712326d
MB
1754 case (WMFW_NAME_TEXT << 8):
1755 case (WMFW_INFO_TEXT << 8):
2159ad93 1756 break;
c712326d 1757 case (WMFW_ABSOLUTE << 8):
f395a218
MB
1758 /*
1759 * Old files may use this for global
1760 * coefficients.
1761 */
1762 if (le32_to_cpu(blk->id) == dsp->fw_id &&
1763 offset == 0) {
1764 region_name = "global coefficients";
1765 mem = wm_adsp_find_region(dsp, type);
1766 if (!mem) {
1767 adsp_err(dsp, "No ZM\n");
1768 break;
1769 }
1770 reg = wm_adsp_region_to_reg(mem, 0);
1771
1772 } else {
1773 region_name = "register";
1774 reg = offset;
1775 }
2159ad93 1776 break;
471f4885
MB
1777
1778 case WMFW_ADSP1_DM:
1779 case WMFW_ADSP1_ZM:
1780 case WMFW_ADSP2_XM:
1781 case WMFW_ADSP2_YM:
1782 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
1783 file, blocks, le32_to_cpu(blk->len),
1784 type, le32_to_cpu(blk->id));
1785
1786 mem = wm_adsp_find_region(dsp, type);
1787 if (!mem) {
1788 adsp_err(dsp, "No base for region %x\n", type);
1789 break;
1790 }
1791
14197095
CK
1792 alg_region = wm_adsp_find_alg_region(dsp, type,
1793 le32_to_cpu(blk->id));
1794 if (alg_region) {
1795 reg = alg_region->base;
1796 reg = wm_adsp_region_to_reg(mem, reg);
1797 reg += offset;
1798 } else {
471f4885
MB
1799 adsp_err(dsp, "No %x for algorithm %x\n",
1800 type, le32_to_cpu(blk->id));
14197095 1801 }
471f4885
MB
1802 break;
1803
2159ad93 1804 default:
25c62f7e
MB
1805 adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
1806 file, blocks, type, pos);
2159ad93
MB
1807 break;
1808 }
1809
1810 if (reg) {
cf17c83c
MB
1811 buf = wm_adsp_buf_alloc(blk->data,
1812 le32_to_cpu(blk->len),
1813 &buf_list);
a76fefab
MB
1814 if (!buf) {
1815 adsp_err(dsp, "Out of memory\n");
f4b82812
WY
1816 ret = -ENOMEM;
1817 goto out_fw;
a76fefab
MB
1818 }
1819
20da6d5a
MB
1820 adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
1821 file, blocks, le32_to_cpu(blk->len),
1822 reg);
cf17c83c
MB
1823 ret = regmap_raw_write_async(regmap, reg, buf->buf,
1824 le32_to_cpu(blk->len));
2159ad93
MB
1825 if (ret != 0) {
1826 adsp_err(dsp,
43bc3bf6
DP
1827 "%s.%d: Failed to write to %x in %s: %d\n",
1828 file, blocks, reg, region_name, ret);
2159ad93
MB
1829 }
1830 }
1831
be951017 1832 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
2159ad93
MB
1833 blocks++;
1834 }
1835
cf17c83c
MB
1836 ret = regmap_async_complete(regmap);
1837 if (ret != 0)
1838 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
1839
2159ad93
MB
1840 if (pos > firmware->size)
1841 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
1842 file, blocks, pos - firmware->size);
1843
f9f55e31
RF
1844 wm_adsp_debugfs_save_binname(dsp, file);
1845
2159ad93 1846out_fw:
9da7a5a9 1847 regmap_async_complete(regmap);
2159ad93 1848 release_firmware(firmware);
cf17c83c 1849 wm_adsp_buf_free(&buf_list);
2159ad93
MB
1850out:
1851 kfree(file);
f4b82812 1852 return ret;
2159ad93
MB
1853}
1854
3809f001 1855int wm_adsp1_init(struct wm_adsp *dsp)
5e7a7a22 1856{
3809f001 1857 INIT_LIST_HEAD(&dsp->alg_regions);
5e7a7a22 1858
078e7183
CK
1859 mutex_init(&dsp->pwr_lock);
1860
5e7a7a22
MB
1861 return 0;
1862}
1863EXPORT_SYMBOL_GPL(wm_adsp1_init);
1864
2159ad93
MB
1865int wm_adsp1_event(struct snd_soc_dapm_widget *w,
1866 struct snd_kcontrol *kcontrol,
1867 int event)
1868{
72718517 1869 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
2159ad93
MB
1870 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1871 struct wm_adsp *dsp = &dsps[w->shift];
b0101b4f 1872 struct wm_adsp_alg_region *alg_region;
6ab2b7b4 1873 struct wm_coeff_ctl *ctl;
2159ad93 1874 int ret;
7585a5b0 1875 unsigned int val;
2159ad93 1876
00200107 1877 dsp->card = codec->component.card;
92bb4c32 1878
078e7183
CK
1879 mutex_lock(&dsp->pwr_lock);
1880
2159ad93
MB
1881 switch (event) {
1882 case SND_SOC_DAPM_POST_PMU:
1883 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1884 ADSP1_SYS_ENA, ADSP1_SYS_ENA);
1885
94e205bf
CR
1886 /*
1887 * For simplicity set the DSP clock rate to be the
1888 * SYSCLK rate rather than making it configurable.
1889 */
7585a5b0 1890 if (dsp->sysclk_reg) {
94e205bf
CR
1891 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
1892 if (ret != 0) {
1893 adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
1894 ret);
078e7183 1895 goto err_mutex;
94e205bf
CR
1896 }
1897
1898 val = (val & dsp->sysclk_mask)
1899 >> dsp->sysclk_shift;
1900
1901 ret = regmap_update_bits(dsp->regmap,
1902 dsp->base + ADSP1_CONTROL_31,
1903 ADSP1_CLK_SEL_MASK, val);
1904 if (ret != 0) {
1905 adsp_err(dsp, "Failed to set clock rate: %d\n",
1906 ret);
078e7183 1907 goto err_mutex;
94e205bf
CR
1908 }
1909 }
1910
2159ad93
MB
1911 ret = wm_adsp_load(dsp);
1912 if (ret != 0)
078e7183 1913 goto err_ena;
2159ad93 1914
b618a185 1915 ret = wm_adsp1_setup_algs(dsp);
db40517c 1916 if (ret != 0)
078e7183 1917 goto err_ena;
db40517c 1918
2159ad93
MB
1919 ret = wm_adsp_load_coeff(dsp);
1920 if (ret != 0)
078e7183 1921 goto err_ena;
2159ad93 1922
0c2e3f34 1923 /* Initialize caches for enabled and unset controls */
81ad93ec 1924 ret = wm_coeff_init_control_caches(dsp);
6ab2b7b4 1925 if (ret != 0)
078e7183 1926 goto err_ena;
6ab2b7b4 1927
0c2e3f34 1928 /* Sync set controls */
81ad93ec 1929 ret = wm_coeff_sync_controls(dsp);
6ab2b7b4 1930 if (ret != 0)
078e7183 1931 goto err_ena;
6ab2b7b4 1932
2159ad93
MB
1933 /* Start the core running */
1934 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1935 ADSP1_CORE_ENA | ADSP1_START,
1936 ADSP1_CORE_ENA | ADSP1_START);
1937 break;
1938
1939 case SND_SOC_DAPM_PRE_PMD:
1940 /* Halt the core */
1941 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1942 ADSP1_CORE_ENA | ADSP1_START, 0);
1943
1944 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
1945 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
1946
1947 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1948 ADSP1_SYS_ENA, 0);
6ab2b7b4 1949
81ad93ec 1950 list_for_each_entry(ctl, &dsp->ctl_list, list)
6ab2b7b4 1951 ctl->enabled = 0;
b0101b4f
DP
1952
1953 while (!list_empty(&dsp->alg_regions)) {
1954 alg_region = list_first_entry(&dsp->alg_regions,
1955 struct wm_adsp_alg_region,
1956 list);
1957 list_del(&alg_region->list);
1958 kfree(alg_region);
1959 }
2159ad93
MB
1960 break;
1961
1962 default:
1963 break;
1964 }
1965
078e7183
CK
1966 mutex_unlock(&dsp->pwr_lock);
1967
2159ad93
MB
1968 return 0;
1969
078e7183 1970err_ena:
2159ad93
MB
1971 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1972 ADSP1_SYS_ENA, 0);
078e7183
CK
1973err_mutex:
1974 mutex_unlock(&dsp->pwr_lock);
1975
2159ad93
MB
1976 return ret;
1977}
1978EXPORT_SYMBOL_GPL(wm_adsp1_event);
1979
1980static int wm_adsp2_ena(struct wm_adsp *dsp)
1981{
1982 unsigned int val;
1983 int ret, count;
1984
1552c325
MB
1985 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
1986 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
2159ad93
MB
1987 if (ret != 0)
1988 return ret;
1989
1990 /* Wait for the RAM to start, should be near instantaneous */
939fd1e8 1991 for (count = 0; count < 10; ++count) {
2159ad93
MB
1992 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
1993 &val);
1994 if (ret != 0)
1995 return ret;
939fd1e8
CK
1996
1997 if (val & ADSP2_RAM_RDY)
1998 break;
1999
2000 msleep(1);
2001 }
2159ad93
MB
2002
2003 if (!(val & ADSP2_RAM_RDY)) {
2004 adsp_err(dsp, "Failed to start DSP RAM\n");
2005 return -EBUSY;
2006 }
2007
2008 adsp_dbg(dsp, "RAM ready after %d polls\n", count);
2159ad93
MB
2009
2010 return 0;
2011}
2012
18b1a902 2013static void wm_adsp2_boot_work(struct work_struct *work)
2159ad93 2014{
d8a64d6a
CK
2015 struct wm_adsp *dsp = container_of(work,
2016 struct wm_adsp,
2017 boot_work);
2159ad93 2018 int ret;
d8a64d6a 2019 unsigned int val;
2159ad93 2020
078e7183
CK
2021 mutex_lock(&dsp->pwr_lock);
2022
d8a64d6a
CK
2023 /*
2024 * For simplicity set the DSP clock rate to be the
2025 * SYSCLK rate rather than making it configurable.
2026 */
2027 ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
2028 if (ret != 0) {
2029 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
078e7183 2030 goto err_mutex;
d8a64d6a
CK
2031 }
2032 val = (val & ARIZONA_SYSCLK_FREQ_MASK)
2033 >> ARIZONA_SYSCLK_FREQ_SHIFT;
92bb4c32 2034
d8a64d6a
CK
2035 ret = regmap_update_bits_async(dsp->regmap,
2036 dsp->base + ADSP2_CLOCKING,
2037 ADSP2_CLK_SEL_MASK, val);
2038 if (ret != 0) {
2039 adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
078e7183 2040 goto err_mutex;
d8a64d6a 2041 }
dd49e2c8 2042
d8a64d6a
CK
2043 ret = wm_adsp2_ena(dsp);
2044 if (ret != 0)
078e7183 2045 goto err_mutex;
2159ad93 2046
d8a64d6a
CK
2047 ret = wm_adsp_load(dsp);
2048 if (ret != 0)
078e7183 2049 goto err_ena;
2159ad93 2050
b618a185 2051 ret = wm_adsp2_setup_algs(dsp);
d8a64d6a 2052 if (ret != 0)
078e7183 2053 goto err_ena;
db40517c 2054
d8a64d6a
CK
2055 ret = wm_adsp_load_coeff(dsp);
2056 if (ret != 0)
078e7183 2057 goto err_ena;
2159ad93 2058
d8a64d6a
CK
2059 /* Initialize caches for enabled and unset controls */
2060 ret = wm_coeff_init_control_caches(dsp);
2061 if (ret != 0)
078e7183 2062 goto err_ena;
6ab2b7b4 2063
d8a64d6a
CK
2064 /* Sync set controls */
2065 ret = wm_coeff_sync_controls(dsp);
2066 if (ret != 0)
078e7183 2067 goto err_ena;
d8a64d6a 2068
d8a64d6a
CK
2069 dsp->running = true;
2070
078e7183
CK
2071 mutex_unlock(&dsp->pwr_lock);
2072
d8a64d6a 2073 return;
6ab2b7b4 2074
078e7183 2075err_ena:
d8a64d6a
CK
2076 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2077 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
078e7183
CK
2078err_mutex:
2079 mutex_unlock(&dsp->pwr_lock);
d8a64d6a
CK
2080}
2081
12db5edd
CK
2082int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
2083 struct snd_kcontrol *kcontrol, int event)
2084{
72718517 2085 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
12db5edd
CK
2086 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
2087 struct wm_adsp *dsp = &dsps[w->shift];
2088
00200107 2089 dsp->card = codec->component.card;
12db5edd
CK
2090
2091 switch (event) {
2092 case SND_SOC_DAPM_PRE_PMU:
2093 queue_work(system_unbound_wq, &dsp->boot_work);
2094 break;
2095 default:
2096 break;
cab27258 2097 }
12db5edd
CK
2098
2099 return 0;
2100}
2101EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
2102
d8a64d6a
CK
2103int wm_adsp2_event(struct snd_soc_dapm_widget *w,
2104 struct snd_kcontrol *kcontrol, int event)
2105{
72718517 2106 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
d8a64d6a
CK
2107 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
2108 struct wm_adsp *dsp = &dsps[w->shift];
2109 struct wm_adsp_alg_region *alg_region;
2110 struct wm_coeff_ctl *ctl;
2111 int ret;
2112
d8a64d6a
CK
2113 switch (event) {
2114 case SND_SOC_DAPM_POST_PMU:
d8a64d6a
CK
2115 flush_work(&dsp->boot_work);
2116
2117 if (!dsp->running)
2118 return -EIO;
6ab2b7b4 2119
d8a64d6a
CK
2120 ret = regmap_update_bits(dsp->regmap,
2121 dsp->base + ADSP2_CONTROL,
00e4c3b6
CK
2122 ADSP2_CORE_ENA | ADSP2_START,
2123 ADSP2_CORE_ENA | ADSP2_START);
2159ad93
MB
2124 if (ret != 0)
2125 goto err;
2126 break;
2127
2128 case SND_SOC_DAPM_PRE_PMD:
10337b07
RF
2129 /* Log firmware state, it can be useful for analysis */
2130 wm_adsp2_show_fw_status(dsp);
2131
078e7183
CK
2132 mutex_lock(&dsp->pwr_lock);
2133
f9f55e31
RF
2134 wm_adsp_debugfs_clear(dsp);
2135
2136 dsp->fw_id = 0;
2137 dsp->fw_id_version = 0;
1023dbd9
MB
2138 dsp->running = false;
2139
2159ad93 2140 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
a7f9be7e
MB
2141 ADSP2_SYS_ENA | ADSP2_CORE_ENA |
2142 ADSP2_START, 0);
973838a0 2143
2d30b575
MB
2144 /* Make sure DMAs are quiesced */
2145 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2146 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
2147 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2148
81ad93ec 2149 list_for_each_entry(ctl, &dsp->ctl_list, list)
6ab2b7b4 2150 ctl->enabled = 0;
6ab2b7b4 2151
471f4885
MB
2152 while (!list_empty(&dsp->alg_regions)) {
2153 alg_region = list_first_entry(&dsp->alg_regions,
2154 struct wm_adsp_alg_region,
2155 list);
2156 list_del(&alg_region->list);
2157 kfree(alg_region);
2158 }
ddbc5efe 2159
078e7183
CK
2160 mutex_unlock(&dsp->pwr_lock);
2161
ddbc5efe 2162 adsp_dbg(dsp, "Shutdown complete\n");
2159ad93
MB
2163 break;
2164
2165 default:
2166 break;
2167 }
2168
2169 return 0;
2170err:
2171 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
a7f9be7e 2172 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
2159ad93
MB
2173 return ret;
2174}
2175EXPORT_SYMBOL_GPL(wm_adsp2_event);
973838a0 2176
f5e2ce92
RF
2177int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)
2178{
f9f55e31
RF
2179 wm_adsp2_init_debugfs(dsp, codec);
2180
218e5087 2181 return snd_soc_add_codec_controls(codec,
336d0442
RF
2182 &wm_adsp_fw_controls[dsp->num - 1],
2183 1);
f5e2ce92
RF
2184}
2185EXPORT_SYMBOL_GPL(wm_adsp2_codec_probe);
2186
2187int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec)
2188{
f9f55e31
RF
2189 wm_adsp2_cleanup_debugfs(dsp);
2190
f5e2ce92
RF
2191 return 0;
2192}
2193EXPORT_SYMBOL_GPL(wm_adsp2_codec_remove);
2194
81ac58b1 2195int wm_adsp2_init(struct wm_adsp *dsp)
973838a0
MB
2196{
2197 int ret;
2198
10a2b662
MB
2199 /*
2200 * Disable the DSP memory by default when in reset for a small
2201 * power saving.
2202 */
3809f001 2203 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
10a2b662
MB
2204 ADSP2_MEM_ENA, 0);
2205 if (ret != 0) {
3809f001 2206 adsp_err(dsp, "Failed to clear memory retention: %d\n", ret);
10a2b662
MB
2207 return ret;
2208 }
2209
3809f001
CK
2210 INIT_LIST_HEAD(&dsp->alg_regions);
2211 INIT_LIST_HEAD(&dsp->ctl_list);
2212 INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
6ab2b7b4 2213
078e7183
CK
2214 mutex_init(&dsp->pwr_lock);
2215
973838a0
MB
2216 return 0;
2217}
2218EXPORT_SYMBOL_GPL(wm_adsp2_init);
0a37c6ef 2219
406abc95
CK
2220int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
2221{
2222 struct wm_adsp_compr *compr;
2223 int ret = 0;
2224
2225 mutex_lock(&dsp->pwr_lock);
2226
2227 if (wm_adsp_fw[dsp->fw].num_caps == 0) {
2228 adsp_err(dsp, "Firmware does not support compressed API\n");
2229 ret = -ENXIO;
2230 goto out;
2231 }
2232
2233 if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
2234 adsp_err(dsp, "Firmware does not support stream direction\n");
2235 ret = -EINVAL;
2236 goto out;
2237 }
2238
2239 compr = kzalloc(sizeof(*compr), GFP_KERNEL);
2240 if (!compr) {
2241 ret = -ENOMEM;
2242 goto out;
2243 }
2244
2245 compr->dsp = dsp;
2246 compr->stream = stream;
2247
2248 dsp->compr = compr;
2249
2250 stream->runtime->private_data = compr;
2251
2252out:
2253 mutex_unlock(&dsp->pwr_lock);
2254
2255 return ret;
2256}
2257EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
2258
2259int wm_adsp_compr_free(struct snd_compr_stream *stream)
2260{
2261 struct wm_adsp_compr *compr = stream->runtime->private_data;
2262 struct wm_adsp *dsp = compr->dsp;
2263
2264 mutex_lock(&dsp->pwr_lock);
2265
2266 dsp->compr = NULL;
2267
2268 kfree(compr);
2269
2270 mutex_unlock(&dsp->pwr_lock);
2271
2272 return 0;
2273}
2274EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
2275
2276static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
2277 struct snd_compr_params *params)
2278{
2279 struct wm_adsp_compr *compr = stream->runtime->private_data;
2280 struct wm_adsp *dsp = compr->dsp;
2281 const struct wm_adsp_fw_caps *caps;
2282 const struct snd_codec_desc *desc;
2283 int i, j;
2284
2285 if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
2286 params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
2287 params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
2288 params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
2289 params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
2290 adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n",
2291 params->buffer.fragment_size,
2292 params->buffer.fragments);
2293
2294 return -EINVAL;
2295 }
2296
2297 for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
2298 caps = &wm_adsp_fw[dsp->fw].caps[i];
2299 desc = &caps->desc;
2300
2301 if (caps->id != params->codec.id)
2302 continue;
2303
2304 if (stream->direction == SND_COMPRESS_PLAYBACK) {
2305 if (desc->max_ch < params->codec.ch_out)
2306 continue;
2307 } else {
2308 if (desc->max_ch < params->codec.ch_in)
2309 continue;
2310 }
2311
2312 if (!(desc->formats & (1 << params->codec.format)))
2313 continue;
2314
2315 for (j = 0; j < desc->num_sample_rates; ++j)
2316 if (desc->sample_rates[j] == params->codec.sample_rate)
2317 return 0;
2318 }
2319
2320 adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
2321 params->codec.id, params->codec.ch_in, params->codec.ch_out,
2322 params->codec.sample_rate, params->codec.format);
2323 return -EINVAL;
2324}
2325
2326int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
2327 struct snd_compr_params *params)
2328{
2329 struct wm_adsp_compr *compr = stream->runtime->private_data;
2330 int ret;
2331
2332 ret = wm_adsp_compr_check_params(stream, params);
2333 if (ret)
2334 return ret;
2335
2336 compr->size = params->buffer;
2337
2338 adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n",
2339 compr->size.fragment_size, compr->size.fragments);
2340
2341 return 0;
2342}
2343EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
2344
2345int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
2346 struct snd_compr_caps *caps)
2347{
2348 struct wm_adsp_compr *compr = stream->runtime->private_data;
2349 int fw = compr->dsp->fw;
2350 int i;
2351
2352 if (wm_adsp_fw[fw].caps) {
2353 for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
2354 caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
2355
2356 caps->num_codecs = i;
2357 caps->direction = wm_adsp_fw[fw].compr_direction;
2358
2359 caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
2360 caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
2361 caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
2362 caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
2363 }
2364
2365 return 0;
2366}
2367EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
2368
0a37c6ef 2369MODULE_LICENSE("GPL v2");
This page took 0.641964 seconds and 5 git commands to generate.