ASoC: wm_adsp: Implement support for algorithm-specific coefficient blocks
[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/pm.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/regmap.h>
21 #include <linux/regulator/consumer.h>
22 #include <linux/slab.h>
23 #include <sound/core.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
26 #include <sound/soc.h>
27 #include <sound/jack.h>
28 #include <sound/initval.h>
29 #include <sound/tlv.h>
30
31 #include <linux/mfd/arizona/registers.h>
32
33 #include "wm_adsp.h"
34
35 #define adsp_crit(_dsp, fmt, ...) \
36 dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
37 #define adsp_err(_dsp, fmt, ...) \
38 dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
39 #define adsp_warn(_dsp, fmt, ...) \
40 dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
41 #define adsp_info(_dsp, fmt, ...) \
42 dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
43 #define adsp_dbg(_dsp, fmt, ...) \
44 dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
45
46 #define ADSP1_CONTROL_1 0x00
47 #define ADSP1_CONTROL_2 0x02
48 #define ADSP1_CONTROL_3 0x03
49 #define ADSP1_CONTROL_4 0x04
50 #define ADSP1_CONTROL_5 0x06
51 #define ADSP1_CONTROL_6 0x07
52 #define ADSP1_CONTROL_7 0x08
53 #define ADSP1_CONTROL_8 0x09
54 #define ADSP1_CONTROL_9 0x0A
55 #define ADSP1_CONTROL_10 0x0B
56 #define ADSP1_CONTROL_11 0x0C
57 #define ADSP1_CONTROL_12 0x0D
58 #define ADSP1_CONTROL_13 0x0F
59 #define ADSP1_CONTROL_14 0x10
60 #define ADSP1_CONTROL_15 0x11
61 #define ADSP1_CONTROL_16 0x12
62 #define ADSP1_CONTROL_17 0x13
63 #define ADSP1_CONTROL_18 0x14
64 #define ADSP1_CONTROL_19 0x16
65 #define ADSP1_CONTROL_20 0x17
66 #define ADSP1_CONTROL_21 0x18
67 #define ADSP1_CONTROL_22 0x1A
68 #define ADSP1_CONTROL_23 0x1B
69 #define ADSP1_CONTROL_24 0x1C
70 #define ADSP1_CONTROL_25 0x1E
71 #define ADSP1_CONTROL_26 0x20
72 #define ADSP1_CONTROL_27 0x21
73 #define ADSP1_CONTROL_28 0x22
74 #define ADSP1_CONTROL_29 0x23
75 #define ADSP1_CONTROL_30 0x24
76 #define ADSP1_CONTROL_31 0x26
77
78 /*
79 * ADSP1 Control 19
80 */
81 #define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
82 #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
83 #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
84
85
86 /*
87 * ADSP1 Control 30
88 */
89 #define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */
90 #define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */
91 #define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */
92 #define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */
93 #define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
94 #define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
95 #define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
96 #define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
97 #define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
98 #define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
99 #define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
100 #define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
101 #define ADSP1_START 0x0001 /* DSP1_START */
102 #define ADSP1_START_MASK 0x0001 /* DSP1_START */
103 #define ADSP1_START_SHIFT 0 /* DSP1_START */
104 #define ADSP1_START_WIDTH 1 /* DSP1_START */
105
106 #define ADSP2_CONTROL 0
107 #define ADSP2_CLOCKING 1
108 #define ADSP2_STATUS1 4
109
110 /*
111 * ADSP2 Control
112 */
113
114 #define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */
115 #define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */
116 #define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */
117 #define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */
118 #define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
119 #define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
120 #define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
121 #define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
122 #define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
123 #define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
124 #define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
125 #define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
126 #define ADSP2_START 0x0001 /* DSP1_START */
127 #define ADSP2_START_MASK 0x0001 /* DSP1_START */
128 #define ADSP2_START_SHIFT 0 /* DSP1_START */
129 #define ADSP2_START_WIDTH 1 /* DSP1_START */
130
131 /*
132 * ADSP2 clocking
133 */
134 #define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
135 #define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
136 #define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
137
138 /*
139 * ADSP2 Status 1
140 */
141 #define ADSP2_RAM_RDY 0x0001
142 #define ADSP2_RAM_RDY_MASK 0x0001
143 #define ADSP2_RAM_RDY_SHIFT 0
144 #define ADSP2_RAM_RDY_WIDTH 1
145
146
147 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
148 int type)
149 {
150 int i;
151
152 for (i = 0; i < dsp->num_mems; i++)
153 if (dsp->mem[i].type == type)
154 return &dsp->mem[i];
155
156 return NULL;
157 }
158
159 static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
160 unsigned int offset)
161 {
162 switch (region->type) {
163 case WMFW_ADSP1_PM:
164 return region->base + (offset * 3);
165 case WMFW_ADSP1_DM:
166 return region->base + (offset * 2);
167 case WMFW_ADSP2_XM:
168 return region->base + (offset * 2);
169 case WMFW_ADSP2_YM:
170 return region->base + (offset * 2);
171 case WMFW_ADSP1_ZM:
172 return region->base + (offset * 2);
173 default:
174 WARN_ON(NULL != "Unknown memory region type");
175 return offset;
176 }
177 }
178
179 static int wm_adsp_load(struct wm_adsp *dsp)
180 {
181 const struct firmware *firmware;
182 struct regmap *regmap = dsp->regmap;
183 unsigned int pos = 0;
184 const struct wmfw_header *header;
185 const struct wmfw_adsp1_sizes *adsp1_sizes;
186 const struct wmfw_adsp2_sizes *adsp2_sizes;
187 const struct wmfw_footer *footer;
188 const struct wmfw_region *region;
189 const struct wm_adsp_region *mem;
190 const char *region_name;
191 char *file, *text;
192 unsigned int reg;
193 int regions = 0;
194 int ret, offset, type, sizes;
195
196 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
197 if (file == NULL)
198 return -ENOMEM;
199
200 snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num);
201 file[PAGE_SIZE - 1] = '\0';
202
203 ret = request_firmware(&firmware, file, dsp->dev);
204 if (ret != 0) {
205 adsp_err(dsp, "Failed to request '%s'\n", file);
206 goto out;
207 }
208 ret = -EINVAL;
209
210 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
211 if (pos >= firmware->size) {
212 adsp_err(dsp, "%s: file too short, %zu bytes\n",
213 file, firmware->size);
214 goto out_fw;
215 }
216
217 header = (void*)&firmware->data[0];
218
219 if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
220 adsp_err(dsp, "%s: invalid magic\n", file);
221 goto out_fw;
222 }
223
224 if (header->ver != 0) {
225 adsp_err(dsp, "%s: unknown file format %d\n",
226 file, header->ver);
227 goto out_fw;
228 }
229
230 if (header->core != dsp->type) {
231 adsp_err(dsp, "%s: invalid core %d != %d\n",
232 file, header->core, dsp->type);
233 goto out_fw;
234 }
235
236 switch (dsp->type) {
237 case WMFW_ADSP1:
238 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
239 adsp1_sizes = (void *)&(header[1]);
240 footer = (void *)&(adsp1_sizes[1]);
241 sizes = sizeof(*adsp1_sizes);
242
243 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
244 file, le32_to_cpu(adsp1_sizes->dm),
245 le32_to_cpu(adsp1_sizes->pm),
246 le32_to_cpu(adsp1_sizes->zm));
247 break;
248
249 case WMFW_ADSP2:
250 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
251 adsp2_sizes = (void *)&(header[1]);
252 footer = (void *)&(adsp2_sizes[1]);
253 sizes = sizeof(*adsp2_sizes);
254
255 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
256 file, le32_to_cpu(adsp2_sizes->xm),
257 le32_to_cpu(adsp2_sizes->ym),
258 le32_to_cpu(adsp2_sizes->pm),
259 le32_to_cpu(adsp2_sizes->zm));
260 break;
261
262 default:
263 BUG_ON(NULL == "Unknown DSP type");
264 goto out_fw;
265 }
266
267 if (le32_to_cpu(header->len) != sizeof(*header) +
268 sizes + sizeof(*footer)) {
269 adsp_err(dsp, "%s: unexpected header length %d\n",
270 file, le32_to_cpu(header->len));
271 goto out_fw;
272 }
273
274 adsp_dbg(dsp, "%s: timestamp %llu\n", file,
275 le64_to_cpu(footer->timestamp));
276
277 while (pos < firmware->size &&
278 pos - firmware->size > sizeof(*region)) {
279 region = (void *)&(firmware->data[pos]);
280 region_name = "Unknown";
281 reg = 0;
282 text = NULL;
283 offset = le32_to_cpu(region->offset) & 0xffffff;
284 type = be32_to_cpu(region->type) & 0xff;
285 mem = wm_adsp_find_region(dsp, type);
286
287 switch (type) {
288 case WMFW_NAME_TEXT:
289 region_name = "Firmware name";
290 text = kzalloc(le32_to_cpu(region->len) + 1,
291 GFP_KERNEL);
292 break;
293 case WMFW_INFO_TEXT:
294 region_name = "Information";
295 text = kzalloc(le32_to_cpu(region->len) + 1,
296 GFP_KERNEL);
297 break;
298 case WMFW_ABSOLUTE:
299 region_name = "Absolute";
300 reg = offset;
301 break;
302 case WMFW_ADSP1_PM:
303 BUG_ON(!mem);
304 region_name = "PM";
305 reg = wm_adsp_region_to_reg(mem, offset);
306 break;
307 case WMFW_ADSP1_DM:
308 BUG_ON(!mem);
309 region_name = "DM";
310 reg = wm_adsp_region_to_reg(mem, offset);
311 break;
312 case WMFW_ADSP2_XM:
313 BUG_ON(!mem);
314 region_name = "XM";
315 reg = wm_adsp_region_to_reg(mem, offset);
316 break;
317 case WMFW_ADSP2_YM:
318 BUG_ON(!mem);
319 region_name = "YM";
320 reg = wm_adsp_region_to_reg(mem, offset);
321 break;
322 case WMFW_ADSP1_ZM:
323 BUG_ON(!mem);
324 region_name = "ZM";
325 reg = wm_adsp_region_to_reg(mem, offset);
326 break;
327 default:
328 adsp_warn(dsp,
329 "%s.%d: Unknown region type %x at %d(%x)\n",
330 file, regions, type, pos, pos);
331 break;
332 }
333
334 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
335 regions, le32_to_cpu(region->len), offset,
336 region_name);
337
338 if (text) {
339 memcpy(text, region->data, le32_to_cpu(region->len));
340 adsp_info(dsp, "%s: %s\n", file, text);
341 kfree(text);
342 }
343
344 if (reg) {
345 ret = regmap_raw_write(regmap, reg, region->data,
346 le32_to_cpu(region->len));
347 if (ret != 0) {
348 adsp_err(dsp,
349 "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
350 file, regions,
351 le32_to_cpu(region->len), offset,
352 region_name, ret);
353 goto out_fw;
354 }
355 }
356
357 pos += le32_to_cpu(region->len) + sizeof(*region);
358 regions++;
359 }
360
361 if (pos > firmware->size)
362 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
363 file, regions, pos - firmware->size);
364
365 out_fw:
366 release_firmware(firmware);
367 out:
368 kfree(file);
369
370 return ret;
371 }
372
373 static int wm_adsp_setup_algs(struct wm_adsp *dsp)
374 {
375 struct regmap *regmap = dsp->regmap;
376 struct wmfw_adsp1_id_hdr adsp1_id;
377 struct wmfw_adsp2_id_hdr adsp2_id;
378 struct wmfw_adsp1_alg_hdr *adsp1_alg;
379 struct wmfw_adsp2_alg_hdr *adsp2_alg;
380 void *alg, *buf;
381 struct wm_adsp_alg_region *region;
382 const struct wm_adsp_region *mem;
383 unsigned int pos, term;
384 size_t algs, buf_size;
385 __be32 val;
386 int i, ret;
387
388 switch (dsp->type) {
389 case WMFW_ADSP1:
390 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
391 break;
392 case WMFW_ADSP2:
393 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
394 break;
395 default:
396 mem = NULL;
397 break;
398 }
399
400 if (mem == NULL) {
401 BUG_ON(mem != NULL);
402 return -EINVAL;
403 }
404
405 switch (dsp->type) {
406 case WMFW_ADSP1:
407 ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
408 sizeof(adsp1_id));
409 if (ret != 0) {
410 adsp_err(dsp, "Failed to read algorithm info: %d\n",
411 ret);
412 return ret;
413 }
414
415 buf = &adsp1_id;
416 buf_size = sizeof(adsp1_id);
417
418 algs = be32_to_cpu(adsp1_id.algs);
419 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
420 be32_to_cpu(adsp1_id.fw.id),
421 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
422 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
423 be32_to_cpu(adsp1_id.fw.ver) & 0xff,
424 algs);
425
426 pos = sizeof(adsp1_id) / 2;
427 term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
428 break;
429
430 case WMFW_ADSP2:
431 ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
432 sizeof(adsp2_id));
433 if (ret != 0) {
434 adsp_err(dsp, "Failed to read algorithm info: %d\n",
435 ret);
436 return ret;
437 }
438
439 buf = &adsp2_id;
440 buf_size = sizeof(adsp2_id);
441
442 algs = be32_to_cpu(adsp2_id.algs);
443 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
444 be32_to_cpu(adsp2_id.fw.id),
445 (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
446 (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
447 be32_to_cpu(adsp2_id.fw.ver) & 0xff,
448 algs);
449
450 pos = sizeof(adsp2_id) / 2;
451 term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
452 break;
453
454 default:
455 BUG_ON(NULL == "Unknown DSP type");
456 return -EINVAL;
457 }
458
459 if (algs == 0) {
460 adsp_err(dsp, "No algorithms\n");
461 return -EINVAL;
462 }
463
464 if (algs > 1024) {
465 adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
466 print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
467 buf, buf_size);
468 return -EINVAL;
469 }
470
471 /* Read the terminator first to validate the length */
472 ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
473 if (ret != 0) {
474 adsp_err(dsp, "Failed to read algorithm list end: %d\n",
475 ret);
476 return ret;
477 }
478
479 if (be32_to_cpu(val) != 0xbedead)
480 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
481 term, be32_to_cpu(val));
482
483 alg = kzalloc((term - pos) * 2, GFP_KERNEL);
484 if (!alg)
485 return -ENOMEM;
486
487 ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
488 if (ret != 0) {
489 adsp_err(dsp, "Failed to read algorithm list: %d\n",
490 ret);
491 goto out;
492 }
493
494 adsp1_alg = alg;
495 adsp2_alg = alg;
496
497 for (i = 0; i < algs; i++) {
498 switch (dsp->type) {
499 case WMFW_ADSP1:
500 adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
501 i, be32_to_cpu(adsp1_alg[i].alg.id),
502 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
503 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
504 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
505 be32_to_cpu(adsp1_alg[i].dm),
506 be32_to_cpu(adsp1_alg[i].zm));
507
508 if (adsp1_alg[i].dm) {
509 region = kzalloc(sizeof(*region), GFP_KERNEL);
510 if (!region)
511 return -ENOMEM;
512 region->type = WMFW_ADSP1_DM;
513 region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
514 region->base = be32_to_cpu(adsp1_alg[i].dm);
515 list_add_tail(&region->list,
516 &dsp->alg_regions);
517 }
518
519 if (adsp1_alg[i].zm) {
520 region = kzalloc(sizeof(*region), GFP_KERNEL);
521 if (!region)
522 return -ENOMEM;
523 region->type = WMFW_ADSP1_ZM;
524 region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
525 region->base = be32_to_cpu(adsp1_alg[i].zm);
526 list_add_tail(&region->list,
527 &dsp->alg_regions);
528 }
529 break;
530
531 case WMFW_ADSP2:
532 adsp_info(dsp,
533 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
534 i, be32_to_cpu(adsp2_alg[i].alg.id),
535 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
536 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
537 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
538 be32_to_cpu(adsp2_alg[i].xm),
539 be32_to_cpu(adsp2_alg[i].ym),
540 be32_to_cpu(adsp2_alg[i].zm));
541
542 if (adsp2_alg[i].xm) {
543 region = kzalloc(sizeof(*region), GFP_KERNEL);
544 if (!region)
545 return -ENOMEM;
546 region->type = WMFW_ADSP2_XM;
547 region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
548 region->base = be32_to_cpu(adsp2_alg[i].xm);
549 list_add_tail(&region->list,
550 &dsp->alg_regions);
551 }
552
553 if (adsp2_alg[i].ym) {
554 region = kzalloc(sizeof(*region), GFP_KERNEL);
555 if (!region)
556 return -ENOMEM;
557 region->type = WMFW_ADSP2_YM;
558 region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
559 region->base = be32_to_cpu(adsp2_alg[i].ym);
560 list_add_tail(&region->list,
561 &dsp->alg_regions);
562 }
563
564 if (adsp2_alg[i].zm) {
565 region = kzalloc(sizeof(*region), GFP_KERNEL);
566 if (!region)
567 return -ENOMEM;
568 region->type = WMFW_ADSP2_ZM;
569 region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
570 region->base = be32_to_cpu(adsp2_alg[i].zm);
571 list_add_tail(&region->list,
572 &dsp->alg_regions);
573 }
574 break;
575 }
576 }
577
578 out:
579 kfree(alg);
580 return ret;
581 }
582
583 static int wm_adsp_load_coeff(struct wm_adsp *dsp)
584 {
585 struct regmap *regmap = dsp->regmap;
586 struct wmfw_coeff_hdr *hdr;
587 struct wmfw_coeff_item *blk;
588 const struct firmware *firmware;
589 const struct wm_adsp_region *mem;
590 struct wm_adsp_alg_region *alg_region;
591 const char *region_name;
592 int ret, pos, blocks, type, offset, reg;
593 char *file;
594
595 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
596 if (file == NULL)
597 return -ENOMEM;
598
599 snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num);
600 file[PAGE_SIZE - 1] = '\0';
601
602 ret = request_firmware(&firmware, file, dsp->dev);
603 if (ret != 0) {
604 adsp_warn(dsp, "Failed to request '%s'\n", file);
605 ret = 0;
606 goto out;
607 }
608 ret = -EINVAL;
609
610 if (sizeof(*hdr) >= firmware->size) {
611 adsp_err(dsp, "%s: file too short, %zu bytes\n",
612 file, firmware->size);
613 goto out_fw;
614 }
615
616 hdr = (void*)&firmware->data[0];
617 if (memcmp(hdr->magic, "WMDR", 4) != 0) {
618 adsp_err(dsp, "%s: invalid magic\n", file);
619 return -EINVAL;
620 }
621
622 adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
623 (le32_to_cpu(hdr->ver) >> 16) & 0xff,
624 (le32_to_cpu(hdr->ver) >> 8) & 0xff,
625 le32_to_cpu(hdr->ver) & 0xff);
626
627 pos = le32_to_cpu(hdr->len);
628
629 blocks = 0;
630 while (pos < firmware->size &&
631 pos - firmware->size > sizeof(*blk)) {
632 blk = (void*)(&firmware->data[pos]);
633
634 type = be32_to_cpu(blk->type) & 0xff;
635 offset = le32_to_cpu(blk->offset) & 0xffffff;
636
637 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
638 file, blocks, le32_to_cpu(blk->id),
639 (le32_to_cpu(blk->ver) >> 16) & 0xff,
640 (le32_to_cpu(blk->ver) >> 8) & 0xff,
641 le32_to_cpu(blk->ver) & 0xff);
642 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
643 file, blocks, le32_to_cpu(blk->len), offset, type);
644
645 reg = 0;
646 region_name = "Unknown";
647 switch (type) {
648 case WMFW_NAME_TEXT:
649 case WMFW_INFO_TEXT:
650 break;
651 case WMFW_ABSOLUTE:
652 region_name = "register";
653 reg = offset;
654 break;
655
656 case WMFW_ADSP1_DM:
657 case WMFW_ADSP1_ZM:
658 case WMFW_ADSP2_XM:
659 case WMFW_ADSP2_YM:
660 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
661 file, blocks, le32_to_cpu(blk->len),
662 type, le32_to_cpu(blk->id));
663
664 mem = wm_adsp_find_region(dsp, type);
665 if (!mem) {
666 adsp_err(dsp, "No base for region %x\n", type);
667 break;
668 }
669
670 reg = 0;
671 list_for_each_entry(alg_region,
672 &dsp->alg_regions, list) {
673 if (le32_to_cpu(blk->id) == alg_region->alg &&
674 type == alg_region->type) {
675 reg = alg_region->base + offset;
676 reg = wm_adsp_region_to_reg(mem,
677 reg);
678 }
679 }
680
681 if (reg == 0)
682 adsp_err(dsp, "No %x for algorithm %x\n",
683 type, le32_to_cpu(blk->id));
684 break;
685
686 default:
687 adsp_err(dsp, "Unknown region type %x\n", type);
688 break;
689 }
690
691 if (reg) {
692 ret = regmap_raw_write(regmap, reg, blk->data,
693 le32_to_cpu(blk->len));
694 if (ret != 0) {
695 adsp_err(dsp,
696 "%s.%d: Failed to write to %x in %s\n",
697 file, blocks, reg, region_name);
698 }
699 }
700
701 pos += le32_to_cpu(blk->len) + sizeof(*blk);
702 blocks++;
703 }
704
705 if (pos > firmware->size)
706 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
707 file, blocks, pos - firmware->size);
708
709 out_fw:
710 release_firmware(firmware);
711 out:
712 kfree(file);
713 return 0;
714 }
715
716 int wm_adsp1_event(struct snd_soc_dapm_widget *w,
717 struct snd_kcontrol *kcontrol,
718 int event)
719 {
720 struct snd_soc_codec *codec = w->codec;
721 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
722 struct wm_adsp *dsp = &dsps[w->shift];
723 int ret;
724
725 switch (event) {
726 case SND_SOC_DAPM_POST_PMU:
727 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
728 ADSP1_SYS_ENA, ADSP1_SYS_ENA);
729
730 ret = wm_adsp_load(dsp);
731 if (ret != 0)
732 goto err;
733
734 ret = wm_adsp_setup_algs(dsp);
735 if (ret != 0)
736 goto err;
737
738 ret = wm_adsp_load_coeff(dsp);
739 if (ret != 0)
740 goto err;
741
742 /* Start the core running */
743 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
744 ADSP1_CORE_ENA | ADSP1_START,
745 ADSP1_CORE_ENA | ADSP1_START);
746 break;
747
748 case SND_SOC_DAPM_PRE_PMD:
749 /* Halt the core */
750 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
751 ADSP1_CORE_ENA | ADSP1_START, 0);
752
753 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
754 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
755
756 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
757 ADSP1_SYS_ENA, 0);
758 break;
759
760 default:
761 break;
762 }
763
764 return 0;
765
766 err:
767 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
768 ADSP1_SYS_ENA, 0);
769 return ret;
770 }
771 EXPORT_SYMBOL_GPL(wm_adsp1_event);
772
773 static int wm_adsp2_ena(struct wm_adsp *dsp)
774 {
775 unsigned int val;
776 int ret, count;
777
778 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
779 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
780 if (ret != 0)
781 return ret;
782
783 /* Wait for the RAM to start, should be near instantaneous */
784 count = 0;
785 do {
786 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
787 &val);
788 if (ret != 0)
789 return ret;
790 } while (!(val & ADSP2_RAM_RDY) && ++count < 10);
791
792 if (!(val & ADSP2_RAM_RDY)) {
793 adsp_err(dsp, "Failed to start DSP RAM\n");
794 return -EBUSY;
795 }
796
797 adsp_dbg(dsp, "RAM ready after %d polls\n", count);
798 adsp_info(dsp, "RAM ready after %d polls\n", count);
799
800 return 0;
801 }
802
803 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
804 struct snd_kcontrol *kcontrol, int event)
805 {
806 struct snd_soc_codec *codec = w->codec;
807 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
808 struct wm_adsp *dsp = &dsps[w->shift];
809 struct wm_adsp_alg_region *alg_region;
810 unsigned int val;
811 int ret;
812
813 switch (event) {
814 case SND_SOC_DAPM_POST_PMU:
815 /*
816 * For simplicity set the DSP clock rate to be the
817 * SYSCLK rate rather than making it configurable.
818 */
819 ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
820 if (ret != 0) {
821 adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
822 ret);
823 return ret;
824 }
825 val = (val & ARIZONA_SYSCLK_FREQ_MASK)
826 >> ARIZONA_SYSCLK_FREQ_SHIFT;
827
828 ret = regmap_update_bits(dsp->regmap,
829 dsp->base + ADSP2_CLOCKING,
830 ADSP2_CLK_SEL_MASK, val);
831 if (ret != 0) {
832 adsp_err(dsp, "Failed to set clock rate: %d\n",
833 ret);
834 return ret;
835 }
836
837 if (dsp->dvfs) {
838 ret = regmap_read(dsp->regmap,
839 dsp->base + ADSP2_CLOCKING, &val);
840 if (ret != 0) {
841 dev_err(dsp->dev,
842 "Failed to read clocking: %d\n", ret);
843 return ret;
844 }
845
846 if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
847 ret = regulator_enable(dsp->dvfs);
848 if (ret != 0) {
849 dev_err(dsp->dev,
850 "Failed to enable supply: %d\n",
851 ret);
852 return ret;
853 }
854
855 ret = regulator_set_voltage(dsp->dvfs,
856 1800000,
857 1800000);
858 if (ret != 0) {
859 dev_err(dsp->dev,
860 "Failed to raise supply: %d\n",
861 ret);
862 return ret;
863 }
864 }
865 }
866
867 ret = wm_adsp2_ena(dsp);
868 if (ret != 0)
869 return ret;
870
871 ret = wm_adsp_load(dsp);
872 if (ret != 0)
873 goto err;
874
875 ret = wm_adsp_setup_algs(dsp);
876 if (ret != 0)
877 goto err;
878
879 ret = wm_adsp_load_coeff(dsp);
880 if (ret != 0)
881 goto err;
882
883 ret = regmap_update_bits(dsp->regmap,
884 dsp->base + ADSP2_CONTROL,
885 ADSP2_CORE_ENA | ADSP2_START,
886 ADSP2_CORE_ENA | ADSP2_START);
887 if (ret != 0)
888 goto err;
889 break;
890
891 case SND_SOC_DAPM_PRE_PMD:
892 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
893 ADSP2_SYS_ENA | ADSP2_CORE_ENA |
894 ADSP2_START, 0);
895
896 if (dsp->dvfs) {
897 ret = regulator_set_voltage(dsp->dvfs, 1200000,
898 1800000);
899 if (ret != 0)
900 dev_warn(dsp->dev,
901 "Failed to lower supply: %d\n",
902 ret);
903
904 ret = regulator_disable(dsp->dvfs);
905 if (ret != 0)
906 dev_err(dsp->dev,
907 "Failed to enable supply: %d\n",
908 ret);
909 }
910
911 while (!list_empty(&dsp->alg_regions)) {
912 alg_region = list_first_entry(&dsp->alg_regions,
913 struct wm_adsp_alg_region,
914 list);
915 list_del(&alg_region->list);
916 kfree(alg_region);
917 }
918 break;
919
920 default:
921 break;
922 }
923
924 return 0;
925 err:
926 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
927 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
928 return ret;
929 }
930 EXPORT_SYMBOL_GPL(wm_adsp2_event);
931
932 int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
933 {
934 int ret;
935
936 /*
937 * Disable the DSP memory by default when in reset for a small
938 * power saving.
939 */
940 ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL,
941 ADSP2_MEM_ENA, 0);
942 if (ret != 0) {
943 adsp_err(adsp, "Failed to clear memory retention: %d\n", ret);
944 return ret;
945 }
946
947 INIT_LIST_HEAD(&adsp->alg_regions);
948
949 if (dvfs) {
950 adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
951 if (IS_ERR(adsp->dvfs)) {
952 ret = PTR_ERR(adsp->dvfs);
953 dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
954 return ret;
955 }
956
957 ret = regulator_enable(adsp->dvfs);
958 if (ret != 0) {
959 dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
960 ret);
961 return ret;
962 }
963
964 ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
965 if (ret != 0) {
966 dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
967 ret);
968 return ret;
969 }
970
971 ret = regulator_disable(adsp->dvfs);
972 if (ret != 0) {
973 dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
974 ret);
975 return ret;
976 }
977 }
978
979 return 0;
980 }
981 EXPORT_SYMBOL_GPL(wm_adsp2_init);
This page took 0.071513 seconds and 6 git commands to generate.