ASoC: wm_adsp: Add support for DSP control flags
[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>
2159ad93
MB
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
dc91428a 36#include "arizona.h"
2159ad93
MB
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
94e205bf
CR
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
2d30b575
MB
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
2159ad93
MB
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
973838a0
MB
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
2159ad93
MB
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
cf17c83c
MB
160struct wm_adsp_buf {
161 struct list_head list;
162 void *buf;
163};
164
165static 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
cdcd7f72 173 buf->buf = vmalloc(len);
cf17c83c 174 if (!buf->buf) {
cdcd7f72 175 vfree(buf);
cf17c83c
MB
176 return NULL;
177 }
cdcd7f72 178 memcpy(buf->buf, src, len);
cf17c83c
MB
179
180 if (list)
181 list_add_tail(&buf->list, list);
182
183 return buf;
184}
185
186static 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);
cdcd7f72 193 vfree(buf->buf);
cf17c83c
MB
194 kfree(buf);
195 }
196}
197
36e8fe99 198#define WM_ADSP_NUM_FW 4
1023dbd9 199
dd84f925
MB
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
1023dbd9 205static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
dd84f925
MB
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",
1023dbd9
MB
210};
211
212static struct {
213 const char *file;
214} wm_adsp_fw[WM_ADSP_NUM_FW] = {
dd84f925
MB
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" },
1023dbd9
MB
219};
220
6ab2b7b4
DP
221struct 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
6ab2b7b4
DP
230struct wm_coeff_ctl {
231 const char *name;
2323736d 232 const char *fw_name;
3809f001 233 struct wm_adsp_alg_region alg_region;
6ab2b7b4 234 struct wm_coeff_ctl_ops ops;
3809f001 235 struct wm_adsp *dsp;
6ab2b7b4
DP
236 unsigned int enabled:1;
237 struct list_head list;
238 void *cache;
2323736d 239 unsigned int offset;
6ab2b7b4 240 size_t len;
0c2e3f34 241 unsigned int set:1;
6ab2b7b4 242 struct snd_kcontrol *kcontrol;
26c22a19 243 unsigned int flags;
6ab2b7b4
DP
244};
245
1023dbd9
MB
246static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
247 struct snd_ctl_elem_value *ucontrol)
248{
ea53bf77 249 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
1023dbd9 250 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
3809f001 251 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
1023dbd9 252
3809f001 253 ucontrol->value.integer.value[0] = dsp[e->shift_l].fw;
1023dbd9
MB
254
255 return 0;
256}
257
258static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
259 struct snd_ctl_elem_value *ucontrol)
260{
ea53bf77 261 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
1023dbd9 262 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
3809f001 263 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
1023dbd9 264
3809f001 265 if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
1023dbd9
MB
266 return 0;
267
268 if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
269 return -EINVAL;
270
3809f001 271 if (dsp[e->shift_l].running)
1023dbd9
MB
272 return -EBUSY;
273
3809f001 274 dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
1023dbd9
MB
275
276 return 0;
277}
278
279static const struct soc_enum wm_adsp_fw_enum[] = {
280 SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
281 SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
282 SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
283 SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
284};
285
b6ed61cf 286const struct snd_kcontrol_new wm_adsp1_fw_controls[] = {
1023dbd9
MB
287 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
288 wm_adsp_fw_get, wm_adsp_fw_put),
289 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
290 wm_adsp_fw_get, wm_adsp_fw_put),
291 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
292 wm_adsp_fw_get, wm_adsp_fw_put),
b6ed61cf
MB
293};
294EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
295
296#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
297static const struct soc_enum wm_adsp2_rate_enum[] = {
dc91428a
MB
298 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
299 ARIZONA_DSP1_RATE_SHIFT, 0xf,
300 ARIZONA_RATE_ENUM_SIZE,
301 arizona_rate_text, arizona_rate_val),
302 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
303 ARIZONA_DSP1_RATE_SHIFT, 0xf,
304 ARIZONA_RATE_ENUM_SIZE,
305 arizona_rate_text, arizona_rate_val),
306 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
307 ARIZONA_DSP1_RATE_SHIFT, 0xf,
308 ARIZONA_RATE_ENUM_SIZE,
309 arizona_rate_text, arizona_rate_val),
5be9c5b4 310 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
dc91428a
MB
311 ARIZONA_DSP1_RATE_SHIFT, 0xf,
312 ARIZONA_RATE_ENUM_SIZE,
313 arizona_rate_text, arizona_rate_val),
314};
315
b6ed61cf 316const struct snd_kcontrol_new wm_adsp2_fw_controls[] = {
1023dbd9
MB
317 SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
318 wm_adsp_fw_get, wm_adsp_fw_put),
b6ed61cf 319 SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
1023dbd9
MB
320 SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
321 wm_adsp_fw_get, wm_adsp_fw_put),
b6ed61cf 322 SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
1023dbd9
MB
323 SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
324 wm_adsp_fw_get, wm_adsp_fw_put),
b6ed61cf 325 SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
1023dbd9
MB
326 SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
327 wm_adsp_fw_get, wm_adsp_fw_put),
b6ed61cf 328 SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
1023dbd9 329};
b6ed61cf
MB
330EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
331#endif
2159ad93
MB
332
333static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
334 int type)
335{
336 int i;
337
338 for (i = 0; i < dsp->num_mems; i++)
339 if (dsp->mem[i].type == type)
340 return &dsp->mem[i];
341
342 return NULL;
343}
344
3809f001 345static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
45b9ee72
MB
346 unsigned int offset)
347{
3809f001 348 if (WARN_ON(!mem))
6c452bda 349 return offset;
3809f001 350 switch (mem->type) {
45b9ee72 351 case WMFW_ADSP1_PM:
3809f001 352 return mem->base + (offset * 3);
45b9ee72 353 case WMFW_ADSP1_DM:
3809f001 354 return mem->base + (offset * 2);
45b9ee72 355 case WMFW_ADSP2_XM:
3809f001 356 return mem->base + (offset * 2);
45b9ee72 357 case WMFW_ADSP2_YM:
3809f001 358 return mem->base + (offset * 2);
45b9ee72 359 case WMFW_ADSP1_ZM:
3809f001 360 return mem->base + (offset * 2);
45b9ee72 361 default:
6c452bda 362 WARN(1, "Unknown memory region type");
45b9ee72
MB
363 return offset;
364 }
365}
366
6ab2b7b4
DP
367static int wm_coeff_info(struct snd_kcontrol *kcontrol,
368 struct snd_ctl_elem_info *uinfo)
369{
370 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
371
372 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
373 uinfo->count = ctl->len;
374 return 0;
375}
376
c9f8dd71 377static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
6ab2b7b4
DP
378 const void *buf, size_t len)
379{
3809f001 380 struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
6ab2b7b4 381 const struct wm_adsp_region *mem;
3809f001 382 struct wm_adsp *dsp = ctl->dsp;
6ab2b7b4
DP
383 void *scratch;
384 int ret;
385 unsigned int reg;
386
3809f001 387 mem = wm_adsp_find_region(dsp, alg_region->type);
6ab2b7b4 388 if (!mem) {
3809f001
CK
389 adsp_err(dsp, "No base for region %x\n",
390 alg_region->type);
6ab2b7b4
DP
391 return -EINVAL;
392 }
393
2323736d 394 reg = ctl->alg_region.base + ctl->offset;
6ab2b7b4
DP
395 reg = wm_adsp_region_to_reg(mem, reg);
396
397 scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
398 if (!scratch)
399 return -ENOMEM;
400
3809f001 401 ret = regmap_raw_write(dsp->regmap, reg, scratch,
6ab2b7b4
DP
402 ctl->len);
403 if (ret) {
3809f001 404 adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
43bc3bf6 405 ctl->len, reg, ret);
6ab2b7b4
DP
406 kfree(scratch);
407 return ret;
408 }
3809f001 409 adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
6ab2b7b4
DP
410
411 kfree(scratch);
412
413 return 0;
414}
415
416static int wm_coeff_put(struct snd_kcontrol *kcontrol,
417 struct snd_ctl_elem_value *ucontrol)
418{
419 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
420 char *p = ucontrol->value.bytes.data;
421
422 memcpy(ctl->cache, p, ctl->len);
423
65d17a9c
NO
424 ctl->set = 1;
425 if (!ctl->enabled)
6ab2b7b4 426 return 0;
6ab2b7b4 427
c9f8dd71 428 return wm_coeff_write_control(ctl, p, ctl->len);
6ab2b7b4
DP
429}
430
c9f8dd71 431static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
6ab2b7b4
DP
432 void *buf, size_t len)
433{
3809f001 434 struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
6ab2b7b4 435 const struct wm_adsp_region *mem;
3809f001 436 struct wm_adsp *dsp = ctl->dsp;
6ab2b7b4
DP
437 void *scratch;
438 int ret;
439 unsigned int reg;
440
3809f001 441 mem = wm_adsp_find_region(dsp, alg_region->type);
6ab2b7b4 442 if (!mem) {
3809f001
CK
443 adsp_err(dsp, "No base for region %x\n",
444 alg_region->type);
6ab2b7b4
DP
445 return -EINVAL;
446 }
447
2323736d 448 reg = ctl->alg_region.base + ctl->offset;
6ab2b7b4
DP
449 reg = wm_adsp_region_to_reg(mem, reg);
450
451 scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
452 if (!scratch)
453 return -ENOMEM;
454
3809f001 455 ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len);
6ab2b7b4 456 if (ret) {
3809f001 457 adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
43bc3bf6 458 ctl->len, reg, ret);
6ab2b7b4
DP
459 kfree(scratch);
460 return ret;
461 }
3809f001 462 adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg);
6ab2b7b4
DP
463
464 memcpy(buf, scratch, ctl->len);
465 kfree(scratch);
466
467 return 0;
468}
469
470static int wm_coeff_get(struct snd_kcontrol *kcontrol,
471 struct snd_ctl_elem_value *ucontrol)
472{
473 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
474 char *p = ucontrol->value.bytes.data;
475
26c22a19
CK
476 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
477 if (ctl->enabled)
478 return wm_coeff_read_control(ctl, p, ctl->len);
479 else
480 return -EPERM;
481 }
482
6ab2b7b4 483 memcpy(p, ctl->cache, ctl->len);
26c22a19 484
6ab2b7b4
DP
485 return 0;
486}
487
6ab2b7b4 488struct wmfw_ctl_work {
3809f001 489 struct wm_adsp *dsp;
6ab2b7b4
DP
490 struct wm_coeff_ctl *ctl;
491 struct work_struct work;
492};
493
3809f001 494static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
6ab2b7b4
DP
495{
496 struct snd_kcontrol_new *kcontrol;
497 int ret;
498
92bb4c32 499 if (!ctl || !ctl->name)
6ab2b7b4
DP
500 return -EINVAL;
501
502 kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
503 if (!kcontrol)
504 return -ENOMEM;
505 kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
506
507 kcontrol->name = ctl->name;
508 kcontrol->info = wm_coeff_info;
509 kcontrol->get = wm_coeff_get;
510 kcontrol->put = wm_coeff_put;
511 kcontrol->private_value = (unsigned long)ctl;
512
26c22a19
CK
513 if (ctl->flags) {
514 if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE)
515 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
516 if (ctl->flags & WMFW_CTL_FLAG_READABLE)
517 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
518 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
519 kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
520 }
521
3809f001 522 ret = snd_soc_add_card_controls(dsp->card,
81ad93ec 523 kcontrol, 1);
6ab2b7b4
DP
524 if (ret < 0)
525 goto err_kcontrol;
526
527 kfree(kcontrol);
528
3809f001 529 ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card,
81ad93ec
DP
530 ctl->name);
531
6ab2b7b4
DP
532 return 0;
533
534err_kcontrol:
535 kfree(kcontrol);
536 return ret;
537}
538
b21acc1c
CK
539static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
540{
541 struct wm_coeff_ctl *ctl;
542 int ret;
543
544 list_for_each_entry(ctl, &dsp->ctl_list, list) {
545 if (!ctl->enabled || ctl->set)
546 continue;
26c22a19
CK
547 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
548 continue;
549
b21acc1c
CK
550 ret = wm_coeff_read_control(ctl,
551 ctl->cache,
552 ctl->len);
553 if (ret < 0)
554 return ret;
555 }
556
557 return 0;
558}
559
560static int wm_coeff_sync_controls(struct wm_adsp *dsp)
561{
562 struct wm_coeff_ctl *ctl;
563 int ret;
564
565 list_for_each_entry(ctl, &dsp->ctl_list, list) {
566 if (!ctl->enabled)
567 continue;
26c22a19 568 if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
b21acc1c
CK
569 ret = wm_coeff_write_control(ctl,
570 ctl->cache,
571 ctl->len);
572 if (ret < 0)
573 return ret;
574 }
575 }
576
577 return 0;
578}
579
580static void wm_adsp_ctl_work(struct work_struct *work)
581{
582 struct wmfw_ctl_work *ctl_work = container_of(work,
583 struct wmfw_ctl_work,
584 work);
585
586 wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
587 kfree(ctl_work);
588}
589
590static int wm_adsp_create_control(struct wm_adsp *dsp,
591 const struct wm_adsp_alg_region *alg_region,
2323736d 592 unsigned int offset, unsigned int len,
26c22a19
CK
593 const char *subname, unsigned int subname_len,
594 unsigned int flags)
b21acc1c
CK
595{
596 struct wm_coeff_ctl *ctl;
597 struct wmfw_ctl_work *ctl_work;
598 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
599 char *region_name;
600 int ret;
601
26c22a19
CK
602 if (flags & WMFW_CTL_FLAG_SYS)
603 return 0;
604
b21acc1c
CK
605 switch (alg_region->type) {
606 case WMFW_ADSP1_PM:
607 region_name = "PM";
608 break;
609 case WMFW_ADSP1_DM:
610 region_name = "DM";
611 break;
612 case WMFW_ADSP2_XM:
613 region_name = "XM";
614 break;
615 case WMFW_ADSP2_YM:
616 region_name = "YM";
617 break;
618 case WMFW_ADSP1_ZM:
619 region_name = "ZM";
620 break;
621 default:
2323736d 622 adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
b21acc1c
CK
623 return -EINVAL;
624 }
625
cb5b57a9
CK
626 switch (dsp->fw_ver) {
627 case 0:
628 case 1:
629 snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
630 dsp->num, region_name, alg_region->alg);
631 break;
632 default:
633 ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
634 "DSP%d%c %.12s %x", dsp->num, *region_name,
635 wm_adsp_fw_text[dsp->fw], alg_region->alg);
636
637 /* Truncate the subname from the start if it is too long */
638 if (subname) {
639 int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
640 int skip = 0;
641
642 if (subname_len > avail)
643 skip = subname_len - avail;
644
645 snprintf(name + ret,
646 SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s",
647 subname_len - skip, subname + skip);
648 }
649 break;
650 }
b21acc1c
CK
651
652 list_for_each_entry(ctl, &dsp->ctl_list,
653 list) {
654 if (!strcmp(ctl->name, name)) {
655 if (!ctl->enabled)
656 ctl->enabled = 1;
657 return 0;
658 }
659 }
660
661 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
662 if (!ctl)
663 return -ENOMEM;
2323736d 664 ctl->fw_name = wm_adsp_fw_text[dsp->fw];
b21acc1c
CK
665 ctl->alg_region = *alg_region;
666 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
667 if (!ctl->name) {
668 ret = -ENOMEM;
669 goto err_ctl;
670 }
671 ctl->enabled = 1;
672 ctl->set = 0;
673 ctl->ops.xget = wm_coeff_get;
674 ctl->ops.xput = wm_coeff_put;
675 ctl->dsp = dsp;
676
26c22a19 677 ctl->flags = flags;
2323736d 678 ctl->offset = offset;
b21acc1c
CK
679 if (len > 512) {
680 adsp_warn(dsp, "Truncating control %s from %d\n",
681 ctl->name, len);
682 len = 512;
683 }
684 ctl->len = len;
685 ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
686 if (!ctl->cache) {
687 ret = -ENOMEM;
688 goto err_ctl_name;
689 }
690
2323736d
CK
691 list_add(&ctl->list, &dsp->ctl_list);
692
b21acc1c
CK
693 ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
694 if (!ctl_work) {
695 ret = -ENOMEM;
696 goto err_ctl_cache;
697 }
698
699 ctl_work->dsp = dsp;
700 ctl_work->ctl = ctl;
701 INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
702 schedule_work(&ctl_work->work);
703
704 return 0;
705
706err_ctl_cache:
707 kfree(ctl->cache);
708err_ctl_name:
709 kfree(ctl->name);
710err_ctl:
711 kfree(ctl);
712
713 return ret;
714}
715
2323736d
CK
716struct wm_coeff_parsed_alg {
717 int id;
718 const u8 *name;
719 int name_len;
720 int ncoeff;
721};
722
723struct wm_coeff_parsed_coeff {
724 int offset;
725 int mem_type;
726 const u8 *name;
727 int name_len;
728 int ctl_type;
729 int flags;
730 int len;
731};
732
cb5b57a9
CK
733static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
734{
735 int length;
736
737 switch (bytes) {
738 case 1:
739 length = **pos;
740 break;
741 case 2:
8299ee81 742 length = le16_to_cpu(*((__le16 *)*pos));
cb5b57a9
CK
743 break;
744 default:
745 return 0;
746 }
747
748 if (str)
749 *str = *pos + bytes;
750
751 *pos += ((length + bytes) + 3) & ~0x03;
752
753 return length;
754}
755
756static int wm_coeff_parse_int(int bytes, const u8 **pos)
757{
758 int val = 0;
759
760 switch (bytes) {
761 case 2:
8299ee81 762 val = le16_to_cpu(*((__le16 *)*pos));
cb5b57a9
CK
763 break;
764 case 4:
8299ee81 765 val = le32_to_cpu(*((__le32 *)*pos));
cb5b57a9
CK
766 break;
767 default:
768 break;
769 }
770
771 *pos += bytes;
772
773 return val;
774}
775
2323736d
CK
776static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
777 struct wm_coeff_parsed_alg *blk)
778{
779 const struct wmfw_adsp_alg_data *raw;
780
cb5b57a9
CK
781 switch (dsp->fw_ver) {
782 case 0:
783 case 1:
784 raw = (const struct wmfw_adsp_alg_data *)*data;
785 *data = raw->data;
2323736d 786
cb5b57a9
CK
787 blk->id = le32_to_cpu(raw->id);
788 blk->name = raw->name;
789 blk->name_len = strlen(raw->name);
790 blk->ncoeff = le32_to_cpu(raw->ncoeff);
791 break;
792 default:
793 blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
794 blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
795 &blk->name);
796 wm_coeff_parse_string(sizeof(u16), data, NULL);
797 blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
798 break;
799 }
2323736d
CK
800
801 adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
802 adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
803 adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
804}
805
806static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
807 struct wm_coeff_parsed_coeff *blk)
808{
809 const struct wmfw_adsp_coeff_data *raw;
cb5b57a9
CK
810 const u8 *tmp;
811 int length;
2323736d 812
cb5b57a9
CK
813 switch (dsp->fw_ver) {
814 case 0:
815 case 1:
816 raw = (const struct wmfw_adsp_coeff_data *)*data;
817 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
818
819 blk->offset = le16_to_cpu(raw->hdr.offset);
820 blk->mem_type = le16_to_cpu(raw->hdr.type);
821 blk->name = raw->name;
822 blk->name_len = strlen(raw->name);
823 blk->ctl_type = le16_to_cpu(raw->ctl_type);
824 blk->flags = le16_to_cpu(raw->flags);
825 blk->len = le32_to_cpu(raw->len);
826 break;
827 default:
828 tmp = *data;
829 blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
830 blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
831 length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
832 blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
833 &blk->name);
834 wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
835 wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
836 blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
837 blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
838 blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
839
840 *data = *data + sizeof(raw->hdr) + length;
841 break;
842 }
2323736d
CK
843
844 adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
845 adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
846 adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
847 adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
848 adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
849 adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
850}
851
852static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
853 const struct wmfw_region *region)
854{
855 struct wm_adsp_alg_region alg_region = {};
856 struct wm_coeff_parsed_alg alg_blk;
857 struct wm_coeff_parsed_coeff coeff_blk;
858 const u8 *data = region->data;
859 int i, ret;
860
861 wm_coeff_parse_alg(dsp, &data, &alg_blk);
862 for (i = 0; i < alg_blk.ncoeff; i++) {
863 wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
864
865 switch (coeff_blk.ctl_type) {
866 case SNDRV_CTL_ELEM_TYPE_BYTES:
867 break;
868 default:
869 adsp_err(dsp, "Unknown control type: %d\n",
870 coeff_blk.ctl_type);
871 return -EINVAL;
872 }
873
874 alg_region.type = coeff_blk.mem_type;
875 alg_region.alg = alg_blk.id;
876
877 ret = wm_adsp_create_control(dsp, &alg_region,
878 coeff_blk.offset,
879 coeff_blk.len,
880 coeff_blk.name,
26c22a19
CK
881 coeff_blk.name_len,
882 coeff_blk.flags);
2323736d
CK
883 if (ret < 0)
884 adsp_err(dsp, "Failed to create control: %.*s, %d\n",
885 coeff_blk.name_len, coeff_blk.name, ret);
886 }
887
888 return 0;
889}
890
2159ad93
MB
891static int wm_adsp_load(struct wm_adsp *dsp)
892{
cf17c83c 893 LIST_HEAD(buf_list);
2159ad93
MB
894 const struct firmware *firmware;
895 struct regmap *regmap = dsp->regmap;
896 unsigned int pos = 0;
897 const struct wmfw_header *header;
898 const struct wmfw_adsp1_sizes *adsp1_sizes;
899 const struct wmfw_adsp2_sizes *adsp2_sizes;
900 const struct wmfw_footer *footer;
901 const struct wmfw_region *region;
902 const struct wm_adsp_region *mem;
903 const char *region_name;
904 char *file, *text;
cf17c83c 905 struct wm_adsp_buf *buf;
2159ad93
MB
906 unsigned int reg;
907 int regions = 0;
908 int ret, offset, type, sizes;
909
910 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
911 if (file == NULL)
912 return -ENOMEM;
913
1023dbd9
MB
914 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
915 wm_adsp_fw[dsp->fw].file);
2159ad93
MB
916 file[PAGE_SIZE - 1] = '\0';
917
918 ret = request_firmware(&firmware, file, dsp->dev);
919 if (ret != 0) {
920 adsp_err(dsp, "Failed to request '%s'\n", file);
921 goto out;
922 }
923 ret = -EINVAL;
924
925 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
926 if (pos >= firmware->size) {
927 adsp_err(dsp, "%s: file too short, %zu bytes\n",
928 file, firmware->size);
929 goto out_fw;
930 }
931
932 header = (void*)&firmware->data[0];
933
934 if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
935 adsp_err(dsp, "%s: invalid magic\n", file);
936 goto out_fw;
937 }
938
2323736d
CK
939 switch (header->ver) {
940 case 0:
c61e59fe
CK
941 adsp_warn(dsp, "%s: Depreciated file format %d\n",
942 file, header->ver);
943 break;
2323736d 944 case 1:
cb5b57a9 945 case 2:
2323736d
CK
946 break;
947 default:
2159ad93
MB
948 adsp_err(dsp, "%s: unknown file format %d\n",
949 file, header->ver);
950 goto out_fw;
951 }
2323736d 952
3626992a 953 adsp_info(dsp, "Firmware version: %d\n", header->ver);
2323736d 954 dsp->fw_ver = header->ver;
2159ad93
MB
955
956 if (header->core != dsp->type) {
957 adsp_err(dsp, "%s: invalid core %d != %d\n",
958 file, header->core, dsp->type);
959 goto out_fw;
960 }
961
962 switch (dsp->type) {
963 case WMFW_ADSP1:
964 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
965 adsp1_sizes = (void *)&(header[1]);
966 footer = (void *)&(adsp1_sizes[1]);
967 sizes = sizeof(*adsp1_sizes);
968
969 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
970 file, le32_to_cpu(adsp1_sizes->dm),
971 le32_to_cpu(adsp1_sizes->pm),
972 le32_to_cpu(adsp1_sizes->zm));
973 break;
974
975 case WMFW_ADSP2:
976 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
977 adsp2_sizes = (void *)&(header[1]);
978 footer = (void *)&(adsp2_sizes[1]);
979 sizes = sizeof(*adsp2_sizes);
980
981 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
982 file, le32_to_cpu(adsp2_sizes->xm),
983 le32_to_cpu(adsp2_sizes->ym),
984 le32_to_cpu(adsp2_sizes->pm),
985 le32_to_cpu(adsp2_sizes->zm));
986 break;
987
988 default:
6c452bda 989 WARN(1, "Unknown DSP type");
2159ad93
MB
990 goto out_fw;
991 }
992
993 if (le32_to_cpu(header->len) != sizeof(*header) +
994 sizes + sizeof(*footer)) {
995 adsp_err(dsp, "%s: unexpected header length %d\n",
996 file, le32_to_cpu(header->len));
997 goto out_fw;
998 }
999
1000 adsp_dbg(dsp, "%s: timestamp %llu\n", file,
1001 le64_to_cpu(footer->timestamp));
1002
1003 while (pos < firmware->size &&
1004 pos - firmware->size > sizeof(*region)) {
1005 region = (void *)&(firmware->data[pos]);
1006 region_name = "Unknown";
1007 reg = 0;
1008 text = NULL;
1009 offset = le32_to_cpu(region->offset) & 0xffffff;
1010 type = be32_to_cpu(region->type) & 0xff;
1011 mem = wm_adsp_find_region(dsp, type);
1012
1013 switch (type) {
1014 case WMFW_NAME_TEXT:
1015 region_name = "Firmware name";
1016 text = kzalloc(le32_to_cpu(region->len) + 1,
1017 GFP_KERNEL);
1018 break;
2323736d
CK
1019 case WMFW_ALGORITHM_DATA:
1020 region_name = "Algorithm";
1021 ret = wm_adsp_parse_coeff(dsp, region);
1022 if (ret != 0)
1023 goto out_fw;
1024 break;
2159ad93
MB
1025 case WMFW_INFO_TEXT:
1026 region_name = "Information";
1027 text = kzalloc(le32_to_cpu(region->len) + 1,
1028 GFP_KERNEL);
1029 break;
1030 case WMFW_ABSOLUTE:
1031 region_name = "Absolute";
1032 reg = offset;
1033 break;
1034 case WMFW_ADSP1_PM:
2159ad93 1035 region_name = "PM";
45b9ee72 1036 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1037 break;
1038 case WMFW_ADSP1_DM:
2159ad93 1039 region_name = "DM";
45b9ee72 1040 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1041 break;
1042 case WMFW_ADSP2_XM:
2159ad93 1043 region_name = "XM";
45b9ee72 1044 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1045 break;
1046 case WMFW_ADSP2_YM:
2159ad93 1047 region_name = "YM";
45b9ee72 1048 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1049 break;
1050 case WMFW_ADSP1_ZM:
2159ad93 1051 region_name = "ZM";
45b9ee72 1052 reg = wm_adsp_region_to_reg(mem, offset);
2159ad93
MB
1053 break;
1054 default:
1055 adsp_warn(dsp,
1056 "%s.%d: Unknown region type %x at %d(%x)\n",
1057 file, regions, type, pos, pos);
1058 break;
1059 }
1060
1061 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
1062 regions, le32_to_cpu(region->len), offset,
1063 region_name);
1064
1065 if (text) {
1066 memcpy(text, region->data, le32_to_cpu(region->len));
1067 adsp_info(dsp, "%s: %s\n", file, text);
1068 kfree(text);
1069 }
1070
1071 if (reg) {
cdcd7f72
CK
1072 buf = wm_adsp_buf_alloc(region->data,
1073 le32_to_cpu(region->len),
1074 &buf_list);
1075 if (!buf) {
1076 adsp_err(dsp, "Out of memory\n");
1077 ret = -ENOMEM;
1078 goto out_fw;
1079 }
c1a7898d 1080
cdcd7f72
CK
1081 ret = regmap_raw_write_async(regmap, reg, buf->buf,
1082 le32_to_cpu(region->len));
1083 if (ret != 0) {
1084 adsp_err(dsp,
1085 "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
1086 file, regions,
1087 le32_to_cpu(region->len), offset,
1088 region_name, ret);
1089 goto out_fw;
2159ad93
MB
1090 }
1091 }
1092
1093 pos += le32_to_cpu(region->len) + sizeof(*region);
1094 regions++;
1095 }
cf17c83c
MB
1096
1097 ret = regmap_async_complete(regmap);
1098 if (ret != 0) {
1099 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
1100 goto out_fw;
1101 }
1102
2159ad93
MB
1103 if (pos > firmware->size)
1104 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
1105 file, regions, pos - firmware->size);
1106
1107out_fw:
cf17c83c
MB
1108 regmap_async_complete(regmap);
1109 wm_adsp_buf_free(&buf_list);
2159ad93
MB
1110 release_firmware(firmware);
1111out:
1112 kfree(file);
1113
1114 return ret;
1115}
1116
2323736d
CK
1117static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
1118 const struct wm_adsp_alg_region *alg_region)
1119{
1120 struct wm_coeff_ctl *ctl;
1121
1122 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1123 if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
1124 alg_region->alg == ctl->alg_region.alg &&
1125 alg_region->type == ctl->alg_region.type) {
1126 ctl->alg_region.base = alg_region->base;
1127 }
1128 }
1129}
1130
3809f001 1131static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
b618a185 1132 unsigned int pos, unsigned int len)
db40517c 1133{
b618a185
CK
1134 void *alg;
1135 int ret;
db40517c 1136 __be32 val;
db40517c 1137
3809f001 1138 if (n_algs == 0) {
b618a185
CK
1139 adsp_err(dsp, "No algorithms\n");
1140 return ERR_PTR(-EINVAL);
db40517c
MB
1141 }
1142
3809f001
CK
1143 if (n_algs > 1024) {
1144 adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
b618a185
CK
1145 return ERR_PTR(-EINVAL);
1146 }
db40517c 1147
b618a185
CK
1148 /* Read the terminator first to validate the length */
1149 ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
1150 if (ret != 0) {
1151 adsp_err(dsp, "Failed to read algorithm list end: %d\n",
1152 ret);
1153 return ERR_PTR(ret);
1154 }
db40517c 1155
b618a185
CK
1156 if (be32_to_cpu(val) != 0xbedead)
1157 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
1158 pos + len, be32_to_cpu(val));
d62f4bc6 1159
b618a185
CK
1160 alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
1161 if (!alg)
1162 return ERR_PTR(-ENOMEM);
db40517c 1163
b618a185
CK
1164 ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
1165 if (ret != 0) {
1166 adsp_err(dsp, "Failed to read algorithm list: %d\n",
1167 ret);
1168 kfree(alg);
1169 return ERR_PTR(ret);
1170 }
ac50009f 1171
b618a185
CK
1172 return alg;
1173}
ac50009f 1174
d9d20e17
CK
1175static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
1176 int type, __be32 id,
1177 __be32 base)
1178{
1179 struct wm_adsp_alg_region *alg_region;
1180
1181 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1182 if (!alg_region)
1183 return ERR_PTR(-ENOMEM);
1184
1185 alg_region->type = type;
1186 alg_region->alg = be32_to_cpu(id);
1187 alg_region->base = be32_to_cpu(base);
1188
1189 list_add_tail(&alg_region->list, &dsp->alg_regions);
1190
2323736d
CK
1191 if (dsp->fw_ver > 0)
1192 wm_adsp_ctl_fixup_base(dsp, alg_region);
1193
d9d20e17
CK
1194 return alg_region;
1195}
1196
b618a185
CK
1197static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
1198{
1199 struct wmfw_adsp1_id_hdr adsp1_id;
1200 struct wmfw_adsp1_alg_hdr *adsp1_alg;
3809f001 1201 struct wm_adsp_alg_region *alg_region;
b618a185
CK
1202 const struct wm_adsp_region *mem;
1203 unsigned int pos, len;
3809f001 1204 size_t n_algs;
b618a185 1205 int i, ret;
db40517c 1206
b618a185
CK
1207 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
1208 if (WARN_ON(!mem))
1209 return -EINVAL;
1210
1211 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
1212 sizeof(adsp1_id));
1213 if (ret != 0) {
1214 adsp_err(dsp, "Failed to read algorithm info: %d\n",
1215 ret);
1216 return ret;
1217 }
db40517c 1218
3809f001 1219 n_algs = be32_to_cpu(adsp1_id.n_algs);
b618a185
CK
1220 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
1221 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
1222 dsp->fw_id,
1223 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
1224 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
1225 be32_to_cpu(adsp1_id.fw.ver) & 0xff,
3809f001 1226 n_algs);
b618a185 1227
d9d20e17
CK
1228 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
1229 adsp1_id.fw.id, adsp1_id.zm);
1230 if (IS_ERR(alg_region))
1231 return PTR_ERR(alg_region);
d62f4bc6 1232
d9d20e17
CK
1233 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
1234 adsp1_id.fw.id, adsp1_id.dm);
1235 if (IS_ERR(alg_region))
1236 return PTR_ERR(alg_region);
db40517c 1237
b618a185 1238 pos = sizeof(adsp1_id) / 2;
3809f001 1239 len = (sizeof(*adsp1_alg) * n_algs) / 2;
b618a185 1240
3809f001 1241 adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
b618a185
CK
1242 if (IS_ERR(adsp1_alg))
1243 return PTR_ERR(adsp1_alg);
1244
3809f001 1245 for (i = 0; i < n_algs; i++) {
b618a185
CK
1246 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
1247 i, be32_to_cpu(adsp1_alg[i].alg.id),
1248 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
1249 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
1250 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
1251 be32_to_cpu(adsp1_alg[i].dm),
1252 be32_to_cpu(adsp1_alg[i].zm));
ac50009f 1253
d9d20e17
CK
1254 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
1255 adsp1_alg[i].alg.id,
1256 adsp1_alg[i].dm);
1257 if (IS_ERR(alg_region)) {
1258 ret = PTR_ERR(alg_region);
b618a185
CK
1259 goto out;
1260 }
2323736d
CK
1261 if (dsp->fw_ver == 0) {
1262 if (i + 1 < n_algs) {
1263 len = be32_to_cpu(adsp1_alg[i + 1].dm);
1264 len -= be32_to_cpu(adsp1_alg[i].dm);
1265 len *= 4;
1266 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1267 len, NULL, 0, 0);
2323736d
CK
1268 } else {
1269 adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
1270 be32_to_cpu(adsp1_alg[i].alg.id));
1271 }
b618a185 1272 }
ac50009f 1273
d9d20e17
CK
1274 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
1275 adsp1_alg[i].alg.id,
1276 adsp1_alg[i].zm);
1277 if (IS_ERR(alg_region)) {
1278 ret = PTR_ERR(alg_region);
b618a185
CK
1279 goto out;
1280 }
2323736d
CK
1281 if (dsp->fw_ver == 0) {
1282 if (i + 1 < n_algs) {
1283 len = be32_to_cpu(adsp1_alg[i + 1].zm);
1284 len -= be32_to_cpu(adsp1_alg[i].zm);
1285 len *= 4;
1286 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1287 len, NULL, 0, 0);
2323736d
CK
1288 } else {
1289 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1290 be32_to_cpu(adsp1_alg[i].alg.id));
1291 }
b618a185 1292 }
db40517c
MB
1293 }
1294
b618a185
CK
1295out:
1296 kfree(adsp1_alg);
1297 return ret;
1298}
db40517c 1299
b618a185
CK
1300static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
1301{
1302 struct wmfw_adsp2_id_hdr adsp2_id;
1303 struct wmfw_adsp2_alg_hdr *adsp2_alg;
3809f001 1304 struct wm_adsp_alg_region *alg_region;
b618a185
CK
1305 const struct wm_adsp_region *mem;
1306 unsigned int pos, len;
3809f001 1307 size_t n_algs;
b618a185
CK
1308 int i, ret;
1309
1310 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
1311 if (WARN_ON(!mem))
d62f4bc6 1312 return -EINVAL;
d62f4bc6 1313
b618a185
CK
1314 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
1315 sizeof(adsp2_id));
db40517c 1316 if (ret != 0) {
b618a185
CK
1317 adsp_err(dsp, "Failed to read algorithm info: %d\n",
1318 ret);
db40517c
MB
1319 return ret;
1320 }
1321
3809f001 1322 n_algs = be32_to_cpu(adsp2_id.n_algs);
b618a185
CK
1323 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
1324 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
1325 dsp->fw_id,
1326 (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
1327 (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
1328 be32_to_cpu(adsp2_id.fw.ver) & 0xff,
3809f001 1329 n_algs);
b618a185 1330
d9d20e17
CK
1331 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
1332 adsp2_id.fw.id, adsp2_id.xm);
1333 if (IS_ERR(alg_region))
1334 return PTR_ERR(alg_region);
db40517c 1335
d9d20e17
CK
1336 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
1337 adsp2_id.fw.id, adsp2_id.ym);
1338 if (IS_ERR(alg_region))
1339 return PTR_ERR(alg_region);
db40517c 1340
d9d20e17
CK
1341 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
1342 adsp2_id.fw.id, adsp2_id.zm);
1343 if (IS_ERR(alg_region))
1344 return PTR_ERR(alg_region);
db40517c 1345
b618a185 1346 pos = sizeof(adsp2_id) / 2;
3809f001 1347 len = (sizeof(*adsp2_alg) * n_algs) / 2;
db40517c 1348
3809f001 1349 adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
b618a185
CK
1350 if (IS_ERR(adsp2_alg))
1351 return PTR_ERR(adsp2_alg);
471f4885 1352
3809f001 1353 for (i = 0; i < n_algs; i++) {
b618a185
CK
1354 adsp_info(dsp,
1355 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
1356 i, be32_to_cpu(adsp2_alg[i].alg.id),
1357 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
1358 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
1359 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
1360 be32_to_cpu(adsp2_alg[i].xm),
1361 be32_to_cpu(adsp2_alg[i].ym),
1362 be32_to_cpu(adsp2_alg[i].zm));
db40517c 1363
d9d20e17
CK
1364 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
1365 adsp2_alg[i].alg.id,
1366 adsp2_alg[i].xm);
1367 if (IS_ERR(alg_region)) {
1368 ret = PTR_ERR(alg_region);
b618a185
CK
1369 goto out;
1370 }
2323736d
CK
1371 if (dsp->fw_ver == 0) {
1372 if (i + 1 < n_algs) {
1373 len = be32_to_cpu(adsp2_alg[i + 1].xm);
1374 len -= be32_to_cpu(adsp2_alg[i].xm);
1375 len *= 4;
1376 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1377 len, NULL, 0, 0);
2323736d
CK
1378 } else {
1379 adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
1380 be32_to_cpu(adsp2_alg[i].alg.id));
1381 }
b618a185 1382 }
471f4885 1383
d9d20e17
CK
1384 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
1385 adsp2_alg[i].alg.id,
1386 adsp2_alg[i].ym);
1387 if (IS_ERR(alg_region)) {
1388 ret = PTR_ERR(alg_region);
b618a185
CK
1389 goto out;
1390 }
2323736d
CK
1391 if (dsp->fw_ver == 0) {
1392 if (i + 1 < n_algs) {
1393 len = be32_to_cpu(adsp2_alg[i + 1].ym);
1394 len -= be32_to_cpu(adsp2_alg[i].ym);
1395 len *= 4;
1396 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1397 len, NULL, 0, 0);
2323736d
CK
1398 } else {
1399 adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
1400 be32_to_cpu(adsp2_alg[i].alg.id));
1401 }
b618a185 1402 }
471f4885 1403
d9d20e17
CK
1404 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
1405 adsp2_alg[i].alg.id,
1406 adsp2_alg[i].zm);
1407 if (IS_ERR(alg_region)) {
1408 ret = PTR_ERR(alg_region);
b618a185
CK
1409 goto out;
1410 }
2323736d
CK
1411 if (dsp->fw_ver == 0) {
1412 if (i + 1 < n_algs) {
1413 len = be32_to_cpu(adsp2_alg[i + 1].zm);
1414 len -= be32_to_cpu(adsp2_alg[i].zm);
1415 len *= 4;
1416 wm_adsp_create_control(dsp, alg_region, 0,
26c22a19 1417 len, NULL, 0, 0);
2323736d
CK
1418 } else {
1419 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1420 be32_to_cpu(adsp2_alg[i].alg.id));
1421 }
db40517c
MB
1422 }
1423 }
1424
1425out:
b618a185 1426 kfree(adsp2_alg);
db40517c
MB
1427 return ret;
1428}
1429
2159ad93
MB
1430static int wm_adsp_load_coeff(struct wm_adsp *dsp)
1431{
cf17c83c 1432 LIST_HEAD(buf_list);
2159ad93
MB
1433 struct regmap *regmap = dsp->regmap;
1434 struct wmfw_coeff_hdr *hdr;
1435 struct wmfw_coeff_item *blk;
1436 const struct firmware *firmware;
471f4885
MB
1437 const struct wm_adsp_region *mem;
1438 struct wm_adsp_alg_region *alg_region;
2159ad93
MB
1439 const char *region_name;
1440 int ret, pos, blocks, type, offset, reg;
1441 char *file;
cf17c83c 1442 struct wm_adsp_buf *buf;
2159ad93
MB
1443
1444 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
1445 if (file == NULL)
1446 return -ENOMEM;
1447
1023dbd9
MB
1448 snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
1449 wm_adsp_fw[dsp->fw].file);
2159ad93
MB
1450 file[PAGE_SIZE - 1] = '\0';
1451
1452 ret = request_firmware(&firmware, file, dsp->dev);
1453 if (ret != 0) {
1454 adsp_warn(dsp, "Failed to request '%s'\n", file);
1455 ret = 0;
1456 goto out;
1457 }
1458 ret = -EINVAL;
1459
1460 if (sizeof(*hdr) >= firmware->size) {
1461 adsp_err(dsp, "%s: file too short, %zu bytes\n",
1462 file, firmware->size);
1463 goto out_fw;
1464 }
1465
1466 hdr = (void*)&firmware->data[0];
1467 if (memcmp(hdr->magic, "WMDR", 4) != 0) {
1468 adsp_err(dsp, "%s: invalid magic\n", file);
a4cdbec7 1469 goto out_fw;
2159ad93
MB
1470 }
1471
c712326d
MB
1472 switch (be32_to_cpu(hdr->rev) & 0xff) {
1473 case 1:
1474 break;
1475 default:
1476 adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
1477 file, be32_to_cpu(hdr->rev) & 0xff);
1478 ret = -EINVAL;
1479 goto out_fw;
1480 }
1481
2159ad93
MB
1482 adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
1483 (le32_to_cpu(hdr->ver) >> 16) & 0xff,
1484 (le32_to_cpu(hdr->ver) >> 8) & 0xff,
1485 le32_to_cpu(hdr->ver) & 0xff);
1486
1487 pos = le32_to_cpu(hdr->len);
1488
1489 blocks = 0;
1490 while (pos < firmware->size &&
1491 pos - firmware->size > sizeof(*blk)) {
1492 blk = (void*)(&firmware->data[pos]);
1493
c712326d
MB
1494 type = le16_to_cpu(blk->type);
1495 offset = le16_to_cpu(blk->offset);
2159ad93
MB
1496
1497 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
1498 file, blocks, le32_to_cpu(blk->id),
1499 (le32_to_cpu(blk->ver) >> 16) & 0xff,
1500 (le32_to_cpu(blk->ver) >> 8) & 0xff,
1501 le32_to_cpu(blk->ver) & 0xff);
1502 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
1503 file, blocks, le32_to_cpu(blk->len), offset, type);
1504
1505 reg = 0;
1506 region_name = "Unknown";
1507 switch (type) {
c712326d
MB
1508 case (WMFW_NAME_TEXT << 8):
1509 case (WMFW_INFO_TEXT << 8):
2159ad93 1510 break;
c712326d 1511 case (WMFW_ABSOLUTE << 8):
f395a218
MB
1512 /*
1513 * Old files may use this for global
1514 * coefficients.
1515 */
1516 if (le32_to_cpu(blk->id) == dsp->fw_id &&
1517 offset == 0) {
1518 region_name = "global coefficients";
1519 mem = wm_adsp_find_region(dsp, type);
1520 if (!mem) {
1521 adsp_err(dsp, "No ZM\n");
1522 break;
1523 }
1524 reg = wm_adsp_region_to_reg(mem, 0);
1525
1526 } else {
1527 region_name = "register";
1528 reg = offset;
1529 }
2159ad93 1530 break;
471f4885
MB
1531
1532 case WMFW_ADSP1_DM:
1533 case WMFW_ADSP1_ZM:
1534 case WMFW_ADSP2_XM:
1535 case WMFW_ADSP2_YM:
1536 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
1537 file, blocks, le32_to_cpu(blk->len),
1538 type, le32_to_cpu(blk->id));
1539
1540 mem = wm_adsp_find_region(dsp, type);
1541 if (!mem) {
1542 adsp_err(dsp, "No base for region %x\n", type);
1543 break;
1544 }
1545
1546 reg = 0;
1547 list_for_each_entry(alg_region,
1548 &dsp->alg_regions, list) {
1549 if (le32_to_cpu(blk->id) == alg_region->alg &&
1550 type == alg_region->type) {
338c5188 1551 reg = alg_region->base;
471f4885
MB
1552 reg = wm_adsp_region_to_reg(mem,
1553 reg);
338c5188 1554 reg += offset;
d733dc08 1555 break;
471f4885
MB
1556 }
1557 }
1558
1559 if (reg == 0)
1560 adsp_err(dsp, "No %x for algorithm %x\n",
1561 type, le32_to_cpu(blk->id));
1562 break;
1563
2159ad93 1564 default:
25c62f7e
MB
1565 adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
1566 file, blocks, type, pos);
2159ad93
MB
1567 break;
1568 }
1569
1570 if (reg) {
cf17c83c
MB
1571 buf = wm_adsp_buf_alloc(blk->data,
1572 le32_to_cpu(blk->len),
1573 &buf_list);
a76fefab
MB
1574 if (!buf) {
1575 adsp_err(dsp, "Out of memory\n");
f4b82812
WY
1576 ret = -ENOMEM;
1577 goto out_fw;
a76fefab
MB
1578 }
1579
20da6d5a
MB
1580 adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
1581 file, blocks, le32_to_cpu(blk->len),
1582 reg);
cf17c83c
MB
1583 ret = regmap_raw_write_async(regmap, reg, buf->buf,
1584 le32_to_cpu(blk->len));
2159ad93
MB
1585 if (ret != 0) {
1586 adsp_err(dsp,
43bc3bf6
DP
1587 "%s.%d: Failed to write to %x in %s: %d\n",
1588 file, blocks, reg, region_name, ret);
2159ad93
MB
1589 }
1590 }
1591
be951017 1592 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
2159ad93
MB
1593 blocks++;
1594 }
1595
cf17c83c
MB
1596 ret = regmap_async_complete(regmap);
1597 if (ret != 0)
1598 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
1599
2159ad93
MB
1600 if (pos > firmware->size)
1601 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
1602 file, blocks, pos - firmware->size);
1603
1604out_fw:
9da7a5a9 1605 regmap_async_complete(regmap);
2159ad93 1606 release_firmware(firmware);
cf17c83c 1607 wm_adsp_buf_free(&buf_list);
2159ad93
MB
1608out:
1609 kfree(file);
f4b82812 1610 return ret;
2159ad93
MB
1611}
1612
3809f001 1613int wm_adsp1_init(struct wm_adsp *dsp)
5e7a7a22 1614{
3809f001 1615 INIT_LIST_HEAD(&dsp->alg_regions);
5e7a7a22
MB
1616
1617 return 0;
1618}
1619EXPORT_SYMBOL_GPL(wm_adsp1_init);
1620
2159ad93
MB
1621int wm_adsp1_event(struct snd_soc_dapm_widget *w,
1622 struct snd_kcontrol *kcontrol,
1623 int event)
1624{
72718517 1625 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
2159ad93
MB
1626 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1627 struct wm_adsp *dsp = &dsps[w->shift];
b0101b4f 1628 struct wm_adsp_alg_region *alg_region;
6ab2b7b4 1629 struct wm_coeff_ctl *ctl;
2159ad93 1630 int ret;
94e205bf 1631 int val;
2159ad93 1632
00200107 1633 dsp->card = codec->component.card;
92bb4c32 1634
2159ad93
MB
1635 switch (event) {
1636 case SND_SOC_DAPM_POST_PMU:
1637 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1638 ADSP1_SYS_ENA, ADSP1_SYS_ENA);
1639
94e205bf
CR
1640 /*
1641 * For simplicity set the DSP clock rate to be the
1642 * SYSCLK rate rather than making it configurable.
1643 */
1644 if(dsp->sysclk_reg) {
1645 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
1646 if (ret != 0) {
1647 adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
1648 ret);
1649 return ret;
1650 }
1651
1652 val = (val & dsp->sysclk_mask)
1653 >> dsp->sysclk_shift;
1654
1655 ret = regmap_update_bits(dsp->regmap,
1656 dsp->base + ADSP1_CONTROL_31,
1657 ADSP1_CLK_SEL_MASK, val);
1658 if (ret != 0) {
1659 adsp_err(dsp, "Failed to set clock rate: %d\n",
1660 ret);
1661 return ret;
1662 }
1663 }
1664
2159ad93
MB
1665 ret = wm_adsp_load(dsp);
1666 if (ret != 0)
1667 goto err;
1668
b618a185 1669 ret = wm_adsp1_setup_algs(dsp);
db40517c
MB
1670 if (ret != 0)
1671 goto err;
1672
2159ad93
MB
1673 ret = wm_adsp_load_coeff(dsp);
1674 if (ret != 0)
1675 goto err;
1676
0c2e3f34 1677 /* Initialize caches for enabled and unset controls */
81ad93ec 1678 ret = wm_coeff_init_control_caches(dsp);
6ab2b7b4
DP
1679 if (ret != 0)
1680 goto err;
1681
0c2e3f34 1682 /* Sync set controls */
81ad93ec 1683 ret = wm_coeff_sync_controls(dsp);
6ab2b7b4
DP
1684 if (ret != 0)
1685 goto err;
1686
2159ad93
MB
1687 /* Start the core running */
1688 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1689 ADSP1_CORE_ENA | ADSP1_START,
1690 ADSP1_CORE_ENA | ADSP1_START);
1691 break;
1692
1693 case SND_SOC_DAPM_PRE_PMD:
1694 /* Halt the core */
1695 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1696 ADSP1_CORE_ENA | ADSP1_START, 0);
1697
1698 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
1699 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
1700
1701 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1702 ADSP1_SYS_ENA, 0);
6ab2b7b4 1703
81ad93ec 1704 list_for_each_entry(ctl, &dsp->ctl_list, list)
6ab2b7b4 1705 ctl->enabled = 0;
b0101b4f
DP
1706
1707 while (!list_empty(&dsp->alg_regions)) {
1708 alg_region = list_first_entry(&dsp->alg_regions,
1709 struct wm_adsp_alg_region,
1710 list);
1711 list_del(&alg_region->list);
1712 kfree(alg_region);
1713 }
2159ad93
MB
1714 break;
1715
1716 default:
1717 break;
1718 }
1719
1720 return 0;
1721
1722err:
1723 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1724 ADSP1_SYS_ENA, 0);
1725 return ret;
1726}
1727EXPORT_SYMBOL_GPL(wm_adsp1_event);
1728
1729static int wm_adsp2_ena(struct wm_adsp *dsp)
1730{
1731 unsigned int val;
1732 int ret, count;
1733
1552c325
MB
1734 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
1735 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
2159ad93
MB
1736 if (ret != 0)
1737 return ret;
1738
1739 /* Wait for the RAM to start, should be near instantaneous */
939fd1e8 1740 for (count = 0; count < 10; ++count) {
2159ad93
MB
1741 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
1742 &val);
1743 if (ret != 0)
1744 return ret;
939fd1e8
CK
1745
1746 if (val & ADSP2_RAM_RDY)
1747 break;
1748
1749 msleep(1);
1750 }
2159ad93
MB
1751
1752 if (!(val & ADSP2_RAM_RDY)) {
1753 adsp_err(dsp, "Failed to start DSP RAM\n");
1754 return -EBUSY;
1755 }
1756
1757 adsp_dbg(dsp, "RAM ready after %d polls\n", count);
2159ad93
MB
1758
1759 return 0;
1760}
1761
18b1a902 1762static void wm_adsp2_boot_work(struct work_struct *work)
2159ad93 1763{
d8a64d6a
CK
1764 struct wm_adsp *dsp = container_of(work,
1765 struct wm_adsp,
1766 boot_work);
2159ad93 1767 int ret;
d8a64d6a 1768 unsigned int val;
2159ad93 1769
d8a64d6a
CK
1770 /*
1771 * For simplicity set the DSP clock rate to be the
1772 * SYSCLK rate rather than making it configurable.
1773 */
1774 ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
1775 if (ret != 0) {
1776 adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
1777 return;
1778 }
1779 val = (val & ARIZONA_SYSCLK_FREQ_MASK)
1780 >> ARIZONA_SYSCLK_FREQ_SHIFT;
92bb4c32 1781
d8a64d6a
CK
1782 ret = regmap_update_bits_async(dsp->regmap,
1783 dsp->base + ADSP2_CLOCKING,
1784 ADSP2_CLK_SEL_MASK, val);
1785 if (ret != 0) {
1786 adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
1787 return;
1788 }
dd49e2c8 1789
d8a64d6a
CK
1790 if (dsp->dvfs) {
1791 ret = regmap_read(dsp->regmap,
1792 dsp->base + ADSP2_CLOCKING, &val);
dd49e2c8 1793 if (ret != 0) {
62c35b3b 1794 adsp_err(dsp, "Failed to read clocking: %d\n", ret);
d8a64d6a 1795 return;
dd49e2c8
MB
1796 }
1797
d8a64d6a
CK
1798 if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
1799 ret = regulator_enable(dsp->dvfs);
973838a0 1800 if (ret != 0) {
62c35b3b
CK
1801 adsp_err(dsp,
1802 "Failed to enable supply: %d\n",
1803 ret);
d8a64d6a 1804 return;
973838a0
MB
1805 }
1806
d8a64d6a
CK
1807 ret = regulator_set_voltage(dsp->dvfs,
1808 1800000,
1809 1800000);
1810 if (ret != 0) {
62c35b3b
CK
1811 adsp_err(dsp,
1812 "Failed to raise supply: %d\n",
1813 ret);
d8a64d6a 1814 return;
973838a0
MB
1815 }
1816 }
d8a64d6a 1817 }
973838a0 1818
d8a64d6a
CK
1819 ret = wm_adsp2_ena(dsp);
1820 if (ret != 0)
1821 return;
2159ad93 1822
d8a64d6a
CK
1823 ret = wm_adsp_load(dsp);
1824 if (ret != 0)
1825 goto err;
2159ad93 1826
b618a185 1827 ret = wm_adsp2_setup_algs(dsp);
d8a64d6a
CK
1828 if (ret != 0)
1829 goto err;
db40517c 1830
d8a64d6a
CK
1831 ret = wm_adsp_load_coeff(dsp);
1832 if (ret != 0)
1833 goto err;
2159ad93 1834
d8a64d6a
CK
1835 /* Initialize caches for enabled and unset controls */
1836 ret = wm_coeff_init_control_caches(dsp);
1837 if (ret != 0)
1838 goto err;
6ab2b7b4 1839
d8a64d6a
CK
1840 /* Sync set controls */
1841 ret = wm_coeff_sync_controls(dsp);
1842 if (ret != 0)
1843 goto err;
1844
d8a64d6a
CK
1845 dsp->running = true;
1846
1847 return;
6ab2b7b4 1848
d8a64d6a
CK
1849err:
1850 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1851 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
1852}
1853
12db5edd
CK
1854int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
1855 struct snd_kcontrol *kcontrol, int event)
1856{
72718517 1857 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
12db5edd
CK
1858 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1859 struct wm_adsp *dsp = &dsps[w->shift];
1860
00200107 1861 dsp->card = codec->component.card;
12db5edd
CK
1862
1863 switch (event) {
1864 case SND_SOC_DAPM_PRE_PMU:
1865 queue_work(system_unbound_wq, &dsp->boot_work);
1866 break;
1867 default:
1868 break;
cab27258 1869 }
12db5edd
CK
1870
1871 return 0;
1872}
1873EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
1874
d8a64d6a
CK
1875int wm_adsp2_event(struct snd_soc_dapm_widget *w,
1876 struct snd_kcontrol *kcontrol, int event)
1877{
72718517 1878 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
d8a64d6a
CK
1879 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1880 struct wm_adsp *dsp = &dsps[w->shift];
1881 struct wm_adsp_alg_region *alg_region;
1882 struct wm_coeff_ctl *ctl;
1883 int ret;
1884
d8a64d6a
CK
1885 switch (event) {
1886 case SND_SOC_DAPM_POST_PMU:
d8a64d6a
CK
1887 flush_work(&dsp->boot_work);
1888
1889 if (!dsp->running)
1890 return -EIO;
6ab2b7b4 1891
d8a64d6a
CK
1892 ret = regmap_update_bits(dsp->regmap,
1893 dsp->base + ADSP2_CONTROL,
00e4c3b6
CK
1894 ADSP2_CORE_ENA | ADSP2_START,
1895 ADSP2_CORE_ENA | ADSP2_START);
2159ad93
MB
1896 if (ret != 0)
1897 goto err;
1898 break;
1899
1900 case SND_SOC_DAPM_PRE_PMD:
1023dbd9
MB
1901 dsp->running = false;
1902
2159ad93 1903 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
a7f9be7e
MB
1904 ADSP2_SYS_ENA | ADSP2_CORE_ENA |
1905 ADSP2_START, 0);
973838a0 1906
2d30b575
MB
1907 /* Make sure DMAs are quiesced */
1908 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
1909 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
1910 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
1911
973838a0
MB
1912 if (dsp->dvfs) {
1913 ret = regulator_set_voltage(dsp->dvfs, 1200000,
1914 1800000);
1915 if (ret != 0)
62c35b3b
CK
1916 adsp_warn(dsp,
1917 "Failed to lower supply: %d\n",
1918 ret);
973838a0
MB
1919
1920 ret = regulator_disable(dsp->dvfs);
1921 if (ret != 0)
62c35b3b
CK
1922 adsp_err(dsp,
1923 "Failed to enable supply: %d\n",
1924 ret);
973838a0 1925 }
471f4885 1926
81ad93ec 1927 list_for_each_entry(ctl, &dsp->ctl_list, list)
6ab2b7b4 1928 ctl->enabled = 0;
6ab2b7b4 1929
471f4885
MB
1930 while (!list_empty(&dsp->alg_regions)) {
1931 alg_region = list_first_entry(&dsp->alg_regions,
1932 struct wm_adsp_alg_region,
1933 list);
1934 list_del(&alg_region->list);
1935 kfree(alg_region);
1936 }
ddbc5efe
CK
1937
1938 adsp_dbg(dsp, "Shutdown complete\n");
2159ad93
MB
1939 break;
1940
1941 default:
1942 break;
1943 }
1944
1945 return 0;
1946err:
1947 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
a7f9be7e 1948 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
2159ad93
MB
1949 return ret;
1950}
1951EXPORT_SYMBOL_GPL(wm_adsp2_event);
973838a0 1952
3809f001 1953int wm_adsp2_init(struct wm_adsp *dsp, bool dvfs)
973838a0
MB
1954{
1955 int ret;
1956
10a2b662
MB
1957 /*
1958 * Disable the DSP memory by default when in reset for a small
1959 * power saving.
1960 */
3809f001 1961 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
10a2b662
MB
1962 ADSP2_MEM_ENA, 0);
1963 if (ret != 0) {
3809f001 1964 adsp_err(dsp, "Failed to clear memory retention: %d\n", ret);
10a2b662
MB
1965 return ret;
1966 }
1967
3809f001
CK
1968 INIT_LIST_HEAD(&dsp->alg_regions);
1969 INIT_LIST_HEAD(&dsp->ctl_list);
1970 INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
6ab2b7b4 1971
973838a0 1972 if (dvfs) {
3809f001
CK
1973 dsp->dvfs = devm_regulator_get(dsp->dev, "DCVDD");
1974 if (IS_ERR(dsp->dvfs)) {
1975 ret = PTR_ERR(dsp->dvfs);
1976 adsp_err(dsp, "Failed to get DCVDD: %d\n", ret);
81ad93ec 1977 return ret;
973838a0
MB
1978 }
1979
3809f001 1980 ret = regulator_enable(dsp->dvfs);
973838a0 1981 if (ret != 0) {
3809f001 1982 adsp_err(dsp, "Failed to enable DCVDD: %d\n", ret);
81ad93ec 1983 return ret;
973838a0
MB
1984 }
1985
3809f001 1986 ret = regulator_set_voltage(dsp->dvfs, 1200000, 1800000);
973838a0 1987 if (ret != 0) {
3809f001 1988 adsp_err(dsp, "Failed to initialise DVFS: %d\n", ret);
81ad93ec 1989 return ret;
973838a0
MB
1990 }
1991
3809f001 1992 ret = regulator_disable(dsp->dvfs);
973838a0 1993 if (ret != 0) {
3809f001 1994 adsp_err(dsp, "Failed to disable DCVDD: %d\n", ret);
81ad93ec 1995 return ret;
973838a0
MB
1996 }
1997 }
1998
1999 return 0;
2000}
2001EXPORT_SYMBOL_GPL(wm_adsp2_init);
0a37c6ef
PD
2002
2003MODULE_LICENSE("GPL v2");
This page took 0.478645 seconds and 5 git commands to generate.