1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * wm_adsp.c  --  Wolfson ADSP support
4 *
5 * Copyright 2012 Wolfson Microelectronics plc
6 *
7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8 */
9
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>
17#include <linux/pm.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
33#include "wm_adsp.h"
34
35#define adsp_crit(_dsp, fmt, ...) \
36	dev_crit(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
37#define adsp_err(_dsp, fmt, ...) \
38	dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
39#define adsp_warn(_dsp, fmt, ...) \
40	dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
41#define adsp_info(_dsp, fmt, ...) \
42	dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
43#define adsp_dbg(_dsp, fmt, ...) \
44	dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
45
46#define compr_err(_obj, fmt, ...) \
47	adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
48		 ##__VA_ARGS__)
49#define compr_dbg(_obj, fmt, ...) \
50	adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
51		 ##__VA_ARGS__)
52
53#define ADSP1_CONTROL_1                   0x00
54#define ADSP1_CONTROL_2                   0x02
55#define ADSP1_CONTROL_3                   0x03
56#define ADSP1_CONTROL_4                   0x04
57#define ADSP1_CONTROL_5                   0x06
58#define ADSP1_CONTROL_6                   0x07
59#define ADSP1_CONTROL_7                   0x08
60#define ADSP1_CONTROL_8                   0x09
61#define ADSP1_CONTROL_9                   0x0A
62#define ADSP1_CONTROL_10                  0x0B
63#define ADSP1_CONTROL_11                  0x0C
64#define ADSP1_CONTROL_12                  0x0D
65#define ADSP1_CONTROL_13                  0x0F
66#define ADSP1_CONTROL_14                  0x10
67#define ADSP1_CONTROL_15                  0x11
68#define ADSP1_CONTROL_16                  0x12
69#define ADSP1_CONTROL_17                  0x13
70#define ADSP1_CONTROL_18                  0x14
71#define ADSP1_CONTROL_19                  0x16
72#define ADSP1_CONTROL_20                  0x17
73#define ADSP1_CONTROL_21                  0x18
74#define ADSP1_CONTROL_22                  0x1A
75#define ADSP1_CONTROL_23                  0x1B
76#define ADSP1_CONTROL_24                  0x1C
77#define ADSP1_CONTROL_25                  0x1E
78#define ADSP1_CONTROL_26                  0x20
79#define ADSP1_CONTROL_27                  0x21
80#define ADSP1_CONTROL_28                  0x22
81#define ADSP1_CONTROL_29                  0x23
82#define ADSP1_CONTROL_30                  0x24
83#define ADSP1_CONTROL_31                  0x26
84
85/*
86 * ADSP1 Control 19
87 */
88#define ADSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
89#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
90#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
91
92
93/*
94 * ADSP1 Control 30
95 */
96#define ADSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
97#define ADSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
98#define ADSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
99#define ADSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
100#define ADSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
101#define ADSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
102#define ADSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
103#define ADSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
104#define ADSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
105#define ADSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
106#define ADSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
107#define ADSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
108#define ADSP1_START                       0x0001  /* DSP1_START */
109#define ADSP1_START_MASK                  0x0001  /* DSP1_START */
110#define ADSP1_START_SHIFT                      0  /* DSP1_START */
111#define ADSP1_START_WIDTH                      1  /* DSP1_START */
112
113/*
114 * ADSP1 Control 31
115 */
116#define ADSP1_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
117#define ADSP1_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
118#define ADSP1_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
119
120#define ADSP2_CONTROL                     0x0
121#define ADSP2_CLOCKING                    0x1
122#define ADSP2V2_CLOCKING                  0x2
123#define ADSP2_STATUS1                     0x4
124#define ADSP2_WDMA_CONFIG_1               0x30
125#define ADSP2_WDMA_CONFIG_2               0x31
126#define ADSP2V2_WDMA_CONFIG_2             0x32
127#define ADSP2_RDMA_CONFIG_1               0x34
128
129#define ADSP2_SCRATCH0                    0x40
130#define ADSP2_SCRATCH1                    0x41
131#define ADSP2_SCRATCH2                    0x42
132#define ADSP2_SCRATCH3                    0x43
133
134#define ADSP2V2_SCRATCH0_1                0x40
135#define ADSP2V2_SCRATCH2_3                0x42
136
137/*
138 * ADSP2 Control
139 */
140
141#define ADSP2_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
142#define ADSP2_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
143#define ADSP2_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
144#define ADSP2_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
145#define ADSP2_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
146#define ADSP2_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
147#define ADSP2_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
148#define ADSP2_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
149#define ADSP2_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
150#define ADSP2_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
151#define ADSP2_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
152#define ADSP2_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
153#define ADSP2_START                       0x0001  /* DSP1_START */
154#define ADSP2_START_MASK                  0x0001  /* DSP1_START */
155#define ADSP2_START_SHIFT                      0  /* DSP1_START */
156#define ADSP2_START_WIDTH                      1  /* DSP1_START */
157
158/*
159 * ADSP2 clocking
160 */
161#define ADSP2_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
162#define ADSP2_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
163#define ADSP2_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
164
165/*
166 * ADSP2V2 clocking
167 */
168#define ADSP2V2_CLK_SEL_MASK             0x70000  /* CLK_SEL_ENA */
169#define ADSP2V2_CLK_SEL_SHIFT                 16  /* CLK_SEL_ENA */
170#define ADSP2V2_CLK_SEL_WIDTH                  3  /* CLK_SEL_ENA */
171
172#define ADSP2V2_RATE_MASK                 0x7800  /* DSP_RATE */
173#define ADSP2V2_RATE_SHIFT                    11  /* DSP_RATE */
174#define ADSP2V2_RATE_WIDTH                     4  /* DSP_RATE */
175
176/*
177 * ADSP2 Status 1
178 */
179#define ADSP2_RAM_RDY                     0x0001
180#define ADSP2_RAM_RDY_MASK                0x0001
181#define ADSP2_RAM_RDY_SHIFT                    0
182#define ADSP2_RAM_RDY_WIDTH                    1
183
184/*
185 * ADSP2 Lock support
186 */
187#define ADSP2_LOCK_CODE_0                    0x5555
188#define ADSP2_LOCK_CODE_1                    0xAAAA
189
190#define ADSP2_WATCHDOG                       0x0A
191#define ADSP2_BUS_ERR_ADDR                   0x52
192#define ADSP2_REGION_LOCK_STATUS             0x64
193#define ADSP2_LOCK_REGION_1_LOCK_REGION_0    0x66
194#define ADSP2_LOCK_REGION_3_LOCK_REGION_2    0x68
195#define ADSP2_LOCK_REGION_5_LOCK_REGION_4    0x6A
196#define ADSP2_LOCK_REGION_7_LOCK_REGION_6    0x6C
197#define ADSP2_LOCK_REGION_9_LOCK_REGION_8    0x6E
198#define ADSP2_LOCK_REGION_CTRL               0x7A
199#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR    0x7C
200
201#define ADSP2_REGION_LOCK_ERR_MASK           0x8000
202#define ADSP2_ADDR_ERR_MASK                  0x4000
203#define ADSP2_WDT_TIMEOUT_STS_MASK           0x2000
204#define ADSP2_CTRL_ERR_PAUSE_ENA             0x0002
205#define ADSP2_CTRL_ERR_EINT                  0x0001
206
207#define ADSP2_BUS_ERR_ADDR_MASK              0x00FFFFFF
208#define ADSP2_XMEM_ERR_ADDR_MASK             0x0000FFFF
209#define ADSP2_PMEM_ERR_ADDR_MASK             0x7FFF0000
210#define ADSP2_PMEM_ERR_ADDR_SHIFT            16
211#define ADSP2_WDT_ENA_MASK                   0xFFFFFFFD
212
213#define ADSP2_LOCK_REGION_SHIFT              16
214
215#define ADSP_MAX_STD_CTRL_SIZE               512
216
217#define WM_ADSP_ACKED_CTL_TIMEOUT_MS         100
218#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS       10
219#define WM_ADSP_ACKED_CTL_MIN_VALUE          0
220#define WM_ADSP_ACKED_CTL_MAX_VALUE          0xFFFFFF
221
222/*
223 * Event control messages
224 */
225#define WM_ADSP_FW_EVENT_SHUTDOWN            0x000001
226
227/*
228 * HALO system info
229 */
230#define HALO_AHBM_WINDOW_DEBUG_0             0x02040
231#define HALO_AHBM_WINDOW_DEBUG_1             0x02044
232
233/*
234 * HALO core
235 */
236#define HALO_SCRATCH1                        0x005c0
237#define HALO_SCRATCH2                        0x005c8
238#define HALO_SCRATCH3                        0x005d0
239#define HALO_SCRATCH4                        0x005d8
240#define HALO_CCM_CORE_CONTROL                0x41000
241#define HALO_CORE_SOFT_RESET                 0x00010
242#define HALO_WDT_CONTROL                     0x47000
243
244/*
245 * HALO MPU banks
246 */
247#define HALO_MPU_XMEM_ACCESS_0               0x43000
248#define HALO_MPU_YMEM_ACCESS_0               0x43004
249#define HALO_MPU_WINDOW_ACCESS_0             0x43008
250#define HALO_MPU_XREG_ACCESS_0               0x4300C
251#define HALO_MPU_YREG_ACCESS_0               0x43014
252#define HALO_MPU_XMEM_ACCESS_1               0x43018
253#define HALO_MPU_YMEM_ACCESS_1               0x4301C
254#define HALO_MPU_WINDOW_ACCESS_1             0x43020
255#define HALO_MPU_XREG_ACCESS_1               0x43024
256#define HALO_MPU_YREG_ACCESS_1               0x4302C
257#define HALO_MPU_XMEM_ACCESS_2               0x43030
258#define HALO_MPU_YMEM_ACCESS_2               0x43034
259#define HALO_MPU_WINDOW_ACCESS_2             0x43038
260#define HALO_MPU_XREG_ACCESS_2               0x4303C
261#define HALO_MPU_YREG_ACCESS_2               0x43044
262#define HALO_MPU_XMEM_ACCESS_3               0x43048
263#define HALO_MPU_YMEM_ACCESS_3               0x4304C
264#define HALO_MPU_WINDOW_ACCESS_3             0x43050
265#define HALO_MPU_XREG_ACCESS_3               0x43054
266#define HALO_MPU_YREG_ACCESS_3               0x4305C
267#define HALO_MPU_XM_VIO_ADDR                 0x43100
268#define HALO_MPU_XM_VIO_STATUS               0x43104
269#define HALO_MPU_YM_VIO_ADDR                 0x43108
270#define HALO_MPU_YM_VIO_STATUS               0x4310C
271#define HALO_MPU_PM_VIO_ADDR                 0x43110
272#define HALO_MPU_PM_VIO_STATUS               0x43114
273#define HALO_MPU_LOCK_CONFIG                 0x43140
274
275/*
276 * HALO_AHBM_WINDOW_DEBUG_1
277 */
278#define HALO_AHBM_CORE_ERR_ADDR_MASK         0x0fffff00
279#define HALO_AHBM_CORE_ERR_ADDR_SHIFT                 8
280#define HALO_AHBM_FLAGS_ERR_MASK             0x000000ff
281
282/*
283 * HALO_CCM_CORE_CONTROL
284 */
285#define HALO_CORE_EN                        0x00000001
286
287/*
288 * HALO_CORE_SOFT_RESET
289 */
290#define HALO_CORE_SOFT_RESET_MASK           0x00000001
291
292/*
293 * HALO_WDT_CONTROL
294 */
295#define HALO_WDT_EN_MASK                    0x00000001
296
297/*
298 * HALO_MPU_?M_VIO_STATUS
299 */
300#define HALO_MPU_VIO_STS_MASK               0x007e0000
301#define HALO_MPU_VIO_STS_SHIFT                      17
302#define HALO_MPU_VIO_ERR_WR_MASK            0x00008000
303#define HALO_MPU_VIO_ERR_SRC_MASK           0x00007fff
304#define HALO_MPU_VIO_ERR_SRC_SHIFT                   0
305
306static struct wm_adsp_ops wm_adsp1_ops;
307static struct wm_adsp_ops wm_adsp2_ops[];
308static struct wm_adsp_ops wm_halo_ops;
309
310struct wm_adsp_buf {
311	struct list_head list;
312	void *buf;
313};
314
315static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
316					     struct list_head *list)
317{
318	struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
319
320	if (buf == NULL)
321		return NULL;
322
323	buf->buf = vmalloc(len);
324	if (!buf->buf) {
325		kfree(buf);
326		return NULL;
327	}
328	memcpy(buf->buf, src, len);
329
330	if (list)
331		list_add_tail(&buf->list, list);
332
333	return buf;
334}
335
336static void wm_adsp_buf_free(struct list_head *list)
337{
338	while (!list_empty(list)) {
339		struct wm_adsp_buf *buf = list_first_entry(list,
340							   struct wm_adsp_buf,
341							   list);
342		list_del(&buf->list);
343		vfree(buf->buf);
344		kfree(buf);
345	}
346}
347
348#define WM_ADSP_FW_MBC_VSS  0
349#define WM_ADSP_FW_HIFI     1
350#define WM_ADSP_FW_TX       2
351#define WM_ADSP_FW_TX_SPK   3
352#define WM_ADSP_FW_RX       4
353#define WM_ADSP_FW_RX_ANC   5
354#define WM_ADSP_FW_CTRL     6
355#define WM_ADSP_FW_ASR      7
356#define WM_ADSP_FW_TRACE    8
357#define WM_ADSP_FW_SPK_PROT 9
358#define WM_ADSP_FW_SPK_CALI 10
359#define WM_ADSP_FW_SPK_DIAG 11
360#define WM_ADSP_FW_MISC     12
361
362#define WM_ADSP_NUM_FW      13
363
364static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
365	[WM_ADSP_FW_MBC_VSS] =  "MBC/VSS",
366	[WM_ADSP_FW_HIFI] =     "MasterHiFi",
367	[WM_ADSP_FW_TX] =       "Tx",
368	[WM_ADSP_FW_TX_SPK] =   "Tx Speaker",
369	[WM_ADSP_FW_RX] =       "Rx",
370	[WM_ADSP_FW_RX_ANC] =   "Rx ANC",
371	[WM_ADSP_FW_CTRL] =     "Voice Ctrl",
372	[WM_ADSP_FW_ASR] =      "ASR Assist",
373	[WM_ADSP_FW_TRACE] =    "Dbg Trace",
374	[WM_ADSP_FW_SPK_PROT] = "Protection",
375	[WM_ADSP_FW_SPK_CALI] = "Calibration",
376	[WM_ADSP_FW_SPK_DIAG] = "Diagnostic",
377	[WM_ADSP_FW_MISC] =     "Misc",
378};
379
380struct wm_adsp_system_config_xm_hdr {
381	__be32 sys_enable;
382	__be32 fw_id;
383	__be32 fw_rev;
384	__be32 boot_status;
385	__be32 watchdog;
386	__be32 dma_buffer_size;
387	__be32 rdma[6];
388	__be32 wdma[8];
389	__be32 build_job_name[3];
390	__be32 build_job_number;
391};
392
393struct wm_halo_system_config_xm_hdr {
394	__be32 halo_heartbeat;
395	__be32 build_job_name[3];
396	__be32 build_job_number;
397};
398
399struct wm_adsp_alg_xm_struct {
400	__be32 magic;
401	__be32 smoothing;
402	__be32 threshold;
403	__be32 host_buf_ptr;
404	__be32 start_seq;
405	__be32 high_water_mark;
406	__be32 low_water_mark;
407	__be64 smoothed_power;
408};
409
410struct wm_adsp_host_buf_coeff_v1 {
411	__be32 host_buf_ptr;		/* Host buffer pointer */
412	__be32 versions;		/* Version numbers */
413	__be32 name[4];			/* The buffer name */
414};
415
416struct wm_adsp_buffer {
417	__be32 buf1_base;		/* Base addr of first buffer area */
418	__be32 buf1_size;		/* Size of buf1 area in DSP words */
419	__be32 buf2_base;		/* Base addr of 2nd buffer area */
420	__be32 buf1_buf2_size;		/* Size of buf1+buf2 in DSP words */
421	__be32 buf3_base;		/* Base addr of buf3 area */
422	__be32 buf_total_size;		/* Size of buf1+buf2+buf3 in DSP words */
423	__be32 high_water_mark;		/* Point at which IRQ is asserted */
424	__be32 irq_count;		/* bits 1-31 count IRQ assertions */
425	__be32 irq_ack;			/* acked IRQ count, bit 0 enables IRQ */
426	__be32 next_write_index;	/* word index of next write */
427	__be32 next_read_index;		/* word index of next read */
428	__be32 error;			/* error if any */
429	__be32 oldest_block_index;	/* word index of oldest surviving */
430	__be32 requested_rewind;	/* how many blocks rewind was done */
431	__be32 reserved_space;		/* internal */
432	__be32 min_free;		/* min free space since stream start */
433	__be32 blocks_written[2];	/* total blocks written (64 bit) */
434	__be32 words_written[2];	/* total words written (64 bit) */
435};
436
437struct wm_adsp_compr;
438
439struct wm_adsp_compr_buf {
440	struct list_head list;
441	struct wm_adsp *dsp;
442	struct wm_adsp_compr *compr;
443
444	struct wm_adsp_buffer_region *regions;
445	u32 host_buf_ptr;
446
447	u32 error;
448	u32 irq_count;
449	int read_index;
450	int avail;
451	int host_buf_mem_type;
452
453	char *name;
454};
455
456struct wm_adsp_compr {
457	struct list_head list;
458	struct wm_adsp *dsp;
459	struct wm_adsp_compr_buf *buf;
460
461	struct snd_compr_stream *stream;
462	struct snd_compressed_buffer size;
463
464	u32 *raw_buf;
465	unsigned int copied_total;
466
467	unsigned int sample_rate;
468
469	const char *name;
470};
471
472#define WM_ADSP_DATA_WORD_SIZE         3
473
474#define WM_ADSP_MIN_FRAGMENTS          1
475#define WM_ADSP_MAX_FRAGMENTS          256
476#define WM_ADSP_MIN_FRAGMENT_SIZE      (64 * WM_ADSP_DATA_WORD_SIZE)
477#define WM_ADSP_MAX_FRAGMENT_SIZE      (4096 * WM_ADSP_DATA_WORD_SIZE)
478
479#define WM_ADSP_ALG_XM_STRUCT_MAGIC    0x49aec7
480
481#define HOST_BUFFER_FIELD(field) \
482	(offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
483
484#define ALG_XM_FIELD(field) \
485	(offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
486
487#define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER	1
488
489#define HOST_BUF_COEFF_COMPAT_VER_MASK		0xFF00
490#define HOST_BUF_COEFF_COMPAT_VER_SHIFT		8
491
492static int wm_adsp_buffer_init(struct wm_adsp *dsp);
493static int wm_adsp_buffer_free(struct wm_adsp *dsp);
494
495struct wm_adsp_buffer_region {
496	unsigned int offset;
497	unsigned int cumulative_size;
498	unsigned int mem_type;
499	unsigned int base_addr;
500};
501
502struct wm_adsp_buffer_region_def {
503	unsigned int mem_type;
504	unsigned int base_offset;
505	unsigned int size_offset;
506};
507
508static const struct wm_adsp_buffer_region_def default_regions[] = {
509	{
510		.mem_type = WMFW_ADSP2_XM,
511		.base_offset = HOST_BUFFER_FIELD(buf1_base),
512		.size_offset = HOST_BUFFER_FIELD(buf1_size),
513	},
514	{
515		.mem_type = WMFW_ADSP2_XM,
516		.base_offset = HOST_BUFFER_FIELD(buf2_base),
517		.size_offset = HOST_BUFFER_FIELD(buf1_buf2_size),
518	},
519	{
520		.mem_type = WMFW_ADSP2_YM,
521		.base_offset = HOST_BUFFER_FIELD(buf3_base),
522		.size_offset = HOST_BUFFER_FIELD(buf_total_size),
523	},
524};
525
526struct wm_adsp_fw_caps {
527	u32 id;
528	struct snd_codec_desc desc;
529	int num_regions;
530	const struct wm_adsp_buffer_region_def *region_defs;
531};
532
533static const struct wm_adsp_fw_caps ctrl_caps[] = {
534	{
535		.id = SND_AUDIOCODEC_BESPOKE,
536		.desc = {
537			.max_ch = 8,
538			.sample_rates = { 16000 },
539			.num_sample_rates = 1,
540			.formats = SNDRV_PCM_FMTBIT_S16_LE,
541		},
542		.num_regions = ARRAY_SIZE(default_regions),
543		.region_defs = default_regions,
544	},
545};
546
547static const struct wm_adsp_fw_caps trace_caps[] = {
548	{
549		.id = SND_AUDIOCODEC_BESPOKE,
550		.desc = {
551			.max_ch = 8,
552			.sample_rates = {
553				4000, 8000, 11025, 12000, 16000, 22050,
554				24000, 32000, 44100, 48000, 64000, 88200,
555				96000, 176400, 192000
556			},
557			.num_sample_rates = 15,
558			.formats = SNDRV_PCM_FMTBIT_S16_LE,
559		},
560		.num_regions = ARRAY_SIZE(default_regions),
561		.region_defs = default_regions,
562	},
563};
564
565static const struct {
566	const char *file;
567	int compr_direction;
568	int num_caps;
569	const struct wm_adsp_fw_caps *caps;
570	bool voice_trigger;
571} wm_adsp_fw[WM_ADSP_NUM_FW] = {
572	[WM_ADSP_FW_MBC_VSS] =  { .file = "mbc-vss" },
573	[WM_ADSP_FW_HIFI] =     { .file = "hifi" },
574	[WM_ADSP_FW_TX] =       { .file = "tx" },
575	[WM_ADSP_FW_TX_SPK] =   { .file = "tx-spk" },
576	[WM_ADSP_FW_RX] =       { .file = "rx" },
577	[WM_ADSP_FW_RX_ANC] =   { .file = "rx-anc" },
578	[WM_ADSP_FW_CTRL] =     {
579		.file = "ctrl",
580		.compr_direction = SND_COMPRESS_CAPTURE,
581		.num_caps = ARRAY_SIZE(ctrl_caps),
582		.caps = ctrl_caps,
583		.voice_trigger = true,
584	},
585	[WM_ADSP_FW_ASR] =      { .file = "asr" },
586	[WM_ADSP_FW_TRACE] =    {
587		.file = "trace",
588		.compr_direction = SND_COMPRESS_CAPTURE,
589		.num_caps = ARRAY_SIZE(trace_caps),
590		.caps = trace_caps,
591	},
592	[WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
593	[WM_ADSP_FW_SPK_CALI] = { .file = "spk-cali" },
594	[WM_ADSP_FW_SPK_DIAG] = { .file = "spk-diag" },
595	[WM_ADSP_FW_MISC] =     { .file = "misc" },
596};
597
598struct wm_coeff_ctl_ops {
599	int (*xget)(struct snd_kcontrol *kcontrol,
600		    struct snd_ctl_elem_value *ucontrol);
601	int (*xput)(struct snd_kcontrol *kcontrol,
602		    struct snd_ctl_elem_value *ucontrol);
603};
604
605struct wm_coeff_ctl {
606	const char *name;
607	const char *fw_name;
608	/* Subname is needed to match with firmware */
609	const char *subname;
610	unsigned int subname_len;
611	struct wm_adsp_alg_region alg_region;
612	struct wm_coeff_ctl_ops ops;
613	struct wm_adsp *dsp;
614	unsigned int enabled:1;
615	struct list_head list;
616	void *cache;
617	unsigned int offset;
618	size_t len;
619	unsigned int set:1;
620	struct soc_bytes_ext bytes_ext;
621	unsigned int flags;
622	unsigned int type;
623};
624
625static const char *wm_adsp_mem_region_name(unsigned int type)
626{
627	switch (type) {
628	case WMFW_ADSP1_PM:
629		return "PM";
630	case WMFW_HALO_PM_PACKED:
631		return "PM_PACKED";
632	case WMFW_ADSP1_DM:
633		return "DM";
634	case WMFW_ADSP2_XM:
635		return "XM";
636	case WMFW_HALO_XM_PACKED:
637		return "XM_PACKED";
638	case WMFW_ADSP2_YM:
639		return "YM";
640	case WMFW_HALO_YM_PACKED:
641		return "YM_PACKED";
642	case WMFW_ADSP1_ZM:
643		return "ZM";
644	default:
645		return NULL;
646	}
647}
648
649#ifdef CONFIG_DEBUG_FS
650static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
651{
652	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
653
654	kfree(dsp->wmfw_file_name);
655	dsp->wmfw_file_name = tmp;
656}
657
658static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
659{
660	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
661
662	kfree(dsp->bin_file_name);
663	dsp->bin_file_name = tmp;
664}
665
666static void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
667{
668	kfree(dsp->wmfw_file_name);
669	kfree(dsp->bin_file_name);
670	dsp->wmfw_file_name = NULL;
671	dsp->bin_file_name = NULL;
672}
673
674static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
675					 char __user *user_buf,
676					 size_t count, loff_t *ppos)
677{
678	struct wm_adsp *dsp = file->private_data;
679	ssize_t ret;
680
681	mutex_lock(&dsp->pwr_lock);
682
683	if (!dsp->wmfw_file_name || !dsp->booted)
684		ret = 0;
685	else
686		ret = simple_read_from_buffer(user_buf, count, ppos,
687					      dsp->wmfw_file_name,
688					      strlen(dsp->wmfw_file_name));
689
690	mutex_unlock(&dsp->pwr_lock);
691	return ret;
692}
693
694static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
695					char __user *user_buf,
696					size_t count, loff_t *ppos)
697{
698	struct wm_adsp *dsp = file->private_data;
699	ssize_t ret;
700
701	mutex_lock(&dsp->pwr_lock);
702
703	if (!dsp->bin_file_name || !dsp->booted)
704		ret = 0;
705	else
706		ret = simple_read_from_buffer(user_buf, count, ppos,
707					      dsp->bin_file_name,
708					      strlen(dsp->bin_file_name));
709
710	mutex_unlock(&dsp->pwr_lock);
711	return ret;
712}
713
714static const struct {
715	const char *name;
716	const struct file_operations fops;
717} wm_adsp_debugfs_fops[] = {
718	{
719		.name = "wmfw_file_name",
720		.fops = {
721			.open = simple_open,
722			.read = wm_adsp_debugfs_wmfw_read,
723		},
724	},
725	{
726		.name = "bin_file_name",
727		.fops = {
728			.open = simple_open,
729			.read = wm_adsp_debugfs_bin_read,
730		},
731	},
732};
733
734static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
735				  struct snd_soc_component *component)
736{
737	struct dentry *root = NULL;
738	int i;
739
740	root = debugfs_create_dir(dsp->name, component->debugfs_root);
741
742	debugfs_create_bool("booted", 0444, root, &dsp->booted);
743	debugfs_create_bool("running", 0444, root, &dsp->running);
744	debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
745	debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
746
747	for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i)
748		debugfs_create_file(wm_adsp_debugfs_fops[i].name, 0444, root,
749				    dsp, &wm_adsp_debugfs_fops[i].fops);
750
751	dsp->debugfs_root = root;
752}
753
754static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
755{
756	wm_adsp_debugfs_clear(dsp);
757	debugfs_remove_recursive(dsp->debugfs_root);
758}
759#else
760static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
761					 struct snd_soc_component *component)
762{
763}
764
765static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
766{
767}
768
769static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp,
770						 const char *s)
771{
772}
773
774static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp,
775						const char *s)
776{
777}
778
779static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
780{
781}
782#endif
783
784int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
785		   struct snd_ctl_elem_value *ucontrol)
786{
787	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
788	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
789	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
790
791	ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
792
793	return 0;
794}
795EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
796
797int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
798		   struct snd_ctl_elem_value *ucontrol)
799{
800	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
801	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
802	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
803	int ret = 1;
804
805	if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
806		return 0;
807
808	if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
809		return -EINVAL;
810
811	mutex_lock(&dsp[e->shift_l].pwr_lock);
812
813	if (dsp[e->shift_l].booted || !list_empty(&dsp[e->shift_l].compr_list))
814		ret = -EBUSY;
815	else
816		dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
817
818	mutex_unlock(&dsp[e->shift_l].pwr_lock);
819
820	return ret;
821}
822EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
823
824const struct soc_enum wm_adsp_fw_enum[] = {
825	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
826	SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
827	SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
828	SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
829	SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
830	SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
831	SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
832};
833EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
834
835static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
836							int type)
837{
838	int i;
839
840	for (i = 0; i < dsp->num_mems; i++)
841		if (dsp->mem[i].type == type)
842			return &dsp->mem[i];
843
844	return NULL;
845}
846
847static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
848					  unsigned int offset)
849{
850	switch (mem->type) {
851	case WMFW_ADSP1_PM:
852		return mem->base + (offset * 3);
853	case WMFW_ADSP1_DM:
854	case WMFW_ADSP2_XM:
855	case WMFW_ADSP2_YM:
856	case WMFW_ADSP1_ZM:
857		return mem->base + (offset * 2);
858	default:
859		WARN(1, "Unknown memory region type");
860		return offset;
861	}
862}
863
864static unsigned int wm_halo_region_to_reg(struct wm_adsp_region const *mem,
865					  unsigned int offset)
866{
867	switch (mem->type) {
868	case WMFW_ADSP2_XM:
869	case WMFW_ADSP2_YM:
870		return mem->base + (offset * 4);
871	case WMFW_HALO_XM_PACKED:
872	case WMFW_HALO_YM_PACKED:
873		return (mem->base + (offset * 3)) & ~0x3;
874	case WMFW_HALO_PM_PACKED:
875		return mem->base + (offset * 5);
876	default:
877		WARN(1, "Unknown memory region type");
878		return offset;
879	}
880}
881
882static void wm_adsp_read_fw_status(struct wm_adsp *dsp,
883				   int noffs, unsigned int *offs)
884{
885	unsigned int i;
886	int ret;
887
888	for (i = 0; i < noffs; ++i) {
889		ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
890		if (ret) {
891			adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
892			return;
893		}
894	}
895}
896
897static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
898{
899	unsigned int offs[] = {
900		ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
901	};
902
903	wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
904
905	adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
906		 offs[0], offs[1], offs[2], offs[3]);
907}
908
909static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp)
910{
911	unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
912
913	wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
914
915	adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
916		 offs[0] & 0xFFFF, offs[0] >> 16,
917		 offs[1] & 0xFFFF, offs[1] >> 16);
918}
919
920static void wm_halo_show_fw_status(struct wm_adsp *dsp)
921{
922	unsigned int offs[] = {
923		HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
924	};
925
926	wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
927
928	adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
929		 offs[0], offs[1], offs[2], offs[3]);
930}
931
932static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
933{
934	return container_of(ext, struct wm_coeff_ctl, bytes_ext);
935}
936
937static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg)
938{
939	const struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
940	struct wm_adsp *dsp = ctl->dsp;
941	const struct wm_adsp_region *mem;
942
943	mem = wm_adsp_find_region(dsp, alg_region->type);
944	if (!mem) {
945		adsp_err(dsp, "No base for region %x\n",
946			 alg_region->type);
947		return -EINVAL;
948	}
949
950	*reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset);
951
952	return 0;
953}
954
955static int wm_coeff_info(struct snd_kcontrol *kctl,
956			 struct snd_ctl_elem_info *uinfo)
957{
958	struct soc_bytes_ext *bytes_ext =
959		(struct soc_bytes_ext *)kctl->private_value;
960	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
961
962	switch (ctl->type) {
963	case WMFW_CTL_TYPE_ACKED:
964		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
965		uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE;
966		uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE;
967		uinfo->value.integer.step = 1;
968		uinfo->count = 1;
969		break;
970	default:
971		uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
972		uinfo->count = ctl->len;
973		break;
974	}
975
976	return 0;
977}
978
979static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
980					unsigned int event_id)
981{
982	struct wm_adsp *dsp = ctl->dsp;
983	u32 val = cpu_to_be32(event_id);
984	unsigned int reg;
985	int i, ret;
986
987	ret = wm_coeff_base_reg(ctl, &reg);
988	if (ret)
989		return ret;
990
991	adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
992		 event_id, ctl->alg_region.alg,
993		 wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset);
994
995	ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
996	if (ret) {
997		adsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
998		return ret;
999	}
1000
1001	/*
1002	 * Poll for ack, we initially poll at ~1ms intervals for firmwares
1003	 * that respond quickly, then go to ~10ms polls. A firmware is unlikely
1004	 * to ack instantly so we do the first 1ms delay before reading the
1005	 * control to avoid a pointless bus transaction
1006	 */
1007	for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) {
1008		switch (i) {
1009		case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1:
1010			usleep_range(1000, 2000);
1011			i++;
1012			break;
1013		default:
1014			usleep_range(10000, 20000);
1015			i += 10;
1016			break;
1017		}
1018
1019		ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
1020		if (ret) {
1021			adsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
1022			return ret;
1023		}
1024
1025		if (val == 0) {
1026			adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
1027			return 0;
1028		}
1029	}
1030
1031	adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
1032		  reg, ctl->alg_region.alg,
1033		  wm_adsp_mem_region_name(ctl->alg_region.type),
1034		  ctl->offset);
1035
1036	return -ETIMEDOUT;
1037}
1038
1039static int wm_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl,
1040				   const void *buf, size_t len)
1041{
1042	struct wm_adsp *dsp = ctl->dsp;
1043	void *scratch;
1044	int ret;
1045	unsigned int reg;
1046
1047	ret = wm_coeff_base_reg(ctl, &reg);
1048	if (ret)
1049		return ret;
1050
1051	scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
1052	if (!scratch)
1053		return -ENOMEM;
1054
1055	ret = regmap_raw_write(dsp->regmap, reg, scratch,
1056			       len);
1057	if (ret) {
1058		adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
1059			 len, reg, ret);
1060		kfree(scratch);
1061		return ret;
1062	}
1063	adsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
1064
1065	kfree(scratch);
1066
1067	return 0;
1068}
1069
1070static int wm_coeff_write_ctrl(struct wm_coeff_ctl *ctl,
1071			       const void *buf, size_t len)
1072{
1073	int ret = 0;
1074
1075	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1076		ret = -EPERM;
1077	else if (buf != ctl->cache)
1078		memcpy(ctl->cache, buf, len);
1079
1080	ctl->set = 1;
1081	if (ctl->enabled && ctl->dsp->running)
1082		ret = wm_coeff_write_ctrl_raw(ctl, buf, len);
1083
1084	return ret;
1085}
1086
1087static int wm_coeff_put(struct snd_kcontrol *kctl,
1088			struct snd_ctl_elem_value *ucontrol)
1089{
1090	struct soc_bytes_ext *bytes_ext =
1091		(struct soc_bytes_ext *)kctl->private_value;
1092	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1093	char *p = ucontrol->value.bytes.data;
1094	int ret = 0;
1095
1096	mutex_lock(&ctl->dsp->pwr_lock);
1097	ret = wm_coeff_write_ctrl(ctl, p, ctl->len);
1098	mutex_unlock(&ctl->dsp->pwr_lock);
1099
1100	return ret;
1101}
1102
1103static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
1104			    const unsigned int __user *bytes, unsigned int size)
1105{
1106	struct soc_bytes_ext *bytes_ext =
1107		(struct soc_bytes_ext *)kctl->private_value;
1108	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1109	int ret = 0;
1110
1111	mutex_lock(&ctl->dsp->pwr_lock);
1112
1113	if (copy_from_user(ctl->cache, bytes, size))
1114		ret = -EFAULT;
1115	else
1116		ret = wm_coeff_write_ctrl(ctl, ctl->cache, size);
1117
1118	mutex_unlock(&ctl->dsp->pwr_lock);
1119
1120	return ret;
1121}
1122
1123static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
1124			      struct snd_ctl_elem_value *ucontrol)
1125{
1126	struct soc_bytes_ext *bytes_ext =
1127		(struct soc_bytes_ext *)kctl->private_value;
1128	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1129	unsigned int val = ucontrol->value.integer.value[0];
1130	int ret;
1131
1132	if (val == 0)
1133		return 0;	/* 0 means no event */
1134
1135	mutex_lock(&ctl->dsp->pwr_lock);
1136
1137	if (ctl->enabled && ctl->dsp->running)
1138		ret = wm_coeff_write_acked_control(ctl, val);
1139	else
1140		ret = -EPERM;
1141
1142	mutex_unlock(&ctl->dsp->pwr_lock);
1143
1144	return ret;
1145}
1146
1147static int wm_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl,
1148				  void *buf, size_t len)
1149{
1150	struct wm_adsp *dsp = ctl->dsp;
1151	void *scratch;
1152	int ret;
1153	unsigned int reg;
1154
1155	ret = wm_coeff_base_reg(ctl, &reg);
1156	if (ret)
1157		return ret;
1158
1159	scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
1160	if (!scratch)
1161		return -ENOMEM;
1162
1163	ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
1164	if (ret) {
1165		adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
1166			 len, reg, ret);
1167		kfree(scratch);
1168		return ret;
1169	}
1170	adsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
1171
1172	memcpy(buf, scratch, len);
1173	kfree(scratch);
1174
1175	return 0;
1176}
1177
1178static int wm_coeff_read_ctrl(struct wm_coeff_ctl *ctl, void *buf, size_t len)
1179{
1180	int ret = 0;
1181
1182	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
1183		if (ctl->enabled && ctl->dsp->running)
1184			return wm_coeff_read_ctrl_raw(ctl, buf, len);
1185		else
1186			return -EPERM;
1187	} else {
1188		if (!ctl->flags && ctl->enabled && ctl->dsp->running)
1189			ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1190
1191		if (buf != ctl->cache)
1192			memcpy(buf, ctl->cache, len);
1193	}
1194
1195	return ret;
1196}
1197
1198static int wm_coeff_get(struct snd_kcontrol *kctl,
1199			struct snd_ctl_elem_value *ucontrol)
1200{
1201	struct soc_bytes_ext *bytes_ext =
1202		(struct soc_bytes_ext *)kctl->private_value;
1203	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1204	char *p = ucontrol->value.bytes.data;
1205	int ret;
1206
1207	mutex_lock(&ctl->dsp->pwr_lock);
1208	ret = wm_coeff_read_ctrl(ctl, p, ctl->len);
1209	mutex_unlock(&ctl->dsp->pwr_lock);
1210
1211	return ret;
1212}
1213
1214static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
1215			    unsigned int __user *bytes, unsigned int size)
1216{
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	int ret = 0;
1221
1222	mutex_lock(&ctl->dsp->pwr_lock);
1223
1224	ret = wm_coeff_read_ctrl(ctl, ctl->cache, size);
1225
1226	if (!ret && copy_to_user(bytes, ctl->cache, size))
1227		ret = -EFAULT;
1228
1229	mutex_unlock(&ctl->dsp->pwr_lock);
1230
1231	return ret;
1232}
1233
1234static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol,
1235			      struct snd_ctl_elem_value *ucontrol)
1236{
1237	/*
1238	 * Although it's not useful to read an acked control, we must satisfy
1239	 * user-side assumptions that all controls are readable and that a
1240	 * write of the same value should be filtered out (it's valid to send
1241	 * the same event number again to the firmware). We therefore return 0,
1242	 * meaning "no event" so valid event numbers will always be a change
1243	 */
1244	ucontrol->value.integer.value[0] = 0;
1245
1246	return 0;
1247}
1248
1249struct wmfw_ctl_work {
1250	struct wm_adsp *dsp;
1251	struct wm_coeff_ctl *ctl;
1252	struct work_struct work;
1253};
1254
1255static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
1256{
1257	unsigned int out, rd, wr, vol;
1258
1259	if (len > ADSP_MAX_STD_CTRL_SIZE) {
1260		rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1261		wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
1262		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
1263
1264		out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1265	} else {
1266		rd = SNDRV_CTL_ELEM_ACCESS_READ;
1267		wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
1268		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
1269
1270		out = 0;
1271	}
1272
1273	if (in) {
1274		out |= rd;
1275		if (in & WMFW_CTL_FLAG_WRITEABLE)
1276			out |= wr;
1277		if (in & WMFW_CTL_FLAG_VOLATILE)
1278			out |= vol;
1279	} else {
1280		out |= rd | wr | vol;
1281	}
1282
1283	return out;
1284}
1285
1286static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
1287{
1288	struct snd_kcontrol_new *kcontrol;
1289	int ret;
1290
1291	if (!ctl || !ctl->name)
1292		return -EINVAL;
1293
1294	kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
1295	if (!kcontrol)
1296		return -ENOMEM;
1297
1298	kcontrol->name = ctl->name;
1299	kcontrol->info = wm_coeff_info;
1300	kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1301	kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
1302	kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
1303	kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len);
1304
1305	switch (ctl->type) {
1306	case WMFW_CTL_TYPE_ACKED:
1307		kcontrol->get = wm_coeff_get_acked;
1308		kcontrol->put = wm_coeff_put_acked;
1309		break;
1310	default:
1311		if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
1312			ctl->bytes_ext.max = ctl->len;
1313			ctl->bytes_ext.get = wm_coeff_tlv_get;
1314			ctl->bytes_ext.put = wm_coeff_tlv_put;
1315		} else {
1316			kcontrol->get = wm_coeff_get;
1317			kcontrol->put = wm_coeff_put;
1318		}
1319		break;
1320	}
1321
1322	ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1);
1323	if (ret < 0)
1324		goto err_kcontrol;
1325
1326	kfree(kcontrol);
1327
1328	return 0;
1329
1330err_kcontrol:
1331	kfree(kcontrol);
1332	return ret;
1333}
1334
1335static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
1336{
1337	struct wm_coeff_ctl *ctl;
1338	int ret;
1339
1340	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1341		if (!ctl->enabled || ctl->set)
1342			continue;
1343		if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1344			continue;
1345
1346		/*
1347		 * For readable controls populate the cache from the DSP memory.
1348		 * For non-readable controls the cache was zero-filled when
1349		 * created so we don't need to do anything.
1350		 */
1351		if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
1352			ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1353			if (ret < 0)
1354				return ret;
1355		}
1356	}
1357
1358	return 0;
1359}
1360
1361static int wm_coeff_sync_controls(struct wm_adsp *dsp)
1362{
1363	struct wm_coeff_ctl *ctl;
1364	int ret;
1365
1366	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1367		if (!ctl->enabled)
1368			continue;
1369		if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
1370			ret = wm_coeff_write_ctrl_raw(ctl, ctl->cache,
1371						      ctl->len);
1372			if (ret < 0)
1373				return ret;
1374		}
1375	}
1376
1377	return 0;
1378}
1379
1380static void wm_adsp_signal_event_controls(struct wm_adsp *dsp,
1381					  unsigned int event)
1382{
1383	struct wm_coeff_ctl *ctl;
1384	int ret;
1385
1386	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1387		if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
1388			continue;
1389
1390		if (!ctl->enabled)
1391			continue;
1392
1393		ret = wm_coeff_write_acked_control(ctl, event);
1394		if (ret)
1395			adsp_warn(dsp,
1396				  "Failed to send 0x%x event to alg 0x%x (%d)\n",
1397				  event, ctl->alg_region.alg, ret);
1398	}
1399}
1400
1401static void wm_adsp_ctl_work(struct work_struct *work)
1402{
1403	struct wmfw_ctl_work *ctl_work = container_of(work,
1404						      struct wmfw_ctl_work,
1405						      work);
1406
1407	wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
1408	kfree(ctl_work);
1409}
1410
1411static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl)
1412{
1413	kfree(ctl->cache);
1414	kfree(ctl->name);
1415	kfree(ctl->subname);
1416	kfree(ctl);
1417}
1418
1419static int wm_adsp_create_control(struct wm_adsp *dsp,
1420				  const struct wm_adsp_alg_region *alg_region,
1421				  unsigned int offset, unsigned int len,
1422				  const char *subname, unsigned int subname_len,
1423				  unsigned int flags, unsigned int type)
1424{
1425	struct wm_coeff_ctl *ctl;
1426	struct wmfw_ctl_work *ctl_work;
1427	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1428	const char *region_name;
1429	int ret;
1430
1431	region_name = wm_adsp_mem_region_name(alg_region->type);
1432	if (!region_name) {
1433		adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
1434		return -EINVAL;
1435	}
1436
1437	switch (dsp->fw_ver) {
1438	case 0:
1439	case 1:
1440		snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
1441			 dsp->name, region_name, alg_region->alg);
1442		subname = NULL; /* don't append subname */
1443		break;
1444	case 2:
1445		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1446				"%s%c %.12s %x", dsp->name, *region_name,
1447				wm_adsp_fw_text[dsp->fw], alg_region->alg);
1448		break;
1449	default:
1450		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1451				"%s %.12s %x", dsp->name,
1452				wm_adsp_fw_text[dsp->fw], alg_region->alg);
1453		break;
1454	}
1455
1456	if (subname) {
1457		int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
1458		int skip = 0;
1459
1460		if (dsp->component->name_prefix)
1461			avail -= strlen(dsp->component->name_prefix) + 1;
1462
1463		/* Truncate the subname from the start if it is too long */
1464		if (subname_len > avail)
1465			skip = subname_len - avail;
1466
1467		snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
1468			 " %.*s", subname_len - skip, subname + skip);
1469	}
1470
1471	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1472		if (!strcmp(ctl->name, name)) {
1473			if (!ctl->enabled)
1474				ctl->enabled = 1;
1475			return 0;
1476		}
1477	}
1478
1479	ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
1480	if (!ctl)
1481		return -ENOMEM;
1482	ctl->fw_name = wm_adsp_fw_text[dsp->fw];
1483	ctl->alg_region = *alg_region;
1484	ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
1485	if (!ctl->name) {
1486		ret = -ENOMEM;
1487		goto err_ctl;
1488	}
1489	if (subname) {
1490		ctl->subname_len = subname_len;
1491		ctl->subname = kmemdup(subname,
1492				       strlen(subname) + 1, GFP_KERNEL);
1493		if (!ctl->subname) {
1494			ret = -ENOMEM;
1495			goto err_ctl_name;
1496		}
1497	}
1498	ctl->enabled = 1;
1499	ctl->set = 0;
1500	ctl->ops.xget = wm_coeff_get;
1501	ctl->ops.xput = wm_coeff_put;
1502	ctl->dsp = dsp;
1503
1504	ctl->flags = flags;
1505	ctl->type = type;
1506	ctl->offset = offset;
1507	ctl->len = len;
1508	ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
1509	if (!ctl->cache) {
1510		ret = -ENOMEM;
1511		goto err_ctl_subname;
1512	}
1513
1514	list_add(&ctl->list, &dsp->ctl_list);
1515
1516	if (flags & WMFW_CTL_FLAG_SYS)
1517		return 0;
1518
1519	ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
1520	if (!ctl_work) {
1521		ret = -ENOMEM;
1522		goto err_list_del;
1523	}
1524
1525	ctl_work->dsp = dsp;
1526	ctl_work->ctl = ctl;
1527	INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
1528	schedule_work(&ctl_work->work);
1529
1530	return 0;
1531
1532err_list_del:
1533	list_del(&ctl->list);
1534	kfree(ctl->cache);
1535err_ctl_subname:
1536	kfree(ctl->subname);
1537err_ctl_name:
1538	kfree(ctl->name);
1539err_ctl:
1540	kfree(ctl);
1541
1542	return ret;
1543}
1544
1545struct wm_coeff_parsed_alg {
1546	int id;
1547	const u8 *name;
1548	int name_len;
1549	int ncoeff;
1550};
1551
1552struct wm_coeff_parsed_coeff {
1553	int offset;
1554	int mem_type;
1555	const u8 *name;
1556	int name_len;
1557	int ctl_type;
1558	int flags;
1559	int len;
1560};
1561
1562static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
1563{
1564	int length;
1565
1566	switch (bytes) {
1567	case 1:
1568		length = **pos;
1569		break;
1570	case 2:
1571		length = le16_to_cpu(*((__le16 *)*pos));
1572		break;
1573	default:
1574		return 0;
1575	}
1576
1577	if (str)
1578		*str = *pos + bytes;
1579
1580	*pos += ((length + bytes) + 3) & ~0x03;
1581
1582	return length;
1583}
1584
1585static int wm_coeff_parse_int(int bytes, const u8 **pos)
1586{
1587	int val = 0;
1588
1589	switch (bytes) {
1590	case 2:
1591		val = le16_to_cpu(*((__le16 *)*pos));
1592		break;
1593	case 4:
1594		val = le32_to_cpu(*((__le32 *)*pos));
1595		break;
1596	default:
1597		break;
1598	}
1599
1600	*pos += bytes;
1601
1602	return val;
1603}
1604
1605static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
1606				      struct wm_coeff_parsed_alg *blk)
1607{
1608	const struct wmfw_adsp_alg_data *raw;
1609
1610	switch (dsp->fw_ver) {
1611	case 0:
1612	case 1:
1613		raw = (const struct wmfw_adsp_alg_data *)*data;
1614		*data = raw->data;
1615
1616		blk->id = le32_to_cpu(raw->id);
1617		blk->name = raw->name;
1618		blk->name_len = strlen(raw->name);
1619		blk->ncoeff = le32_to_cpu(raw->ncoeff);
1620		break;
1621	default:
1622		blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
1623		blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
1624						      &blk->name);
1625		wm_coeff_parse_string(sizeof(u16), data, NULL);
1626		blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
1627		break;
1628	}
1629
1630	adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
1631	adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
1632	adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
1633}
1634
1635static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
1636					struct wm_coeff_parsed_coeff *blk)
1637{
1638	const struct wmfw_adsp_coeff_data *raw;
1639	const u8 *tmp;
1640	int length;
1641
1642	switch (dsp->fw_ver) {
1643	case 0:
1644	case 1:
1645		raw = (const struct wmfw_adsp_coeff_data *)*data;
1646		*data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
1647
1648		blk->offset = le16_to_cpu(raw->hdr.offset);
1649		blk->mem_type = le16_to_cpu(raw->hdr.type);
1650		blk->name = raw->name;
1651		blk->name_len = strlen(raw->name);
1652		blk->ctl_type = le16_to_cpu(raw->ctl_type);
1653		blk->flags = le16_to_cpu(raw->flags);
1654		blk->len = le32_to_cpu(raw->len);
1655		break;
1656	default:
1657		tmp = *data;
1658		blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
1659		blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
1660		length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
1661		blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
1662						      &blk->name);
1663		wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
1664		wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
1665		blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
1666		blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
1667		blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
1668
1669		*data = *data + sizeof(raw->hdr) + length;
1670		break;
1671	}
1672
1673	adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
1674	adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
1675	adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
1676	adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
1677	adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
1678	adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
1679}
1680
1681static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp,
1682				const struct wm_coeff_parsed_coeff *coeff_blk,
1683				unsigned int f_required,
1684				unsigned int f_illegal)
1685{
1686	if ((coeff_blk->flags & f_illegal) ||
1687	    ((coeff_blk->flags & f_required) != f_required)) {
1688		adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
1689			 coeff_blk->flags, coeff_blk->ctl_type);
1690		return -EINVAL;
1691	}
1692
1693	return 0;
1694}
1695
1696static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
1697			       const struct wmfw_region *region)
1698{
1699	struct wm_adsp_alg_region alg_region = {};
1700	struct wm_coeff_parsed_alg alg_blk;
1701	struct wm_coeff_parsed_coeff coeff_blk;
1702	const u8 *data = region->data;
1703	int i, ret;
1704
1705	wm_coeff_parse_alg(dsp, &data, &alg_blk);
1706	for (i = 0; i < alg_blk.ncoeff; i++) {
1707		wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
1708
1709		switch (coeff_blk.ctl_type) {
1710		case SNDRV_CTL_ELEM_TYPE_BYTES:
1711			break;
1712		case WMFW_CTL_TYPE_ACKED:
1713			if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
1714				continue;	/* ignore */
1715
1716			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
1717						WMFW_CTL_FLAG_VOLATILE |
1718						WMFW_CTL_FLAG_WRITEABLE |
1719						WMFW_CTL_FLAG_READABLE,
1720						0);
1721			if (ret)
1722				return -EINVAL;
1723			break;
1724		case WMFW_CTL_TYPE_HOSTEVENT:
1725			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
1726						WMFW_CTL_FLAG_SYS |
1727						WMFW_CTL_FLAG_VOLATILE |
1728						WMFW_CTL_FLAG_WRITEABLE |
1729						WMFW_CTL_FLAG_READABLE,
1730						0);
1731			if (ret)
1732				return -EINVAL;
1733			break;
1734		case WMFW_CTL_TYPE_HOST_BUFFER:
1735			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
1736						WMFW_CTL_FLAG_SYS |
1737						WMFW_CTL_FLAG_VOLATILE |
1738						WMFW_CTL_FLAG_READABLE,
1739						0);
1740			if (ret)
1741				return -EINVAL;
1742			break;
1743		default:
1744			adsp_err(dsp, "Unknown control type: %d\n",
1745				 coeff_blk.ctl_type);
1746			return -EINVAL;
1747		}
1748
1749		alg_region.type = coeff_blk.mem_type;
1750		alg_region.alg = alg_blk.id;
1751
1752		ret = wm_adsp_create_control(dsp, &alg_region,
1753					     coeff_blk.offset,
1754					     coeff_blk.len,
1755					     coeff_blk.name,
1756					     coeff_blk.name_len,
1757					     coeff_blk.flags,
1758					     coeff_blk.ctl_type);
1759		if (ret < 0)
1760			adsp_err(dsp, "Failed to create control: %.*s, %d\n",
1761				 coeff_blk.name_len, coeff_blk.name, ret);
1762	}
1763
1764	return 0;
1765}
1766
1767static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp,
1768					 const char * const file,
1769					 unsigned int pos,
1770					 const struct firmware *firmware)
1771{
1772	const struct wmfw_adsp1_sizes *adsp1_sizes;
1773
1774	adsp1_sizes = (void *)&firmware->data[pos];
1775
1776	adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
1777		 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
1778		 le32_to_cpu(adsp1_sizes->zm));
1779
1780	return pos + sizeof(*adsp1_sizes);
1781}
1782
1783static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp,
1784					 const char * const file,
1785					 unsigned int pos,
1786					 const struct firmware *firmware)
1787{
1788	const struct wmfw_adsp2_sizes *adsp2_sizes;
1789
1790	adsp2_sizes = (void *)&firmware->data[pos];
1791
1792	adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
1793		 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
1794		 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
1795
1796	return pos + sizeof(*adsp2_sizes);
1797}
1798
1799static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version)
1800{
1801	switch (version) {
1802	case 0:
1803		adsp_warn(dsp, "Deprecated file format %d\n", version);
1804		return true;
1805	case 1:
1806	case 2:
1807		return true;
1808	default:
1809		return false;
1810	}
1811}
1812
1813static bool wm_halo_validate_version(struct wm_adsp *dsp, unsigned int version)
1814{
1815	switch (version) {
1816	case 3:
1817		return true;
1818	default:
1819		return false;
1820	}
1821}
1822
1823static int wm_adsp_load(struct wm_adsp *dsp)
1824{
1825	LIST_HEAD(buf_list);
1826	const struct firmware *firmware;
1827	struct regmap *regmap = dsp->regmap;
1828	unsigned int pos = 0;
1829	const struct wmfw_header *header;
1830	const struct wmfw_adsp1_sizes *adsp1_sizes;
1831	const struct wmfw_footer *footer;
1832	const struct wmfw_region *region;
1833	const struct wm_adsp_region *mem;
1834	const char *region_name;
1835	char *file, *text = NULL;
1836	struct wm_adsp_buf *buf;
1837	unsigned int reg;
1838	int regions = 0;
1839	int ret, offset, type;
1840
1841	file = kzalloc(PAGE_SIZE, GFP_KERNEL);
1842	if (file == NULL)
1843		return -ENOMEM;
1844
1845	snprintf(file, PAGE_SIZE, "%s-%s-%s.wmfw", dsp->part, dsp->fwf_name,
1846		 wm_adsp_fw[dsp->fw].file);
1847	file[PAGE_SIZE - 1] = '\0';
1848
1849	ret = request_firmware(&firmware, file, dsp->dev);
1850	if (ret != 0) {
1851		adsp_err(dsp, "Failed to request '%s'\n", file);
1852		goto out;
1853	}
1854	ret = -EINVAL;
1855
1856	pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1857	if (pos >= firmware->size) {
1858		adsp_err(dsp, "%s: file too short, %zu bytes\n",
1859			 file, firmware->size);
1860		goto out_fw;
1861	}
1862
1863	header = (void *)&firmware->data[0];
1864
1865	if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
1866		adsp_err(dsp, "%s: invalid magic\n", file);
1867		goto out_fw;
1868	}
1869
1870	if (!dsp->ops->validate_version(dsp, header->ver)) {
1871		adsp_err(dsp, "%s: unknown file format %d\n",
1872			 file, header->ver);
1873		goto out_fw;
1874	}
1875
1876	adsp_info(dsp, "Firmware version: %d\n", header->ver);
1877	dsp->fw_ver = header->ver;
1878
1879	if (header->core != dsp->type) {
1880		adsp_err(dsp, "%s: invalid core %d != %d\n",
1881			 file, header->core, dsp->type);
1882		goto out_fw;
1883	}
1884
1885	pos = sizeof(*header);
1886	pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
1887
1888	footer = (void *)&firmware->data[pos];
1889	pos += sizeof(*footer);
1890
1891	if (le32_to_cpu(header->len) != pos) {
1892		adsp_err(dsp, "%s: unexpected header length %d\n",
1893			 file, le32_to_cpu(header->len));
1894		goto out_fw;
1895	}
1896
1897	adsp_dbg(dsp, "%s: timestamp %llu\n", file,
1898		 le64_to_cpu(footer->timestamp));
1899
1900	while (pos < firmware->size &&
1901	       sizeof(*region) < firmware->size - pos) {
1902		region = (void *)&(firmware->data[pos]);
1903		region_name = "Unknown";
1904		reg = 0;
1905		text = NULL;
1906		offset = le32_to_cpu(region->offset) & 0xffffff;
1907		type = be32_to_cpu(region->type) & 0xff;
1908
1909		switch (type) {
1910		case WMFW_NAME_TEXT:
1911			region_name = "Firmware name";
1912			text = kzalloc(le32_to_cpu(region->len) + 1,
1913				       GFP_KERNEL);
1914			break;
1915		case WMFW_ALGORITHM_DATA:
1916			region_name = "Algorithm";
1917			ret = wm_adsp_parse_coeff(dsp, region);
1918			if (ret != 0)
1919				goto out_fw;
1920			break;
1921		case WMFW_INFO_TEXT:
1922			region_name = "Information";
1923			text = kzalloc(le32_to_cpu(region->len) + 1,
1924				       GFP_KERNEL);
1925			break;
1926		case WMFW_ABSOLUTE:
1927			region_name = "Absolute";
1928			reg = offset;
1929			break;
1930		case WMFW_ADSP1_PM:
1931		case WMFW_ADSP1_DM:
1932		case WMFW_ADSP2_XM:
1933		case WMFW_ADSP2_YM:
1934		case WMFW_ADSP1_ZM:
1935		case WMFW_HALO_PM_PACKED:
1936		case WMFW_HALO_XM_PACKED:
1937		case WMFW_HALO_YM_PACKED:
1938			mem = wm_adsp_find_region(dsp, type);
1939			if (!mem) {
1940				adsp_err(dsp, "No region of type: %x\n", type);
1941				ret = -EINVAL;
1942				goto out_fw;
1943			}
1944
1945			region_name = wm_adsp_mem_region_name(type);
1946			reg = dsp->ops->region_to_reg(mem, offset);
1947			break;
1948		default:
1949			adsp_warn(dsp,
1950				  "%s.%d: Unknown region type %x at %d(%x)\n",
1951				  file, regions, type, pos, pos);
1952			break;
1953		}
1954
1955		adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
1956			 regions, le32_to_cpu(region->len), offset,
1957			 region_name);
1958
1959		if (le32_to_cpu(region->len) >
1960		    firmware->size - pos - sizeof(*region)) {
1961			adsp_err(dsp,
1962				 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
1963				 file, regions, region_name,
1964				 le32_to_cpu(region->len), firmware->size);
1965			ret = -EINVAL;
1966			goto out_fw;
1967		}
1968
1969		if (text) {
1970			memcpy(text, region->data, le32_to_cpu(region->len));
1971			adsp_info(dsp, "%s: %s\n", file, text);
1972			kfree(text);
1973			text = NULL;
1974		}
1975
1976		if (reg) {
1977			buf = wm_adsp_buf_alloc(region->data,
1978						le32_to_cpu(region->len),
1979						&buf_list);
1980			if (!buf) {
1981				adsp_err(dsp, "Out of memory\n");
1982				ret = -ENOMEM;
1983				goto out_fw;
1984			}
1985
1986			ret = regmap_raw_write_async(regmap, reg, buf->buf,
1987						     le32_to_cpu(region->len));
1988			if (ret != 0) {
1989				adsp_err(dsp,
1990					"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
1991					file, regions,
1992					le32_to_cpu(region->len), offset,
1993					region_name, ret);
1994				goto out_fw;
1995			}
1996		}
1997
1998		pos += le32_to_cpu(region->len) + sizeof(*region);
1999		regions++;
2000	}
2001
2002	ret = regmap_async_complete(regmap);
2003	if (ret != 0) {
2004		adsp_err(dsp, "Failed to complete async write: %d\n", ret);
2005		goto out_fw;
2006	}
2007
2008	if (pos > firmware->size)
2009		adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2010			  file, regions, pos - firmware->size);
2011
2012	wm_adsp_debugfs_save_wmfwname(dsp, file);
2013
2014out_fw:
2015	regmap_async_complete(regmap);
2016	wm_adsp_buf_free(&buf_list);
2017	release_firmware(firmware);
2018	kfree(text);
2019out:
2020	kfree(file);
2021
2022	return ret;
2023}
2024
2025/*
2026 * Find wm_coeff_ctl with input name as its subname
2027 * If not found, return NULL
2028 */
2029static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp,
2030					     const char *name, int type,
2031					     unsigned int alg)
2032{
2033	struct wm_coeff_ctl *pos, *rslt = NULL;
2034	const char *fw_txt = wm_adsp_fw_text[dsp->fw];
2035
2036	list_for_each_entry(pos, &dsp->ctl_list, list) {
2037		if (!pos->subname)
2038			continue;
2039		if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
2040		    strncmp(pos->fw_name, fw_txt,
2041			    SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0 &&
2042				pos->alg_region.alg == alg &&
2043				pos->alg_region.type == type) {
2044			rslt = pos;
2045			break;
2046		}
2047	}
2048
2049	return rslt;
2050}
2051
2052int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
2053		      unsigned int alg, void *buf, size_t len)
2054{
2055	struct wm_coeff_ctl *ctl;
2056	struct snd_kcontrol *kcontrol;
2057	char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
2058	int ret;
2059
2060	ctl = wm_adsp_get_ctl(dsp, name, type, alg);
2061	if (!ctl)
2062		return -EINVAL;
2063
2064	if (len > ctl->len)
2065		return -EINVAL;
2066
2067	ret = wm_coeff_write_ctrl(ctl, buf, len);
2068	if (ret)
2069		return ret;
2070
2071	if (ctl->flags & WMFW_CTL_FLAG_SYS)
2072		return 0;
2073
2074	if (dsp->component->name_prefix)
2075		snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s",
2076			 dsp->component->name_prefix, ctl->name);
2077	else
2078		snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s",
2079			 ctl->name);
2080
2081	kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl_name);
2082	if (!kcontrol) {
2083		adsp_err(dsp, "Can't find kcontrol %s\n", ctl_name);
2084		return -EINVAL;
2085	}
2086
2087	snd_ctl_notify(dsp->component->card->snd_card,
2088		       SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
2089
2090	return ret;
2091}
2092EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
2093
2094int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
2095		     unsigned int alg, void *buf, size_t len)
2096{
2097	struct wm_coeff_ctl *ctl;
2098
2099	ctl = wm_adsp_get_ctl(dsp, name, type, alg);
2100	if (!ctl)
2101		return -EINVAL;
2102
2103	if (len > ctl->len)
2104		return -EINVAL;
2105
2106	return wm_coeff_read_ctrl(ctl, buf, len);
2107}
2108EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
2109
2110static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
2111				  const struct wm_adsp_alg_region *alg_region)
2112{
2113	struct wm_coeff_ctl *ctl;
2114
2115	list_for_each_entry(ctl, &dsp->ctl_list, list) {
2116		if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
2117		    alg_region->alg == ctl->alg_region.alg &&
2118		    alg_region->type == ctl->alg_region.type) {
2119			ctl->alg_region.base = alg_region->base;
2120		}
2121	}
2122}
2123
2124static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
2125			       const struct wm_adsp_region *mem,
2126			       unsigned int pos, unsigned int len)
2127{
2128	void *alg;
2129	unsigned int reg;
2130	int ret;
2131	__be32 val;
2132
2133	if (n_algs == 0) {
2134		adsp_err(dsp, "No algorithms\n");
2135		return ERR_PTR(-EINVAL);
2136	}
2137
2138	if (n_algs > 1024) {
2139		adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
2140		return ERR_PTR(-EINVAL);
2141	}
2142
2143	/* Read the terminator first to validate the length */
2144	reg = dsp->ops->region_to_reg(mem, pos + len);
2145
2146	ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
2147	if (ret != 0) {
2148		adsp_err(dsp, "Failed to read algorithm list end: %d\n",
2149			ret);
2150		return ERR_PTR(ret);
2151	}
2152
2153	if (be32_to_cpu(val) != 0xbedead)
2154		adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
2155			  reg, be32_to_cpu(val));
2156
2157	/* Convert length from DSP words to bytes */
2158	len *= sizeof(u32);
2159
2160	alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
2161	if (!alg)
2162		return ERR_PTR(-ENOMEM);
2163
2164	reg = dsp->ops->region_to_reg(mem, pos);
2165
2166	ret = regmap_raw_read(dsp->regmap, reg, alg, len);
2167	if (ret != 0) {
2168		adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
2169		kfree(alg);
2170		return ERR_PTR(ret);
2171	}
2172
2173	return alg;
2174}
2175
2176static struct wm_adsp_alg_region *
2177	wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id)
2178{
2179	struct wm_adsp_alg_region *alg_region;
2180
2181	list_for_each_entry(alg_region, &dsp->alg_regions, list) {
2182		if (id == alg_region->alg && type == alg_region->type)
2183			return alg_region;
2184	}
2185
2186	return NULL;
2187}
2188
2189static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
2190							int type, __be32 id,
2191							__be32 base)
2192{
2193	struct wm_adsp_alg_region *alg_region;
2194
2195	alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
2196	if (!alg_region)
2197		return ERR_PTR(-ENOMEM);
2198
2199	alg_region->type = type;
2200	alg_region->alg = be32_to_cpu(id);
2201	alg_region->base = be32_to_cpu(base);
2202
2203	list_add_tail(&alg_region->list, &dsp->alg_regions);
2204
2205	if (dsp->fw_ver > 0)
2206		wm_adsp_ctl_fixup_base(dsp, alg_region);
2207
2208	return alg_region;
2209}
2210
2211static void wm_adsp_free_alg_regions(struct wm_adsp *dsp)
2212{
2213	struct wm_adsp_alg_region *alg_region;
2214
2215	while (!list_empty(&dsp->alg_regions)) {
2216		alg_region = list_first_entry(&dsp->alg_regions,
2217					      struct wm_adsp_alg_region,
2218					      list);
2219		list_del(&alg_region->list);
2220		kfree(alg_region);
2221	}
2222}
2223
2224static void wmfw_parse_id_header(struct wm_adsp *dsp,
2225				 struct wmfw_id_hdr *fw, int nalgs)
2226{
2227	dsp->fw_id = be32_to_cpu(fw->id);
2228	dsp->fw_id_version = be32_to_cpu(fw->ver);
2229
2230	adsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n",
2231		  dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16,
2232		  (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2233		  nalgs);
2234}
2235
2236static void wmfw_v3_parse_id_header(struct wm_adsp *dsp,
2237				    struct wmfw_v3_id_hdr *fw, int nalgs)
2238{
2239	dsp->fw_id = be32_to_cpu(fw->id);
2240	dsp->fw_id_version = be32_to_cpu(fw->ver);
2241	dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id);
2242
2243	adsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n",
2244		  dsp->fw_id, dsp->fw_vendor_id,
2245		  (dsp->fw_id_version & 0xff0000) >> 16,
2246		  (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2247		  nalgs);
2248}
2249
2250static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions,
2251				int *type, __be32 *base)
2252{
2253	struct wm_adsp_alg_region *alg_region;
2254	int i;
2255
2256	for (i = 0; i < nregions; i++) {
2257		alg_region = wm_adsp_create_region(dsp, type[i], id, base[i]);
2258		if (IS_ERR(alg_region))
2259			return PTR_ERR(alg_region);
2260	}
2261
2262	return 0;
2263}
2264
2265static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
2266{
2267	struct wmfw_adsp1_id_hdr adsp1_id;
2268	struct wmfw_adsp1_alg_hdr *adsp1_alg;
2269	struct wm_adsp_alg_region *alg_region;
2270	const struct wm_adsp_region *mem;
2271	unsigned int pos, len;
2272	size_t n_algs;
2273	int i, ret;
2274
2275	mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
2276	if (WARN_ON(!mem))
2277		return -EINVAL;
2278
2279	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
2280			      sizeof(adsp1_id));
2281	if (ret != 0) {
2282		adsp_err(dsp, "Failed to read algorithm info: %d\n",
2283			 ret);
2284		return ret;
2285	}
2286
2287	n_algs = be32_to_cpu(adsp1_id.n_algs);
2288
2289	wmfw_parse_id_header(dsp, &adsp1_id.fw, n_algs);
2290
2291	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
2292					   adsp1_id.fw.id, adsp1_id.zm);
2293	if (IS_ERR(alg_region))
2294		return PTR_ERR(alg_region);
2295
2296	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
2297					   adsp1_id.fw.id, adsp1_id.dm);
2298	if (IS_ERR(alg_region))
2299		return PTR_ERR(alg_region);
2300
2301	/* Calculate offset and length in DSP words */
2302	pos = sizeof(adsp1_id) / sizeof(u32);
2303	len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
2304
2305	adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2306	if (IS_ERR(adsp1_alg))
2307		return PTR_ERR(adsp1_alg);
2308
2309	for (i = 0; i < n_algs; i++) {
2310		adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
2311			  i, be32_to_cpu(adsp1_alg[i].alg.id),
2312			  (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
2313			  (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
2314			  be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
2315			  be32_to_cpu(adsp1_alg[i].dm),
2316			  be32_to_cpu(adsp1_alg[i].zm));
2317
2318		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
2319						   adsp1_alg[i].alg.id,
2320						   adsp1_alg[i].dm);
2321		if (IS_ERR(alg_region)) {
2322			ret = PTR_ERR(alg_region);
2323			goto out;
2324		}
2325		if (dsp->fw_ver == 0) {
2326			if (i + 1 < n_algs) {
2327				len = be32_to_cpu(adsp1_alg[i + 1].dm);
2328				len -= be32_to_cpu(adsp1_alg[i].dm);
2329				len *= 4;
2330				wm_adsp_create_control(dsp, alg_region, 0,
2331						     len, NULL, 0, 0,
2332						     SNDRV_CTL_ELEM_TYPE_BYTES);
2333			} else {
2334				adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
2335					  be32_to_cpu(adsp1_alg[i].alg.id));
2336			}
2337		}
2338
2339		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
2340						   adsp1_alg[i].alg.id,
2341						   adsp1_alg[i].zm);
2342		if (IS_ERR(alg_region)) {
2343			ret = PTR_ERR(alg_region);
2344			goto out;
2345		}
2346		if (dsp->fw_ver == 0) {
2347			if (i + 1 < n_algs) {
2348				len = be32_to_cpu(adsp1_alg[i + 1].zm);
2349				len -= be32_to_cpu(adsp1_alg[i].zm);
2350				len *= 4;
2351				wm_adsp_create_control(dsp, alg_region, 0,
2352						     len, NULL, 0, 0,
2353						     SNDRV_CTL_ELEM_TYPE_BYTES);
2354			} else {
2355				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2356					  be32_to_cpu(adsp1_alg[i].alg.id));
2357			}
2358		}
2359	}
2360
2361out:
2362	kfree(adsp1_alg);
2363	return ret;
2364}
2365
2366static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
2367{
2368	struct wmfw_adsp2_id_hdr adsp2_id;
2369	struct wmfw_adsp2_alg_hdr *adsp2_alg;
2370	struct wm_adsp_alg_region *alg_region;
2371	const struct wm_adsp_region *mem;
2372	unsigned int pos, len;
2373	size_t n_algs;
2374	int i, ret;
2375
2376	mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
2377	if (WARN_ON(!mem))
2378		return -EINVAL;
2379
2380	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
2381			      sizeof(adsp2_id));
2382	if (ret != 0) {
2383		adsp_err(dsp, "Failed to read algorithm info: %d\n",
2384			 ret);
2385		return ret;
2386	}
2387
2388	n_algs = be32_to_cpu(adsp2_id.n_algs);
2389
2390	wmfw_parse_id_header(dsp, &adsp2_id.fw, n_algs);
2391
2392	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
2393					   adsp2_id.fw.id, adsp2_id.xm);
2394	if (IS_ERR(alg_region))
2395		return PTR_ERR(alg_region);
2396
2397	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
2398					   adsp2_id.fw.id, adsp2_id.ym);
2399	if (IS_ERR(alg_region))
2400		return PTR_ERR(alg_region);
2401
2402	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
2403					   adsp2_id.fw.id, adsp2_id.zm);
2404	if (IS_ERR(alg_region))
2405		return PTR_ERR(alg_region);
2406
2407	/* Calculate offset and length in DSP words */
2408	pos = sizeof(adsp2_id) / sizeof(u32);
2409	len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
2410
2411	adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2412	if (IS_ERR(adsp2_alg))
2413		return PTR_ERR(adsp2_alg);
2414
2415	for (i = 0; i < n_algs; i++) {
2416		adsp_info(dsp,
2417			  "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
2418			  i, be32_to_cpu(adsp2_alg[i].alg.id),
2419			  (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
2420			  (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
2421			  be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
2422			  be32_to_cpu(adsp2_alg[i].xm),
2423			  be32_to_cpu(adsp2_alg[i].ym),
2424			  be32_to_cpu(adsp2_alg[i].zm));
2425
2426		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
2427						   adsp2_alg[i].alg.id,
2428						   adsp2_alg[i].xm);
2429		if (IS_ERR(alg_region)) {
2430			ret = PTR_ERR(alg_region);
2431			goto out;
2432		}
2433		if (dsp->fw_ver == 0) {
2434			if (i + 1 < n_algs) {
2435				len = be32_to_cpu(adsp2_alg[i + 1].xm);
2436				len -= be32_to_cpu(adsp2_alg[i].xm);
2437				len *= 4;
2438				wm_adsp_create_control(dsp, alg_region, 0,
2439						     len, NULL, 0, 0,
2440						     SNDRV_CTL_ELEM_TYPE_BYTES);
2441			} else {
2442				adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
2443					  be32_to_cpu(adsp2_alg[i].alg.id));
2444			}
2445		}
2446
2447		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
2448						   adsp2_alg[i].alg.id,
2449						   adsp2_alg[i].ym);
2450		if (IS_ERR(alg_region)) {
2451			ret = PTR_ERR(alg_region);
2452			goto out;
2453		}
2454		if (dsp->fw_ver == 0) {
2455			if (i + 1 < n_algs) {
2456				len = be32_to_cpu(adsp2_alg[i + 1].ym);
2457				len -= be32_to_cpu(adsp2_alg[i].ym);
2458				len *= 4;
2459				wm_adsp_create_control(dsp, alg_region, 0,
2460						     len, NULL, 0, 0,
2461						     SNDRV_CTL_ELEM_TYPE_BYTES);
2462			} else {
2463				adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
2464					  be32_to_cpu(adsp2_alg[i].alg.id));
2465			}
2466		}
2467
2468		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
2469						   adsp2_alg[i].alg.id,
2470						   adsp2_alg[i].zm);
2471		if (IS_ERR(alg_region)) {
2472			ret = PTR_ERR(alg_region);
2473			goto out;
2474		}
2475		if (dsp->fw_ver == 0) {
2476			if (i + 1 < n_algs) {
2477				len = be32_to_cpu(adsp2_alg[i + 1].zm);
2478				len -= be32_to_cpu(adsp2_alg[i].zm);
2479				len *= 4;
2480				wm_adsp_create_control(dsp, alg_region, 0,
2481						     len, NULL, 0, 0,
2482						     SNDRV_CTL_ELEM_TYPE_BYTES);
2483			} else {
2484				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2485					  be32_to_cpu(adsp2_alg[i].alg.id));
2486			}
2487		}
2488	}
2489
2490out:
2491	kfree(adsp2_alg);
2492	return ret;
2493}
2494
2495static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id,
2496				  __be32 xm_base, __be32 ym_base)
2497{
2498	int types[] = {
2499		WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED,
2500		WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED
2501	};
2502	__be32 bases[] = { xm_base, xm_base, ym_base, ym_base };
2503
2504	return wm_adsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases);
2505}
2506
2507static int wm_halo_setup_algs(struct wm_adsp *dsp)
2508{
2509	struct wmfw_halo_id_hdr halo_id;
2510	struct wmfw_halo_alg_hdr *halo_alg;
2511	const struct wm_adsp_region *mem;
2512	unsigned int pos, len;
2513	size_t n_algs;
2514	int i, ret;
2515
2516	mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
2517	if (WARN_ON(!mem))
2518		return -EINVAL;
2519
2520	ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id,
2521			      sizeof(halo_id));
2522	if (ret != 0) {
2523		adsp_err(dsp, "Failed to read algorithm info: %d\n",
2524			 ret);
2525		return ret;
2526	}
2527
2528	n_algs = be32_to_cpu(halo_id.n_algs);
2529
2530	wmfw_v3_parse_id_header(dsp, &halo_id.fw, n_algs);
2531
2532	ret = wm_halo_create_regions(dsp, halo_id.fw.id,
2533				     halo_id.xm_base, halo_id.ym_base);
2534	if (ret)
2535		return ret;
2536
2537	/* Calculate offset and length in DSP words */
2538	pos = sizeof(halo_id) / sizeof(u32);
2539	len = (sizeof(*halo_alg) * n_algs) / sizeof(u32);
2540
2541	halo_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2542	if (IS_ERR(halo_alg))
2543		return PTR_ERR(halo_alg);
2544
2545	for (i = 0; i < n_algs; i++) {
2546		adsp_info(dsp,
2547			  "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
2548			  i, be32_to_cpu(halo_alg[i].alg.id),
2549			  (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
2550			  (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
2551			  be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
2552			  be32_to_cpu(halo_alg[i].xm_base),
2553			  be32_to_cpu(halo_alg[i].ym_base));
2554
2555		ret = wm_halo_create_regions(dsp, halo_alg[i].alg.id,
2556					     halo_alg[i].xm_base,
2557					     halo_alg[i].ym_base);
2558		if (ret)
2559			goto out;
2560	}
2561
2562out:
2563	kfree(halo_alg);
2564	return ret;
2565}
2566
2567static int wm_adsp_load_coeff(struct wm_adsp *dsp)
2568{
2569	LIST_HEAD(buf_list);
2570	struct regmap *regmap = dsp->regmap;
2571	struct wmfw_coeff_hdr *hdr;
2572	struct wmfw_coeff_item *blk;
2573	const struct firmware *firmware;
2574	const struct wm_adsp_region *mem;
2575	struct wm_adsp_alg_region *alg_region;
2576	const char *region_name;
2577	int ret, pos, blocks, type, offset, reg;
2578	char *file;
2579	struct wm_adsp_buf *buf;
2580
2581	file = kzalloc(PAGE_SIZE, GFP_KERNEL);
2582	if (file == NULL)
2583		return -ENOMEM;
2584
2585	snprintf(file, PAGE_SIZE, "%s-%s-%s.bin", dsp->part, dsp->fwf_name,
2586		 wm_adsp_fw[dsp->fw].file);
2587	file[PAGE_SIZE - 1] = '\0';
2588
2589	ret = request_firmware(&firmware, file, dsp->dev);
2590	if (ret != 0) {
2591		adsp_warn(dsp, "Failed to request '%s'\n", file);
2592		ret = 0;
2593		goto out;
2594	}
2595	ret = -EINVAL;
2596
2597	if (sizeof(*hdr) >= firmware->size) {
2598		adsp_err(dsp, "%s: file too short, %zu bytes\n",
2599			file, firmware->size);
2600		goto out_fw;
2601	}
2602
2603	hdr = (void *)&firmware->data[0];
2604	if (memcmp(hdr->magic, "WMDR", 4) != 0) {
2605		adsp_err(dsp, "%s: invalid magic\n", file);
2606		goto out_fw;
2607	}
2608
2609	switch (be32_to_cpu(hdr->rev) & 0xff) {
2610	case 1:
2611		break;
2612	default:
2613		adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
2614			 file, be32_to_cpu(hdr->rev) & 0xff);
2615		ret = -EINVAL;
2616		goto out_fw;
2617	}
2618
2619	adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
2620		(le32_to_cpu(hdr->ver) >> 16) & 0xff,
2621		(le32_to_cpu(hdr->ver) >>  8) & 0xff,
2622		le32_to_cpu(hdr->ver) & 0xff);
2623
2624	pos = le32_to_cpu(hdr->len);
2625
2626	blocks = 0;
2627	while (pos < firmware->size &&
2628	       sizeof(*blk) < firmware->size - pos) {
2629		blk = (void *)(&firmware->data[pos]);
2630
2631		type = le16_to_cpu(blk->type);
2632		offset = le16_to_cpu(blk->offset);
2633
2634		adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
2635			 file, blocks, le32_to_cpu(blk->id),
2636			 (le32_to_cpu(blk->ver) >> 16) & 0xff,
2637			 (le32_to_cpu(blk->ver) >>  8) & 0xff,
2638			 le32_to_cpu(blk->ver) & 0xff);
2639		adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
2640			 file, blocks, le32_to_cpu(blk->len), offset, type);
2641
2642		reg = 0;
2643		region_name = "Unknown";
2644		switch (type) {
2645		case (WMFW_NAME_TEXT << 8):
2646		case (WMFW_INFO_TEXT << 8):
2647		case (WMFW_METADATA << 8):
2648			break;
2649		case (WMFW_ABSOLUTE << 8):
2650			/*
2651			 * Old files may use this for global
2652			 * coefficients.
2653			 */
2654			if (le32_to_cpu(blk->id) == dsp->fw_id &&
2655			    offset == 0) {
2656				region_name = "global coefficients";
2657				mem = wm_adsp_find_region(dsp, type);
2658				if (!mem) {
2659					adsp_err(dsp, "No ZM\n");
2660					break;
2661				}
2662				reg = dsp->ops->region_to_reg(mem, 0);
2663
2664			} else {
2665				region_name = "register";
2666				reg = offset;
2667			}
2668			break;
2669
2670		case WMFW_ADSP1_DM:
2671		case WMFW_ADSP1_ZM:
2672		case WMFW_ADSP2_XM:
2673		case WMFW_ADSP2_YM:
2674		case WMFW_HALO_XM_PACKED:
2675		case WMFW_HALO_YM_PACKED:
2676		case WMFW_HALO_PM_PACKED:
2677			adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
2678				 file, blocks, le32_to_cpu(blk->len),
2679				 type, le32_to_cpu(blk->id));
2680
2681			mem = wm_adsp_find_region(dsp, type);
2682			if (!mem) {
2683				adsp_err(dsp, "No base for region %x\n", type);
2684				break;
2685			}
2686
2687			alg_region = wm_adsp_find_alg_region(dsp, type,
2688						le32_to_cpu(blk->id));
2689			if (alg_region) {
2690				reg = alg_region->base;
2691				reg = dsp->ops->region_to_reg(mem, reg);
2692				reg += offset;
2693			} else {
2694				adsp_err(dsp, "No %x for algorithm %x\n",
2695					 type, le32_to_cpu(blk->id));
2696			}
2697			break;
2698
2699		default:
2700			adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
2701				 file, blocks, type, pos);
2702			break;
2703		}
2704
2705		if (reg) {
2706			if (le32_to_cpu(blk->len) >
2707			    firmware->size - pos - sizeof(*blk)) {
2708				adsp_err(dsp,
2709					 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2710					 file, blocks, region_name,
2711					 le32_to_cpu(blk->len),
2712					 firmware->size);
2713				ret = -EINVAL;
2714				goto out_fw;
2715			}
2716
2717			buf = wm_adsp_buf_alloc(blk->data,
2718						le32_to_cpu(blk->len),
2719						&buf_list);
2720			if (!buf) {
2721				adsp_err(dsp, "Out of memory\n");
2722				ret = -ENOMEM;
2723				goto out_fw;
2724			}
2725
2726			adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
2727				 file, blocks, le32_to_cpu(blk->len),
2728				 reg);
2729			ret = regmap_raw_write_async(regmap, reg, buf->buf,
2730						     le32_to_cpu(blk->len));
2731			if (ret != 0) {
2732				adsp_err(dsp,
2733					"%s.%d: Failed to write to %x in %s: %d\n",
2734					file, blocks, reg, region_name, ret);
2735			}
2736		}
2737
2738		pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
2739		blocks++;
2740	}
2741
2742	ret = regmap_async_complete(regmap);
2743	if (ret != 0)
2744		adsp_err(dsp, "Failed to complete async write: %d\n", ret);
2745
2746	if (pos > firmware->size)
2747		adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2748			  file, blocks, pos - firmware->size);
2749
2750	wm_adsp_debugfs_save_binname(dsp, file);
2751
2752out_fw:
2753	regmap_async_complete(regmap);
2754	release_firmware(firmware);
2755	wm_adsp_buf_free(&buf_list);
2756out:
2757	kfree(file);
2758	return ret;
2759}
2760
2761static int wm_adsp_create_name(struct wm_adsp *dsp)
2762{
2763	char *p;
2764
2765	if (!dsp->name) {
2766		dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
2767					   dsp->num);
2768		if (!dsp->name)
2769			return -ENOMEM;
2770	}
2771
2772	if (!dsp->fwf_name) {
2773		p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL);
2774		if (!p)
2775			return -ENOMEM;
2776
2777		dsp->fwf_name = p;
2778		for (; *p != 0; ++p)
2779			*p = tolower(*p);
2780	}
2781
2782	return 0;
2783}
2784
2785static int wm_adsp_common_init(struct wm_adsp *dsp)
2786{
2787	int ret;
2788
2789	ret = wm_adsp_create_name(dsp);
2790	if (ret)
2791		return ret;
2792
2793	INIT_LIST_HEAD(&dsp->alg_regions);
2794	INIT_LIST_HEAD(&dsp->ctl_list);
2795	INIT_LIST_HEAD(&dsp->compr_list);
2796	INIT_LIST_HEAD(&dsp->buffer_list);
2797
2798	mutex_init(&dsp->pwr_lock);
2799
2800	return 0;
2801}
2802
2803int wm_adsp1_init(struct wm_adsp *dsp)
2804{
2805	dsp->ops = &wm_adsp1_ops;
2806
2807	return wm_adsp_common_init(dsp);
2808}
2809EXPORT_SYMBOL_GPL(wm_adsp1_init);
2810
2811int wm_adsp1_event(struct snd_soc_dapm_widget *w,
2812		   struct snd_kcontrol *kcontrol,
2813		   int event)
2814{
2815	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
2816	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
2817	struct wm_adsp *dsp = &dsps[w->shift];
2818	struct wm_coeff_ctl *ctl;
2819	int ret;
2820	unsigned int val;
2821
2822	dsp->component = component;
2823
2824	mutex_lock(&dsp->pwr_lock);
2825
2826	switch (event) {
2827	case SND_SOC_DAPM_POST_PMU:
2828		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2829				   ADSP1_SYS_ENA, ADSP1_SYS_ENA);
2830
2831		/*
2832		 * For simplicity set the DSP clock rate to be the
2833		 * SYSCLK rate rather than making it configurable.
2834		 */
2835		if (dsp->sysclk_reg) {
2836			ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
2837			if (ret != 0) {
2838				adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
2839				ret);
2840				goto err_mutex;
2841			}
2842
2843			val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
2844
2845			ret = regmap_update_bits(dsp->regmap,
2846						 dsp->base + ADSP1_CONTROL_31,
2847						 ADSP1_CLK_SEL_MASK, val);
2848			if (ret != 0) {
2849				adsp_err(dsp, "Failed to set clock rate: %d\n",
2850					 ret);
2851				goto err_mutex;
2852			}
2853		}
2854
2855		ret = wm_adsp_load(dsp);
2856		if (ret != 0)
2857			goto err_ena;
2858
2859		ret = wm_adsp1_setup_algs(dsp);
2860		if (ret != 0)
2861			goto err_ena;
2862
2863		ret = wm_adsp_load_coeff(dsp);
2864		if (ret != 0)
2865			goto err_ena;
2866
2867		/* Initialize caches for enabled and unset controls */
2868		ret = wm_coeff_init_control_caches(dsp);
2869		if (ret != 0)
2870			goto err_ena;
2871
2872		/* Sync set controls */
2873		ret = wm_coeff_sync_controls(dsp);
2874		if (ret != 0)
2875			goto err_ena;
2876
2877		dsp->booted = true;
2878
2879		/* Start the core running */
2880		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2881				   ADSP1_CORE_ENA | ADSP1_START,
2882				   ADSP1_CORE_ENA | ADSP1_START);
2883
2884		dsp->running = true;
2885		break;
2886
2887	case SND_SOC_DAPM_PRE_PMD:
2888		dsp->running = false;
2889		dsp->booted = false;
2890
2891		/* Halt the core */
2892		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2893				   ADSP1_CORE_ENA | ADSP1_START, 0);
2894
2895		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
2896				   ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
2897
2898		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2899				   ADSP1_SYS_ENA, 0);
2900
2901		list_for_each_entry(ctl, &dsp->ctl_list, list)
2902			ctl->enabled = 0;
2903
2904
2905		wm_adsp_free_alg_regions(dsp);
2906		break;
2907
2908	default:
2909		break;
2910	}
2911
2912	mutex_unlock(&dsp->pwr_lock);
2913
2914	return 0;
2915
2916err_ena:
2917	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2918			   ADSP1_SYS_ENA, 0);
2919err_mutex:
2920	mutex_unlock(&dsp->pwr_lock);
2921
2922	return ret;
2923}
2924EXPORT_SYMBOL_GPL(wm_adsp1_event);
2925
2926static int wm_adsp2v2_enable_core(struct wm_adsp *dsp)
2927{
2928	unsigned int val;
2929	int ret, count;
2930
2931	/* Wait for the RAM to start, should be near instantaneous */
2932	for (count = 0; count < 10; ++count) {
2933		ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
2934		if (ret != 0)
2935			return ret;
2936
2937		if (val & ADSP2_RAM_RDY)
2938			break;
2939
2940		usleep_range(250, 500);
2941	}
2942
2943	if (!(val & ADSP2_RAM_RDY)) {
2944		adsp_err(dsp, "Failed to start DSP RAM\n");
2945		return -EBUSY;
2946	}
2947
2948	adsp_dbg(dsp, "RAM ready after %d polls\n", count);
2949
2950	return 0;
2951}
2952
2953static int wm_adsp2_enable_core(struct wm_adsp *dsp)
2954{
2955	int ret;
2956
2957	ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
2958				       ADSP2_SYS_ENA, ADSP2_SYS_ENA);
2959	if (ret != 0)
2960		return ret;
2961
2962	return wm_adsp2v2_enable_core(dsp);
2963}
2964
2965static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
2966{
2967	struct regmap *regmap = dsp->regmap;
2968	unsigned int code0, code1, lock_reg;
2969
2970	if (!(lock_regions & WM_ADSP2_REGION_ALL))
2971		return 0;
2972
2973	lock_regions &= WM_ADSP2_REGION_ALL;
2974	lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
2975
2976	while (lock_regions) {
2977		code0 = code1 = 0;
2978		if (lock_regions & BIT(0)) {
2979			code0 = ADSP2_LOCK_CODE_0;
2980			code1 = ADSP2_LOCK_CODE_1;
2981		}
2982		if (lock_regions & BIT(1)) {
2983			code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
2984			code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
2985		}
2986		regmap_write(regmap, lock_reg, code0);
2987		regmap_write(regmap, lock_reg, code1);
2988		lock_regions >>= 2;
2989		lock_reg += 2;
2990	}
2991
2992	return 0;
2993}
2994
2995static int wm_adsp2_enable_memory(struct wm_adsp *dsp)
2996{
2997	return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2998				  ADSP2_MEM_ENA, ADSP2_MEM_ENA);
2999}
3000
3001static void wm_adsp2_disable_memory(struct wm_adsp *dsp)
3002{
3003	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3004			   ADSP2_MEM_ENA, 0);
3005}
3006
3007static void wm_adsp2_disable_core(struct wm_adsp *dsp)
3008{
3009	regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
3010	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
3011	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
3012
3013	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3014			   ADSP2_SYS_ENA, 0);
3015}
3016
3017static void wm_adsp2v2_disable_core(struct wm_adsp *dsp)
3018{
3019	regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
3020	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
3021	regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
3022}
3023
3024static void wm_adsp_boot_work(struct work_struct *work)
3025{
3026	struct wm_adsp *dsp = container_of(work,
3027					   struct wm_adsp,
3028					   boot_work);
3029	int ret;
3030
3031	mutex_lock(&dsp->pwr_lock);
3032
3033	if (dsp->ops->enable_memory) {
3034		ret = dsp->ops->enable_memory(dsp);
3035		if (ret != 0)
3036			goto err_mutex;
3037	}
3038
3039	if (dsp->ops->enable_core) {
3040		ret = dsp->ops->enable_core(dsp);
3041		if (ret != 0)
3042			goto err_mem;
3043	}
3044
3045	ret = wm_adsp_load(dsp);
3046	if (ret != 0)
3047		goto err_ena;
3048
3049	ret = dsp->ops->setup_algs(dsp);
3050	if (ret != 0)
3051		goto err_ena;
3052
3053	ret = wm_adsp_load_coeff(dsp);
3054	if (ret != 0)
3055		goto err_ena;
3056
3057	/* Initialize caches for enabled and unset controls */
3058	ret = wm_coeff_init_control_caches(dsp);
3059	if (ret != 0)
3060		goto err_ena;
3061
3062	if (dsp->ops->disable_core)
3063		dsp->ops->disable_core(dsp);
3064
3065	dsp->booted = true;
3066
3067	mutex_unlock(&dsp->pwr_lock);
3068
3069	return;
3070
3071err_ena:
3072	if (dsp->ops->disable_core)
3073		dsp->ops->disable_core(dsp);
3074err_mem:
3075	if (dsp->ops->disable_memory)
3076		dsp->ops->disable_memory(dsp);
3077err_mutex:
3078	mutex_unlock(&dsp->pwr_lock);
3079}
3080
3081static int wm_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions)
3082{
3083	struct reg_sequence config[] = {
3084		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0x5555 },
3085		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0xAAAA },
3086		{ dsp->base + HALO_MPU_XMEM_ACCESS_0,   0xFFFFFFFF },
3087		{ dsp->base + HALO_MPU_YMEM_ACCESS_0,   0xFFFFFFFF },
3088		{ dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions },
3089		{ dsp->base + HALO_MPU_XREG_ACCESS_0,   lock_regions },
3090		{ dsp->base + HALO_MPU_YREG_ACCESS_0,   lock_regions },
3091		{ dsp->base + HALO_MPU_XMEM_ACCESS_1,   0xFFFFFFFF },
3092		{ dsp->base + HALO_MPU_YMEM_ACCESS_1,   0xFFFFFFFF },
3093		{ dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions },
3094		{ dsp->base + HALO_MPU_XREG_ACCESS_1,   lock_regions },
3095		{ dsp->base + HALO_MPU_YREG_ACCESS_1,   lock_regions },
3096		{ dsp->base + HALO_MPU_XMEM_ACCESS_2,   0xFFFFFFFF },
3097		{ dsp->base + HALO_MPU_YMEM_ACCESS_2,   0xFFFFFFFF },
3098		{ dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions },
3099		{ dsp->base + HALO_MPU_XREG_ACCESS_2,   lock_regions },
3100		{ dsp->base + HALO_MPU_YREG_ACCESS_2,   lock_regions },
3101		{ dsp->base + HALO_MPU_XMEM_ACCESS_3,   0xFFFFFFFF },
3102		{ dsp->base + HALO_MPU_YMEM_ACCESS_3,   0xFFFFFFFF },
3103		{ dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions },
3104		{ dsp->base + HALO_MPU_XREG_ACCESS_3,   lock_regions },
3105		{ dsp->base + HALO_MPU_YREG_ACCESS_3,   lock_regions },
3106		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0 },
3107	};
3108
3109	return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config));
3110}
3111
3112int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
3113{
3114	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3115	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3116	struct wm_adsp *dsp = &dsps[w->shift];
3117	int ret;
3118
3119	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING,
3120				 ADSP2_CLK_SEL_MASK,
3121				 freq << ADSP2_CLK_SEL_SHIFT);
3122	if (ret)
3123		adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
3124
3125	return ret;
3126}
3127EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk);
3128
3129int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
3130			   struct snd_ctl_elem_value *ucontrol)
3131{
3132	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3133	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3134	struct soc_mixer_control *mc =
3135		(struct soc_mixer_control *)kcontrol->private_value;
3136	struct wm_adsp *dsp = &dsps[mc->shift - 1];
3137
3138	ucontrol->value.integer.value[0] = dsp->preloaded;
3139
3140	return 0;
3141}
3142EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
3143
3144int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
3145			   struct snd_ctl_elem_value *ucontrol)
3146{
3147	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3148	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3149	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
3150	struct soc_mixer_control *mc =
3151		(struct soc_mixer_control *)kcontrol->private_value;
3152	struct wm_adsp *dsp = &dsps[mc->shift - 1];
3153	char preload[32];
3154
3155	snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
3156
3157	dsp->preloaded = ucontrol->value.integer.value[0];
3158
3159	if (ucontrol->value.integer.value[0])
3160		snd_soc_component_force_enable_pin(component, preload);
3161	else
3162		snd_soc_component_disable_pin(component, preload);
3163
3164	snd_soc_dapm_sync(dapm);
3165
3166	flush_work(&dsp->boot_work);
3167
3168	return 0;
3169}
3170EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
3171
3172static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
3173{
3174	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
3175			   ADSP2_WDT_ENA_MASK, 0);
3176}
3177
3178static void wm_halo_stop_watchdog(struct wm_adsp *dsp)
3179{
3180	regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL,
3181			   HALO_WDT_EN_MASK, 0);
3182}
3183
3184int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
3185			struct snd_kcontrol *kcontrol, int event)
3186{
3187	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3188	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3189	struct wm_adsp *dsp = &dsps[w->shift];
3190	struct wm_coeff_ctl *ctl;
3191
3192	switch (event) {
3193	case SND_SOC_DAPM_PRE_PMU:
3194		queue_work(system_unbound_wq, &dsp->boot_work);
3195		break;
3196	case SND_SOC_DAPM_PRE_PMD:
3197		mutex_lock(&dsp->pwr_lock);
3198
3199		wm_adsp_debugfs_clear(dsp);
3200
3201		dsp->fw_id = 0;
3202		dsp->fw_id_version = 0;
3203
3204		dsp->booted = false;
3205
3206		if (dsp->ops->disable_memory)
3207			dsp->ops->disable_memory(dsp);
3208
3209		list_for_each_entry(ctl, &dsp->ctl_list, list)
3210			ctl->enabled = 0;
3211
3212		wm_adsp_free_alg_regions(dsp);
3213
3214		mutex_unlock(&dsp->pwr_lock);
3215
3216		adsp_dbg(dsp, "Shutdown complete\n");
3217		break;
3218	default:
3219		break;
3220	}
3221
3222	return 0;
3223}
3224EXPORT_SYMBOL_GPL(wm_adsp_early_event);
3225
3226static int wm_adsp2_start_core(struct wm_adsp *dsp)
3227{
3228	return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3229				 ADSP2_CORE_ENA | ADSP2_START,
3230				 ADSP2_CORE_ENA | ADSP2_START);
3231}
3232
3233static void wm_adsp2_stop_core(struct wm_adsp *dsp)
3234{
3235	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3236			   ADSP2_CORE_ENA | ADSP2_START, 0);
3237}
3238
3239int wm_adsp_event(struct snd_soc_dapm_widget *w,
3240		  struct snd_kcontrol *kcontrol, int event)
3241{
3242	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3243	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3244	struct wm_adsp *dsp = &dsps[w->shift];
3245	int ret;
3246
3247	switch (event) {
3248	case SND_SOC_DAPM_POST_PMU:
3249		flush_work(&dsp->boot_work);
3250
3251		mutex_lock(&dsp->pwr_lock);
3252
3253		if (!dsp->booted) {
3254			ret = -EIO;
3255			goto err;
3256		}
3257
3258		if (dsp->ops->enable_core) {
3259			ret = dsp->ops->enable_core(dsp);
3260			if (ret != 0)
3261				goto err;
3262		}
3263
3264		/* Sync set controls */
3265		ret = wm_coeff_sync_controls(dsp);
3266		if (ret != 0)
3267			goto err;
3268
3269		if (dsp->ops->lock_memory) {
3270			ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
3271			if (ret != 0) {
3272				adsp_err(dsp, "Error configuring MPU: %d\n",
3273					 ret);
3274				goto err;
3275			}
3276		}
3277
3278		if (dsp->ops->start_core) {
3279			ret = dsp->ops->start_core(dsp);
3280			if (ret != 0)
3281				goto err;
3282		}
3283
3284		if (wm_adsp_fw[dsp->fw].num_caps != 0) {
3285			ret = wm_adsp_buffer_init(dsp);
3286			if (ret < 0)
3287				goto err;
3288		}
3289
3290		dsp->running = true;
3291
3292		mutex_unlock(&dsp->pwr_lock);
3293		break;
3294
3295	case SND_SOC_DAPM_PRE_PMD:
3296		/* Tell the firmware to cleanup */
3297		wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
3298
3299		if (dsp->ops->stop_watchdog)
3300			dsp->ops->stop_watchdog(dsp);
3301
3302		/* Log firmware state, it can be useful for analysis */
3303		if (dsp->ops->show_fw_status)
3304			dsp->ops->show_fw_status(dsp);
3305
3306		mutex_lock(&dsp->pwr_lock);
3307
3308		dsp->running = false;
3309
3310		if (dsp->ops->stop_core)
3311			dsp->ops->stop_core(dsp);
3312		if (dsp->ops->disable_core)
3313			dsp->ops->disable_core(dsp);
3314
3315		if (wm_adsp_fw[dsp->fw].num_caps != 0)
3316			wm_adsp_buffer_free(dsp);
3317
3318		dsp->fatal_error = false;
3319
3320		mutex_unlock(&dsp->pwr_lock);
3321
3322		adsp_dbg(dsp, "Execution stopped\n");
3323		break;
3324
3325	default:
3326		break;
3327	}
3328
3329	return 0;
3330err:
3331	if (dsp->ops->stop_core)
3332		dsp->ops->stop_core(dsp);
3333	if (dsp->ops->disable_core)
3334		dsp->ops->disable_core(dsp);
3335	mutex_unlock(&dsp->pwr_lock);
3336	return ret;
3337}
3338EXPORT_SYMBOL_GPL(wm_adsp_event);
3339
3340static int wm_halo_start_core(struct wm_adsp *dsp)
3341{
3342	return regmap_update_bits(dsp->regmap,
3343				  dsp->base + HALO_CCM_CORE_CONTROL,
3344				  HALO_CORE_EN, HALO_CORE_EN);
3345}
3346
3347static void wm_halo_stop_core(struct wm_adsp *dsp)
3348{
3349	regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
3350			   HALO_CORE_EN, 0);
3351
3352	/* reset halo core with CORE_SOFT_RESET */
3353	regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
3354			   HALO_CORE_SOFT_RESET_MASK, 1);
3355}
3356
3357int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
3358{
3359	char preload[32];
3360
3361	snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
3362	snd_soc_component_disable_pin(component, preload);
3363
3364	wm_adsp2_init_debugfs(dsp, component);
3365
3366	dsp->component = component;
3367
3368	return 0;
3369}
3370EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
3371
3372int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
3373{
3374	wm_adsp2_cleanup_debugfs(dsp);
3375
3376	return 0;
3377}
3378EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
3379
3380int wm_adsp2_init(struct wm_adsp *dsp)
3381{
3382	int ret;
3383
3384	ret = wm_adsp_common_init(dsp);
3385	if (ret)
3386		return ret;
3387
3388	switch (dsp->rev) {
3389	case 0:
3390		/*
3391		 * Disable the DSP memory by default when in reset for a small
3392		 * power saving.
3393		 */
3394		ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3395					 ADSP2_MEM_ENA, 0);
3396		if (ret) {
3397			adsp_err(dsp,
3398				 "Failed to clear memory retention: %d\n", ret);
3399			return ret;
3400		}
3401
3402		dsp->ops = &wm_adsp2_ops[0];
3403		break;
3404	case 1:
3405		dsp->ops = &wm_adsp2_ops[1];
3406		break;
3407	default:
3408		dsp->ops = &wm_adsp2_ops[2];
3409		break;
3410	}
3411
3412	INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3413
3414	return 0;
3415}
3416EXPORT_SYMBOL_GPL(wm_adsp2_init);
3417
3418int wm_halo_init(struct wm_adsp *dsp)
3419{
3420	int ret;
3421
3422	ret = wm_adsp_common_init(dsp);
3423	if (ret)
3424		return ret;
3425
3426	dsp->ops = &wm_halo_ops;
3427
3428	INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3429
3430	return 0;
3431}
3432EXPORT_SYMBOL_GPL(wm_halo_init);
3433
3434void wm_adsp2_remove(struct wm_adsp *dsp)
3435{
3436	struct wm_coeff_ctl *ctl;
3437
3438	while (!list_empty(&dsp->ctl_list)) {
3439		ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl,
3440					list);
3441		list_del(&ctl->list);
3442		wm_adsp_free_ctl_blk(ctl);
3443	}
3444}
3445EXPORT_SYMBOL_GPL(wm_adsp2_remove);
3446
3447static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
3448{
3449	return compr->buf != NULL;
3450}
3451
3452static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
3453{
3454	struct wm_adsp_compr_buf *buf = NULL, *tmp;
3455
3456	if (compr->dsp->fatal_error)
3457		return -EINVAL;
3458
3459	list_for_each_entry(tmp, &compr->dsp->buffer_list, list) {
3460		if (!tmp->name || !strcmp(compr->name, tmp->name)) {
3461			buf = tmp;
3462			break;
3463		}
3464	}
3465
3466	if (!buf)
3467		return -EINVAL;
3468
3469	compr->buf = buf;
3470	buf->compr = compr;
3471
3472	return 0;
3473}
3474
3475static void wm_adsp_compr_detach(struct wm_adsp_compr *compr)
3476{
3477	if (!compr)
3478		return;
3479
3480	/* Wake the poll so it can see buffer is no longer attached */
3481	if (compr->stream)
3482		snd_compr_fragment_elapsed(compr->stream);
3483
3484	if (wm_adsp_compr_attached(compr)) {
3485		compr->buf->compr = NULL;
3486		compr->buf = NULL;
3487	}
3488}
3489
3490int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
3491{
3492	struct wm_adsp_compr *compr, *tmp;
3493	struct snd_soc_pcm_runtime *rtd = stream->private_data;
3494	int ret = 0;
3495
3496	mutex_lock(&dsp->pwr_lock);
3497
3498	if (wm_adsp_fw[dsp->fw].num_caps == 0) {
3499		adsp_err(dsp, "%s: Firmware does not support compressed API\n",
3500			 asoc_rtd_to_codec(rtd, 0)->name);
3501		ret = -ENXIO;
3502		goto out;
3503	}
3504
3505	if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
3506		adsp_err(dsp, "%s: Firmware does not support stream direction\n",
3507			 asoc_rtd_to_codec(rtd, 0)->name);
3508		ret = -EINVAL;
3509		goto out;
3510	}
3511
3512	list_for_each_entry(tmp, &dsp->compr_list, list) {
3513		if (!strcmp(tmp->name, asoc_rtd_to_codec(rtd, 0)->name)) {
3514			adsp_err(dsp, "%s: Only a single stream supported per dai\n",
3515				 asoc_rtd_to_codec(rtd, 0)->name);
3516			ret = -EBUSY;
3517			goto out;
3518		}
3519	}
3520
3521	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
3522	if (!compr) {
3523		ret = -ENOMEM;
3524		goto out;
3525	}
3526
3527	compr->dsp = dsp;
3528	compr->stream = stream;
3529	compr->name = asoc_rtd_to_codec(rtd, 0)->name;
3530
3531	list_add_tail(&compr->list, &dsp->compr_list);
3532
3533	stream->runtime->private_data = compr;
3534
3535out:
3536	mutex_unlock(&dsp->pwr_lock);
3537
3538	return ret;
3539}
3540EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
3541
3542int wm_adsp_compr_free(struct snd_soc_component *component,
3543		       struct snd_compr_stream *stream)
3544{
3545	struct wm_adsp_compr *compr = stream->runtime->private_data;
3546	struct wm_adsp *dsp = compr->dsp;
3547
3548	mutex_lock(&dsp->pwr_lock);
3549
3550	wm_adsp_compr_detach(compr);
3551	list_del(&compr->list);
3552
3553	kfree(compr->raw_buf);
3554	kfree(compr);
3555
3556	mutex_unlock(&dsp->pwr_lock);
3557
3558	return 0;
3559}
3560EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
3561
3562static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
3563				      struct snd_compr_params *params)
3564{
3565	struct wm_adsp_compr *compr = stream->runtime->private_data;
3566	struct wm_adsp *dsp = compr->dsp;
3567	const struct wm_adsp_fw_caps *caps;
3568	const struct snd_codec_desc *desc;
3569	int i, j;
3570
3571	if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
3572	    params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
3573	    params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
3574	    params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
3575	    params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
3576		compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n",
3577			  params->buffer.fragment_size,
3578			  params->buffer.fragments);
3579
3580		return -EINVAL;
3581	}
3582
3583	for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
3584		caps = &wm_adsp_fw[dsp->fw].caps[i];
3585		desc = &caps->desc;
3586
3587		if (caps->id != params->codec.id)
3588			continue;
3589
3590		if (stream->direction == SND_COMPRESS_PLAYBACK) {
3591			if (desc->max_ch < params->codec.ch_out)
3592				continue;
3593		} else {
3594			if (desc->max_ch < params->codec.ch_in)
3595				continue;
3596		}
3597
3598		if (!(desc->formats & (1 << params->codec.format)))
3599			continue;
3600
3601		for (j = 0; j < desc->num_sample_rates; ++j)
3602			if (desc->sample_rates[j] == params->codec.sample_rate)
3603				return 0;
3604	}
3605
3606	compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
3607		  params->codec.id, params->codec.ch_in, params->codec.ch_out,
3608		  params->codec.sample_rate, params->codec.format);
3609	return -EINVAL;
3610}
3611
3612static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
3613{
3614	return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE;
3615}
3616
3617int wm_adsp_compr_set_params(struct snd_soc_component *component,
3618			     struct snd_compr_stream *stream,
3619			     struct snd_compr_params *params)
3620{
3621	struct wm_adsp_compr *compr = stream->runtime->private_data;
3622	unsigned int size;
3623	int ret;
3624
3625	ret = wm_adsp_compr_check_params(stream, params);
3626	if (ret)
3627		return ret;
3628
3629	compr->size = params->buffer;
3630
3631	compr_dbg(compr, "fragment_size=%d fragments=%d\n",
3632		  compr->size.fragment_size, compr->size.fragments);
3633
3634	size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
3635	compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
3636	if (!compr->raw_buf)
3637		return -ENOMEM;
3638
3639	compr->sample_rate = params->codec.sample_rate;
3640
3641	return 0;
3642}
3643EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
3644
3645int wm_adsp_compr_get_caps(struct snd_soc_component *component,
3646			   struct snd_compr_stream *stream,
3647			   struct snd_compr_caps *caps)
3648{
3649	struct wm_adsp_compr *compr = stream->runtime->private_data;
3650	int fw = compr->dsp->fw;
3651	int i;
3652
3653	if (wm_adsp_fw[fw].caps) {
3654		for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
3655			caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
3656
3657		caps->num_codecs = i;
3658		caps->direction = wm_adsp_fw[fw].compr_direction;
3659
3660		caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
3661		caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
3662		caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
3663		caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
3664	}
3665
3666	return 0;
3667}
3668EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
3669
3670static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
3671				   unsigned int mem_addr,
3672				   unsigned int num_words, u32 *data)
3673{
3674	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
3675	unsigned int i, reg;
3676	int ret;
3677
3678	if (!mem)
3679		return -EINVAL;
3680
3681	reg = dsp->ops->region_to_reg(mem, mem_addr);
3682
3683	ret = regmap_raw_read(dsp->regmap, reg, data,
3684			      sizeof(*data) * num_words);
3685	if (ret < 0)
3686		return ret;
3687
3688	for (i = 0; i < num_words; ++i)
3689		data[i] = be32_to_cpu(data[i]) & 0x00ffffffu;
3690
3691	return 0;
3692}
3693
3694static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type,
3695					 unsigned int mem_addr, u32 *data)
3696{
3697	return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data);
3698}
3699
3700static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
3701				   unsigned int mem_addr, u32 data)
3702{
3703	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
3704	unsigned int reg;
3705
3706	if (!mem)
3707		return -EINVAL;
3708
3709	reg = dsp->ops->region_to_reg(mem, mem_addr);
3710
3711	data = cpu_to_be32(data & 0x00ffffffu);
3712
3713	return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data));
3714}
3715
3716static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
3717				      unsigned int field_offset, u32 *data)
3718{
3719	return wm_adsp_read_data_word(buf->dsp, buf->host_buf_mem_type,
3720				      buf->host_buf_ptr + field_offset, data);
3721}
3722
3723static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
3724				       unsigned int field_offset, u32 data)
3725{
3726	return wm_adsp_write_data_word(buf->dsp, buf->host_buf_mem_type,
3727				       buf->host_buf_ptr + field_offset, data);
3728}
3729
3730static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size)
3731{
3732	u8 *pack_in = (u8 *)buf;
3733	u8 *pack_out = (u8 *)buf;
3734	int i, j;
3735
3736	/* Remove the padding bytes from the data read from the DSP */
3737	for (i = 0; i < nwords; i++) {
3738		for (j = 0; j < data_word_size; j++)
3739			*pack_out++ = *pack_in++;
3740
3741		pack_in += sizeof(*buf) - data_word_size;
3742	}
3743}
3744
3745static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
3746{
3747	const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
3748	struct wm_adsp_buffer_region *region;
3749	u32 offset = 0;
3750	int i, ret;
3751
3752	buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),
3753			       GFP_KERNEL);
3754	if (!buf->regions)
3755		return -ENOMEM;
3756
3757	for (i = 0; i < caps->num_regions; ++i) {
3758		region = &buf->regions[i];
3759
3760		region->offset = offset;
3761		region->mem_type = caps->region_defs[i].mem_type;
3762
3763		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
3764					  &region->base_addr);
3765		if (ret < 0)
3766			goto err;
3767
3768		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
3769					  &offset);
3770		if (ret < 0)
3771			goto err;
3772
3773		region->cumulative_size = offset;
3774
3775		compr_dbg(buf,
3776			  "region=%d type=%d base=%08x off=%08x size=%08x\n",
3777			  i, region->mem_type, region->base_addr,
3778			  region->offset, region->cumulative_size);
3779	}
3780
3781	return 0;
3782
3783err:
3784	kfree(buf->regions);
3785	return ret;
3786}
3787
3788static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
3789{
3790	buf->irq_count = 0xFFFFFFFF;
3791	buf->read_index = -1;
3792	buf->avail = 0;
3793}
3794
3795static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp)
3796{
3797	struct wm_adsp_compr_buf *buf;
3798
3799	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
3800	if (!buf)
3801		return NULL;
3802
3803	buf->dsp = dsp;
3804
3805	wm_adsp_buffer_clear(buf);
3806
3807	list_add_tail(&buf->list, &dsp->buffer_list);
3808
3809	return buf;
3810}
3811
3812static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
3813{
3814	struct wm_adsp_alg_region *alg_region;
3815	struct wm_adsp_compr_buf *buf;
3816	u32 xmalg, addr, magic;
3817	int i, ret;
3818
3819	alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
3820	if (!alg_region) {
3821		adsp_err(dsp, "No algorithm region found\n");
3822		return -EINVAL;
3823	}
3824
3825	buf = wm_adsp_buffer_alloc(dsp);
3826	if (!buf)
3827		return -ENOMEM;
3828
3829	xmalg = dsp->ops->sys_config_size / sizeof(__be32);
3830
3831	addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
3832	ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
3833	if (ret < 0)
3834		return ret;
3835
3836	if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
3837		return -ENODEV;
3838
3839	addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
3840	for (i = 0; i < 5; ++i) {
3841		ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
3842					     &buf->host_buf_ptr);
3843		if (ret < 0)
3844			return ret;
3845
3846		if (buf->host_buf_ptr)
3847			break;
3848
3849		usleep_range(1000, 2000);
3850	}
3851
3852	if (!buf->host_buf_ptr)
3853		return -EIO;
3854
3855	buf->host_buf_mem_type = WMFW_ADSP2_XM;
3856
3857	ret = wm_adsp_buffer_populate(buf);
3858	if (ret < 0)
3859		return ret;
3860
3861	compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr);
3862
3863	return 0;
3864}
3865
3866static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
3867{
3868	struct wm_adsp_host_buf_coeff_v1 coeff_v1;
3869	struct wm_adsp_compr_buf *buf;
3870	unsigned int val, reg;
3871	int ret, i;
3872
3873	ret = wm_coeff_base_reg(ctl, &reg);
3874	if (ret)
3875		return ret;
3876
3877	for (i = 0; i < 5; ++i) {
3878		ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val));
3879		if (ret < 0)
3880			return ret;
3881
3882		if (val)
3883			break;
3884
3885		usleep_range(1000, 2000);
3886	}
3887
3888	if (!val) {
3889		adsp_err(ctl->dsp, "Failed to acquire host buffer\n");
3890		return -EIO;
3891	}
3892
3893	buf = wm_adsp_buffer_alloc(ctl->dsp);
3894	if (!buf)
3895		return -ENOMEM;
3896
3897	buf->host_buf_mem_type = ctl->alg_region.type;
3898	buf->host_buf_ptr = be32_to_cpu(val);
3899
3900	ret = wm_adsp_buffer_populate(buf);
3901	if (ret < 0)
3902		return ret;
3903
3904	/*
3905	 * v0 host_buffer coefficients didn't have versioning, so if the
3906	 * control is one word, assume version 0.
3907	 */
3908	if (ctl->len == 4) {
3909		compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr);
3910		return 0;
3911	}
3912
3913	ret = regmap_raw_read(ctl->dsp->regmap, reg, &coeff_v1,
3914			      sizeof(coeff_v1));
3915	if (ret < 0)
3916		return ret;
3917
3918	coeff_v1.versions = be32_to_cpu(coeff_v1.versions);
3919	val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK;
3920	val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
3921
3922	if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
3923		adsp_err(ctl->dsp,
3924			 "Host buffer coeff ver %u > supported version %u\n",
3925			 val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
3926		return -EINVAL;
3927	}
3928
3929	for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++)
3930		coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]);
3931
3932	wm_adsp_remove_padding((u32 *)&coeff_v1.name,
3933			       ARRAY_SIZE(coeff_v1.name),
3934			       WM_ADSP_DATA_WORD_SIZE);
3935
3936	buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part,
3937			      (char *)&coeff_v1.name);
3938
3939	compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
3940		  buf->host_buf_ptr, val);
3941
3942	return val;
3943}
3944
3945static int wm_adsp_buffer_init(struct wm_adsp *dsp)
3946{
3947	struct wm_coeff_ctl *ctl;
3948	int ret;
3949
3950	list_for_each_entry(ctl, &dsp->ctl_list, list) {
3951		if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
3952			continue;
3953
3954		if (!ctl->enabled)
3955			continue;
3956
3957		ret = wm_adsp_buffer_parse_coeff(ctl);
3958		if (ret < 0) {
3959			adsp_err(dsp, "Failed to parse coeff: %d\n", ret);
3960			goto error;
3961		} else if (ret == 0) {
3962			/* Only one buffer supported for version 0 */
3963			return 0;
3964		}
3965	}
3966
3967	if (list_empty(&dsp->buffer_list)) {
3968		/* Fall back to legacy support */
3969		ret = wm_adsp_buffer_parse_legacy(dsp);
3970		if (ret) {
3971			adsp_err(dsp, "Failed to parse legacy: %d\n", ret);
3972			goto error;
3973		}
3974	}
3975
3976	return 0;
3977
3978error:
3979	wm_adsp_buffer_free(dsp);
3980	return ret;
3981}
3982
3983static int wm_adsp_buffer_free(struct wm_adsp *dsp)
3984{
3985	struct wm_adsp_compr_buf *buf, *tmp;
3986
3987	list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) {
3988		wm_adsp_compr_detach(buf->compr);
3989
3990		kfree(buf->name);
3991		kfree(buf->regions);
3992		list_del(&buf->list);
3993		kfree(buf);
3994	}
3995
3996	return 0;
3997}
3998
3999static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
4000{
4001	int ret;
4002
4003	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
4004	if (ret < 0) {
4005		compr_err(buf, "Failed to check buffer error: %d\n", ret);
4006		return ret;
4007	}
4008	if (buf->error != 0) {
4009		compr_err(buf, "Buffer error occurred: %d\n", buf->error);
4010		return -EIO;
4011	}
4012
4013	return 0;
4014}
4015
4016int wm_adsp_compr_trigger(struct snd_soc_component *component,
4017			  struct snd_compr_stream *stream, int cmd)
4018{
4019	struct wm_adsp_compr *compr = stream->runtime->private_data;
4020	struct wm_adsp *dsp = compr->dsp;
4021	int ret = 0;
4022
4023	compr_dbg(compr, "Trigger: %d\n", cmd);
4024
4025	mutex_lock(&dsp->pwr_lock);
4026
4027	switch (cmd) {
4028	case SNDRV_PCM_TRIGGER_START:
4029		if (!wm_adsp_compr_attached(compr)) {
4030			ret = wm_adsp_compr_attach(compr);
4031			if (ret < 0) {
4032				compr_err(compr, "Failed to link buffer and stream: %d\n",
4033					  ret);
4034				break;
4035			}
4036		}
4037
4038		ret = wm_adsp_buffer_get_error(compr->buf);
4039		if (ret < 0)
4040			break;
4041
4042		/* Trigger the IRQ at one fragment of data */
4043		ret = wm_adsp_buffer_write(compr->buf,
4044					   HOST_BUFFER_FIELD(high_water_mark),
4045					   wm_adsp_compr_frag_words(compr));
4046		if (ret < 0) {
4047			compr_err(compr, "Failed to set high water mark: %d\n",
4048				  ret);
4049			break;
4050		}
4051		break;
4052	case SNDRV_PCM_TRIGGER_STOP:
4053		if (wm_adsp_compr_attached(compr))
4054			wm_adsp_buffer_clear(compr->buf);
4055		break;
4056	default:
4057		ret = -EINVAL;
4058		break;
4059	}
4060
4061	mutex_unlock(&dsp->pwr_lock);
4062
4063	return ret;
4064}
4065EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
4066
4067static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
4068{
4069	int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
4070
4071	return buf->regions[last_region].cumulative_size;
4072}
4073
4074static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
4075{
4076	u32 next_read_index, next_write_index;
4077	int write_index, read_index, avail;
4078	int ret;
4079
4080	/* Only sync read index if we haven't already read a valid index */
4081	if (buf->read_index < 0) {
4082		ret = wm_adsp_buffer_read(buf,
4083				HOST_BUFFER_FIELD(next_read_index),
4084				&next_read_index);
4085		if (ret < 0)
4086			return ret;
4087
4088		read_index = sign_extend32(next_read_index, 23);
4089
4090		if (read_index < 0) {
4091			compr_dbg(buf, "Avail check on unstarted stream\n");
4092			return 0;
4093		}
4094
4095		buf->read_index = read_index;
4096	}
4097
4098	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
4099			&next_write_index);
4100	if (ret < 0)
4101		return ret;
4102
4103	write_index = sign_extend32(next_write_index, 23);
4104
4105	avail = write_index - buf->read_index;
4106	if (avail < 0)
4107		avail += wm_adsp_buffer_size(buf);
4108
4109	compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
4110		  buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE);
4111
4112	buf->avail = avail;
4113
4114	return 0;
4115}
4116
4117int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
4118{
4119	struct wm_adsp_compr_buf *buf;
4120	struct wm_adsp_compr *compr;
4121	int ret = 0;
4122
4123	mutex_lock(&dsp->pwr_lock);
4124
4125	if (list_empty(&dsp->buffer_list)) {
4126		ret = -ENODEV;
4127		goto out;
4128	}
4129
4130	adsp_dbg(dsp, "Handling buffer IRQ\n");
4131
4132	list_for_each_entry(buf, &dsp->buffer_list, list) {
4133		compr = buf->compr;
4134
4135		ret = wm_adsp_buffer_get_error(buf);
4136		if (ret < 0)
4137			goto out_notify; /* Wake poll to report error */
4138
4139		ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
4140					  &buf->irq_count);
4141		if (ret < 0) {
4142			compr_err(buf, "Failed to get irq_count: %d\n", ret);
4143			goto out;
4144		}
4145
4146		ret = wm_adsp_buffer_update_avail(buf);
4147		if (ret < 0) {
4148			compr_err(buf, "Error reading avail: %d\n", ret);
4149			goto out;
4150		}
4151
4152		if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
4153			ret = WM_ADSP_COMPR_VOICE_TRIGGER;
4154
4155out_notify:
4156		if (compr && compr->stream)
4157			snd_compr_fragment_elapsed(compr->stream);
4158	}
4159
4160out:
4161	mutex_unlock(&dsp->pwr_lock);
4162
4163	return ret;
4164}
4165EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
4166
4167static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
4168{
4169	if (buf->irq_count & 0x01)
4170		return 0;
4171
4172	compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count);
4173
4174	buf->irq_count |= 0x01;
4175
4176	return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
4177				    buf->irq_count);
4178}
4179
4180int wm_adsp_compr_pointer(struct snd_soc_component *component,
4181			  struct snd_compr_stream *stream,
4182			  struct snd_compr_tstamp *tstamp)
4183{
4184	struct wm_adsp_compr *compr = stream->runtime->private_data;
4185	struct wm_adsp *dsp = compr->dsp;
4186	struct wm_adsp_compr_buf *buf;
4187	int ret = 0;
4188
4189	compr_dbg(compr, "Pointer request\n");
4190
4191	mutex_lock(&dsp->pwr_lock);
4192
4193	buf = compr->buf;
4194
4195	if (dsp->fatal_error || !buf || buf->error) {
4196		snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
4197		ret = -EIO;
4198		goto out;
4199	}
4200
4201	if (buf->avail < wm_adsp_compr_frag_words(compr)) {
4202		ret = wm_adsp_buffer_update_avail(buf);
4203		if (ret < 0) {
4204			compr_err(compr, "Error reading avail: %d\n", ret);
4205			goto out;
4206		}
4207
4208		/*
4209		 * If we really have less than 1 fragment available tell the
4210		 * DSP to inform us once a whole fragment is available.
4211		 */
4212		if (buf->avail < wm_adsp_compr_frag_words(compr)) {
4213			ret = wm_adsp_buffer_get_error(buf);
4214			if (ret < 0) {
4215				if (buf->error)
4216					snd_compr_stop_error(stream,
4217							SNDRV_PCM_STATE_XRUN);
4218				goto out;
4219			}
4220
4221			ret = wm_adsp_buffer_reenable_irq(buf);
4222			if (ret < 0) {
4223				compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
4224					  ret);
4225				goto out;
4226			}
4227		}
4228	}
4229
4230	tstamp->copied_total = compr->copied_total;
4231	tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
4232	tstamp->sampling_rate = compr->sample_rate;
4233
4234out:
4235	mutex_unlock(&dsp->pwr_lock);
4236
4237	return ret;
4238}
4239EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
4240
4241static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
4242{
4243	struct wm_adsp_compr_buf *buf = compr->buf;
4244	unsigned int adsp_addr;
4245	int mem_type, nwords, max_read;
4246	int i, ret;
4247
4248	/* Calculate read parameters */
4249	for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
4250		if (buf->read_index < buf->regions[i].cumulative_size)
4251			break;
4252
4253	if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
4254		return -EINVAL;
4255
4256	mem_type = buf->regions[i].mem_type;
4257	adsp_addr = buf->regions[i].base_addr +
4258		    (buf->read_index - buf->regions[i].offset);
4259
4260	max_read = wm_adsp_compr_frag_words(compr);
4261	nwords = buf->regions[i].cumulative_size - buf->read_index;
4262
4263	if (nwords > target)
4264		nwords = target;
4265	if (nwords > buf->avail)
4266		nwords = buf->avail;
4267	if (nwords > max_read)
4268		nwords = max_read;
4269	if (!nwords)
4270		return 0;
4271
4272	/* Read data from DSP */
4273	ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
4274				      nwords, compr->raw_buf);
4275	if (ret < 0)
4276		return ret;
4277
4278	wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE);
4279
4280	/* update read index to account for words read */
4281	buf->read_index += nwords;
4282	if (buf->read_index == wm_adsp_buffer_size(buf))
4283		buf->read_index = 0;
4284
4285	ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
4286				   buf->read_index);
4287	if (ret < 0)
4288		return ret;
4289
4290	/* update avail to account for words read */
4291	buf->avail -= nwords;
4292
4293	return nwords;
4294}
4295
4296static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
4297			      char __user *buf, size_t count)
4298{
4299	struct wm_adsp *dsp = compr->dsp;
4300	int ntotal = 0;
4301	int nwords, nbytes;
4302
4303	compr_dbg(compr, "Requested read of %zu bytes\n", count);
4304
4305	if (dsp->fatal_error || !compr->buf || compr->buf->error) {
4306		snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
4307		return -EIO;
4308	}
4309
4310	count /= WM_ADSP_DATA_WORD_SIZE;
4311
4312	do {
4313		nwords = wm_adsp_buffer_capture_block(compr, count);
4314		if (nwords < 0) {
4315			compr_err(compr, "Failed to capture block: %d\n",
4316				  nwords);
4317			return nwords;
4318		}
4319
4320		nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
4321
4322		compr_dbg(compr, "Read %d bytes\n", nbytes);
4323
4324		if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
4325			compr_err(compr, "Failed to copy data to user: %d, %d\n",
4326				  ntotal, nbytes);
4327			return -EFAULT;
4328		}
4329
4330		count -= nwords;
4331		ntotal += nbytes;
4332	} while (nwords > 0 && count > 0);
4333
4334	compr->copied_total += ntotal;
4335
4336	return ntotal;
4337}
4338
4339int wm_adsp_compr_copy(struct snd_soc_component *component,
4340		       struct snd_compr_stream *stream, char __user *buf,
4341		       size_t count)
4342{
4343	struct wm_adsp_compr *compr = stream->runtime->private_data;
4344	struct wm_adsp *dsp = compr->dsp;
4345	int ret;
4346
4347	mutex_lock(&dsp->pwr_lock);
4348
4349	if (stream->direction == SND_COMPRESS_CAPTURE)
4350		ret = wm_adsp_compr_read(compr, buf, count);
4351	else
4352		ret = -ENOTSUPP;
4353
4354	mutex_unlock(&dsp->pwr_lock);
4355
4356	return ret;
4357}
4358EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
4359
4360static void wm_adsp_fatal_error(struct wm_adsp *dsp)
4361{
4362	struct wm_adsp_compr *compr;
4363
4364	dsp->fatal_error = true;
4365
4366	list_for_each_entry(compr, &dsp->compr_list, list) {
4367		if (compr->stream)
4368			snd_compr_fragment_elapsed(compr->stream);
4369	}
4370}
4371
4372irqreturn_t wm_adsp2_bus_error(int irq, void *data)
4373{
4374	struct wm_adsp *dsp = (struct wm_adsp *)data;
4375	unsigned int val;
4376	struct regmap *regmap = dsp->regmap;
4377	int ret = 0;
4378
4379	mutex_lock(&dsp->pwr_lock);
4380
4381	ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
4382	if (ret) {
4383		adsp_err(dsp,
4384			"Failed to read Region Lock Ctrl register: %d\n", ret);
4385		goto error;
4386	}
4387
4388	if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
4389		adsp_err(dsp, "watchdog timeout error\n");
4390		dsp->ops->stop_watchdog(dsp);
4391		wm_adsp_fatal_error(dsp);
4392	}
4393
4394	if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
4395		if (val & ADSP2_ADDR_ERR_MASK)
4396			adsp_err(dsp, "bus error: address error\n");
4397		else
4398			adsp_err(dsp, "bus error: region lock error\n");
4399
4400		ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
4401		if (ret) {
4402			adsp_err(dsp,
4403				 "Failed to read Bus Err Addr register: %d\n",
4404				 ret);
4405			goto error;
4406		}
4407
4408		adsp_err(dsp, "bus error address = 0x%x\n",
4409			 val & ADSP2_BUS_ERR_ADDR_MASK);
4410
4411		ret = regmap_read(regmap,
4412				  dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
4413				  &val);
4414		if (ret) {
4415			adsp_err(dsp,
4416				 "Failed to read Pmem Xmem Err Addr register: %d\n",
4417				 ret);
4418			goto error;
4419		}
4420
4421		adsp_err(dsp, "xmem error address = 0x%x\n",
4422			 val & ADSP2_XMEM_ERR_ADDR_MASK);
4423		adsp_err(dsp, "pmem error address = 0x%x\n",
4424			 (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
4425			 ADSP2_PMEM_ERR_ADDR_SHIFT);
4426	}
4427
4428	regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
4429			   ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
4430
4431error:
4432	mutex_unlock(&dsp->pwr_lock);
4433
4434	return IRQ_HANDLED;
4435}
4436EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
4437
4438irqreturn_t wm_halo_bus_error(int irq, void *data)
4439{
4440	struct wm_adsp *dsp = (struct wm_adsp *)data;
4441	struct regmap *regmap = dsp->regmap;
4442	unsigned int fault[6];
4443	struct reg_sequence clear[] = {
4444		{ dsp->base + HALO_MPU_XM_VIO_STATUS,     0x0 },
4445		{ dsp->base + HALO_MPU_YM_VIO_STATUS,     0x0 },
4446		{ dsp->base + HALO_MPU_PM_VIO_STATUS,     0x0 },
4447	};
4448	int ret;
4449
4450	mutex_lock(&dsp->pwr_lock);
4451
4452	ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
4453			  fault);
4454	if (ret) {
4455		adsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
4456		goto exit_unlock;
4457	}
4458
4459	adsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
4460		  *fault & HALO_AHBM_FLAGS_ERR_MASK,
4461		  (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
4462		  HALO_AHBM_CORE_ERR_ADDR_SHIFT);
4463
4464	ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
4465			  fault);
4466	if (ret) {
4467		adsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
4468		goto exit_unlock;
4469	}
4470
4471	adsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
4472
4473	ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
4474			       fault, ARRAY_SIZE(fault));
4475	if (ret) {
4476		adsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
4477		goto exit_unlock;
4478	}
4479
4480	adsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
4481	adsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
4482	adsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
4483
4484	ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
4485	if (ret)
4486		adsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
4487
4488exit_unlock:
4489	mutex_unlock(&dsp->pwr_lock);
4490
4491	return IRQ_HANDLED;
4492}
4493EXPORT_SYMBOL_GPL(wm_halo_bus_error);
4494
4495irqreturn_t wm_halo_wdt_expire(int irq, void *data)
4496{
4497	struct wm_adsp *dsp = data;
4498
4499	mutex_lock(&dsp->pwr_lock);
4500
4501	adsp_warn(dsp, "WDT Expiry Fault\n");
4502	dsp->ops->stop_watchdog(dsp);
4503	wm_adsp_fatal_error(dsp);
4504
4505	mutex_unlock(&dsp->pwr_lock);
4506
4507	return IRQ_HANDLED;
4508}
4509EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
4510
4511static struct wm_adsp_ops wm_adsp1_ops = {
4512	.validate_version = wm_adsp_validate_version,
4513	.parse_sizes = wm_adsp1_parse_sizes,
4514	.region_to_reg = wm_adsp_region_to_reg,
4515};
4516
4517static struct wm_adsp_ops wm_adsp2_ops[] = {
4518	{
4519		.sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4520		.parse_sizes = wm_adsp2_parse_sizes,
4521		.validate_version = wm_adsp_validate_version,
4522		.setup_algs = wm_adsp2_setup_algs,
4523		.region_to_reg = wm_adsp_region_to_reg,
4524
4525		.show_fw_status = wm_adsp2_show_fw_status,
4526
4527		.enable_memory = wm_adsp2_enable_memory,
4528		.disable_memory = wm_adsp2_disable_memory,
4529
4530		.enable_core = wm_adsp2_enable_core,
4531		.disable_core = wm_adsp2_disable_core,
4532
4533		.start_core = wm_adsp2_start_core,
4534		.stop_core = wm_adsp2_stop_core,
4535
4536	},
4537	{
4538		.sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4539		.parse_sizes = wm_adsp2_parse_sizes,
4540		.validate_version = wm_adsp_validate_version,
4541		.setup_algs = wm_adsp2_setup_algs,
4542		.region_to_reg = wm_adsp_region_to_reg,
4543
4544		.show_fw_status = wm_adsp2v2_show_fw_status,
4545
4546		.enable_memory = wm_adsp2_enable_memory,
4547		.disable_memory = wm_adsp2_disable_memory,
4548		.lock_memory = wm_adsp2_lock,
4549
4550		.enable_core = wm_adsp2v2_enable_core,
4551		.disable_core = wm_adsp2v2_disable_core,
4552
4553		.start_core = wm_adsp2_start_core,
4554		.stop_core = wm_adsp2_stop_core,
4555	},
4556	{
4557		.sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4558		.parse_sizes = wm_adsp2_parse_sizes,
4559		.validate_version = wm_adsp_validate_version,
4560		.setup_algs = wm_adsp2_setup_algs,
4561		.region_to_reg = wm_adsp_region_to_reg,
4562
4563		.show_fw_status = wm_adsp2v2_show_fw_status,
4564		.stop_watchdog = wm_adsp_stop_watchdog,
4565
4566		.enable_memory = wm_adsp2_enable_memory,
4567		.disable_memory = wm_adsp2_disable_memory,
4568		.lock_memory = wm_adsp2_lock,
4569
4570		.enable_core = wm_adsp2v2_enable_core,
4571		.disable_core = wm_adsp2v2_disable_core,
4572
4573		.start_core = wm_adsp2_start_core,
4574		.stop_core = wm_adsp2_stop_core,
4575	},
4576};
4577
4578static struct wm_adsp_ops wm_halo_ops = {
4579	.sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr),
4580	.parse_sizes = wm_adsp2_parse_sizes,
4581	.validate_version = wm_halo_validate_version,
4582	.setup_algs = wm_halo_setup_algs,
4583	.region_to_reg = wm_halo_region_to_reg,
4584
4585	.show_fw_status = wm_halo_show_fw_status,
4586	.stop_watchdog = wm_halo_stop_watchdog,
4587
4588	.lock_memory = wm_halo_configure_mpu,
4589
4590	.start_core = wm_halo_start_core,
4591	.stop_core = wm_halo_stop_core,
4592};
4593
4594MODULE_LICENSE("GPL v2");
4595