1 // SPDX-License-Identifier: GPL-2.0-only
3 * wm_adsp.c -- Wolfson ADSP support
5 * Copyright 2012 Wolfson Microelectronics plc
7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
10 #include <linux/ctype.h>
11 #include <linux/module.h>
12 #include <linux/moduleparam.h>
13 #include <linux/init.h>
14 #include <linux/delay.h>
15 #include <linux/firmware.h>
16 #include <linux/list.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/regmap.h>
20 #include <linux/regulator/consumer.h>
21 #include <linux/slab.h>
22 #include <linux/vmalloc.h>
23 #include <linux/workqueue.h>
24 #include <linux/debugfs.h>
25 #include <sound/core.h>
26 #include <sound/pcm.h>
27 #include <sound/pcm_params.h>
28 #include <sound/soc.h>
29 #include <sound/jack.h>
30 #include <sound/initval.h>
31 #include <sound/tlv.h>
32 #include <linux/firmware.h>
36 #define adsp_crit(_dsp, fmt, ...) \
37 dev_crit(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
38 #define adsp_err(_dsp, fmt, ...) \
39 dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
40 #define adsp_warn(_dsp, fmt, ...) \
41 dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
42 #define adsp_info(_dsp, fmt, ...) \
43 dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
44 #define adsp_dbg(_dsp, fmt, ...) \
45 dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
47 #define cs_dsp_err(_dsp, fmt, ...) \
48 dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
49 #define cs_dsp_warn(_dsp, fmt, ...) \
50 dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
51 #define cs_dsp_info(_dsp, fmt, ...) \
52 dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
53 #define cs_dsp_dbg(_dsp, fmt, ...) \
54 dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
56 #define compr_err(_obj, fmt, ...) \
57 adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
59 #define compr_dbg(_obj, fmt, ...) \
60 adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
63 #define ADSP1_CONTROL_1 0x00
64 #define ADSP1_CONTROL_2 0x02
65 #define ADSP1_CONTROL_3 0x03
66 #define ADSP1_CONTROL_4 0x04
67 #define ADSP1_CONTROL_5 0x06
68 #define ADSP1_CONTROL_6 0x07
69 #define ADSP1_CONTROL_7 0x08
70 #define ADSP1_CONTROL_8 0x09
71 #define ADSP1_CONTROL_9 0x0A
72 #define ADSP1_CONTROL_10 0x0B
73 #define ADSP1_CONTROL_11 0x0C
74 #define ADSP1_CONTROL_12 0x0D
75 #define ADSP1_CONTROL_13 0x0F
76 #define ADSP1_CONTROL_14 0x10
77 #define ADSP1_CONTROL_15 0x11
78 #define ADSP1_CONTROL_16 0x12
79 #define ADSP1_CONTROL_17 0x13
80 #define ADSP1_CONTROL_18 0x14
81 #define ADSP1_CONTROL_19 0x16
82 #define ADSP1_CONTROL_20 0x17
83 #define ADSP1_CONTROL_21 0x18
84 #define ADSP1_CONTROL_22 0x1A
85 #define ADSP1_CONTROL_23 0x1B
86 #define ADSP1_CONTROL_24 0x1C
87 #define ADSP1_CONTROL_25 0x1E
88 #define ADSP1_CONTROL_26 0x20
89 #define ADSP1_CONTROL_27 0x21
90 #define ADSP1_CONTROL_28 0x22
91 #define ADSP1_CONTROL_29 0x23
92 #define ADSP1_CONTROL_30 0x24
93 #define ADSP1_CONTROL_31 0x26
98 #define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
99 #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
100 #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
106 #define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */
107 #define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */
108 #define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */
109 #define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */
110 #define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
111 #define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
112 #define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
113 #define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
114 #define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
115 #define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
116 #define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
117 #define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
118 #define ADSP1_START 0x0001 /* DSP1_START */
119 #define ADSP1_START_MASK 0x0001 /* DSP1_START */
120 #define ADSP1_START_SHIFT 0 /* DSP1_START */
121 #define ADSP1_START_WIDTH 1 /* DSP1_START */
126 #define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
127 #define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
128 #define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
130 #define ADSP2_CONTROL 0x0
131 #define ADSP2_CLOCKING 0x1
132 #define ADSP2V2_CLOCKING 0x2
133 #define ADSP2_STATUS1 0x4
134 #define ADSP2_WDMA_CONFIG_1 0x30
135 #define ADSP2_WDMA_CONFIG_2 0x31
136 #define ADSP2V2_WDMA_CONFIG_2 0x32
137 #define ADSP2_RDMA_CONFIG_1 0x34
139 #define ADSP2_SCRATCH0 0x40
140 #define ADSP2_SCRATCH1 0x41
141 #define ADSP2_SCRATCH2 0x42
142 #define ADSP2_SCRATCH3 0x43
144 #define ADSP2V2_SCRATCH0_1 0x40
145 #define ADSP2V2_SCRATCH2_3 0x42
151 #define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */
152 #define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */
153 #define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */
154 #define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */
155 #define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
156 #define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
157 #define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
158 #define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
159 #define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
160 #define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
161 #define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
162 #define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
163 #define ADSP2_START 0x0001 /* DSP1_START */
164 #define ADSP2_START_MASK 0x0001 /* DSP1_START */
165 #define ADSP2_START_SHIFT 0 /* DSP1_START */
166 #define ADSP2_START_WIDTH 1 /* DSP1_START */
171 #define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
172 #define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
173 #define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
178 #define ADSP2V2_CLK_SEL_MASK 0x70000 /* CLK_SEL_ENA */
179 #define ADSP2V2_CLK_SEL_SHIFT 16 /* CLK_SEL_ENA */
180 #define ADSP2V2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
182 #define ADSP2V2_RATE_MASK 0x7800 /* DSP_RATE */
183 #define ADSP2V2_RATE_SHIFT 11 /* DSP_RATE */
184 #define ADSP2V2_RATE_WIDTH 4 /* DSP_RATE */
189 #define ADSP2_RAM_RDY 0x0001
190 #define ADSP2_RAM_RDY_MASK 0x0001
191 #define ADSP2_RAM_RDY_SHIFT 0
192 #define ADSP2_RAM_RDY_WIDTH 1
197 #define ADSP2_LOCK_CODE_0 0x5555
198 #define ADSP2_LOCK_CODE_1 0xAAAA
200 #define ADSP2_WATCHDOG 0x0A
201 #define ADSP2_BUS_ERR_ADDR 0x52
202 #define ADSP2_REGION_LOCK_STATUS 0x64
203 #define ADSP2_LOCK_REGION_1_LOCK_REGION_0 0x66
204 #define ADSP2_LOCK_REGION_3_LOCK_REGION_2 0x68
205 #define ADSP2_LOCK_REGION_5_LOCK_REGION_4 0x6A
206 #define ADSP2_LOCK_REGION_7_LOCK_REGION_6 0x6C
207 #define ADSP2_LOCK_REGION_9_LOCK_REGION_8 0x6E
208 #define ADSP2_LOCK_REGION_CTRL 0x7A
209 #define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR 0x7C
211 #define ADSP2_REGION_LOCK_ERR_MASK 0x8000
212 #define ADSP2_ADDR_ERR_MASK 0x4000
213 #define ADSP2_WDT_TIMEOUT_STS_MASK 0x2000
214 #define ADSP2_CTRL_ERR_PAUSE_ENA 0x0002
215 #define ADSP2_CTRL_ERR_EINT 0x0001
217 #define ADSP2_BUS_ERR_ADDR_MASK 0x00FFFFFF
218 #define ADSP2_XMEM_ERR_ADDR_MASK 0x0000FFFF
219 #define ADSP2_PMEM_ERR_ADDR_MASK 0x7FFF0000
220 #define ADSP2_PMEM_ERR_ADDR_SHIFT 16
221 #define ADSP2_WDT_ENA_MASK 0xFFFFFFFD
223 #define ADSP2_LOCK_REGION_SHIFT 16
225 #define ADSP_MAX_STD_CTRL_SIZE 512
227 #define CS_DSP_ACKED_CTL_TIMEOUT_MS 100
228 #define CS_DSP_ACKED_CTL_N_QUICKPOLLS 10
229 #define CS_DSP_ACKED_CTL_MIN_VALUE 0
230 #define CS_DSP_ACKED_CTL_MAX_VALUE 0xFFFFFF
233 * Event control messages
235 #define CS_DSP_FW_EVENT_SHUTDOWN 0x000001
240 #define HALO_AHBM_WINDOW_DEBUG_0 0x02040
241 #define HALO_AHBM_WINDOW_DEBUG_1 0x02044
246 #define HALO_SCRATCH1 0x005c0
247 #define HALO_SCRATCH2 0x005c8
248 #define HALO_SCRATCH3 0x005d0
249 #define HALO_SCRATCH4 0x005d8
250 #define HALO_CCM_CORE_CONTROL 0x41000
251 #define HALO_CORE_SOFT_RESET 0x00010
252 #define HALO_WDT_CONTROL 0x47000
257 #define HALO_MPU_XMEM_ACCESS_0 0x43000
258 #define HALO_MPU_YMEM_ACCESS_0 0x43004
259 #define HALO_MPU_WINDOW_ACCESS_0 0x43008
260 #define HALO_MPU_XREG_ACCESS_0 0x4300C
261 #define HALO_MPU_YREG_ACCESS_0 0x43014
262 #define HALO_MPU_XMEM_ACCESS_1 0x43018
263 #define HALO_MPU_YMEM_ACCESS_1 0x4301C
264 #define HALO_MPU_WINDOW_ACCESS_1 0x43020
265 #define HALO_MPU_XREG_ACCESS_1 0x43024
266 #define HALO_MPU_YREG_ACCESS_1 0x4302C
267 #define HALO_MPU_XMEM_ACCESS_2 0x43030
268 #define HALO_MPU_YMEM_ACCESS_2 0x43034
269 #define HALO_MPU_WINDOW_ACCESS_2 0x43038
270 #define HALO_MPU_XREG_ACCESS_2 0x4303C
271 #define HALO_MPU_YREG_ACCESS_2 0x43044
272 #define HALO_MPU_XMEM_ACCESS_3 0x43048
273 #define HALO_MPU_YMEM_ACCESS_3 0x4304C
274 #define HALO_MPU_WINDOW_ACCESS_3 0x43050
275 #define HALO_MPU_XREG_ACCESS_3 0x43054
276 #define HALO_MPU_YREG_ACCESS_3 0x4305C
277 #define HALO_MPU_XM_VIO_ADDR 0x43100
278 #define HALO_MPU_XM_VIO_STATUS 0x43104
279 #define HALO_MPU_YM_VIO_ADDR 0x43108
280 #define HALO_MPU_YM_VIO_STATUS 0x4310C
281 #define HALO_MPU_PM_VIO_ADDR 0x43110
282 #define HALO_MPU_PM_VIO_STATUS 0x43114
283 #define HALO_MPU_LOCK_CONFIG 0x43140
286 * HALO_AHBM_WINDOW_DEBUG_1
288 #define HALO_AHBM_CORE_ERR_ADDR_MASK 0x0fffff00
289 #define HALO_AHBM_CORE_ERR_ADDR_SHIFT 8
290 #define HALO_AHBM_FLAGS_ERR_MASK 0x000000ff
293 * HALO_CCM_CORE_CONTROL
295 #define HALO_CORE_RESET 0x00000200
296 #define HALO_CORE_EN 0x00000001
299 * HALO_CORE_SOFT_RESET
301 #define HALO_CORE_SOFT_RESET_MASK 0x00000001
306 #define HALO_WDT_EN_MASK 0x00000001
309 * HALO_MPU_?M_VIO_STATUS
311 #define HALO_MPU_VIO_STS_MASK 0x007e0000
312 #define HALO_MPU_VIO_STS_SHIFT 17
313 #define HALO_MPU_VIO_ERR_WR_MASK 0x00008000
314 #define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff
315 #define HALO_MPU_VIO_ERR_SRC_SHIFT 0
317 static const struct cs_dsp_ops cs_dsp_adsp1_ops;
318 static const struct cs_dsp_ops cs_dsp_adsp2_ops[];
319 static const struct cs_dsp_ops cs_dsp_halo_ops;
322 struct list_head list;
326 static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len,
327 struct list_head *list)
329 struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
334 buf->buf = vmalloc(len);
339 memcpy(buf->buf, src, len);
342 list_add_tail(&buf->list, list);
347 static void cs_dsp_buf_free(struct list_head *list)
349 while (!list_empty(list)) {
350 struct cs_dsp_buf *buf = list_first_entry(list,
353 list_del(&buf->list);
359 #define WM_ADSP_FW_MBC_VSS 0
360 #define WM_ADSP_FW_HIFI 1
361 #define WM_ADSP_FW_TX 2
362 #define WM_ADSP_FW_TX_SPK 3
363 #define WM_ADSP_FW_RX 4
364 #define WM_ADSP_FW_RX_ANC 5
365 #define WM_ADSP_FW_CTRL 6
366 #define WM_ADSP_FW_ASR 7
367 #define WM_ADSP_FW_TRACE 8
368 #define WM_ADSP_FW_SPK_PROT 9
369 #define WM_ADSP_FW_SPK_CALI 10
370 #define WM_ADSP_FW_SPK_DIAG 11
371 #define WM_ADSP_FW_MISC 12
373 #define WM_ADSP_NUM_FW 13
375 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
376 [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
377 [WM_ADSP_FW_HIFI] = "MasterHiFi",
378 [WM_ADSP_FW_TX] = "Tx",
379 [WM_ADSP_FW_TX_SPK] = "Tx Speaker",
380 [WM_ADSP_FW_RX] = "Rx",
381 [WM_ADSP_FW_RX_ANC] = "Rx ANC",
382 [WM_ADSP_FW_CTRL] = "Voice Ctrl",
383 [WM_ADSP_FW_ASR] = "ASR Assist",
384 [WM_ADSP_FW_TRACE] = "Dbg Trace",
385 [WM_ADSP_FW_SPK_PROT] = "Protection",
386 [WM_ADSP_FW_SPK_CALI] = "Calibration",
387 [WM_ADSP_FW_SPK_DIAG] = "Diagnostic",
388 [WM_ADSP_FW_MISC] = "Misc",
391 struct wm_adsp_system_config_xm_hdr {
397 __be32 dma_buffer_size;
400 __be32 build_job_name[3];
401 __be32 build_job_number;
404 struct wm_halo_system_config_xm_hdr {
405 __be32 halo_heartbeat;
406 __be32 build_job_name[3];
407 __be32 build_job_number;
410 struct wm_adsp_alg_xm_struct {
416 __be32 high_water_mark;
417 __be32 low_water_mark;
418 __be64 smoothed_power;
421 struct wm_adsp_host_buf_coeff_v1 {
422 __be32 host_buf_ptr; /* Host buffer pointer */
423 __be32 versions; /* Version numbers */
424 __be32 name[4]; /* The buffer name */
427 struct wm_adsp_buffer {
428 __be32 buf1_base; /* Base addr of first buffer area */
429 __be32 buf1_size; /* Size of buf1 area in DSP words */
430 __be32 buf2_base; /* Base addr of 2nd buffer area */
431 __be32 buf1_buf2_size; /* Size of buf1+buf2 in DSP words */
432 __be32 buf3_base; /* Base addr of buf3 area */
433 __be32 buf_total_size; /* Size of buf1+buf2+buf3 in DSP words */
434 __be32 high_water_mark; /* Point at which IRQ is asserted */
435 __be32 irq_count; /* bits 1-31 count IRQ assertions */
436 __be32 irq_ack; /* acked IRQ count, bit 0 enables IRQ */
437 __be32 next_write_index; /* word index of next write */
438 __be32 next_read_index; /* word index of next read */
439 __be32 error; /* error if any */
440 __be32 oldest_block_index; /* word index of oldest surviving */
441 __be32 requested_rewind; /* how many blocks rewind was done */
442 __be32 reserved_space; /* internal */
443 __be32 min_free; /* min free space since stream start */
444 __be32 blocks_written[2]; /* total blocks written (64 bit) */
445 __be32 words_written[2]; /* total words written (64 bit) */
448 struct wm_adsp_compr;
450 struct wm_adsp_compr_buf {
451 struct list_head list;
453 struct wm_adsp_compr *compr;
455 struct wm_adsp_buffer_region *regions;
462 int host_buf_mem_type;
467 struct wm_adsp_compr {
468 struct list_head list;
470 struct wm_adsp_compr_buf *buf;
472 struct snd_compr_stream *stream;
473 struct snd_compressed_buffer size;
476 unsigned int copied_total;
478 unsigned int sample_rate;
483 #define CS_DSP_DATA_WORD_SIZE 3
485 #define WM_ADSP_MIN_FRAGMENTS 1
486 #define WM_ADSP_MAX_FRAGMENTS 256
487 #define WM_ADSP_MIN_FRAGMENT_SIZE (64 * CS_DSP_DATA_WORD_SIZE)
488 #define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * CS_DSP_DATA_WORD_SIZE)
490 #define WM_ADSP_ALG_XM_STRUCT_MAGIC 0x49aec7
492 #define HOST_BUFFER_FIELD(field) \
493 (offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
495 #define ALG_XM_FIELD(field) \
496 (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
498 #define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER 1
500 #define HOST_BUF_COEFF_COMPAT_VER_MASK 0xFF00
501 #define HOST_BUF_COEFF_COMPAT_VER_SHIFT 8
503 static int wm_adsp_buffer_init(struct wm_adsp *dsp);
504 static int wm_adsp_buffer_free(struct wm_adsp *dsp);
506 struct wm_adsp_buffer_region {
508 unsigned int cumulative_size;
509 unsigned int mem_type;
510 unsigned int base_addr;
513 struct wm_adsp_buffer_region_def {
514 unsigned int mem_type;
515 unsigned int base_offset;
516 unsigned int size_offset;
519 static const struct wm_adsp_buffer_region_def default_regions[] = {
521 .mem_type = WMFW_ADSP2_XM,
522 .base_offset = HOST_BUFFER_FIELD(buf1_base),
523 .size_offset = HOST_BUFFER_FIELD(buf1_size),
526 .mem_type = WMFW_ADSP2_XM,
527 .base_offset = HOST_BUFFER_FIELD(buf2_base),
528 .size_offset = HOST_BUFFER_FIELD(buf1_buf2_size),
531 .mem_type = WMFW_ADSP2_YM,
532 .base_offset = HOST_BUFFER_FIELD(buf3_base),
533 .size_offset = HOST_BUFFER_FIELD(buf_total_size),
537 struct wm_adsp_fw_caps {
539 struct snd_codec_desc desc;
541 const struct wm_adsp_buffer_region_def *region_defs;
544 static const struct wm_adsp_fw_caps ctrl_caps[] = {
546 .id = SND_AUDIOCODEC_BESPOKE,
549 .sample_rates = { 16000 },
550 .num_sample_rates = 1,
551 .formats = SNDRV_PCM_FMTBIT_S16_LE,
553 .num_regions = ARRAY_SIZE(default_regions),
554 .region_defs = default_regions,
558 static const struct wm_adsp_fw_caps trace_caps[] = {
560 .id = SND_AUDIOCODEC_BESPOKE,
564 4000, 8000, 11025, 12000, 16000, 22050,
565 24000, 32000, 44100, 48000, 64000, 88200,
566 96000, 176400, 192000
568 .num_sample_rates = 15,
569 .formats = SNDRV_PCM_FMTBIT_S16_LE,
571 .num_regions = ARRAY_SIZE(default_regions),
572 .region_defs = default_regions,
576 static const struct {
580 const struct wm_adsp_fw_caps *caps;
582 } wm_adsp_fw[WM_ADSP_NUM_FW] = {
583 [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
584 [WM_ADSP_FW_HIFI] = { .file = "hifi" },
585 [WM_ADSP_FW_TX] = { .file = "tx" },
586 [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" },
587 [WM_ADSP_FW_RX] = { .file = "rx" },
588 [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" },
589 [WM_ADSP_FW_CTRL] = {
591 .compr_direction = SND_COMPRESS_CAPTURE,
592 .num_caps = ARRAY_SIZE(ctrl_caps),
594 .voice_trigger = true,
596 [WM_ADSP_FW_ASR] = { .file = "asr" },
597 [WM_ADSP_FW_TRACE] = {
599 .compr_direction = SND_COMPRESS_CAPTURE,
600 .num_caps = ARRAY_SIZE(trace_caps),
603 [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
604 [WM_ADSP_FW_SPK_CALI] = { .file = "spk-cali" },
605 [WM_ADSP_FW_SPK_DIAG] = { .file = "spk-diag" },
606 [WM_ADSP_FW_MISC] = { .file = "misc" },
609 struct wm_coeff_ctl {
611 struct cs_dsp_coeff_ctl *cs_ctl;
612 struct soc_bytes_ext bytes_ext;
613 struct work_struct work;
616 static const char *cs_dsp_mem_region_name(unsigned int type)
621 case WMFW_HALO_PM_PACKED:
627 case WMFW_HALO_XM_PACKED:
631 case WMFW_HALO_YM_PACKED:
640 #ifdef CONFIG_DEBUG_FS
641 static void cs_dsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
643 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
645 kfree(dsp->wmfw_file_name);
646 dsp->wmfw_file_name = tmp;
649 static void cs_dsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
651 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
653 kfree(dsp->bin_file_name);
654 dsp->bin_file_name = tmp;
657 static void cs_dsp_debugfs_clear(struct wm_adsp *dsp)
659 kfree(dsp->wmfw_file_name);
660 kfree(dsp->bin_file_name);
661 dsp->wmfw_file_name = NULL;
662 dsp->bin_file_name = NULL;
665 static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file,
666 char __user *user_buf,
667 size_t count, loff_t *ppos)
669 struct wm_adsp *dsp = file->private_data;
672 mutex_lock(&dsp->pwr_lock);
674 if (!dsp->wmfw_file_name || !dsp->booted)
677 ret = simple_read_from_buffer(user_buf, count, ppos,
679 strlen(dsp->wmfw_file_name));
681 mutex_unlock(&dsp->pwr_lock);
685 static ssize_t cs_dsp_debugfs_bin_read(struct file *file,
686 char __user *user_buf,
687 size_t count, loff_t *ppos)
689 struct wm_adsp *dsp = file->private_data;
692 mutex_lock(&dsp->pwr_lock);
694 if (!dsp->bin_file_name || !dsp->booted)
697 ret = simple_read_from_buffer(user_buf, count, ppos,
699 strlen(dsp->bin_file_name));
701 mutex_unlock(&dsp->pwr_lock);
705 static const struct {
707 const struct file_operations fops;
708 } cs_dsp_debugfs_fops[] = {
710 .name = "wmfw_file_name",
713 .read = cs_dsp_debugfs_wmfw_read,
717 .name = "bin_file_name",
720 .read = cs_dsp_debugfs_bin_read,
725 static void cs_dsp_init_debugfs(struct wm_adsp *dsp,
726 struct snd_soc_component *component)
728 struct dentry *root = NULL;
731 root = debugfs_create_dir(dsp->name, component->debugfs_root);
733 debugfs_create_bool("booted", 0444, root, &dsp->booted);
734 debugfs_create_bool("running", 0444, root, &dsp->running);
735 debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
736 debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
738 for (i = 0; i < ARRAY_SIZE(cs_dsp_debugfs_fops); ++i)
739 debugfs_create_file(cs_dsp_debugfs_fops[i].name, 0444, root,
740 dsp, &cs_dsp_debugfs_fops[i].fops);
742 dsp->debugfs_root = root;
745 static void cs_dsp_cleanup_debugfs(struct wm_adsp *dsp)
747 cs_dsp_debugfs_clear(dsp);
748 debugfs_remove_recursive(dsp->debugfs_root);
749 dsp->debugfs_root = NULL;
752 static inline void cs_dsp_init_debugfs(struct wm_adsp *dsp,
753 struct snd_soc_component *component)
757 static inline void cs_dsp_cleanup_debugfs(struct wm_adsp *dsp)
761 static inline void cs_dsp_debugfs_save_wmfwname(struct wm_adsp *dsp,
766 static inline void cs_dsp_debugfs_save_binname(struct wm_adsp *dsp,
771 static inline void cs_dsp_debugfs_clear(struct wm_adsp *dsp)
776 int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
777 struct snd_ctl_elem_value *ucontrol)
779 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
780 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
781 struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
783 ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
787 EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
789 int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
790 struct snd_ctl_elem_value *ucontrol)
792 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
793 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
794 struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
797 if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
800 if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
803 mutex_lock(&dsp[e->shift_l].pwr_lock);
805 if (dsp[e->shift_l].booted || !list_empty(&dsp[e->shift_l].compr_list))
808 dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
810 mutex_unlock(&dsp[e->shift_l].pwr_lock);
814 EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
816 const struct soc_enum wm_adsp_fw_enum[] = {
817 SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
818 SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
819 SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
820 SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
821 SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
822 SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
823 SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
825 EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
827 static const struct cs_dsp_region *cs_dsp_find_region(struct wm_adsp *dsp,
832 for (i = 0; i < dsp->num_mems; i++)
833 if (dsp->mem[i].type == type)
839 static unsigned int cs_dsp_region_to_reg(struct cs_dsp_region const *mem,
844 return mem->base + (offset * 3);
849 return mem->base + (offset * 2);
851 WARN(1, "Unknown memory region type");
856 static unsigned int cs_dsp_halo_region_to_reg(struct cs_dsp_region const *mem,
862 return mem->base + (offset * 4);
863 case WMFW_HALO_XM_PACKED:
864 case WMFW_HALO_YM_PACKED:
865 return (mem->base + (offset * 3)) & ~0x3;
866 case WMFW_HALO_PM_PACKED:
867 return mem->base + (offset * 5);
869 WARN(1, "Unknown memory region type");
874 static void cs_dsp_read_fw_status(struct wm_adsp *dsp,
875 int noffs, unsigned int *offs)
880 for (i = 0; i < noffs; ++i) {
881 ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
883 cs_dsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
889 static void cs_dsp_adsp2_show_fw_status(struct wm_adsp *dsp)
891 unsigned int offs[] = {
892 ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
895 cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
897 cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
898 offs[0], offs[1], offs[2], offs[3]);
901 static void cs_dsp_adsp2v2_show_fw_status(struct wm_adsp *dsp)
903 unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
905 cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
907 cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
908 offs[0] & 0xFFFF, offs[0] >> 16,
909 offs[1] & 0xFFFF, offs[1] >> 16);
912 static void cs_dsp_halo_show_fw_status(struct wm_adsp *dsp)
914 unsigned int offs[] = {
915 HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
918 cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
920 cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
921 offs[0], offs[1], offs[2], offs[3]);
924 static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
926 return container_of(ext, struct wm_coeff_ctl, bytes_ext);
929 static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg)
931 const struct cs_dsp_alg_region *alg_region = &ctl->alg_region;
932 struct wm_adsp *dsp = ctl->dsp;
933 const struct cs_dsp_region *mem;
935 mem = cs_dsp_find_region(dsp, alg_region->type);
937 cs_dsp_err(dsp, "No base for region %x\n",
942 *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset);
947 static int wm_coeff_info(struct snd_kcontrol *kctl,
948 struct snd_ctl_elem_info *uinfo)
950 struct soc_bytes_ext *bytes_ext =
951 (struct soc_bytes_ext *)kctl->private_value;
952 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
953 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
955 switch (cs_ctl->type) {
956 case WMFW_CTL_TYPE_ACKED:
957 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
958 uinfo->value.integer.min = CS_DSP_ACKED_CTL_MIN_VALUE;
959 uinfo->value.integer.max = CS_DSP_ACKED_CTL_MAX_VALUE;
960 uinfo->value.integer.step = 1;
964 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
965 uinfo->count = cs_ctl->len;
972 static int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl,
973 unsigned int event_id)
975 struct wm_adsp *dsp = ctl->dsp;
976 __be32 val = cpu_to_be32(event_id);
983 ret = cs_dsp_coeff_base_reg(ctl, ®);
987 cs_dsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
988 event_id, ctl->alg_region.alg,
989 cs_dsp_mem_region_name(ctl->alg_region.type), ctl->offset);
991 ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
993 cs_dsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
998 * Poll for ack, we initially poll at ~1ms intervals for firmwares
999 * that respond quickly, then go to ~10ms polls. A firmware is unlikely
1000 * to ack instantly so we do the first 1ms delay before reading the
1001 * control to avoid a pointless bus transaction
1003 for (i = 0; i < CS_DSP_ACKED_CTL_TIMEOUT_MS;) {
1005 case 0 ... CS_DSP_ACKED_CTL_N_QUICKPOLLS - 1:
1006 usleep_range(1000, 2000);
1010 usleep_range(10000, 20000);
1015 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
1017 cs_dsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
1022 cs_dsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
1027 cs_dsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
1028 reg, ctl->alg_region.alg,
1029 cs_dsp_mem_region_name(ctl->alg_region.type),
1035 static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
1036 const void *buf, size_t len)
1038 struct wm_adsp *dsp = ctl->dsp;
1043 ret = cs_dsp_coeff_base_reg(ctl, ®);
1047 scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
1051 ret = regmap_raw_write(dsp->regmap, reg, scratch,
1054 cs_dsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
1059 cs_dsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
1066 static int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
1067 const void *buf, size_t len)
1071 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1073 else if (buf != ctl->cache)
1074 memcpy(ctl->cache, buf, len);
1077 if (ctl->enabled && ctl->dsp->running)
1078 ret = cs_dsp_coeff_write_ctrl_raw(ctl, buf, len);
1083 static int wm_coeff_put(struct snd_kcontrol *kctl,
1084 struct snd_ctl_elem_value *ucontrol)
1086 struct soc_bytes_ext *bytes_ext =
1087 (struct soc_bytes_ext *)kctl->private_value;
1088 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1089 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
1090 char *p = ucontrol->value.bytes.data;
1093 mutex_lock(&cs_ctl->dsp->pwr_lock);
1094 ret = cs_dsp_coeff_write_ctrl(cs_ctl, p, cs_ctl->len);
1095 mutex_unlock(&cs_ctl->dsp->pwr_lock);
1100 static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
1101 const unsigned int __user *bytes, unsigned int size)
1103 struct soc_bytes_ext *bytes_ext =
1104 (struct soc_bytes_ext *)kctl->private_value;
1105 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1106 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
1109 mutex_lock(&cs_ctl->dsp->pwr_lock);
1111 if (copy_from_user(cs_ctl->cache, bytes, size))
1114 ret = cs_dsp_coeff_write_ctrl(cs_ctl, cs_ctl->cache, size);
1116 mutex_unlock(&cs_ctl->dsp->pwr_lock);
1121 static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
1122 struct snd_ctl_elem_value *ucontrol)
1124 struct soc_bytes_ext *bytes_ext =
1125 (struct soc_bytes_ext *)kctl->private_value;
1126 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1127 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
1128 unsigned int val = ucontrol->value.integer.value[0];
1132 return 0; /* 0 means no event */
1134 mutex_lock(&cs_ctl->dsp->pwr_lock);
1136 if (cs_ctl->enabled)
1137 ret = cs_dsp_coeff_write_acked_control(cs_ctl, val);
1141 mutex_unlock(&cs_ctl->dsp->pwr_lock);
1146 static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
1147 void *buf, size_t len)
1149 struct wm_adsp *dsp = ctl->dsp;
1154 ret = cs_dsp_coeff_base_reg(ctl, ®);
1158 scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
1162 ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
1164 cs_dsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
1169 cs_dsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
1171 memcpy(buf, scratch, len);
1177 static int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len)
1181 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
1182 if (ctl->enabled && ctl->dsp->running)
1183 return cs_dsp_coeff_read_ctrl_raw(ctl, buf, len);
1187 if (!ctl->flags && ctl->enabled && ctl->dsp->running)
1188 ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1190 if (buf != ctl->cache)
1191 memcpy(buf, ctl->cache, len);
1197 static int wm_coeff_get(struct snd_kcontrol *kctl,
1198 struct snd_ctl_elem_value *ucontrol)
1200 struct soc_bytes_ext *bytes_ext =
1201 (struct soc_bytes_ext *)kctl->private_value;
1202 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1203 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
1204 char *p = ucontrol->value.bytes.data;
1207 mutex_lock(&cs_ctl->dsp->pwr_lock);
1208 ret = cs_dsp_coeff_read_ctrl(cs_ctl, p, cs_ctl->len);
1209 mutex_unlock(&cs_ctl->dsp->pwr_lock);
1214 static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
1215 unsigned int __user *bytes, unsigned int size)
1217 struct soc_bytes_ext *bytes_ext =
1218 (struct soc_bytes_ext *)kctl->private_value;
1219 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1220 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
1223 mutex_lock(&cs_ctl->dsp->pwr_lock);
1225 ret = cs_dsp_coeff_read_ctrl(cs_ctl, cs_ctl->cache, size);
1227 if (!ret && copy_to_user(bytes, cs_ctl->cache, size))
1230 mutex_unlock(&cs_ctl->dsp->pwr_lock);
1235 static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol,
1236 struct snd_ctl_elem_value *ucontrol)
1239 * Although it's not useful to read an acked control, we must satisfy
1240 * user-side assumptions that all controls are readable and that a
1241 * write of the same value should be filtered out (it's valid to send
1242 * the same event number again to the firmware). We therefore return 0,
1243 * meaning "no event" so valid event numbers will always be a change
1245 ucontrol->value.integer.value[0] = 0;
1250 static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
1252 unsigned int out, rd, wr, vol;
1254 if (len > ADSP_MAX_STD_CTRL_SIZE) {
1255 rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1256 wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
1257 vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
1259 out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1261 rd = SNDRV_CTL_ELEM_ACCESS_READ;
1262 wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
1263 vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
1270 if (in & WMFW_CTL_FLAG_WRITEABLE)
1272 if (in & WMFW_CTL_FLAG_VOLATILE)
1275 out |= rd | wr | vol;
1281 static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
1283 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
1284 struct snd_kcontrol_new *kcontrol;
1287 kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
1291 kcontrol->name = ctl->name;
1292 kcontrol->info = wm_coeff_info;
1293 kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1294 kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
1295 kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
1296 kcontrol->access = wmfw_convert_flags(cs_ctl->flags, cs_ctl->len);
1298 switch (cs_ctl->type) {
1299 case WMFW_CTL_TYPE_ACKED:
1300 kcontrol->get = wm_coeff_get_acked;
1301 kcontrol->put = wm_coeff_put_acked;
1304 if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
1305 ctl->bytes_ext.max = cs_ctl->len;
1306 ctl->bytes_ext.get = wm_coeff_tlv_get;
1307 ctl->bytes_ext.put = wm_coeff_tlv_put;
1309 kcontrol->get = wm_coeff_get;
1310 kcontrol->put = wm_coeff_put;
1315 ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1);
1328 static int cs_dsp_coeff_init_control_caches(struct wm_adsp *dsp)
1330 struct cs_dsp_coeff_ctl *ctl;
1333 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1334 if (!ctl->enabled || ctl->set)
1336 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1340 * For readable controls populate the cache from the DSP memory.
1341 * For non-readable controls the cache was zero-filled when
1342 * created so we don't need to do anything.
1344 if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
1345 ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1354 static int cs_dsp_coeff_sync_controls(struct wm_adsp *dsp)
1356 struct cs_dsp_coeff_ctl *ctl;
1359 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1362 if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
1363 ret = cs_dsp_coeff_write_ctrl_raw(ctl, ctl->cache,
1373 static void cs_dsp_signal_event_controls(struct wm_adsp *dsp,
1376 struct cs_dsp_coeff_ctl *ctl;
1379 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1380 if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
1386 ret = cs_dsp_coeff_write_acked_control(ctl, event);
1389 "Failed to send 0x%x event to alg 0x%x (%d)\n",
1390 event, ctl->alg_region.alg, ret);
1394 static void wm_adsp_ctl_work(struct work_struct *work)
1396 struct wm_coeff_ctl *ctl = container_of(work,
1397 struct wm_coeff_ctl,
1399 wmfw_add_ctl(ctl->cs_ctl->dsp, ctl);
1402 static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl)
1405 kfree(ctl->subname);
1409 static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
1411 struct wm_adsp *dsp = cs_ctl->dsp;
1412 struct wm_coeff_ctl *ctl;
1413 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1414 const char *region_name;
1417 if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
1420 region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type);
1422 adsp_err(dsp, "Unknown region type: %d\n", cs_ctl->alg_region.type);
1426 switch (dsp->fw_ver) {
1429 snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
1430 dsp->name, region_name, cs_ctl->alg_region.alg);
1433 ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1434 "%s%c %.12s %x", dsp->name, *region_name,
1435 wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg);
1438 ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1439 "%s %.12s %x", dsp->name,
1440 wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg);
1444 if (cs_ctl->subname) {
1445 int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
1448 if (dsp->component->name_prefix)
1449 avail -= strlen(dsp->component->name_prefix) + 1;
1451 /* Truncate the subname from the start if it is too long */
1452 if (cs_ctl->subname_len > avail)
1453 skip = cs_ctl->subname_len - avail;
1455 snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
1456 " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip);
1459 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
1462 ctl->cs_ctl = cs_ctl;
1464 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
1472 INIT_WORK(&ctl->work, wm_adsp_ctl_work);
1473 schedule_work(&ctl->work);
1483 static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
1485 struct wm_coeff_ctl *ctl = cs_ctl->priv;
1487 cancel_work_sync(&ctl->work);
1493 static int cs_dsp_create_control(struct wm_adsp *dsp,
1494 const struct cs_dsp_alg_region *alg_region,
1495 unsigned int offset, unsigned int len,
1496 const char *subname, unsigned int subname_len,
1497 unsigned int flags, unsigned int type)
1499 struct cs_dsp_coeff_ctl *ctl;
1502 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1503 if (ctl->fw_name == dsp->fw_name &&
1504 ctl->alg_region.alg == alg_region->alg &&
1505 ctl->alg_region.type == alg_region->type) {
1506 if ((!subname && !ctl->subname) ||
1507 (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) {
1515 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
1519 ctl->fw_name = dsp->fw_name;
1520 ctl->alg_region = *alg_region;
1521 if (subname && dsp->fw_ver >= 2) {
1522 ctl->subname_len = subname_len;
1523 ctl->subname = kmemdup(subname,
1524 strlen(subname) + 1, GFP_KERNEL);
1525 if (!ctl->subname) {
1536 ctl->offset = offset;
1538 ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
1541 goto err_ctl_subname;
1544 list_add(&ctl->list, &dsp->ctl_list);
1546 ret = wm_adsp_control_add(ctl);
1553 list_del(&ctl->list);
1556 kfree(ctl->subname);
1563 struct cs_dsp_coeff_parsed_alg {
1570 struct cs_dsp_coeff_parsed_coeff {
1575 unsigned int ctl_type;
1580 static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
1589 length = le16_to_cpu(*((__le16 *)*pos));
1596 *str = *pos + bytes;
1598 *pos += ((length + bytes) + 3) & ~0x03;
1603 static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos)
1609 val = le16_to_cpu(*((__le16 *)*pos));
1612 val = le32_to_cpu(*((__le32 *)*pos));
1623 static inline void cs_dsp_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
1624 struct cs_dsp_coeff_parsed_alg *blk)
1626 const struct wmfw_adsp_alg_data *raw;
1628 switch (dsp->fw_ver) {
1631 raw = (const struct wmfw_adsp_alg_data *)*data;
1634 blk->id = le32_to_cpu(raw->id);
1635 blk->name = raw->name;
1636 blk->name_len = strlen(raw->name);
1637 blk->ncoeff = le32_to_cpu(raw->ncoeff);
1640 blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data);
1641 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data,
1643 cs_dsp_coeff_parse_string(sizeof(u16), data, NULL);
1644 blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data);
1648 cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
1649 cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
1650 cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
1653 static inline void cs_dsp_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
1654 struct cs_dsp_coeff_parsed_coeff *blk)
1656 const struct wmfw_adsp_coeff_data *raw;
1660 switch (dsp->fw_ver) {
1663 raw = (const struct wmfw_adsp_coeff_data *)*data;
1664 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
1666 blk->offset = le16_to_cpu(raw->hdr.offset);
1667 blk->mem_type = le16_to_cpu(raw->hdr.type);
1668 blk->name = raw->name;
1669 blk->name_len = strlen(raw->name);
1670 blk->ctl_type = le16_to_cpu(raw->ctl_type);
1671 blk->flags = le16_to_cpu(raw->flags);
1672 blk->len = le32_to_cpu(raw->len);
1676 blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
1677 blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
1678 length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
1679 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp,
1681 cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL);
1682 cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL);
1683 blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
1684 blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp);
1685 blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp);
1687 *data = *data + sizeof(raw->hdr) + length;
1691 cs_dsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
1692 cs_dsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
1693 cs_dsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
1694 cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
1695 cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
1696 cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
1699 static int cs_dsp_check_coeff_flags(struct wm_adsp *dsp,
1700 const struct cs_dsp_coeff_parsed_coeff *coeff_blk,
1701 unsigned int f_required,
1702 unsigned int f_illegal)
1704 if ((coeff_blk->flags & f_illegal) ||
1705 ((coeff_blk->flags & f_required) != f_required)) {
1706 cs_dsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
1707 coeff_blk->flags, coeff_blk->ctl_type);
1714 static int cs_dsp_parse_coeff(struct wm_adsp *dsp,
1715 const struct wmfw_region *region)
1717 struct cs_dsp_alg_region alg_region = {};
1718 struct cs_dsp_coeff_parsed_alg alg_blk;
1719 struct cs_dsp_coeff_parsed_coeff coeff_blk;
1720 const u8 *data = region->data;
1723 cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk);
1724 for (i = 0; i < alg_blk.ncoeff; i++) {
1725 cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk);
1727 switch (coeff_blk.ctl_type) {
1728 case WMFW_CTL_TYPE_BYTES:
1730 case WMFW_CTL_TYPE_ACKED:
1731 if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
1732 continue; /* ignore */
1734 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1735 WMFW_CTL_FLAG_VOLATILE |
1736 WMFW_CTL_FLAG_WRITEABLE |
1737 WMFW_CTL_FLAG_READABLE,
1742 case WMFW_CTL_TYPE_HOSTEVENT:
1743 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1745 WMFW_CTL_FLAG_VOLATILE |
1746 WMFW_CTL_FLAG_WRITEABLE |
1747 WMFW_CTL_FLAG_READABLE,
1752 case WMFW_CTL_TYPE_HOST_BUFFER:
1753 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1755 WMFW_CTL_FLAG_VOLATILE |
1756 WMFW_CTL_FLAG_READABLE,
1762 cs_dsp_err(dsp, "Unknown control type: %d\n",
1763 coeff_blk.ctl_type);
1767 alg_region.type = coeff_blk.mem_type;
1768 alg_region.alg = alg_blk.id;
1770 ret = cs_dsp_create_control(dsp, &alg_region,
1776 coeff_blk.ctl_type);
1778 cs_dsp_err(dsp, "Failed to create control: %.*s, %d\n",
1779 coeff_blk.name_len, coeff_blk.name, ret);
1785 static unsigned int cs_dsp_adsp1_parse_sizes(struct wm_adsp *dsp,
1786 const char * const file,
1788 const struct firmware *firmware)
1790 const struct wmfw_adsp1_sizes *adsp1_sizes;
1792 adsp1_sizes = (void *)&firmware->data[pos];
1794 cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
1795 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
1796 le32_to_cpu(adsp1_sizes->zm));
1798 return pos + sizeof(*adsp1_sizes);
1801 static void wm_adsp_release_firmware_files(struct wm_adsp *dsp,
1802 const struct firmware *wmfw_firmware,
1803 char *wmfw_filename,
1804 const struct firmware *coeff_firmware,
1805 char *coeff_filename)
1808 release_firmware(wmfw_firmware);
1809 kfree(wmfw_filename);
1812 release_firmware(coeff_firmware);
1813 kfree(coeff_filename);
1816 static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
1817 const struct firmware **firmware,
1823 *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", dsp->part, dsp->fwf_name,
1824 wm_adsp_fw[dsp->fw].file, suffix);
1825 if (*filename == NULL)
1828 ret = request_firmware(firmware, *filename, dsp->dev);
1830 adsp_err(dsp, "Failed to request '%s'\n", *filename);
1838 static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
1839 const struct firmware **wmfw_firmware,
1840 char **wmfw_filename,
1841 const struct firmware **coeff_firmware,
1842 char **coeff_filename)
1846 ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, "wmfw");
1850 wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, "bin");
1855 static unsigned int cs_dsp_adsp2_parse_sizes(struct wm_adsp *dsp,
1856 const char * const file,
1858 const struct firmware *firmware)
1860 const struct wmfw_adsp2_sizes *adsp2_sizes;
1862 adsp2_sizes = (void *)&firmware->data[pos];
1864 cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
1865 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
1866 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
1868 return pos + sizeof(*adsp2_sizes);
1871 static bool cs_dsp_validate_version(struct wm_adsp *dsp, unsigned int version)
1875 cs_dsp_warn(dsp, "Deprecated file format %d\n", version);
1885 static bool cs_dsp_halo_validate_version(struct wm_adsp *dsp, unsigned int version)
1895 static int cs_dsp_load(struct wm_adsp *dsp, const struct firmware *firmware,
1898 LIST_HEAD(buf_list);
1899 struct regmap *regmap = dsp->regmap;
1900 unsigned int pos = 0;
1901 const struct wmfw_header *header;
1902 const struct wmfw_adsp1_sizes *adsp1_sizes;
1903 const struct wmfw_footer *footer;
1904 const struct wmfw_region *region;
1905 const struct cs_dsp_region *mem;
1906 const char *region_name;
1908 struct cs_dsp_buf *buf;
1911 int ret, offset, type;
1915 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1916 if (pos >= firmware->size) {
1917 cs_dsp_err(dsp, "%s: file too short, %zu bytes\n",
1918 file, firmware->size);
1922 header = (void *)&firmware->data[0];
1924 if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
1925 cs_dsp_err(dsp, "%s: invalid magic\n", file);
1929 if (!dsp->ops->validate_version(dsp, header->ver)) {
1930 cs_dsp_err(dsp, "%s: unknown file format %d\n",
1935 cs_dsp_info(dsp, "Firmware version: %d\n", header->ver);
1936 dsp->fw_ver = header->ver;
1938 if (header->core != dsp->type) {
1939 cs_dsp_err(dsp, "%s: invalid core %d != %d\n",
1940 file, header->core, dsp->type);
1944 pos = sizeof(*header);
1945 pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
1947 footer = (void *)&firmware->data[pos];
1948 pos += sizeof(*footer);
1950 if (le32_to_cpu(header->len) != pos) {
1951 cs_dsp_err(dsp, "%s: unexpected header length %d\n",
1952 file, le32_to_cpu(header->len));
1956 cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file,
1957 le64_to_cpu(footer->timestamp));
1959 while (pos < firmware->size &&
1960 sizeof(*region) < firmware->size - pos) {
1961 region = (void *)&(firmware->data[pos]);
1962 region_name = "Unknown";
1965 offset = le32_to_cpu(region->offset) & 0xffffff;
1966 type = be32_to_cpu(region->type) & 0xff;
1969 case WMFW_NAME_TEXT:
1970 region_name = "Firmware name";
1971 text = kzalloc(le32_to_cpu(region->len) + 1,
1974 case WMFW_ALGORITHM_DATA:
1975 region_name = "Algorithm";
1976 ret = cs_dsp_parse_coeff(dsp, region);
1980 case WMFW_INFO_TEXT:
1981 region_name = "Information";
1982 text = kzalloc(le32_to_cpu(region->len) + 1,
1986 region_name = "Absolute";
1994 case WMFW_HALO_PM_PACKED:
1995 case WMFW_HALO_XM_PACKED:
1996 case WMFW_HALO_YM_PACKED:
1997 mem = cs_dsp_find_region(dsp, type);
1999 cs_dsp_err(dsp, "No region of type: %x\n", type);
2004 region_name = cs_dsp_mem_region_name(type);
2005 reg = dsp->ops->region_to_reg(mem, offset);
2009 "%s.%d: Unknown region type %x at %d(%x)\n",
2010 file, regions, type, pos, pos);
2014 cs_dsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
2015 regions, le32_to_cpu(region->len), offset,
2018 if (le32_to_cpu(region->len) >
2019 firmware->size - pos - sizeof(*region)) {
2021 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2022 file, regions, region_name,
2023 le32_to_cpu(region->len), firmware->size);
2029 memcpy(text, region->data, le32_to_cpu(region->len));
2030 cs_dsp_info(dsp, "%s: %s\n", file, text);
2036 buf = cs_dsp_buf_alloc(region->data,
2037 le32_to_cpu(region->len),
2040 cs_dsp_err(dsp, "Out of memory\n");
2045 ret = regmap_raw_write_async(regmap, reg, buf->buf,
2046 le32_to_cpu(region->len));
2049 "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
2051 le32_to_cpu(region->len), offset,
2057 pos += le32_to_cpu(region->len) + sizeof(*region);
2061 ret = regmap_async_complete(regmap);
2063 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
2067 if (pos > firmware->size)
2068 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2069 file, regions, pos - firmware->size);
2071 cs_dsp_debugfs_save_wmfwname(dsp, file);
2074 regmap_async_complete(regmap);
2075 cs_dsp_buf_free(&buf_list);
2082 * Find cs_dsp_coeff_ctl with input name as its subname
2083 * If not found, return NULL
2085 static struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct wm_adsp *dsp,
2086 const char *name, int type,
2089 struct cs_dsp_coeff_ctl *pos, *rslt = NULL;
2091 list_for_each_entry(pos, &dsp->ctl_list, list) {
2094 if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
2095 pos->fw_name == dsp->fw_name &&
2096 pos->alg_region.alg == alg &&
2097 pos->alg_region.type == type) {
2106 int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
2107 unsigned int alg, void *buf, size_t len)
2109 struct cs_dsp_coeff_ctl *cs_ctl;
2110 struct wm_coeff_ctl *ctl;
2111 struct snd_kcontrol *kcontrol;
2112 char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
2115 cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg);
2121 if (len > cs_ctl->len)
2124 ret = cs_dsp_coeff_write_ctrl(cs_ctl, buf, len);
2128 if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
2131 if (dsp->component->name_prefix)
2132 snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s",
2133 dsp->component->name_prefix, ctl->name);
2135 snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s",
2138 kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl_name);
2140 adsp_err(dsp, "Can't find kcontrol %s\n", ctl_name);
2144 snd_ctl_notify(dsp->component->card->snd_card,
2145 SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
2149 EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
2151 int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
2152 unsigned int alg, void *buf, size_t len)
2154 struct cs_dsp_coeff_ctl *cs_ctl;
2156 cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg);
2160 if (len > cs_ctl->len)
2163 return cs_dsp_coeff_read_ctrl(cs_ctl, buf, len);
2165 EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
2167 static void cs_dsp_ctl_fixup_base(struct wm_adsp *dsp,
2168 const struct cs_dsp_alg_region *alg_region)
2170 struct cs_dsp_coeff_ctl *ctl;
2172 list_for_each_entry(ctl, &dsp->ctl_list, list) {
2173 if (ctl->fw_name == dsp->fw_name &&
2174 alg_region->alg == ctl->alg_region.alg &&
2175 alg_region->type == ctl->alg_region.type) {
2176 ctl->alg_region.base = alg_region->base;
2181 static void *cs_dsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
2182 const struct cs_dsp_region *mem,
2183 unsigned int pos, unsigned int len)
2191 cs_dsp_err(dsp, "No algorithms\n");
2192 return ERR_PTR(-EINVAL);
2195 if (n_algs > 1024) {
2196 cs_dsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
2197 return ERR_PTR(-EINVAL);
2200 /* Read the terminator first to validate the length */
2201 reg = dsp->ops->region_to_reg(mem, pos + len);
2203 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
2205 cs_dsp_err(dsp, "Failed to read algorithm list end: %d\n",
2207 return ERR_PTR(ret);
2210 if (be32_to_cpu(val) != 0xbedead)
2211 cs_dsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
2212 reg, be32_to_cpu(val));
2214 /* Convert length from DSP words to bytes */
2217 alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
2219 return ERR_PTR(-ENOMEM);
2221 reg = dsp->ops->region_to_reg(mem, pos);
2223 ret = regmap_raw_read(dsp->regmap, reg, alg, len);
2225 cs_dsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
2227 return ERR_PTR(ret);
2233 static struct cs_dsp_alg_region *
2234 cs_dsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id)
2236 struct cs_dsp_alg_region *alg_region;
2238 list_for_each_entry(alg_region, &dsp->alg_regions, list) {
2239 if (id == alg_region->alg && type == alg_region->type)
2246 static struct cs_dsp_alg_region *cs_dsp_create_region(struct wm_adsp *dsp,
2247 int type, __be32 id,
2250 struct cs_dsp_alg_region *alg_region;
2252 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
2254 return ERR_PTR(-ENOMEM);
2256 alg_region->type = type;
2257 alg_region->alg = be32_to_cpu(id);
2258 alg_region->base = be32_to_cpu(base);
2260 list_add_tail(&alg_region->list, &dsp->alg_regions);
2262 if (dsp->fw_ver > 0)
2263 cs_dsp_ctl_fixup_base(dsp, alg_region);
2268 static void cs_dsp_free_alg_regions(struct wm_adsp *dsp)
2270 struct cs_dsp_alg_region *alg_region;
2272 while (!list_empty(&dsp->alg_regions)) {
2273 alg_region = list_first_entry(&dsp->alg_regions,
2274 struct cs_dsp_alg_region,
2276 list_del(&alg_region->list);
2281 static void cs_dsp_parse_wmfw_id_header(struct wm_adsp *dsp,
2282 struct wmfw_id_hdr *fw, int nalgs)
2284 dsp->fw_id = be32_to_cpu(fw->id);
2285 dsp->fw_id_version = be32_to_cpu(fw->ver);
2287 cs_dsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n",
2288 dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16,
2289 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2293 static void cs_dsp_parse_wmfw_v3_id_header(struct wm_adsp *dsp,
2294 struct wmfw_v3_id_hdr *fw, int nalgs)
2296 dsp->fw_id = be32_to_cpu(fw->id);
2297 dsp->fw_id_version = be32_to_cpu(fw->ver);
2298 dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id);
2300 cs_dsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n",
2301 dsp->fw_id, dsp->fw_vendor_id,
2302 (dsp->fw_id_version & 0xff0000) >> 16,
2303 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2307 static int cs_dsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions,
2308 const int *type, __be32 *base)
2310 struct cs_dsp_alg_region *alg_region;
2313 for (i = 0; i < nregions; i++) {
2314 alg_region = cs_dsp_create_region(dsp, type[i], id, base[i]);
2315 if (IS_ERR(alg_region))
2316 return PTR_ERR(alg_region);
2322 static int cs_dsp_adsp1_setup_algs(struct wm_adsp *dsp)
2324 struct wmfw_adsp1_id_hdr adsp1_id;
2325 struct wmfw_adsp1_alg_hdr *adsp1_alg;
2326 struct cs_dsp_alg_region *alg_region;
2327 const struct cs_dsp_region *mem;
2328 unsigned int pos, len;
2332 mem = cs_dsp_find_region(dsp, WMFW_ADSP1_DM);
2336 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
2339 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
2344 n_algs = be32_to_cpu(adsp1_id.n_algs);
2346 cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs);
2348 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM,
2349 adsp1_id.fw.id, adsp1_id.zm);
2350 if (IS_ERR(alg_region))
2351 return PTR_ERR(alg_region);
2353 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM,
2354 adsp1_id.fw.id, adsp1_id.dm);
2355 if (IS_ERR(alg_region))
2356 return PTR_ERR(alg_region);
2358 /* Calculate offset and length in DSP words */
2359 pos = sizeof(adsp1_id) / sizeof(u32);
2360 len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
2362 adsp1_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
2363 if (IS_ERR(adsp1_alg))
2364 return PTR_ERR(adsp1_alg);
2366 for (i = 0; i < n_algs; i++) {
2367 cs_dsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
2368 i, be32_to_cpu(adsp1_alg[i].alg.id),
2369 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
2370 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
2371 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
2372 be32_to_cpu(adsp1_alg[i].dm),
2373 be32_to_cpu(adsp1_alg[i].zm));
2375 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM,
2376 adsp1_alg[i].alg.id,
2378 if (IS_ERR(alg_region)) {
2379 ret = PTR_ERR(alg_region);
2382 if (dsp->fw_ver == 0) {
2383 if (i + 1 < n_algs) {
2384 len = be32_to_cpu(adsp1_alg[i + 1].dm);
2385 len -= be32_to_cpu(adsp1_alg[i].dm);
2387 cs_dsp_create_control(dsp, alg_region, 0,
2389 WMFW_CTL_TYPE_BYTES);
2391 cs_dsp_warn(dsp, "Missing length info for region DM with ID %x\n",
2392 be32_to_cpu(adsp1_alg[i].alg.id));
2396 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM,
2397 adsp1_alg[i].alg.id,
2399 if (IS_ERR(alg_region)) {
2400 ret = PTR_ERR(alg_region);
2403 if (dsp->fw_ver == 0) {
2404 if (i + 1 < n_algs) {
2405 len = be32_to_cpu(adsp1_alg[i + 1].zm);
2406 len -= be32_to_cpu(adsp1_alg[i].zm);
2408 cs_dsp_create_control(dsp, alg_region, 0,
2410 WMFW_CTL_TYPE_BYTES);
2412 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2413 be32_to_cpu(adsp1_alg[i].alg.id));
2423 static int cs_dsp_adsp2_setup_algs(struct wm_adsp *dsp)
2425 struct wmfw_adsp2_id_hdr adsp2_id;
2426 struct wmfw_adsp2_alg_hdr *adsp2_alg;
2427 struct cs_dsp_alg_region *alg_region;
2428 const struct cs_dsp_region *mem;
2429 unsigned int pos, len;
2433 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM);
2437 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
2440 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
2445 n_algs = be32_to_cpu(adsp2_id.n_algs);
2447 cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs);
2449 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
2450 adsp2_id.fw.id, adsp2_id.xm);
2451 if (IS_ERR(alg_region))
2452 return PTR_ERR(alg_region);
2454 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
2455 adsp2_id.fw.id, adsp2_id.ym);
2456 if (IS_ERR(alg_region))
2457 return PTR_ERR(alg_region);
2459 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
2460 adsp2_id.fw.id, adsp2_id.zm);
2461 if (IS_ERR(alg_region))
2462 return PTR_ERR(alg_region);
2464 /* Calculate offset and length in DSP words */
2465 pos = sizeof(adsp2_id) / sizeof(u32);
2466 len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
2468 adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
2469 if (IS_ERR(adsp2_alg))
2470 return PTR_ERR(adsp2_alg);
2472 for (i = 0; i < n_algs; i++) {
2474 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
2475 i, be32_to_cpu(adsp2_alg[i].alg.id),
2476 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
2477 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
2478 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
2479 be32_to_cpu(adsp2_alg[i].xm),
2480 be32_to_cpu(adsp2_alg[i].ym),
2481 be32_to_cpu(adsp2_alg[i].zm));
2483 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
2484 adsp2_alg[i].alg.id,
2486 if (IS_ERR(alg_region)) {
2487 ret = PTR_ERR(alg_region);
2490 if (dsp->fw_ver == 0) {
2491 if (i + 1 < n_algs) {
2492 len = be32_to_cpu(adsp2_alg[i + 1].xm);
2493 len -= be32_to_cpu(adsp2_alg[i].xm);
2495 cs_dsp_create_control(dsp, alg_region, 0,
2497 WMFW_CTL_TYPE_BYTES);
2499 cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n",
2500 be32_to_cpu(adsp2_alg[i].alg.id));
2504 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
2505 adsp2_alg[i].alg.id,
2507 if (IS_ERR(alg_region)) {
2508 ret = PTR_ERR(alg_region);
2511 if (dsp->fw_ver == 0) {
2512 if (i + 1 < n_algs) {
2513 len = be32_to_cpu(adsp2_alg[i + 1].ym);
2514 len -= be32_to_cpu(adsp2_alg[i].ym);
2516 cs_dsp_create_control(dsp, alg_region, 0,
2518 WMFW_CTL_TYPE_BYTES);
2520 cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n",
2521 be32_to_cpu(adsp2_alg[i].alg.id));
2525 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
2526 adsp2_alg[i].alg.id,
2528 if (IS_ERR(alg_region)) {
2529 ret = PTR_ERR(alg_region);
2532 if (dsp->fw_ver == 0) {
2533 if (i + 1 < n_algs) {
2534 len = be32_to_cpu(adsp2_alg[i + 1].zm);
2535 len -= be32_to_cpu(adsp2_alg[i].zm);
2537 cs_dsp_create_control(dsp, alg_region, 0,
2539 WMFW_CTL_TYPE_BYTES);
2541 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2542 be32_to_cpu(adsp2_alg[i].alg.id));
2552 static int cs_dsp_halo_create_regions(struct wm_adsp *dsp, __be32 id,
2553 __be32 xm_base, __be32 ym_base)
2555 static const int types[] = {
2556 WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED,
2557 WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED
2559 __be32 bases[] = { xm_base, xm_base, ym_base, ym_base };
2561 return cs_dsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases);
2564 static int cs_dsp_halo_setup_algs(struct wm_adsp *dsp)
2566 struct wmfw_halo_id_hdr halo_id;
2567 struct wmfw_halo_alg_hdr *halo_alg;
2568 const struct cs_dsp_region *mem;
2569 unsigned int pos, len;
2573 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM);
2577 ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id,
2580 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
2585 n_algs = be32_to_cpu(halo_id.n_algs);
2587 cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs);
2589 ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id,
2590 halo_id.xm_base, halo_id.ym_base);
2594 /* Calculate offset and length in DSP words */
2595 pos = sizeof(halo_id) / sizeof(u32);
2596 len = (sizeof(*halo_alg) * n_algs) / sizeof(u32);
2598 halo_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
2599 if (IS_ERR(halo_alg))
2600 return PTR_ERR(halo_alg);
2602 for (i = 0; i < n_algs; i++) {
2604 "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
2605 i, be32_to_cpu(halo_alg[i].alg.id),
2606 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
2607 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
2608 be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
2609 be32_to_cpu(halo_alg[i].xm_base),
2610 be32_to_cpu(halo_alg[i].ym_base));
2612 ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id,
2613 halo_alg[i].xm_base,
2614 halo_alg[i].ym_base);
2624 static int cs_dsp_load_coeff(struct wm_adsp *dsp, const struct firmware *firmware,
2627 LIST_HEAD(buf_list);
2628 struct regmap *regmap = dsp->regmap;
2629 struct wmfw_coeff_hdr *hdr;
2630 struct wmfw_coeff_item *blk;
2631 const struct cs_dsp_region *mem;
2632 struct cs_dsp_alg_region *alg_region;
2633 const char *region_name;
2634 int ret, pos, blocks, type, offset, reg;
2635 struct cs_dsp_buf *buf;
2642 if (sizeof(*hdr) >= firmware->size) {
2643 cs_dsp_err(dsp, "%s: coefficient file too short, %zu bytes\n",
2644 file, firmware->size);
2648 hdr = (void *)&firmware->data[0];
2649 if (memcmp(hdr->magic, "WMDR", 4) != 0) {
2650 cs_dsp_err(dsp, "%s: invalid coefficient magic\n", file);
2654 switch (be32_to_cpu(hdr->rev) & 0xff) {
2658 cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
2659 file, be32_to_cpu(hdr->rev) & 0xff);
2664 cs_dsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
2665 (le32_to_cpu(hdr->ver) >> 16) & 0xff,
2666 (le32_to_cpu(hdr->ver) >> 8) & 0xff,
2667 le32_to_cpu(hdr->ver) & 0xff);
2669 pos = le32_to_cpu(hdr->len);
2672 while (pos < firmware->size &&
2673 sizeof(*blk) < firmware->size - pos) {
2674 blk = (void *)(&firmware->data[pos]);
2676 type = le16_to_cpu(blk->type);
2677 offset = le16_to_cpu(blk->offset);
2679 cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
2680 file, blocks, le32_to_cpu(blk->id),
2681 (le32_to_cpu(blk->ver) >> 16) & 0xff,
2682 (le32_to_cpu(blk->ver) >> 8) & 0xff,
2683 le32_to_cpu(blk->ver) & 0xff);
2684 cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
2685 file, blocks, le32_to_cpu(blk->len), offset, type);
2688 region_name = "Unknown";
2690 case (WMFW_NAME_TEXT << 8):
2691 case (WMFW_INFO_TEXT << 8):
2692 case (WMFW_METADATA << 8):
2694 case (WMFW_ABSOLUTE << 8):
2696 * Old files may use this for global
2699 if (le32_to_cpu(blk->id) == dsp->fw_id &&
2701 region_name = "global coefficients";
2702 mem = cs_dsp_find_region(dsp, type);
2704 cs_dsp_err(dsp, "No ZM\n");
2707 reg = dsp->ops->region_to_reg(mem, 0);
2710 region_name = "register";
2719 case WMFW_HALO_XM_PACKED:
2720 case WMFW_HALO_YM_PACKED:
2721 case WMFW_HALO_PM_PACKED:
2722 cs_dsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
2723 file, blocks, le32_to_cpu(blk->len),
2724 type, le32_to_cpu(blk->id));
2726 mem = cs_dsp_find_region(dsp, type);
2728 cs_dsp_err(dsp, "No base for region %x\n", type);
2732 alg_region = cs_dsp_find_alg_region(dsp, type,
2733 le32_to_cpu(blk->id));
2735 reg = alg_region->base;
2736 reg = dsp->ops->region_to_reg(mem, reg);
2739 cs_dsp_err(dsp, "No %x for algorithm %x\n",
2740 type, le32_to_cpu(blk->id));
2745 cs_dsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
2746 file, blocks, type, pos);
2751 if (le32_to_cpu(blk->len) >
2752 firmware->size - pos - sizeof(*blk)) {
2754 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2755 file, blocks, region_name,
2756 le32_to_cpu(blk->len),
2762 buf = cs_dsp_buf_alloc(blk->data,
2763 le32_to_cpu(blk->len),
2766 cs_dsp_err(dsp, "Out of memory\n");
2771 cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
2772 file, blocks, le32_to_cpu(blk->len),
2774 ret = regmap_raw_write_async(regmap, reg, buf->buf,
2775 le32_to_cpu(blk->len));
2778 "%s.%d: Failed to write to %x in %s: %d\n",
2779 file, blocks, reg, region_name, ret);
2783 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
2787 ret = regmap_async_complete(regmap);
2789 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
2791 if (pos > firmware->size)
2792 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2793 file, blocks, pos - firmware->size);
2795 cs_dsp_debugfs_save_binname(dsp, file);
2798 regmap_async_complete(regmap);
2799 cs_dsp_buf_free(&buf_list);
2803 static int cs_dsp_create_name(struct wm_adsp *dsp)
2808 dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
2814 if (!dsp->fwf_name) {
2815 p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL);
2820 for (; *p != 0; ++p)
2827 static int cs_dsp_common_init(struct wm_adsp *dsp)
2831 ret = cs_dsp_create_name(dsp);
2835 INIT_LIST_HEAD(&dsp->alg_regions);
2836 INIT_LIST_HEAD(&dsp->ctl_list);
2838 mutex_init(&dsp->pwr_lock);
2843 static void wm_adsp_common_init(struct wm_adsp *dsp)
2845 INIT_LIST_HEAD(&dsp->compr_list);
2846 INIT_LIST_HEAD(&dsp->buffer_list);
2849 static int cs_dsp_adsp1_init(struct wm_adsp *dsp)
2851 dsp->ops = &cs_dsp_adsp1_ops;
2853 return cs_dsp_common_init(dsp);
2856 int wm_adsp1_init(struct wm_adsp *dsp)
2858 wm_adsp_common_init(dsp);
2860 return cs_dsp_adsp1_init(dsp);
2862 EXPORT_SYMBOL_GPL(wm_adsp1_init);
2864 static int cs_dsp_adsp1_power_up(struct wm_adsp *dsp,
2865 const struct firmware *wmfw_firmware, char *wmfw_filename,
2866 const struct firmware *coeff_firmware, char *coeff_filename,
2867 const char *fw_name)
2872 mutex_lock(&dsp->pwr_lock);
2874 dsp->fw_name = fw_name;
2876 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2877 ADSP1_SYS_ENA, ADSP1_SYS_ENA);
2880 * For simplicity set the DSP clock rate to be the
2881 * SYSCLK rate rather than making it configurable.
2883 if (dsp->sysclk_reg) {
2884 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
2886 cs_dsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
2890 val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
2892 ret = regmap_update_bits(dsp->regmap,
2893 dsp->base + ADSP1_CONTROL_31,
2894 ADSP1_CLK_SEL_MASK, val);
2896 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret);
2901 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename);
2905 ret = cs_dsp_adsp1_setup_algs(dsp);
2909 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename);
2913 /* Initialize caches for enabled and unset controls */
2914 ret = cs_dsp_coeff_init_control_caches(dsp);
2918 /* Sync set controls */
2919 ret = cs_dsp_coeff_sync_controls(dsp);
2925 /* Start the core running */
2926 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2927 ADSP1_CORE_ENA | ADSP1_START,
2928 ADSP1_CORE_ENA | ADSP1_START);
2930 dsp->running = true;
2932 mutex_unlock(&dsp->pwr_lock);
2937 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2940 mutex_unlock(&dsp->pwr_lock);
2944 static void cs_dsp_adsp1_power_down(struct wm_adsp *dsp)
2946 struct cs_dsp_coeff_ctl *ctl;
2948 mutex_lock(&dsp->pwr_lock);
2950 dsp->running = false;
2951 dsp->booted = false;
2954 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2955 ADSP1_CORE_ENA | ADSP1_START, 0);
2957 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
2958 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
2960 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2963 list_for_each_entry(ctl, &dsp->ctl_list, list)
2966 cs_dsp_free_alg_regions(dsp);
2968 mutex_unlock(&dsp->pwr_lock);
2971 int wm_adsp1_event(struct snd_soc_dapm_widget *w,
2972 struct snd_kcontrol *kcontrol,
2975 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
2976 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
2977 struct wm_adsp *dsp = &dsps[w->shift];
2979 char *wmfw_filename = NULL;
2980 const struct firmware *wmfw_firmware = NULL;
2981 char *coeff_filename = NULL;
2982 const struct firmware *coeff_firmware = NULL;
2984 dsp->component = component;
2987 case SND_SOC_DAPM_POST_PMU:
2988 ret = wm_adsp_request_firmware_files(dsp,
2989 &wmfw_firmware, &wmfw_filename,
2990 &coeff_firmware, &coeff_filename);
2994 ret = cs_dsp_adsp1_power_up(dsp,
2995 wmfw_firmware, wmfw_filename,
2996 coeff_firmware, coeff_filename,
2997 wm_adsp_fw_text[dsp->fw]);
2999 wm_adsp_release_firmware_files(dsp,
3000 wmfw_firmware, wmfw_filename,
3001 coeff_firmware, coeff_filename);
3003 case SND_SOC_DAPM_PRE_PMD:
3004 cs_dsp_adsp1_power_down(dsp);
3012 EXPORT_SYMBOL_GPL(wm_adsp1_event);
3014 static int cs_dsp_adsp2v2_enable_core(struct wm_adsp *dsp)
3019 /* Wait for the RAM to start, should be near instantaneous */
3020 for (count = 0; count < 10; ++count) {
3021 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
3025 if (val & ADSP2_RAM_RDY)
3028 usleep_range(250, 500);
3031 if (!(val & ADSP2_RAM_RDY)) {
3032 cs_dsp_err(dsp, "Failed to start DSP RAM\n");
3036 cs_dsp_dbg(dsp, "RAM ready after %d polls\n", count);
3041 static int cs_dsp_adsp2_enable_core(struct wm_adsp *dsp)
3045 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
3046 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
3050 return cs_dsp_adsp2v2_enable_core(dsp);
3053 static int cs_dsp_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
3055 struct regmap *regmap = dsp->regmap;
3056 unsigned int code0, code1, lock_reg;
3058 if (!(lock_regions & CS_ADSP2_REGION_ALL))
3061 lock_regions &= CS_ADSP2_REGION_ALL;
3062 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
3064 while (lock_regions) {
3066 if (lock_regions & BIT(0)) {
3067 code0 = ADSP2_LOCK_CODE_0;
3068 code1 = ADSP2_LOCK_CODE_1;
3070 if (lock_regions & BIT(1)) {
3071 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
3072 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
3074 regmap_write(regmap, lock_reg, code0);
3075 regmap_write(regmap, lock_reg, code1);
3083 static int cs_dsp_adsp2_enable_memory(struct wm_adsp *dsp)
3085 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3086 ADSP2_MEM_ENA, ADSP2_MEM_ENA);
3089 static void cs_dsp_adsp2_disable_memory(struct wm_adsp *dsp)
3091 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3095 static void cs_dsp_adsp2_disable_core(struct wm_adsp *dsp)
3097 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
3098 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
3099 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
3101 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3105 static void cs_dsp_adsp2v2_disable_core(struct wm_adsp *dsp)
3107 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
3108 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
3109 regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
3112 static int cs_dsp_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions)
3114 struct reg_sequence config[] = {
3115 { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 },
3116 { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA },
3117 { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF },
3118 { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF },
3119 { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions },
3120 { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions },
3121 { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions },
3122 { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF },
3123 { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF },
3124 { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions },
3125 { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions },
3126 { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions },
3127 { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF },
3128 { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF },
3129 { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions },
3130 { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions },
3131 { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions },
3132 { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF },
3133 { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF },
3134 { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions },
3135 { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions },
3136 { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions },
3137 { dsp->base + HALO_MPU_LOCK_CONFIG, 0 },
3140 return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config));
3143 static int cs_dsp_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
3147 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING,
3149 freq << ADSP2_CLK_SEL_SHIFT);
3151 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret);
3156 int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
3158 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3159 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3160 struct wm_adsp *dsp = &dsps[w->shift];
3162 return cs_dsp_set_dspclk(dsp, freq);
3164 EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk);
3166 int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
3167 struct snd_ctl_elem_value *ucontrol)
3169 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3170 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3171 struct soc_mixer_control *mc =
3172 (struct soc_mixer_control *)kcontrol->private_value;
3173 struct wm_adsp *dsp = &dsps[mc->shift - 1];
3175 ucontrol->value.integer.value[0] = dsp->preloaded;
3179 EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
3181 int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
3182 struct snd_ctl_elem_value *ucontrol)
3184 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3185 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3186 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
3187 struct soc_mixer_control *mc =
3188 (struct soc_mixer_control *)kcontrol->private_value;
3189 struct wm_adsp *dsp = &dsps[mc->shift - 1];
3192 snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
3194 dsp->preloaded = ucontrol->value.integer.value[0];
3196 if (ucontrol->value.integer.value[0])
3197 snd_soc_component_force_enable_pin(component, preload);
3199 snd_soc_component_disable_pin(component, preload);
3201 snd_soc_dapm_sync(dapm);
3203 flush_work(&dsp->boot_work);
3207 EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
3209 static void cs_dsp_stop_watchdog(struct wm_adsp *dsp)
3211 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
3212 ADSP2_WDT_ENA_MASK, 0);
3215 static void cs_dsp_halo_stop_watchdog(struct wm_adsp *dsp)
3217 regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL,
3218 HALO_WDT_EN_MASK, 0);
3221 static int cs_dsp_power_up(struct wm_adsp *dsp,
3222 const struct firmware *wmfw_firmware, char *wmfw_filename,
3223 const struct firmware *coeff_firmware, char *coeff_filename,
3224 const char *fw_name)
3228 mutex_lock(&dsp->pwr_lock);
3230 dsp->fw_name = fw_name;
3232 if (dsp->ops->enable_memory) {
3233 ret = dsp->ops->enable_memory(dsp);
3238 if (dsp->ops->enable_core) {
3239 ret = dsp->ops->enable_core(dsp);
3244 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename);
3248 ret = dsp->ops->setup_algs(dsp);
3252 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename);
3256 /* Initialize caches for enabled and unset controls */
3257 ret = cs_dsp_coeff_init_control_caches(dsp);
3261 if (dsp->ops->disable_core)
3262 dsp->ops->disable_core(dsp);
3266 mutex_unlock(&dsp->pwr_lock);
3270 if (dsp->ops->disable_core)
3271 dsp->ops->disable_core(dsp);
3273 if (dsp->ops->disable_memory)
3274 dsp->ops->disable_memory(dsp);
3276 mutex_unlock(&dsp->pwr_lock);
3281 static void cs_dsp_power_down(struct wm_adsp *dsp)
3283 struct cs_dsp_coeff_ctl *ctl;
3285 mutex_lock(&dsp->pwr_lock);
3287 cs_dsp_debugfs_clear(dsp);
3290 dsp->fw_id_version = 0;
3292 dsp->booted = false;
3294 if (dsp->ops->disable_memory)
3295 dsp->ops->disable_memory(dsp);
3297 list_for_each_entry(ctl, &dsp->ctl_list, list)
3300 cs_dsp_free_alg_regions(dsp);
3302 mutex_unlock(&dsp->pwr_lock);
3304 cs_dsp_dbg(dsp, "Shutdown complete\n");
3307 static void wm_adsp_boot_work(struct work_struct *work)
3309 struct wm_adsp *dsp = container_of(work,
3313 char *wmfw_filename = NULL;
3314 const struct firmware *wmfw_firmware = NULL;
3315 char *coeff_filename = NULL;
3316 const struct firmware *coeff_firmware = NULL;
3318 ret = wm_adsp_request_firmware_files(dsp,
3319 &wmfw_firmware, &wmfw_filename,
3320 &coeff_firmware, &coeff_filename);
3324 cs_dsp_power_up(dsp,
3325 wmfw_firmware, wmfw_filename,
3326 coeff_firmware, coeff_filename,
3327 wm_adsp_fw_text[dsp->fw]);
3329 wm_adsp_release_firmware_files(dsp,
3330 wmfw_firmware, wmfw_filename,
3331 coeff_firmware, coeff_filename);
3334 int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
3335 struct snd_kcontrol *kcontrol, int event)
3337 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3338 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3339 struct wm_adsp *dsp = &dsps[w->shift];
3342 case SND_SOC_DAPM_PRE_PMU:
3343 queue_work(system_unbound_wq, &dsp->boot_work);
3345 case SND_SOC_DAPM_PRE_PMD:
3346 cs_dsp_power_down(dsp);
3354 EXPORT_SYMBOL_GPL(wm_adsp_early_event);
3356 static int cs_dsp_adsp2_start_core(struct wm_adsp *dsp)
3358 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3359 ADSP2_CORE_ENA | ADSP2_START,
3360 ADSP2_CORE_ENA | ADSP2_START);
3363 static void cs_dsp_adsp2_stop_core(struct wm_adsp *dsp)
3365 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3366 ADSP2_CORE_ENA | ADSP2_START, 0);
3369 static int wm_adsp_event_post_run(struct wm_adsp *dsp)
3371 if (wm_adsp_fw[dsp->fw].num_caps != 0)
3372 return wm_adsp_buffer_init(dsp);
3377 static void wm_adsp_event_post_stop(struct wm_adsp *dsp)
3379 if (wm_adsp_fw[dsp->fw].num_caps != 0)
3380 wm_adsp_buffer_free(dsp);
3382 dsp->fatal_error = false;
3385 static int cs_dsp_run(struct wm_adsp *dsp)
3389 mutex_lock(&dsp->pwr_lock);
3396 if (dsp->ops->enable_core) {
3397 ret = dsp->ops->enable_core(dsp);
3402 /* Sync set controls */
3403 ret = cs_dsp_coeff_sync_controls(dsp);
3407 if (dsp->ops->lock_memory) {
3408 ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
3410 cs_dsp_err(dsp, "Error configuring MPU: %d\n", ret);
3415 if (dsp->ops->start_core) {
3416 ret = dsp->ops->start_core(dsp);
3421 dsp->running = true;
3423 ret = wm_adsp_event_post_run(dsp);
3427 mutex_unlock(&dsp->pwr_lock);
3432 if (dsp->ops->stop_core)
3433 dsp->ops->stop_core(dsp);
3434 if (dsp->ops->disable_core)
3435 dsp->ops->disable_core(dsp);
3436 mutex_unlock(&dsp->pwr_lock);
3441 static void cs_dsp_stop(struct wm_adsp *dsp)
3443 /* Tell the firmware to cleanup */
3444 cs_dsp_signal_event_controls(dsp, CS_DSP_FW_EVENT_SHUTDOWN);
3446 if (dsp->ops->stop_watchdog)
3447 dsp->ops->stop_watchdog(dsp);
3449 /* Log firmware state, it can be useful for analysis */
3450 if (dsp->ops->show_fw_status)
3451 dsp->ops->show_fw_status(dsp);
3453 mutex_lock(&dsp->pwr_lock);
3455 dsp->running = false;
3457 if (dsp->ops->stop_core)
3458 dsp->ops->stop_core(dsp);
3459 if (dsp->ops->disable_core)
3460 dsp->ops->disable_core(dsp);
3462 wm_adsp_event_post_stop(dsp);
3464 mutex_unlock(&dsp->pwr_lock);
3466 cs_dsp_dbg(dsp, "Execution stopped\n");
3469 int wm_adsp_event(struct snd_soc_dapm_widget *w,
3470 struct snd_kcontrol *kcontrol, int event)
3472 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3473 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3474 struct wm_adsp *dsp = &dsps[w->shift];
3478 case SND_SOC_DAPM_POST_PMU:
3479 flush_work(&dsp->boot_work);
3480 ret = cs_dsp_run(dsp);
3482 case SND_SOC_DAPM_PRE_PMD:
3491 EXPORT_SYMBOL_GPL(wm_adsp_event);
3493 static int cs_dsp_halo_start_core(struct wm_adsp *dsp)
3495 return regmap_update_bits(dsp->regmap,
3496 dsp->base + HALO_CCM_CORE_CONTROL,
3497 HALO_CORE_RESET | HALO_CORE_EN,
3498 HALO_CORE_RESET | HALO_CORE_EN);
3501 static void cs_dsp_halo_stop_core(struct wm_adsp *dsp)
3503 regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
3506 /* reset halo core with CORE_SOFT_RESET */
3507 regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
3508 HALO_CORE_SOFT_RESET_MASK, 1);
3511 int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
3515 snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
3516 snd_soc_component_disable_pin(component, preload);
3518 cs_dsp_init_debugfs(dsp, component);
3520 dsp->component = component;
3524 EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
3526 int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
3528 cs_dsp_cleanup_debugfs(dsp);
3532 EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
3534 static int cs_dsp_adsp2_init(struct wm_adsp *dsp)
3541 * Disable the DSP memory by default when in reset for a small
3544 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3548 "Failed to clear memory retention: %d\n", ret);
3552 dsp->ops = &cs_dsp_adsp2_ops[0];
3555 dsp->ops = &cs_dsp_adsp2_ops[1];
3558 dsp->ops = &cs_dsp_adsp2_ops[2];
3562 return cs_dsp_common_init(dsp);
3565 int wm_adsp2_init(struct wm_adsp *dsp)
3567 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3569 dsp->sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr);
3571 wm_adsp_common_init(dsp);
3573 return cs_dsp_adsp2_init(dsp);
3575 EXPORT_SYMBOL_GPL(wm_adsp2_init);
3577 static int cs_dsp_halo_init(struct wm_adsp *dsp)
3579 dsp->ops = &cs_dsp_halo_ops;
3581 return cs_dsp_common_init(dsp);
3584 int wm_halo_init(struct wm_adsp *dsp)
3586 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3588 dsp->sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr);
3590 wm_adsp_common_init(dsp);
3592 return cs_dsp_halo_init(dsp);
3594 EXPORT_SYMBOL_GPL(wm_halo_init);
3596 static void cs_dsp_remove(struct wm_adsp *dsp)
3598 struct cs_dsp_coeff_ctl *ctl;
3600 while (!list_empty(&dsp->ctl_list)) {
3601 ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
3603 wm_adsp_control_remove(ctl);
3605 list_del(&ctl->list);
3606 cs_dsp_free_ctl_blk(ctl);
3610 void wm_adsp2_remove(struct wm_adsp *dsp)
3614 EXPORT_SYMBOL_GPL(wm_adsp2_remove);
3616 static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
3618 return compr->buf != NULL;
3621 static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
3623 struct wm_adsp_compr_buf *buf = NULL, *tmp;
3625 if (compr->dsp->fatal_error)
3628 list_for_each_entry(tmp, &compr->dsp->buffer_list, list) {
3629 if (!tmp->name || !strcmp(compr->name, tmp->name)) {
3644 static void wm_adsp_compr_detach(struct wm_adsp_compr *compr)
3649 /* Wake the poll so it can see buffer is no longer attached */
3651 snd_compr_fragment_elapsed(compr->stream);
3653 if (wm_adsp_compr_attached(compr)) {
3654 compr->buf->compr = NULL;
3659 int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
3661 struct wm_adsp_compr *compr, *tmp;
3662 struct snd_soc_pcm_runtime *rtd = stream->private_data;
3665 mutex_lock(&dsp->pwr_lock);
3667 if (wm_adsp_fw[dsp->fw].num_caps == 0) {
3668 adsp_err(dsp, "%s: Firmware does not support compressed API\n",
3669 asoc_rtd_to_codec(rtd, 0)->name);
3674 if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
3675 adsp_err(dsp, "%s: Firmware does not support stream direction\n",
3676 asoc_rtd_to_codec(rtd, 0)->name);
3681 list_for_each_entry(tmp, &dsp->compr_list, list) {
3682 if (!strcmp(tmp->name, asoc_rtd_to_codec(rtd, 0)->name)) {
3683 adsp_err(dsp, "%s: Only a single stream supported per dai\n",
3684 asoc_rtd_to_codec(rtd, 0)->name);
3690 compr = kzalloc(sizeof(*compr), GFP_KERNEL);
3697 compr->stream = stream;
3698 compr->name = asoc_rtd_to_codec(rtd, 0)->name;
3700 list_add_tail(&compr->list, &dsp->compr_list);
3702 stream->runtime->private_data = compr;
3705 mutex_unlock(&dsp->pwr_lock);
3709 EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
3711 int wm_adsp_compr_free(struct snd_soc_component *component,
3712 struct snd_compr_stream *stream)
3714 struct wm_adsp_compr *compr = stream->runtime->private_data;
3715 struct wm_adsp *dsp = compr->dsp;
3717 mutex_lock(&dsp->pwr_lock);
3719 wm_adsp_compr_detach(compr);
3720 list_del(&compr->list);
3722 kfree(compr->raw_buf);
3725 mutex_unlock(&dsp->pwr_lock);
3729 EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
3731 static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
3732 struct snd_compr_params *params)
3734 struct wm_adsp_compr *compr = stream->runtime->private_data;
3735 struct wm_adsp *dsp = compr->dsp;
3736 const struct wm_adsp_fw_caps *caps;
3737 const struct snd_codec_desc *desc;
3740 if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
3741 params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
3742 params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
3743 params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
3744 params->buffer.fragment_size % CS_DSP_DATA_WORD_SIZE) {
3745 compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n",
3746 params->buffer.fragment_size,
3747 params->buffer.fragments);
3752 for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
3753 caps = &wm_adsp_fw[dsp->fw].caps[i];
3756 if (caps->id != params->codec.id)
3759 if (stream->direction == SND_COMPRESS_PLAYBACK) {
3760 if (desc->max_ch < params->codec.ch_out)
3763 if (desc->max_ch < params->codec.ch_in)
3767 if (!(desc->formats & (1 << params->codec.format)))
3770 for (j = 0; j < desc->num_sample_rates; ++j)
3771 if (desc->sample_rates[j] == params->codec.sample_rate)
3775 compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
3776 params->codec.id, params->codec.ch_in, params->codec.ch_out,
3777 params->codec.sample_rate, params->codec.format);
3781 static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
3783 return compr->size.fragment_size / CS_DSP_DATA_WORD_SIZE;
3786 int wm_adsp_compr_set_params(struct snd_soc_component *component,
3787 struct snd_compr_stream *stream,
3788 struct snd_compr_params *params)
3790 struct wm_adsp_compr *compr = stream->runtime->private_data;
3794 ret = wm_adsp_compr_check_params(stream, params);
3798 compr->size = params->buffer;
3800 compr_dbg(compr, "fragment_size=%d fragments=%d\n",
3801 compr->size.fragment_size, compr->size.fragments);
3803 size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
3804 compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
3805 if (!compr->raw_buf)
3808 compr->sample_rate = params->codec.sample_rate;
3812 EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
3814 int wm_adsp_compr_get_caps(struct snd_soc_component *component,
3815 struct snd_compr_stream *stream,
3816 struct snd_compr_caps *caps)
3818 struct wm_adsp_compr *compr = stream->runtime->private_data;
3819 int fw = compr->dsp->fw;
3822 if (wm_adsp_fw[fw].caps) {
3823 for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
3824 caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
3826 caps->num_codecs = i;
3827 caps->direction = wm_adsp_fw[fw].compr_direction;
3829 caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
3830 caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
3831 caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
3832 caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
3837 EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
3839 static int cs_dsp_read_raw_data_block(struct wm_adsp *dsp, int mem_type,
3840 unsigned int mem_addr,
3841 unsigned int num_words, __be32 *data)
3843 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
3850 reg = dsp->ops->region_to_reg(mem, mem_addr);
3852 ret = regmap_raw_read(dsp->regmap, reg, data,
3853 sizeof(*data) * num_words);
3860 static inline int cs_dsp_read_data_word(struct wm_adsp *dsp, int mem_type,
3861 unsigned int mem_addr, u32 *data)
3866 ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw);
3870 *data = be32_to_cpu(raw) & 0x00ffffffu;
3875 static int cs_dsp_write_data_word(struct wm_adsp *dsp, int mem_type,
3876 unsigned int mem_addr, u32 data)
3878 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
3879 __be32 val = cpu_to_be32(data & 0x00ffffffu);
3885 reg = dsp->ops->region_to_reg(mem, mem_addr);
3887 return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
3890 static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
3891 unsigned int field_offset, u32 *data)
3893 return cs_dsp_read_data_word(buf->dsp, buf->host_buf_mem_type,
3894 buf->host_buf_ptr + field_offset, data);
3897 static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
3898 unsigned int field_offset, u32 data)
3900 return cs_dsp_write_data_word(buf->dsp, buf->host_buf_mem_type,
3901 buf->host_buf_ptr + field_offset, data);
3904 static void cs_dsp_remove_padding(u32 *buf, int nwords)
3906 const __be32 *pack_in = (__be32 *)buf;
3907 u8 *pack_out = (u8 *)buf;
3911 * DSP words from the register map have pad bytes and the data bytes
3912 * are in swapped order. This swaps back to the original little-endian
3913 * order and strips the pad bytes.
3915 for (i = 0; i < nwords; i++) {
3916 u32 word = be32_to_cpu(*pack_in++);
3917 *pack_out++ = (u8)word;
3918 *pack_out++ = (u8)(word >> 8);
3919 *pack_out++ = (u8)(word >> 16);
3923 static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
3925 const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
3926 struct wm_adsp_buffer_region *region;
3930 buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),
3935 for (i = 0; i < caps->num_regions; ++i) {
3936 region = &buf->regions[i];
3938 region->offset = offset;
3939 region->mem_type = caps->region_defs[i].mem_type;
3941 ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
3942 ®ion->base_addr);
3946 ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
3951 region->cumulative_size = offset;
3954 "region=%d type=%d base=%08x off=%08x size=%08x\n",
3955 i, region->mem_type, region->base_addr,
3956 region->offset, region->cumulative_size);
3962 static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
3964 buf->irq_count = 0xFFFFFFFF;
3965 buf->read_index = -1;
3969 static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp)
3971 struct wm_adsp_compr_buf *buf;
3973 buf = kzalloc(sizeof(*buf), GFP_KERNEL);
3979 wm_adsp_buffer_clear(buf);
3981 list_add_tail(&buf->list, &dsp->buffer_list);
3986 static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
3988 struct cs_dsp_alg_region *alg_region;
3989 struct wm_adsp_compr_buf *buf;
3990 u32 xmalg, addr, magic;
3993 alg_region = cs_dsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
3995 adsp_err(dsp, "No algorithm region found\n");
3999 buf = wm_adsp_buffer_alloc(dsp);
4003 xmalg = dsp->sys_config_size / sizeof(__be32);
4005 addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
4006 ret = cs_dsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
4010 if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
4013 addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
4014 for (i = 0; i < 5; ++i) {
4015 ret = cs_dsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
4016 &buf->host_buf_ptr);
4020 if (buf->host_buf_ptr)
4023 usleep_range(1000, 2000);
4026 if (!buf->host_buf_ptr)
4029 buf->host_buf_mem_type = WMFW_ADSP2_XM;
4031 ret = wm_adsp_buffer_populate(buf);
4035 compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr);
4040 static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
4042 struct wm_adsp_host_buf_coeff_v1 coeff_v1;
4043 struct wm_adsp_compr_buf *buf;
4044 struct wm_adsp *dsp = cs_ctl->dsp;
4045 unsigned int version;
4048 for (i = 0; i < 5; ++i) {
4049 ret = cs_dsp_coeff_read_ctrl(cs_ctl, &coeff_v1, sizeof(coeff_v1));
4053 if (coeff_v1.host_buf_ptr)
4056 usleep_range(1000, 2000);
4059 if (!coeff_v1.host_buf_ptr) {
4060 adsp_err(dsp, "Failed to acquire host buffer\n");
4064 buf = wm_adsp_buffer_alloc(dsp);
4068 buf->host_buf_mem_type = cs_ctl->alg_region.type;
4069 buf->host_buf_ptr = be32_to_cpu(coeff_v1.host_buf_ptr);
4071 ret = wm_adsp_buffer_populate(buf);
4076 * v0 host_buffer coefficients didn't have versioning, so if the
4077 * control is one word, assume version 0.
4079 if (cs_ctl->len == 4) {
4080 compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr);
4084 version = be32_to_cpu(coeff_v1.versions) & HOST_BUF_COEFF_COMPAT_VER_MASK;
4085 version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
4087 if (version > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
4089 "Host buffer coeff ver %u > supported version %u\n",
4090 version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
4094 cs_dsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name));
4096 buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", dsp->part,
4097 (char *)&coeff_v1.name);
4099 compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
4100 buf->host_buf_ptr, version);
4105 static int wm_adsp_buffer_init(struct wm_adsp *dsp)
4107 struct cs_dsp_coeff_ctl *cs_ctl;
4110 list_for_each_entry(cs_ctl, &dsp->ctl_list, list) {
4111 if (cs_ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
4114 if (!cs_ctl->enabled)
4117 ret = wm_adsp_buffer_parse_coeff(cs_ctl);
4119 adsp_err(dsp, "Failed to parse coeff: %d\n", ret);
4121 } else if (ret == 0) {
4122 /* Only one buffer supported for version 0 */
4127 if (list_empty(&dsp->buffer_list)) {
4128 /* Fall back to legacy support */
4129 ret = wm_adsp_buffer_parse_legacy(dsp);
4131 adsp_err(dsp, "Failed to parse legacy: %d\n", ret);
4139 wm_adsp_buffer_free(dsp);
4143 static int wm_adsp_buffer_free(struct wm_adsp *dsp)
4145 struct wm_adsp_compr_buf *buf, *tmp;
4147 list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) {
4148 wm_adsp_compr_detach(buf->compr);
4151 kfree(buf->regions);
4152 list_del(&buf->list);
4159 static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
4163 ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
4165 compr_err(buf, "Failed to check buffer error: %d\n", ret);
4168 if (buf->error != 0) {
4169 compr_err(buf, "Buffer error occurred: %d\n", buf->error);
4176 int wm_adsp_compr_trigger(struct snd_soc_component *component,
4177 struct snd_compr_stream *stream, int cmd)
4179 struct wm_adsp_compr *compr = stream->runtime->private_data;
4180 struct wm_adsp *dsp = compr->dsp;
4183 compr_dbg(compr, "Trigger: %d\n", cmd);
4185 mutex_lock(&dsp->pwr_lock);
4188 case SNDRV_PCM_TRIGGER_START:
4189 if (!wm_adsp_compr_attached(compr)) {
4190 ret = wm_adsp_compr_attach(compr);
4192 compr_err(compr, "Failed to link buffer and stream: %d\n",
4198 ret = wm_adsp_buffer_get_error(compr->buf);
4202 /* Trigger the IRQ at one fragment of data */
4203 ret = wm_adsp_buffer_write(compr->buf,
4204 HOST_BUFFER_FIELD(high_water_mark),
4205 wm_adsp_compr_frag_words(compr));
4207 compr_err(compr, "Failed to set high water mark: %d\n",
4212 case SNDRV_PCM_TRIGGER_STOP:
4213 if (wm_adsp_compr_attached(compr))
4214 wm_adsp_buffer_clear(compr->buf);
4221 mutex_unlock(&dsp->pwr_lock);
4225 EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
4227 static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
4229 int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
4231 return buf->regions[last_region].cumulative_size;
4234 static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
4236 u32 next_read_index, next_write_index;
4237 int write_index, read_index, avail;
4240 /* Only sync read index if we haven't already read a valid index */
4241 if (buf->read_index < 0) {
4242 ret = wm_adsp_buffer_read(buf,
4243 HOST_BUFFER_FIELD(next_read_index),
4248 read_index = sign_extend32(next_read_index, 23);
4250 if (read_index < 0) {
4251 compr_dbg(buf, "Avail check on unstarted stream\n");
4255 buf->read_index = read_index;
4258 ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
4263 write_index = sign_extend32(next_write_index, 23);
4265 avail = write_index - buf->read_index;
4267 avail += wm_adsp_buffer_size(buf);
4269 compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
4270 buf->read_index, write_index, avail * CS_DSP_DATA_WORD_SIZE);
4277 int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
4279 struct wm_adsp_compr_buf *buf;
4280 struct wm_adsp_compr *compr;
4283 mutex_lock(&dsp->pwr_lock);
4285 if (list_empty(&dsp->buffer_list)) {
4290 adsp_dbg(dsp, "Handling buffer IRQ\n");
4292 list_for_each_entry(buf, &dsp->buffer_list, list) {
4295 ret = wm_adsp_buffer_get_error(buf);
4297 goto out_notify; /* Wake poll to report error */
4299 ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
4302 compr_err(buf, "Failed to get irq_count: %d\n", ret);
4306 ret = wm_adsp_buffer_update_avail(buf);
4308 compr_err(buf, "Error reading avail: %d\n", ret);
4312 if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
4313 ret = WM_ADSP_COMPR_VOICE_TRIGGER;
4316 if (compr && compr->stream)
4317 snd_compr_fragment_elapsed(compr->stream);
4321 mutex_unlock(&dsp->pwr_lock);
4325 EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
4327 static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
4329 if (buf->irq_count & 0x01)
4332 compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count);
4334 buf->irq_count |= 0x01;
4336 return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
4340 int wm_adsp_compr_pointer(struct snd_soc_component *component,
4341 struct snd_compr_stream *stream,
4342 struct snd_compr_tstamp *tstamp)
4344 struct wm_adsp_compr *compr = stream->runtime->private_data;
4345 struct wm_adsp *dsp = compr->dsp;
4346 struct wm_adsp_compr_buf *buf;
4349 compr_dbg(compr, "Pointer request\n");
4351 mutex_lock(&dsp->pwr_lock);
4355 if (dsp->fatal_error || !buf || buf->error) {
4356 snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
4361 if (buf->avail < wm_adsp_compr_frag_words(compr)) {
4362 ret = wm_adsp_buffer_update_avail(buf);
4364 compr_err(compr, "Error reading avail: %d\n", ret);
4369 * If we really have less than 1 fragment available tell the
4370 * DSP to inform us once a whole fragment is available.
4372 if (buf->avail < wm_adsp_compr_frag_words(compr)) {
4373 ret = wm_adsp_buffer_get_error(buf);
4376 snd_compr_stop_error(stream,
4377 SNDRV_PCM_STATE_XRUN);
4381 ret = wm_adsp_buffer_reenable_irq(buf);
4383 compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
4390 tstamp->copied_total = compr->copied_total;
4391 tstamp->copied_total += buf->avail * CS_DSP_DATA_WORD_SIZE;
4392 tstamp->sampling_rate = compr->sample_rate;
4395 mutex_unlock(&dsp->pwr_lock);
4399 EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
4401 static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
4403 struct wm_adsp_compr_buf *buf = compr->buf;
4404 unsigned int adsp_addr;
4405 int mem_type, nwords, max_read;
4408 /* Calculate read parameters */
4409 for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
4410 if (buf->read_index < buf->regions[i].cumulative_size)
4413 if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
4416 mem_type = buf->regions[i].mem_type;
4417 adsp_addr = buf->regions[i].base_addr +
4418 (buf->read_index - buf->regions[i].offset);
4420 max_read = wm_adsp_compr_frag_words(compr);
4421 nwords = buf->regions[i].cumulative_size - buf->read_index;
4423 if (nwords > target)
4425 if (nwords > buf->avail)
4426 nwords = buf->avail;
4427 if (nwords > max_read)
4432 /* Read data from DSP */
4433 ret = cs_dsp_read_raw_data_block(buf->dsp, mem_type, adsp_addr,
4434 nwords, (__be32 *)compr->raw_buf);
4438 cs_dsp_remove_padding(compr->raw_buf, nwords);
4440 /* update read index to account for words read */
4441 buf->read_index += nwords;
4442 if (buf->read_index == wm_adsp_buffer_size(buf))
4443 buf->read_index = 0;
4445 ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
4450 /* update avail to account for words read */
4451 buf->avail -= nwords;
4456 static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
4457 char __user *buf, size_t count)
4459 struct wm_adsp *dsp = compr->dsp;
4463 compr_dbg(compr, "Requested read of %zu bytes\n", count);
4465 if (dsp->fatal_error || !compr->buf || compr->buf->error) {
4466 snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
4470 count /= CS_DSP_DATA_WORD_SIZE;
4473 nwords = wm_adsp_buffer_capture_block(compr, count);
4475 compr_err(compr, "Failed to capture block: %d\n",
4480 nbytes = nwords * CS_DSP_DATA_WORD_SIZE;
4482 compr_dbg(compr, "Read %d bytes\n", nbytes);
4484 if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
4485 compr_err(compr, "Failed to copy data to user: %d, %d\n",
4492 } while (nwords > 0 && count > 0);
4494 compr->copied_total += ntotal;
4499 int wm_adsp_compr_copy(struct snd_soc_component *component,
4500 struct snd_compr_stream *stream, char __user *buf,
4503 struct wm_adsp_compr *compr = stream->runtime->private_data;
4504 struct wm_adsp *dsp = compr->dsp;
4507 mutex_lock(&dsp->pwr_lock);
4509 if (stream->direction == SND_COMPRESS_CAPTURE)
4510 ret = wm_adsp_compr_read(compr, buf, count);
4514 mutex_unlock(&dsp->pwr_lock);
4518 EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
4520 static void wm_adsp_fatal_error(struct wm_adsp *dsp)
4522 struct wm_adsp_compr *compr;
4524 dsp->fatal_error = true;
4526 list_for_each_entry(compr, &dsp->compr_list, list) {
4528 snd_compr_fragment_elapsed(compr->stream);
4532 static void cs_dsp_adsp2_bus_error(struct wm_adsp *dsp)
4535 struct regmap *regmap = dsp->regmap;
4538 mutex_lock(&dsp->pwr_lock);
4540 ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
4543 "Failed to read Region Lock Ctrl register: %d\n", ret);
4547 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
4548 cs_dsp_err(dsp, "watchdog timeout error\n");
4549 dsp->ops->stop_watchdog(dsp);
4550 wm_adsp_fatal_error(dsp);
4553 if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
4554 if (val & ADSP2_ADDR_ERR_MASK)
4555 cs_dsp_err(dsp, "bus error: address error\n");
4557 cs_dsp_err(dsp, "bus error: region lock error\n");
4559 ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
4562 "Failed to read Bus Err Addr register: %d\n",
4567 cs_dsp_err(dsp, "bus error address = 0x%x\n",
4568 val & ADSP2_BUS_ERR_ADDR_MASK);
4570 ret = regmap_read(regmap,
4571 dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
4575 "Failed to read Pmem Xmem Err Addr register: %d\n",
4580 cs_dsp_err(dsp, "xmem error address = 0x%x\n",
4581 val & ADSP2_XMEM_ERR_ADDR_MASK);
4582 cs_dsp_err(dsp, "pmem error address = 0x%x\n",
4583 (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
4584 ADSP2_PMEM_ERR_ADDR_SHIFT);
4587 regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
4588 ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
4591 mutex_unlock(&dsp->pwr_lock);
4594 irqreturn_t wm_adsp2_bus_error(int irq, void *data)
4596 struct wm_adsp *dsp = (struct wm_adsp *)data;
4598 cs_dsp_adsp2_bus_error(dsp);
4602 EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
4604 static void cs_dsp_halo_bus_error(struct wm_adsp *dsp)
4606 struct regmap *regmap = dsp->regmap;
4607 unsigned int fault[6];
4608 struct reg_sequence clear[] = {
4609 { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 },
4610 { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 },
4611 { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 },
4615 mutex_lock(&dsp->pwr_lock);
4617 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
4620 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
4624 cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
4625 *fault & HALO_AHBM_FLAGS_ERR_MASK,
4626 (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
4627 HALO_AHBM_CORE_ERR_ADDR_SHIFT);
4629 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
4632 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
4636 cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
4638 ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
4639 fault, ARRAY_SIZE(fault));
4641 cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
4645 cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
4646 cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
4647 cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
4649 ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
4651 cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
4654 mutex_unlock(&dsp->pwr_lock);
4657 irqreturn_t wm_halo_bus_error(int irq, void *data)
4659 struct wm_adsp *dsp = (struct wm_adsp *)data;
4661 cs_dsp_halo_bus_error(dsp);
4665 EXPORT_SYMBOL_GPL(wm_halo_bus_error);
4667 static void cs_dsp_halo_wdt_expire(struct wm_adsp *dsp)
4669 mutex_lock(&dsp->pwr_lock);
4671 cs_dsp_warn(dsp, "WDT Expiry Fault\n");
4673 dsp->ops->stop_watchdog(dsp);
4674 wm_adsp_fatal_error(dsp);
4676 mutex_unlock(&dsp->pwr_lock);
4679 irqreturn_t wm_halo_wdt_expire(int irq, void *data)
4681 struct wm_adsp *dsp = data;
4683 cs_dsp_halo_wdt_expire(dsp);
4687 EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
4689 static const struct cs_dsp_ops cs_dsp_adsp1_ops = {
4690 .validate_version = cs_dsp_validate_version,
4691 .parse_sizes = cs_dsp_adsp1_parse_sizes,
4692 .region_to_reg = cs_dsp_region_to_reg,
4695 static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = {
4697 .parse_sizes = cs_dsp_adsp2_parse_sizes,
4698 .validate_version = cs_dsp_validate_version,
4699 .setup_algs = cs_dsp_adsp2_setup_algs,
4700 .region_to_reg = cs_dsp_region_to_reg,
4702 .show_fw_status = cs_dsp_adsp2_show_fw_status,
4704 .enable_memory = cs_dsp_adsp2_enable_memory,
4705 .disable_memory = cs_dsp_adsp2_disable_memory,
4707 .enable_core = cs_dsp_adsp2_enable_core,
4708 .disable_core = cs_dsp_adsp2_disable_core,
4710 .start_core = cs_dsp_adsp2_start_core,
4711 .stop_core = cs_dsp_adsp2_stop_core,
4715 .parse_sizes = cs_dsp_adsp2_parse_sizes,
4716 .validate_version = cs_dsp_validate_version,
4717 .setup_algs = cs_dsp_adsp2_setup_algs,
4718 .region_to_reg = cs_dsp_region_to_reg,
4720 .show_fw_status = cs_dsp_adsp2v2_show_fw_status,
4722 .enable_memory = cs_dsp_adsp2_enable_memory,
4723 .disable_memory = cs_dsp_adsp2_disable_memory,
4724 .lock_memory = cs_dsp_adsp2_lock,
4726 .enable_core = cs_dsp_adsp2v2_enable_core,
4727 .disable_core = cs_dsp_adsp2v2_disable_core,
4729 .start_core = cs_dsp_adsp2_start_core,
4730 .stop_core = cs_dsp_adsp2_stop_core,
4733 .parse_sizes = cs_dsp_adsp2_parse_sizes,
4734 .validate_version = cs_dsp_validate_version,
4735 .setup_algs = cs_dsp_adsp2_setup_algs,
4736 .region_to_reg = cs_dsp_region_to_reg,
4738 .show_fw_status = cs_dsp_adsp2v2_show_fw_status,
4739 .stop_watchdog = cs_dsp_stop_watchdog,
4741 .enable_memory = cs_dsp_adsp2_enable_memory,
4742 .disable_memory = cs_dsp_adsp2_disable_memory,
4743 .lock_memory = cs_dsp_adsp2_lock,
4745 .enable_core = cs_dsp_adsp2v2_enable_core,
4746 .disable_core = cs_dsp_adsp2v2_disable_core,
4748 .start_core = cs_dsp_adsp2_start_core,
4749 .stop_core = cs_dsp_adsp2_stop_core,
4753 static const struct cs_dsp_ops cs_dsp_halo_ops = {
4754 .parse_sizes = cs_dsp_adsp2_parse_sizes,
4755 .validate_version = cs_dsp_halo_validate_version,
4756 .setup_algs = cs_dsp_halo_setup_algs,
4757 .region_to_reg = cs_dsp_halo_region_to_reg,
4759 .show_fw_status = cs_dsp_halo_show_fw_status,
4760 .stop_watchdog = cs_dsp_halo_stop_watchdog,
4762 .lock_memory = cs_dsp_halo_configure_mpu,
4764 .start_core = cs_dsp_halo_start_core,
4765 .stop_core = cs_dsp_halo_stop_core,
4768 MODULE_LICENSE("GPL v2");