ASoC: wm_adsp: Clean up low level control read/write functions
[deliverable/linux.git] / sound / soc / codecs / wm_adsp.c
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>
18 #include <linux/list.h>
19 #include <linux/pm.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/regmap.h>
22 #include <linux/regulator/consumer.h>
23 #include <linux/slab.h>
24 #include <linux/vmalloc.h>
25 #include <linux/workqueue.h>
26 #include <sound/core.h>
27 #include <sound/pcm.h>
28 #include <sound/pcm_params.h>
29 #include <sound/soc.h>
30 #include <sound/jack.h>
31 #include <sound/initval.h>
32 #include <sound/tlv.h>
33
34 #include <linux/mfd/arizona/registers.h>
35
36 #include "arizona.h"
37 #include "wm_adsp.h"
38
39 #define adsp_crit(_dsp, fmt, ...) \
40 dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
41 #define adsp_err(_dsp, fmt, ...) \
42 dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
43 #define adsp_warn(_dsp, fmt, ...) \
44 dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
45 #define adsp_info(_dsp, fmt, ...) \
46 dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
47 #define adsp_dbg(_dsp, fmt, ...) \
48 dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
49
50 #define ADSP1_CONTROL_1 0x00
51 #define ADSP1_CONTROL_2 0x02
52 #define ADSP1_CONTROL_3 0x03
53 #define ADSP1_CONTROL_4 0x04
54 #define ADSP1_CONTROL_5 0x06
55 #define ADSP1_CONTROL_6 0x07
56 #define ADSP1_CONTROL_7 0x08
57 #define ADSP1_CONTROL_8 0x09
58 #define ADSP1_CONTROL_9 0x0A
59 #define ADSP1_CONTROL_10 0x0B
60 #define ADSP1_CONTROL_11 0x0C
61 #define ADSP1_CONTROL_12 0x0D
62 #define ADSP1_CONTROL_13 0x0F
63 #define ADSP1_CONTROL_14 0x10
64 #define ADSP1_CONTROL_15 0x11
65 #define ADSP1_CONTROL_16 0x12
66 #define ADSP1_CONTROL_17 0x13
67 #define ADSP1_CONTROL_18 0x14
68 #define ADSP1_CONTROL_19 0x16
69 #define ADSP1_CONTROL_20 0x17
70 #define ADSP1_CONTROL_21 0x18
71 #define ADSP1_CONTROL_22 0x1A
72 #define ADSP1_CONTROL_23 0x1B
73 #define ADSP1_CONTROL_24 0x1C
74 #define ADSP1_CONTROL_25 0x1E
75 #define ADSP1_CONTROL_26 0x20
76 #define ADSP1_CONTROL_27 0x21
77 #define ADSP1_CONTROL_28 0x22
78 #define ADSP1_CONTROL_29 0x23
79 #define ADSP1_CONTROL_30 0x24
80 #define ADSP1_CONTROL_31 0x26
81
82 /*
83 * ADSP1 Control 19
84 */
85 #define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
86 #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
87 #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
88
89
90 /*
91 * ADSP1 Control 30
92 */
93 #define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */
94 #define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */
95 #define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */
96 #define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */
97 #define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
98 #define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
99 #define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
100 #define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
101 #define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
102 #define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
103 #define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
104 #define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
105 #define ADSP1_START 0x0001 /* DSP1_START */
106 #define ADSP1_START_MASK 0x0001 /* DSP1_START */
107 #define ADSP1_START_SHIFT 0 /* DSP1_START */
108 #define ADSP1_START_WIDTH 1 /* DSP1_START */
109
110 /*
111 * ADSP1 Control 31
112 */
113 #define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
114 #define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
115 #define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
116
117 #define ADSP2_CONTROL 0x0
118 #define ADSP2_CLOCKING 0x1
119 #define ADSP2_STATUS1 0x4
120 #define ADSP2_WDMA_CONFIG_1 0x30
121 #define ADSP2_WDMA_CONFIG_2 0x31
122 #define ADSP2_RDMA_CONFIG_1 0x34
123
124 /*
125 * ADSP2 Control
126 */
127
128 #define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */
129 #define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */
130 #define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */
131 #define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */
132 #define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
133 #define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
134 #define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
135 #define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
136 #define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
137 #define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
138 #define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
139 #define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
140 #define ADSP2_START 0x0001 /* DSP1_START */
141 #define ADSP2_START_MASK 0x0001 /* DSP1_START */
142 #define ADSP2_START_SHIFT 0 /* DSP1_START */
143 #define ADSP2_START_WIDTH 1 /* DSP1_START */
144
145 /*
146 * ADSP2 clocking
147 */
148 #define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
149 #define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
150 #define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
151
152 /*
153 * ADSP2 Status 1
154 */
155 #define ADSP2_RAM_RDY 0x0001
156 #define ADSP2_RAM_RDY_MASK 0x0001
157 #define ADSP2_RAM_RDY_SHIFT 0
158 #define ADSP2_RAM_RDY_WIDTH 1
159
160 struct wm_adsp_buf {
161 struct list_head list;
162 void *buf;
163 };
164
165 static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
166 struct list_head *list)
167 {
168 struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
169
170 if (buf == NULL)
171 return NULL;
172
173 buf->buf = vmalloc(len);
174 if (!buf->buf) {
175 vfree(buf);
176 return NULL;
177 }
178 memcpy(buf->buf, src, len);
179
180 if (list)
181 list_add_tail(&buf->list, list);
182
183 return buf;
184 }
185
186 static void wm_adsp_buf_free(struct list_head *list)
187 {
188 while (!list_empty(list)) {
189 struct wm_adsp_buf *buf = list_first_entry(list,
190 struct wm_adsp_buf,
191 list);
192 list_del(&buf->list);
193 vfree(buf->buf);
194 kfree(buf);
195 }
196 }
197
198 #define WM_ADSP_NUM_FW 4
199
200 #define WM_ADSP_FW_MBC_VSS 0
201 #define WM_ADSP_FW_TX 1
202 #define WM_ADSP_FW_TX_SPK 2
203 #define WM_ADSP_FW_RX_ANC 3
204
205 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
206 [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
207 [WM_ADSP_FW_TX] = "Tx",
208 [WM_ADSP_FW_TX_SPK] = "Tx Speaker",
209 [WM_ADSP_FW_RX_ANC] = "Rx ANC",
210 };
211
212 static struct {
213 const char *file;
214 } wm_adsp_fw[WM_ADSP_NUM_FW] = {
215 [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
216 [WM_ADSP_FW_TX] = { .file = "tx" },
217 [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" },
218 [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" },
219 };
220
221 struct wm_coeff_ctl_ops {
222 int (*xget)(struct snd_kcontrol *kcontrol,
223 struct snd_ctl_elem_value *ucontrol);
224 int (*xput)(struct snd_kcontrol *kcontrol,
225 struct snd_ctl_elem_value *ucontrol);
226 int (*xinfo)(struct snd_kcontrol *kcontrol,
227 struct snd_ctl_elem_info *uinfo);
228 };
229
230 struct wm_coeff_ctl {
231 const char *name;
232 struct wm_adsp_alg_region alg_region;
233 struct wm_coeff_ctl_ops ops;
234 struct wm_adsp *dsp;
235 void *private;
236 unsigned int enabled:1;
237 struct list_head list;
238 void *cache;
239 size_t len;
240 unsigned int set:1;
241 struct snd_kcontrol *kcontrol;
242 };
243
244 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
245 struct snd_ctl_elem_value *ucontrol)
246 {
247 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
248 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
249 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
250
251 ucontrol->value.integer.value[0] = dsp[e->shift_l].fw;
252
253 return 0;
254 }
255
256 static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
257 struct snd_ctl_elem_value *ucontrol)
258 {
259 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
260 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
261 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
262
263 if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
264 return 0;
265
266 if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
267 return -EINVAL;
268
269 if (dsp[e->shift_l].running)
270 return -EBUSY;
271
272 dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
273
274 return 0;
275 }
276
277 static const struct soc_enum wm_adsp_fw_enum[] = {
278 SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
279 SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
280 SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
281 SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
282 };
283
284 const struct snd_kcontrol_new wm_adsp1_fw_controls[] = {
285 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
286 wm_adsp_fw_get, wm_adsp_fw_put),
287 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
288 wm_adsp_fw_get, wm_adsp_fw_put),
289 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
290 wm_adsp_fw_get, wm_adsp_fw_put),
291 };
292 EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
293
294 #if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
295 static const struct soc_enum wm_adsp2_rate_enum[] = {
296 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
297 ARIZONA_DSP1_RATE_SHIFT, 0xf,
298 ARIZONA_RATE_ENUM_SIZE,
299 arizona_rate_text, arizona_rate_val),
300 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
301 ARIZONA_DSP1_RATE_SHIFT, 0xf,
302 ARIZONA_RATE_ENUM_SIZE,
303 arizona_rate_text, arizona_rate_val),
304 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
305 ARIZONA_DSP1_RATE_SHIFT, 0xf,
306 ARIZONA_RATE_ENUM_SIZE,
307 arizona_rate_text, arizona_rate_val),
308 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
309 ARIZONA_DSP1_RATE_SHIFT, 0xf,
310 ARIZONA_RATE_ENUM_SIZE,
311 arizona_rate_text, arizona_rate_val),
312 };
313
314 const struct snd_kcontrol_new wm_adsp2_fw_controls[] = {
315 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
316 wm_adsp_fw_get, wm_adsp_fw_put),
317 SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
318 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
319 wm_adsp_fw_get, wm_adsp_fw_put),
320 SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
321 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
322 wm_adsp_fw_get, wm_adsp_fw_put),
323 SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
324 SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
325 wm_adsp_fw_get, wm_adsp_fw_put),
326 SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
327 };
328 EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
329 #endif
330
331 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
332 int type)
333 {
334 int i;
335
336 for (i = 0; i < dsp->num_mems; i++)
337 if (dsp->mem[i].type == type)
338 return &dsp->mem[i];
339
340 return NULL;
341 }
342
343 static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
344 unsigned int offset)
345 {
346 if (WARN_ON(!mem))
347 return offset;
348 switch (mem->type) {
349 case WMFW_ADSP1_PM:
350 return mem->base + (offset * 3);
351 case WMFW_ADSP1_DM:
352 return mem->base + (offset * 2);
353 case WMFW_ADSP2_XM:
354 return mem->base + (offset * 2);
355 case WMFW_ADSP2_YM:
356 return mem->base + (offset * 2);
357 case WMFW_ADSP1_ZM:
358 return mem->base + (offset * 2);
359 default:
360 WARN(1, "Unknown memory region type");
361 return offset;
362 }
363 }
364
365 static int wm_coeff_info(struct snd_kcontrol *kcontrol,
366 struct snd_ctl_elem_info *uinfo)
367 {
368 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
369
370 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
371 uinfo->count = ctl->len;
372 return 0;
373 }
374
375 static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
376 const void *buf, size_t len)
377 {
378 struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
379 const struct wm_adsp_region *mem;
380 struct wm_adsp *dsp = ctl->dsp;
381 void *scratch;
382 int ret;
383 unsigned int reg;
384
385 mem = wm_adsp_find_region(dsp, alg_region->type);
386 if (!mem) {
387 adsp_err(dsp, "No base for region %x\n",
388 alg_region->type);
389 return -EINVAL;
390 }
391
392 reg = ctl->alg_region.base;
393 reg = wm_adsp_region_to_reg(mem, reg);
394
395 scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
396 if (!scratch)
397 return -ENOMEM;
398
399 ret = regmap_raw_write(dsp->regmap, reg, scratch,
400 ctl->len);
401 if (ret) {
402 adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
403 ctl->len, reg, ret);
404 kfree(scratch);
405 return ret;
406 }
407 adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
408
409 kfree(scratch);
410
411 return 0;
412 }
413
414 static int wm_coeff_put(struct snd_kcontrol *kcontrol,
415 struct snd_ctl_elem_value *ucontrol)
416 {
417 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
418 char *p = ucontrol->value.bytes.data;
419
420 memcpy(ctl->cache, p, ctl->len);
421
422 ctl->set = 1;
423 if (!ctl->enabled)
424 return 0;
425
426 return wm_coeff_write_control(ctl, p, ctl->len);
427 }
428
429 static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
430 void *buf, size_t len)
431 {
432 struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
433 const struct wm_adsp_region *mem;
434 struct wm_adsp *dsp = ctl->dsp;
435 void *scratch;
436 int ret;
437 unsigned int reg;
438
439 mem = wm_adsp_find_region(dsp, alg_region->type);
440 if (!mem) {
441 adsp_err(dsp, "No base for region %x\n",
442 alg_region->type);
443 return -EINVAL;
444 }
445
446 reg = ctl->alg_region.base;
447 reg = wm_adsp_region_to_reg(mem, reg);
448
449 scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
450 if (!scratch)
451 return -ENOMEM;
452
453 ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len);
454 if (ret) {
455 adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
456 ctl->len, reg, ret);
457 kfree(scratch);
458 return ret;
459 }
460 adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg);
461
462 memcpy(buf, scratch, ctl->len);
463 kfree(scratch);
464
465 return 0;
466 }
467
468 static int wm_coeff_get(struct snd_kcontrol *kcontrol,
469 struct snd_ctl_elem_value *ucontrol)
470 {
471 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
472 char *p = ucontrol->value.bytes.data;
473
474 memcpy(p, ctl->cache, ctl->len);
475 return 0;
476 }
477
478 struct wmfw_ctl_work {
479 struct wm_adsp *dsp;
480 struct wm_coeff_ctl *ctl;
481 struct work_struct work;
482 };
483
484 static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
485 {
486 struct snd_kcontrol_new *kcontrol;
487 int ret;
488
489 if (!ctl || !ctl->name)
490 return -EINVAL;
491
492 kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
493 if (!kcontrol)
494 return -ENOMEM;
495 kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
496
497 kcontrol->name = ctl->name;
498 kcontrol->info = wm_coeff_info;
499 kcontrol->get = wm_coeff_get;
500 kcontrol->put = wm_coeff_put;
501 kcontrol->private_value = (unsigned long)ctl;
502
503 ret = snd_soc_add_card_controls(dsp->card,
504 kcontrol, 1);
505 if (ret < 0)
506 goto err_kcontrol;
507
508 kfree(kcontrol);
509
510 ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card,
511 ctl->name);
512
513 list_add(&ctl->list, &dsp->ctl_list);
514
515 return 0;
516
517 err_kcontrol:
518 kfree(kcontrol);
519 return ret;
520 }
521
522 static int wm_adsp_load(struct wm_adsp *dsp)
523 {
524 LIST_HEAD(buf_list);
525 const struct firmware *firmware;
526 struct regmap *regmap = dsp->regmap;
527 unsigned int pos = 0;
528 const struct wmfw_header *header;
529 const struct wmfw_adsp1_sizes *adsp1_sizes;
530 const struct wmfw_adsp2_sizes *adsp2_sizes;
531 const struct wmfw_footer *footer;
532 const struct wmfw_region *region;
533 const struct wm_adsp_region *mem;
534 const char *region_name;
535 char *file, *text;
536 struct wm_adsp_buf *buf;
537 unsigned int reg;
538 int regions = 0;
539 int ret, offset, type, sizes;
540
541 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
542 if (file == NULL)
543 return -ENOMEM;
544
545 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
546 wm_adsp_fw[dsp->fw].file);
547 file[PAGE_SIZE - 1] = '\0';
548
549 ret = request_firmware(&firmware, file, dsp->dev);
550 if (ret != 0) {
551 adsp_err(dsp, "Failed to request '%s'\n", file);
552 goto out;
553 }
554 ret = -EINVAL;
555
556 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
557 if (pos >= firmware->size) {
558 adsp_err(dsp, "%s: file too short, %zu bytes\n",
559 file, firmware->size);
560 goto out_fw;
561 }
562
563 header = (void*)&firmware->data[0];
564
565 if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
566 adsp_err(dsp, "%s: invalid magic\n", file);
567 goto out_fw;
568 }
569
570 if (header->ver != 0) {
571 adsp_err(dsp, "%s: unknown file format %d\n",
572 file, header->ver);
573 goto out_fw;
574 }
575 adsp_info(dsp, "Firmware version: %d\n", header->ver);
576
577 if (header->core != dsp->type) {
578 adsp_err(dsp, "%s: invalid core %d != %d\n",
579 file, header->core, dsp->type);
580 goto out_fw;
581 }
582
583 switch (dsp->type) {
584 case WMFW_ADSP1:
585 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
586 adsp1_sizes = (void *)&(header[1]);
587 footer = (void *)&(adsp1_sizes[1]);
588 sizes = sizeof(*adsp1_sizes);
589
590 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
591 file, le32_to_cpu(adsp1_sizes->dm),
592 le32_to_cpu(adsp1_sizes->pm),
593 le32_to_cpu(adsp1_sizes->zm));
594 break;
595
596 case WMFW_ADSP2:
597 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
598 adsp2_sizes = (void *)&(header[1]);
599 footer = (void *)&(adsp2_sizes[1]);
600 sizes = sizeof(*adsp2_sizes);
601
602 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
603 file, le32_to_cpu(adsp2_sizes->xm),
604 le32_to_cpu(adsp2_sizes->ym),
605 le32_to_cpu(adsp2_sizes->pm),
606 le32_to_cpu(adsp2_sizes->zm));
607 break;
608
609 default:
610 WARN(1, "Unknown DSP type");
611 goto out_fw;
612 }
613
614 if (le32_to_cpu(header->len) != sizeof(*header) +
615 sizes + sizeof(*footer)) {
616 adsp_err(dsp, "%s: unexpected header length %d\n",
617 file, le32_to_cpu(header->len));
618 goto out_fw;
619 }
620
621 adsp_dbg(dsp, "%s: timestamp %llu\n", file,
622 le64_to_cpu(footer->timestamp));
623
624 while (pos < firmware->size &&
625 pos - firmware->size > sizeof(*region)) {
626 region = (void *)&(firmware->data[pos]);
627 region_name = "Unknown";
628 reg = 0;
629 text = NULL;
630 offset = le32_to_cpu(region->offset) & 0xffffff;
631 type = be32_to_cpu(region->type) & 0xff;
632 mem = wm_adsp_find_region(dsp, type);
633
634 switch (type) {
635 case WMFW_NAME_TEXT:
636 region_name = "Firmware name";
637 text = kzalloc(le32_to_cpu(region->len) + 1,
638 GFP_KERNEL);
639 break;
640 case WMFW_INFO_TEXT:
641 region_name = "Information";
642 text = kzalloc(le32_to_cpu(region->len) + 1,
643 GFP_KERNEL);
644 break;
645 case WMFW_ABSOLUTE:
646 region_name = "Absolute";
647 reg = offset;
648 break;
649 case WMFW_ADSP1_PM:
650 region_name = "PM";
651 reg = wm_adsp_region_to_reg(mem, offset);
652 break;
653 case WMFW_ADSP1_DM:
654 region_name = "DM";
655 reg = wm_adsp_region_to_reg(mem, offset);
656 break;
657 case WMFW_ADSP2_XM:
658 region_name = "XM";
659 reg = wm_adsp_region_to_reg(mem, offset);
660 break;
661 case WMFW_ADSP2_YM:
662 region_name = "YM";
663 reg = wm_adsp_region_to_reg(mem, offset);
664 break;
665 case WMFW_ADSP1_ZM:
666 region_name = "ZM";
667 reg = wm_adsp_region_to_reg(mem, offset);
668 break;
669 default:
670 adsp_warn(dsp,
671 "%s.%d: Unknown region type %x at %d(%x)\n",
672 file, regions, type, pos, pos);
673 break;
674 }
675
676 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
677 regions, le32_to_cpu(region->len), offset,
678 region_name);
679
680 if (text) {
681 memcpy(text, region->data, le32_to_cpu(region->len));
682 adsp_info(dsp, "%s: %s\n", file, text);
683 kfree(text);
684 }
685
686 if (reg) {
687 buf = wm_adsp_buf_alloc(region->data,
688 le32_to_cpu(region->len),
689 &buf_list);
690 if (!buf) {
691 adsp_err(dsp, "Out of memory\n");
692 ret = -ENOMEM;
693 goto out_fw;
694 }
695
696 ret = regmap_raw_write_async(regmap, reg, buf->buf,
697 le32_to_cpu(region->len));
698 if (ret != 0) {
699 adsp_err(dsp,
700 "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
701 file, regions,
702 le32_to_cpu(region->len), offset,
703 region_name, ret);
704 goto out_fw;
705 }
706 }
707
708 pos += le32_to_cpu(region->len) + sizeof(*region);
709 regions++;
710 }
711
712 ret = regmap_async_complete(regmap);
713 if (ret != 0) {
714 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
715 goto out_fw;
716 }
717
718 if (pos > firmware->size)
719 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
720 file, regions, pos - firmware->size);
721
722 out_fw:
723 regmap_async_complete(regmap);
724 wm_adsp_buf_free(&buf_list);
725 release_firmware(firmware);
726 out:
727 kfree(file);
728
729 return ret;
730 }
731
732 static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
733 {
734 struct wm_coeff_ctl *ctl;
735 int ret;
736
737 list_for_each_entry(ctl, &dsp->ctl_list, list) {
738 if (!ctl->enabled || ctl->set)
739 continue;
740 ret = wm_coeff_read_control(ctl,
741 ctl->cache,
742 ctl->len);
743 if (ret < 0)
744 return ret;
745 }
746
747 return 0;
748 }
749
750 static int wm_coeff_sync_controls(struct wm_adsp *dsp)
751 {
752 struct wm_coeff_ctl *ctl;
753 int ret;
754
755 list_for_each_entry(ctl, &dsp->ctl_list, list) {
756 if (!ctl->enabled)
757 continue;
758 if (ctl->set) {
759 ret = wm_coeff_write_control(ctl,
760 ctl->cache,
761 ctl->len);
762 if (ret < 0)
763 return ret;
764 }
765 }
766
767 return 0;
768 }
769
770 static void wm_adsp_ctl_work(struct work_struct *work)
771 {
772 struct wmfw_ctl_work *ctl_work = container_of(work,
773 struct wmfw_ctl_work,
774 work);
775
776 wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
777 kfree(ctl_work);
778 }
779
780 static int wm_adsp_create_control(struct wm_adsp *dsp,
781 const struct wm_adsp_alg_region *alg_region,
782 unsigned int len)
783 {
784 struct wm_coeff_ctl *ctl;
785 struct wmfw_ctl_work *ctl_work;
786 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
787 char *region_name;
788 int ret;
789
790 switch (alg_region->type) {
791 case WMFW_ADSP1_PM:
792 region_name = "PM";
793 break;
794 case WMFW_ADSP1_DM:
795 region_name = "DM";
796 break;
797 case WMFW_ADSP2_XM:
798 region_name = "XM";
799 break;
800 case WMFW_ADSP2_YM:
801 region_name = "YM";
802 break;
803 case WMFW_ADSP1_ZM:
804 region_name = "ZM";
805 break;
806 default:
807 return -EINVAL;
808 }
809
810 snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
811 dsp->num, region_name, alg_region->alg);
812
813 list_for_each_entry(ctl, &dsp->ctl_list,
814 list) {
815 if (!strcmp(ctl->name, name)) {
816 if (!ctl->enabled)
817 ctl->enabled = 1;
818 return 0;
819 }
820 }
821
822 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
823 if (!ctl)
824 return -ENOMEM;
825 ctl->alg_region = *alg_region;
826 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
827 if (!ctl->name) {
828 ret = -ENOMEM;
829 goto err_ctl;
830 }
831 ctl->enabled = 1;
832 ctl->set = 0;
833 ctl->ops.xget = wm_coeff_get;
834 ctl->ops.xput = wm_coeff_put;
835 ctl->dsp = dsp;
836
837 if (len > 512) {
838 adsp_warn(dsp, "Truncating control %s from %d\n",
839 ctl->name, len);
840 len = 512;
841 }
842 ctl->len = len;
843 ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
844 if (!ctl->cache) {
845 ret = -ENOMEM;
846 goto err_ctl_name;
847 }
848
849 ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
850 if (!ctl_work) {
851 ret = -ENOMEM;
852 goto err_ctl_cache;
853 }
854
855 ctl_work->dsp = dsp;
856 ctl_work->ctl = ctl;
857 INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
858 schedule_work(&ctl_work->work);
859
860 return 0;
861
862 err_ctl_cache:
863 kfree(ctl->cache);
864 err_ctl_name:
865 kfree(ctl->name);
866 err_ctl:
867 kfree(ctl);
868
869 return ret;
870 }
871
872 static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
873 unsigned int pos, unsigned int len)
874 {
875 void *alg;
876 int ret;
877 __be32 val;
878
879 if (n_algs == 0) {
880 adsp_err(dsp, "No algorithms\n");
881 return ERR_PTR(-EINVAL);
882 }
883
884 if (n_algs > 1024) {
885 adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
886 return ERR_PTR(-EINVAL);
887 }
888
889 /* Read the terminator first to validate the length */
890 ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
891 if (ret != 0) {
892 adsp_err(dsp, "Failed to read algorithm list end: %d\n",
893 ret);
894 return ERR_PTR(ret);
895 }
896
897 if (be32_to_cpu(val) != 0xbedead)
898 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
899 pos + len, be32_to_cpu(val));
900
901 alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
902 if (!alg)
903 return ERR_PTR(-ENOMEM);
904
905 ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
906 if (ret != 0) {
907 adsp_err(dsp, "Failed to read algorithm list: %d\n",
908 ret);
909 kfree(alg);
910 return ERR_PTR(ret);
911 }
912
913 return alg;
914 }
915
916 static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
917 {
918 struct wmfw_adsp1_id_hdr adsp1_id;
919 struct wmfw_adsp1_alg_hdr *adsp1_alg;
920 struct wm_adsp_alg_region *alg_region;
921 const struct wm_adsp_region *mem;
922 unsigned int pos, len;
923 size_t n_algs;
924 int i, ret;
925
926 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
927 if (WARN_ON(!mem))
928 return -EINVAL;
929
930 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
931 sizeof(adsp1_id));
932 if (ret != 0) {
933 adsp_err(dsp, "Failed to read algorithm info: %d\n",
934 ret);
935 return ret;
936 }
937
938 n_algs = be32_to_cpu(adsp1_id.n_algs);
939 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
940 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
941 dsp->fw_id,
942 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
943 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
944 be32_to_cpu(adsp1_id.fw.ver) & 0xff,
945 n_algs);
946
947 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
948 if (!alg_region)
949 return -ENOMEM;
950 alg_region->type = WMFW_ADSP1_ZM;
951 alg_region->alg = be32_to_cpu(adsp1_id.fw.id);
952 alg_region->base = be32_to_cpu(adsp1_id.zm);
953 list_add_tail(&alg_region->list, &dsp->alg_regions);
954
955 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
956 if (!alg_region)
957 return -ENOMEM;
958 alg_region->type = WMFW_ADSP1_DM;
959 alg_region->alg = be32_to_cpu(adsp1_id.fw.id);
960 alg_region->base = be32_to_cpu(adsp1_id.dm);
961 list_add_tail(&alg_region->list, &dsp->alg_regions);
962
963 pos = sizeof(adsp1_id) / 2;
964 len = (sizeof(*adsp1_alg) * n_algs) / 2;
965
966 adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
967 if (IS_ERR(adsp1_alg))
968 return PTR_ERR(adsp1_alg);
969
970 for (i = 0; i < n_algs; i++) {
971 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
972 i, be32_to_cpu(adsp1_alg[i].alg.id),
973 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
974 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
975 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
976 be32_to_cpu(adsp1_alg[i].dm),
977 be32_to_cpu(adsp1_alg[i].zm));
978
979 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
980 if (!alg_region) {
981 ret = -ENOMEM;
982 goto out;
983 }
984 alg_region->type = WMFW_ADSP1_DM;
985 alg_region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
986 alg_region->base = be32_to_cpu(adsp1_alg[i].dm);
987 list_add_tail(&alg_region->list, &dsp->alg_regions);
988 if (i + 1 < n_algs) {
989 len = be32_to_cpu(adsp1_alg[i + 1].dm);
990 len -= be32_to_cpu(adsp1_alg[i].dm);
991 len *= 4;
992 wm_adsp_create_control(dsp, alg_region, len);
993 } else {
994 adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
995 be32_to_cpu(adsp1_alg[i].alg.id));
996 }
997
998 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
999 if (!alg_region) {
1000 ret = -ENOMEM;
1001 goto out;
1002 }
1003 alg_region->type = WMFW_ADSP1_ZM;
1004 alg_region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
1005 alg_region->base = be32_to_cpu(adsp1_alg[i].zm);
1006 list_add_tail(&alg_region->list, &dsp->alg_regions);
1007 if (i + 1 < n_algs) {
1008 len = be32_to_cpu(adsp1_alg[i + 1].zm);
1009 len -= be32_to_cpu(adsp1_alg[i].zm);
1010 len *= 4;
1011 wm_adsp_create_control(dsp, alg_region, len);
1012 } else {
1013 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1014 be32_to_cpu(adsp1_alg[i].alg.id));
1015 }
1016 }
1017
1018 out:
1019 kfree(adsp1_alg);
1020 return ret;
1021 }
1022
1023 static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
1024 {
1025 struct wmfw_adsp2_id_hdr adsp2_id;
1026 struct wmfw_adsp2_alg_hdr *adsp2_alg;
1027 struct wm_adsp_alg_region *alg_region;
1028 const struct wm_adsp_region *mem;
1029 unsigned int pos, len;
1030 size_t n_algs;
1031 int i, ret;
1032
1033 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
1034 if (WARN_ON(!mem))
1035 return -EINVAL;
1036
1037 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
1038 sizeof(adsp2_id));
1039 if (ret != 0) {
1040 adsp_err(dsp, "Failed to read algorithm info: %d\n",
1041 ret);
1042 return ret;
1043 }
1044
1045 n_algs = be32_to_cpu(adsp2_id.n_algs);
1046 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
1047 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
1048 dsp->fw_id,
1049 (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
1050 (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
1051 be32_to_cpu(adsp2_id.fw.ver) & 0xff,
1052 n_algs);
1053
1054 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1055 if (!alg_region)
1056 return -ENOMEM;
1057 alg_region->type = WMFW_ADSP2_XM;
1058 alg_region->alg = be32_to_cpu(adsp2_id.fw.id);
1059 alg_region->base = be32_to_cpu(adsp2_id.xm);
1060 list_add_tail(&alg_region->list, &dsp->alg_regions);
1061
1062 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1063 if (!alg_region)
1064 return -ENOMEM;
1065 alg_region->type = WMFW_ADSP2_YM;
1066 alg_region->alg = be32_to_cpu(adsp2_id.fw.id);
1067 alg_region->base = be32_to_cpu(adsp2_id.ym);
1068 list_add_tail(&alg_region->list, &dsp->alg_regions);
1069
1070 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1071 if (!alg_region)
1072 return -ENOMEM;
1073 alg_region->type = WMFW_ADSP2_ZM;
1074 alg_region->alg = be32_to_cpu(adsp2_id.fw.id);
1075 alg_region->base = be32_to_cpu(adsp2_id.zm);
1076 list_add_tail(&alg_region->list, &dsp->alg_regions);
1077
1078 pos = sizeof(adsp2_id) / 2;
1079 len = (sizeof(*adsp2_alg) * n_algs) / 2;
1080
1081 adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
1082 if (IS_ERR(adsp2_alg))
1083 return PTR_ERR(adsp2_alg);
1084
1085 for (i = 0; i < n_algs; i++) {
1086 adsp_info(dsp,
1087 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
1088 i, be32_to_cpu(adsp2_alg[i].alg.id),
1089 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
1090 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
1091 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
1092 be32_to_cpu(adsp2_alg[i].xm),
1093 be32_to_cpu(adsp2_alg[i].ym),
1094 be32_to_cpu(adsp2_alg[i].zm));
1095
1096 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1097 if (!alg_region) {
1098 ret = -ENOMEM;
1099 goto out;
1100 }
1101 alg_region->type = WMFW_ADSP2_XM;
1102 alg_region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
1103 alg_region->base = be32_to_cpu(adsp2_alg[i].xm);
1104 list_add_tail(&alg_region->list, &dsp->alg_regions);
1105 if (i + 1 < n_algs) {
1106 len = be32_to_cpu(adsp2_alg[i + 1].xm);
1107 len -= be32_to_cpu(adsp2_alg[i].xm);
1108 len *= 4;
1109 wm_adsp_create_control(dsp, alg_region, len);
1110 } else {
1111 adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
1112 be32_to_cpu(adsp2_alg[i].alg.id));
1113 }
1114
1115 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1116 if (!alg_region) {
1117 ret = -ENOMEM;
1118 goto out;
1119 }
1120 alg_region->type = WMFW_ADSP2_YM;
1121 alg_region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
1122 alg_region->base = be32_to_cpu(adsp2_alg[i].ym);
1123 list_add_tail(&alg_region->list, &dsp->alg_regions);
1124 if (i + 1 < n_algs) {
1125 len = be32_to_cpu(adsp2_alg[i + 1].ym);
1126 len -= be32_to_cpu(adsp2_alg[i].ym);
1127 len *= 4;
1128 wm_adsp_create_control(dsp, alg_region, len);
1129 } else {
1130 adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
1131 be32_to_cpu(adsp2_alg[i].alg.id));
1132 }
1133
1134 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1135 if (!alg_region) {
1136 ret = -ENOMEM;
1137 goto out;
1138 }
1139 alg_region->type = WMFW_ADSP2_ZM;
1140 alg_region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
1141 alg_region->base = be32_to_cpu(adsp2_alg[i].zm);
1142 list_add_tail(&alg_region->list, &dsp->alg_regions);
1143 if (i + 1 < n_algs) {
1144 len = be32_to_cpu(adsp2_alg[i + 1].zm);
1145 len -= be32_to_cpu(adsp2_alg[i].zm);
1146 len *= 4;
1147 wm_adsp_create_control(dsp, alg_region, len);
1148 } else {
1149 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1150 be32_to_cpu(adsp2_alg[i].alg.id));
1151 }
1152 }
1153
1154 out:
1155 kfree(adsp2_alg);
1156 return ret;
1157 }
1158
1159 static int wm_adsp_load_coeff(struct wm_adsp *dsp)
1160 {
1161 LIST_HEAD(buf_list);
1162 struct regmap *regmap = dsp->regmap;
1163 struct wmfw_coeff_hdr *hdr;
1164 struct wmfw_coeff_item *blk;
1165 const struct firmware *firmware;
1166 const struct wm_adsp_region *mem;
1167 struct wm_adsp_alg_region *alg_region;
1168 const char *region_name;
1169 int ret, pos, blocks, type, offset, reg;
1170 char *file;
1171 struct wm_adsp_buf *buf;
1172
1173 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
1174 if (file == NULL)
1175 return -ENOMEM;
1176
1177 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
1178 wm_adsp_fw[dsp->fw].file);
1179 file[PAGE_SIZE - 1] = '\0';
1180
1181 ret = request_firmware(&firmware, file, dsp->dev);
1182 if (ret != 0) {
1183 adsp_warn(dsp, "Failed to request '%s'\n", file);
1184 ret = 0;
1185 goto out;
1186 }
1187 ret = -EINVAL;
1188
1189 if (sizeof(*hdr) >= firmware->size) {
1190 adsp_err(dsp, "%s: file too short, %zu bytes\n",
1191 file, firmware->size);
1192 goto out_fw;
1193 }
1194
1195 hdr = (void*)&firmware->data[0];
1196 if (memcmp(hdr->magic, "WMDR", 4) != 0) {
1197 adsp_err(dsp, "%s: invalid magic\n", file);
1198 goto out_fw;
1199 }
1200
1201 switch (be32_to_cpu(hdr->rev) & 0xff) {
1202 case 1:
1203 break;
1204 default:
1205 adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
1206 file, be32_to_cpu(hdr->rev) & 0xff);
1207 ret = -EINVAL;
1208 goto out_fw;
1209 }
1210
1211 adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
1212 (le32_to_cpu(hdr->ver) >> 16) & 0xff,
1213 (le32_to_cpu(hdr->ver) >> 8) & 0xff,
1214 le32_to_cpu(hdr->ver) & 0xff);
1215
1216 pos = le32_to_cpu(hdr->len);
1217
1218 blocks = 0;
1219 while (pos < firmware->size &&
1220 pos - firmware->size > sizeof(*blk)) {
1221 blk = (void*)(&firmware->data[pos]);
1222
1223 type = le16_to_cpu(blk->type);
1224 offset = le16_to_cpu(blk->offset);
1225
1226 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
1227 file, blocks, le32_to_cpu(blk->id),
1228 (le32_to_cpu(blk->ver) >> 16) & 0xff,
1229 (le32_to_cpu(blk->ver) >> 8) & 0xff,
1230 le32_to_cpu(blk->ver) & 0xff);
1231 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
1232 file, blocks, le32_to_cpu(blk->len), offset, type);
1233
1234 reg = 0;
1235 region_name = "Unknown";
1236 switch (type) {
1237 case (WMFW_NAME_TEXT << 8):
1238 case (WMFW_INFO_TEXT << 8):
1239 break;
1240 case (WMFW_ABSOLUTE << 8):
1241 /*
1242 * Old files may use this for global
1243 * coefficients.
1244 */
1245 if (le32_to_cpu(blk->id) == dsp->fw_id &&
1246 offset == 0) {
1247 region_name = "global coefficients";
1248 mem = wm_adsp_find_region(dsp, type);
1249 if (!mem) {
1250 adsp_err(dsp, "No ZM\n");
1251 break;
1252 }
1253 reg = wm_adsp_region_to_reg(mem, 0);
1254
1255 } else {
1256 region_name = "register";
1257 reg = offset;
1258 }
1259 break;
1260
1261 case WMFW_ADSP1_DM:
1262 case WMFW_ADSP1_ZM:
1263 case WMFW_ADSP2_XM:
1264 case WMFW_ADSP2_YM:
1265 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
1266 file, blocks, le32_to_cpu(blk->len),
1267 type, le32_to_cpu(blk->id));
1268
1269 mem = wm_adsp_find_region(dsp, type);
1270 if (!mem) {
1271 adsp_err(dsp, "No base for region %x\n", type);
1272 break;
1273 }
1274
1275 reg = 0;
1276 list_for_each_entry(alg_region,
1277 &dsp->alg_regions, list) {
1278 if (le32_to_cpu(blk->id) == alg_region->alg &&
1279 type == alg_region->type) {
1280 reg = alg_region->base;
1281 reg = wm_adsp_region_to_reg(mem,
1282 reg);
1283 reg += offset;
1284 break;
1285 }
1286 }
1287
1288 if (reg == 0)
1289 adsp_err(dsp, "No %x for algorithm %x\n",
1290 type, le32_to_cpu(blk->id));
1291 break;
1292
1293 default:
1294 adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
1295 file, blocks, type, pos);
1296 break;
1297 }
1298
1299 if (reg) {
1300 buf = wm_adsp_buf_alloc(blk->data,
1301 le32_to_cpu(blk->len),
1302 &buf_list);
1303 if (!buf) {
1304 adsp_err(dsp, "Out of memory\n");
1305 ret = -ENOMEM;
1306 goto out_fw;
1307 }
1308
1309 adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
1310 file, blocks, le32_to_cpu(blk->len),
1311 reg);
1312 ret = regmap_raw_write_async(regmap, reg, buf->buf,
1313 le32_to_cpu(blk->len));
1314 if (ret != 0) {
1315 adsp_err(dsp,
1316 "%s.%d: Failed to write to %x in %s: %d\n",
1317 file, blocks, reg, region_name, ret);
1318 }
1319 }
1320
1321 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
1322 blocks++;
1323 }
1324
1325 ret = regmap_async_complete(regmap);
1326 if (ret != 0)
1327 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
1328
1329 if (pos > firmware->size)
1330 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
1331 file, blocks, pos - firmware->size);
1332
1333 out_fw:
1334 regmap_async_complete(regmap);
1335 release_firmware(firmware);
1336 wm_adsp_buf_free(&buf_list);
1337 out:
1338 kfree(file);
1339 return ret;
1340 }
1341
1342 int wm_adsp1_init(struct wm_adsp *dsp)
1343 {
1344 INIT_LIST_HEAD(&dsp->alg_regions);
1345
1346 return 0;
1347 }
1348 EXPORT_SYMBOL_GPL(wm_adsp1_init);
1349
1350 int wm_adsp1_event(struct snd_soc_dapm_widget *w,
1351 struct snd_kcontrol *kcontrol,
1352 int event)
1353 {
1354 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1355 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1356 struct wm_adsp *dsp = &dsps[w->shift];
1357 struct wm_adsp_alg_region *alg_region;
1358 struct wm_coeff_ctl *ctl;
1359 int ret;
1360 int val;
1361
1362 dsp->card = codec->component.card;
1363
1364 switch (event) {
1365 case SND_SOC_DAPM_POST_PMU:
1366 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1367 ADSP1_SYS_ENA, ADSP1_SYS_ENA);
1368
1369 /*
1370 * For simplicity set the DSP clock rate to be the
1371 * SYSCLK rate rather than making it configurable.
1372 */
1373 if(dsp->sysclk_reg) {
1374 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
1375 if (ret != 0) {
1376 adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
1377 ret);
1378 return ret;
1379 }
1380
1381 val = (val & dsp->sysclk_mask)
1382 >> dsp->sysclk_shift;
1383
1384 ret = regmap_update_bits(dsp->regmap,
1385 dsp->base + ADSP1_CONTROL_31,
1386 ADSP1_CLK_SEL_MASK, val);
1387 if (ret != 0) {
1388 adsp_err(dsp, "Failed to set clock rate: %d\n",
1389 ret);
1390 return ret;
1391 }
1392 }
1393
1394 ret = wm_adsp_load(dsp);
1395 if (ret != 0)
1396 goto err;
1397
1398 ret = wm_adsp1_setup_algs(dsp);
1399 if (ret != 0)
1400 goto err;
1401
1402 ret = wm_adsp_load_coeff(dsp);
1403 if (ret != 0)
1404 goto err;
1405
1406 /* Initialize caches for enabled and unset controls */
1407 ret = wm_coeff_init_control_caches(dsp);
1408 if (ret != 0)
1409 goto err;
1410
1411 /* Sync set controls */
1412 ret = wm_coeff_sync_controls(dsp);
1413 if (ret != 0)
1414 goto err;
1415
1416 /* Start the core running */
1417 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1418 ADSP1_CORE_ENA | ADSP1_START,
1419 ADSP1_CORE_ENA | ADSP1_START);
1420 break;
1421
1422 case SND_SOC_DAPM_PRE_PMD:
1423 /* Halt the core */
1424 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1425 ADSP1_CORE_ENA | ADSP1_START, 0);
1426
1427 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
1428 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
1429
1430 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1431 ADSP1_SYS_ENA, 0);
1432
1433 list_for_each_entry(ctl, &dsp->ctl_list, list)
1434 ctl->enabled = 0;
1435
1436 while (!list_empty(&dsp->alg_regions)) {
1437 alg_region = list_first_entry(&dsp->alg_regions,
1438 struct wm_adsp_alg_region,
1439 list);
1440 list_del(&alg_region->list);
1441 kfree(alg_region);
1442 }
1443 break;
1444
1445 default:
1446 break;
1447 }
1448
1449 return 0;
1450
1451 err:
1452 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1453 ADSP1_SYS_ENA, 0);
1454 return ret;
1455 }
1456 EXPORT_SYMBOL_GPL(wm_adsp1_event);
1457
1458 static int wm_adsp2_ena(struct wm_adsp *dsp)
1459 {
1460 unsigned int val;
1461 int ret, count;
1462
1463 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
1464 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
1465 if (ret != 0)
1466 return ret;
1467
1468 /* Wait for the RAM to start, should be near instantaneous */
1469 for (count = 0; count < 10; ++count) {
1470 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
1471 &val);
1472 if (ret != 0)
1473 return ret;
1474
1475 if (val & ADSP2_RAM_RDY)
1476 break;
1477
1478 msleep(1);
1479 }
1480
1481 if (!(val & ADSP2_RAM_RDY)) {
1482 adsp_err(dsp, "Failed to start DSP RAM\n");
1483 return -EBUSY;
1484 }
1485
1486 adsp_dbg(dsp, "RAM ready after %d polls\n", count);
1487
1488 return 0;
1489 }
1490
1491 static void wm_adsp2_boot_work(struct work_struct *work)
1492 {
1493 struct wm_adsp *dsp = container_of(work,
1494 struct wm_adsp,
1495 boot_work);
1496 int ret;
1497 unsigned int val;
1498
1499 /*
1500 * For simplicity set the DSP clock rate to be the
1501 * SYSCLK rate rather than making it configurable.
1502 */
1503 ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
1504 if (ret != 0) {
1505 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
1506 return;
1507 }
1508 val = (val & ARIZONA_SYSCLK_FREQ_MASK)
1509 >> ARIZONA_SYSCLK_FREQ_SHIFT;
1510
1511 ret = regmap_update_bits_async(dsp->regmap,
1512 dsp->base + ADSP2_CLOCKING,
1513 ADSP2_CLK_SEL_MASK, val);
1514 if (ret != 0) {
1515 adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
1516 return;
1517 }
1518
1519 if (dsp->dvfs) {
1520 ret = regmap_read(dsp->regmap,
1521 dsp->base + ADSP2_CLOCKING, &val);
1522 if (ret != 0) {
1523 adsp_err(dsp, "Failed to read clocking: %d\n", ret);
1524 return;
1525 }
1526
1527 if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
1528 ret = regulator_enable(dsp->dvfs);
1529 if (ret != 0) {
1530 adsp_err(dsp,
1531 "Failed to enable supply: %d\n",
1532 ret);
1533 return;
1534 }
1535
1536 ret = regulator_set_voltage(dsp->dvfs,
1537 1800000,
1538 1800000);
1539 if (ret != 0) {
1540 adsp_err(dsp,
1541 "Failed to raise supply: %d\n",
1542 ret);
1543 return;
1544 }
1545 }
1546 }
1547
1548 ret = wm_adsp2_ena(dsp);
1549 if (ret != 0)
1550 return;
1551
1552 ret = wm_adsp_load(dsp);
1553 if (ret != 0)
1554 goto err;
1555
1556 ret = wm_adsp2_setup_algs(dsp);
1557 if (ret != 0)
1558 goto err;
1559
1560 ret = wm_adsp_load_coeff(dsp);
1561 if (ret != 0)
1562 goto err;
1563
1564 /* Initialize caches for enabled and unset controls */
1565 ret = wm_coeff_init_control_caches(dsp);
1566 if (ret != 0)
1567 goto err;
1568
1569 /* Sync set controls */
1570 ret = wm_coeff_sync_controls(dsp);
1571 if (ret != 0)
1572 goto err;
1573
1574 dsp->running = true;
1575
1576 return;
1577
1578 err:
1579 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1580 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
1581 }
1582
1583 int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
1584 struct snd_kcontrol *kcontrol, int event)
1585 {
1586 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1587 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1588 struct wm_adsp *dsp = &dsps[w->shift];
1589
1590 dsp->card = codec->component.card;
1591
1592 switch (event) {
1593 case SND_SOC_DAPM_PRE_PMU:
1594 queue_work(system_unbound_wq, &dsp->boot_work);
1595 break;
1596 default:
1597 break;
1598 }
1599
1600 return 0;
1601 }
1602 EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
1603
1604 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
1605 struct snd_kcontrol *kcontrol, int event)
1606 {
1607 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1608 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1609 struct wm_adsp *dsp = &dsps[w->shift];
1610 struct wm_adsp_alg_region *alg_region;
1611 struct wm_coeff_ctl *ctl;
1612 int ret;
1613
1614 switch (event) {
1615 case SND_SOC_DAPM_POST_PMU:
1616 flush_work(&dsp->boot_work);
1617
1618 if (!dsp->running)
1619 return -EIO;
1620
1621 ret = regmap_update_bits(dsp->regmap,
1622 dsp->base + ADSP2_CONTROL,
1623 ADSP2_CORE_ENA | ADSP2_START,
1624 ADSP2_CORE_ENA | ADSP2_START);
1625 if (ret != 0)
1626 goto err;
1627 break;
1628
1629 case SND_SOC_DAPM_PRE_PMD:
1630 dsp->running = false;
1631
1632 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1633 ADSP2_SYS_ENA | ADSP2_CORE_ENA |
1634 ADSP2_START, 0);
1635
1636 /* Make sure DMAs are quiesced */
1637 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
1638 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
1639 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
1640
1641 if (dsp->dvfs) {
1642 ret = regulator_set_voltage(dsp->dvfs, 1200000,
1643 1800000);
1644 if (ret != 0)
1645 adsp_warn(dsp,
1646 "Failed to lower supply: %d\n",
1647 ret);
1648
1649 ret = regulator_disable(dsp->dvfs);
1650 if (ret != 0)
1651 adsp_err(dsp,
1652 "Failed to enable supply: %d\n",
1653 ret);
1654 }
1655
1656 list_for_each_entry(ctl, &dsp->ctl_list, list)
1657 ctl->enabled = 0;
1658
1659 while (!list_empty(&dsp->alg_regions)) {
1660 alg_region = list_first_entry(&dsp->alg_regions,
1661 struct wm_adsp_alg_region,
1662 list);
1663 list_del(&alg_region->list);
1664 kfree(alg_region);
1665 }
1666
1667 adsp_dbg(dsp, "Shutdown complete\n");
1668 break;
1669
1670 default:
1671 break;
1672 }
1673
1674 return 0;
1675 err:
1676 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1677 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
1678 return ret;
1679 }
1680 EXPORT_SYMBOL_GPL(wm_adsp2_event);
1681
1682 int wm_adsp2_init(struct wm_adsp *dsp, bool dvfs)
1683 {
1684 int ret;
1685
1686 /*
1687 * Disable the DSP memory by default when in reset for a small
1688 * power saving.
1689 */
1690 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1691 ADSP2_MEM_ENA, 0);
1692 if (ret != 0) {
1693 adsp_err(dsp, "Failed to clear memory retention: %d\n", ret);
1694 return ret;
1695 }
1696
1697 INIT_LIST_HEAD(&dsp->alg_regions);
1698 INIT_LIST_HEAD(&dsp->ctl_list);
1699 INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
1700
1701 if (dvfs) {
1702 dsp->dvfs = devm_regulator_get(dsp->dev, "DCVDD");
1703 if (IS_ERR(dsp->dvfs)) {
1704 ret = PTR_ERR(dsp->dvfs);
1705 adsp_err(dsp, "Failed to get DCVDD: %d\n", ret);
1706 return ret;
1707 }
1708
1709 ret = regulator_enable(dsp->dvfs);
1710 if (ret != 0) {
1711 adsp_err(dsp, "Failed to enable DCVDD: %d\n", ret);
1712 return ret;
1713 }
1714
1715 ret = regulator_set_voltage(dsp->dvfs, 1200000, 1800000);
1716 if (ret != 0) {
1717 adsp_err(dsp, "Failed to initialise DVFS: %d\n", ret);
1718 return ret;
1719 }
1720
1721 ret = regulator_disable(dsp->dvfs);
1722 if (ret != 0) {
1723 adsp_err(dsp, "Failed to disable DCVDD: %d\n", ret);
1724 return ret;
1725 }
1726 }
1727
1728 return 0;
1729 }
1730 EXPORT_SYMBOL_GPL(wm_adsp2_init);
1731
1732 MODULE_LICENSE("GPL v2");
This page took 0.115754 seconds and 5 git commands to generate.