xref: /linux/drivers/firmware/cirrus/cs_dsp.c (revision 34f7c6e7d4396090692a09789db231e12cb4762b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * cs_dsp.c  --  Cirrus Logic DSP firmware support
4  *
5  * Based on sound/soc/codecs/wm_adsp.c
6  *
7  * Copyright 2012 Wolfson Microelectronics plc
8  * Copyright (C) 2015-2021 Cirrus Logic, Inc. and
9  *                         Cirrus Logic International Semiconductor Ltd.
10  */
11 
12 #include <linux/ctype.h>
13 #include <linux/debugfs.h>
14 #include <linux/delay.h>
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/slab.h>
18 #include <linux/vmalloc.h>
19 
20 #include <linux/firmware/cirrus/cs_dsp.h>
21 #include <linux/firmware/cirrus/wmfw.h>
22 
23 #define cs_dsp_err(_dsp, fmt, ...) \
24 	dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
25 #define cs_dsp_warn(_dsp, fmt, ...) \
26 	dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
27 #define cs_dsp_info(_dsp, fmt, ...) \
28 	dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
29 #define cs_dsp_dbg(_dsp, fmt, ...) \
30 	dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
31 
32 #define ADSP1_CONTROL_1                   0x00
33 #define ADSP1_CONTROL_2                   0x02
34 #define ADSP1_CONTROL_3                   0x03
35 #define ADSP1_CONTROL_4                   0x04
36 #define ADSP1_CONTROL_5                   0x06
37 #define ADSP1_CONTROL_6                   0x07
38 #define ADSP1_CONTROL_7                   0x08
39 #define ADSP1_CONTROL_8                   0x09
40 #define ADSP1_CONTROL_9                   0x0A
41 #define ADSP1_CONTROL_10                  0x0B
42 #define ADSP1_CONTROL_11                  0x0C
43 #define ADSP1_CONTROL_12                  0x0D
44 #define ADSP1_CONTROL_13                  0x0F
45 #define ADSP1_CONTROL_14                  0x10
46 #define ADSP1_CONTROL_15                  0x11
47 #define ADSP1_CONTROL_16                  0x12
48 #define ADSP1_CONTROL_17                  0x13
49 #define ADSP1_CONTROL_18                  0x14
50 #define ADSP1_CONTROL_19                  0x16
51 #define ADSP1_CONTROL_20                  0x17
52 #define ADSP1_CONTROL_21                  0x18
53 #define ADSP1_CONTROL_22                  0x1A
54 #define ADSP1_CONTROL_23                  0x1B
55 #define ADSP1_CONTROL_24                  0x1C
56 #define ADSP1_CONTROL_25                  0x1E
57 #define ADSP1_CONTROL_26                  0x20
58 #define ADSP1_CONTROL_27                  0x21
59 #define ADSP1_CONTROL_28                  0x22
60 #define ADSP1_CONTROL_29                  0x23
61 #define ADSP1_CONTROL_30                  0x24
62 #define ADSP1_CONTROL_31                  0x26
63 
64 /*
65  * ADSP1 Control 19
66  */
67 #define ADSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
68 #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
69 #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
70 
71 /*
72  * ADSP1 Control 30
73  */
74 #define ADSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
75 #define ADSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
76 #define ADSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
77 #define ADSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
78 #define ADSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
79 #define ADSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
80 #define ADSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
81 #define ADSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
82 #define ADSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
83 #define ADSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
84 #define ADSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
85 #define ADSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
86 #define ADSP1_START                       0x0001  /* DSP1_START */
87 #define ADSP1_START_MASK                  0x0001  /* DSP1_START */
88 #define ADSP1_START_SHIFT                      0  /* DSP1_START */
89 #define ADSP1_START_WIDTH                      1  /* DSP1_START */
90 
91 /*
92  * ADSP1 Control 31
93  */
94 #define ADSP1_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
95 #define ADSP1_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
96 #define ADSP1_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
97 
98 #define ADSP2_CONTROL                     0x0
99 #define ADSP2_CLOCKING                    0x1
100 #define ADSP2V2_CLOCKING                  0x2
101 #define ADSP2_STATUS1                     0x4
102 #define ADSP2_WDMA_CONFIG_1               0x30
103 #define ADSP2_WDMA_CONFIG_2               0x31
104 #define ADSP2V2_WDMA_CONFIG_2             0x32
105 #define ADSP2_RDMA_CONFIG_1               0x34
106 
107 #define ADSP2_SCRATCH0                    0x40
108 #define ADSP2_SCRATCH1                    0x41
109 #define ADSP2_SCRATCH2                    0x42
110 #define ADSP2_SCRATCH3                    0x43
111 
112 #define ADSP2V2_SCRATCH0_1                0x40
113 #define ADSP2V2_SCRATCH2_3                0x42
114 
115 /*
116  * ADSP2 Control
117  */
118 #define ADSP2_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
119 #define ADSP2_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
120 #define ADSP2_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
121 #define ADSP2_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
122 #define ADSP2_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
123 #define ADSP2_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
124 #define ADSP2_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
125 #define ADSP2_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
126 #define ADSP2_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
127 #define ADSP2_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
128 #define ADSP2_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
129 #define ADSP2_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
130 #define ADSP2_START                       0x0001  /* DSP1_START */
131 #define ADSP2_START_MASK                  0x0001  /* DSP1_START */
132 #define ADSP2_START_SHIFT                      0  /* DSP1_START */
133 #define ADSP2_START_WIDTH                      1  /* DSP1_START */
134 
135 /*
136  * ADSP2 clocking
137  */
138 #define ADSP2_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
139 #define ADSP2_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
140 #define ADSP2_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
141 
142 /*
143  * ADSP2V2 clocking
144  */
145 #define ADSP2V2_CLK_SEL_MASK             0x70000  /* CLK_SEL_ENA */
146 #define ADSP2V2_CLK_SEL_SHIFT                 16  /* CLK_SEL_ENA */
147 #define ADSP2V2_CLK_SEL_WIDTH                  3  /* CLK_SEL_ENA */
148 
149 #define ADSP2V2_RATE_MASK                 0x7800  /* DSP_RATE */
150 #define ADSP2V2_RATE_SHIFT                    11  /* DSP_RATE */
151 #define ADSP2V2_RATE_WIDTH                     4  /* DSP_RATE */
152 
153 /*
154  * ADSP2 Status 1
155  */
156 #define ADSP2_RAM_RDY                     0x0001
157 #define ADSP2_RAM_RDY_MASK                0x0001
158 #define ADSP2_RAM_RDY_SHIFT                    0
159 #define ADSP2_RAM_RDY_WIDTH                    1
160 
161 /*
162  * ADSP2 Lock support
163  */
164 #define ADSP2_LOCK_CODE_0                    0x5555
165 #define ADSP2_LOCK_CODE_1                    0xAAAA
166 
167 #define ADSP2_WATCHDOG                       0x0A
168 #define ADSP2_BUS_ERR_ADDR                   0x52
169 #define ADSP2_REGION_LOCK_STATUS             0x64
170 #define ADSP2_LOCK_REGION_1_LOCK_REGION_0    0x66
171 #define ADSP2_LOCK_REGION_3_LOCK_REGION_2    0x68
172 #define ADSP2_LOCK_REGION_5_LOCK_REGION_4    0x6A
173 #define ADSP2_LOCK_REGION_7_LOCK_REGION_6    0x6C
174 #define ADSP2_LOCK_REGION_9_LOCK_REGION_8    0x6E
175 #define ADSP2_LOCK_REGION_CTRL               0x7A
176 #define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR    0x7C
177 
178 #define ADSP2_REGION_LOCK_ERR_MASK           0x8000
179 #define ADSP2_ADDR_ERR_MASK                  0x4000
180 #define ADSP2_WDT_TIMEOUT_STS_MASK           0x2000
181 #define ADSP2_CTRL_ERR_PAUSE_ENA             0x0002
182 #define ADSP2_CTRL_ERR_EINT                  0x0001
183 
184 #define ADSP2_BUS_ERR_ADDR_MASK              0x00FFFFFF
185 #define ADSP2_XMEM_ERR_ADDR_MASK             0x0000FFFF
186 #define ADSP2_PMEM_ERR_ADDR_MASK             0x7FFF0000
187 #define ADSP2_PMEM_ERR_ADDR_SHIFT            16
188 #define ADSP2_WDT_ENA_MASK                   0xFFFFFFFD
189 
190 #define ADSP2_LOCK_REGION_SHIFT              16
191 
192 /*
193  * Event control messages
194  */
195 #define CS_DSP_FW_EVENT_SHUTDOWN             0x000001
196 
197 /*
198  * HALO system info
199  */
200 #define HALO_AHBM_WINDOW_DEBUG_0             0x02040
201 #define HALO_AHBM_WINDOW_DEBUG_1             0x02044
202 
203 /*
204  * HALO core
205  */
206 #define HALO_SCRATCH1                        0x005c0
207 #define HALO_SCRATCH2                        0x005c8
208 #define HALO_SCRATCH3                        0x005d0
209 #define HALO_SCRATCH4                        0x005d8
210 #define HALO_CCM_CORE_CONTROL                0x41000
211 #define HALO_CORE_SOFT_RESET                 0x00010
212 #define HALO_WDT_CONTROL                     0x47000
213 
214 /*
215  * HALO MPU banks
216  */
217 #define HALO_MPU_XMEM_ACCESS_0               0x43000
218 #define HALO_MPU_YMEM_ACCESS_0               0x43004
219 #define HALO_MPU_WINDOW_ACCESS_0             0x43008
220 #define HALO_MPU_XREG_ACCESS_0               0x4300C
221 #define HALO_MPU_YREG_ACCESS_0               0x43014
222 #define HALO_MPU_XMEM_ACCESS_1               0x43018
223 #define HALO_MPU_YMEM_ACCESS_1               0x4301C
224 #define HALO_MPU_WINDOW_ACCESS_1             0x43020
225 #define HALO_MPU_XREG_ACCESS_1               0x43024
226 #define HALO_MPU_YREG_ACCESS_1               0x4302C
227 #define HALO_MPU_XMEM_ACCESS_2               0x43030
228 #define HALO_MPU_YMEM_ACCESS_2               0x43034
229 #define HALO_MPU_WINDOW_ACCESS_2             0x43038
230 #define HALO_MPU_XREG_ACCESS_2               0x4303C
231 #define HALO_MPU_YREG_ACCESS_2               0x43044
232 #define HALO_MPU_XMEM_ACCESS_3               0x43048
233 #define HALO_MPU_YMEM_ACCESS_3               0x4304C
234 #define HALO_MPU_WINDOW_ACCESS_3             0x43050
235 #define HALO_MPU_XREG_ACCESS_3               0x43054
236 #define HALO_MPU_YREG_ACCESS_3               0x4305C
237 #define HALO_MPU_XM_VIO_ADDR                 0x43100
238 #define HALO_MPU_XM_VIO_STATUS               0x43104
239 #define HALO_MPU_YM_VIO_ADDR                 0x43108
240 #define HALO_MPU_YM_VIO_STATUS               0x4310C
241 #define HALO_MPU_PM_VIO_ADDR                 0x43110
242 #define HALO_MPU_PM_VIO_STATUS               0x43114
243 #define HALO_MPU_LOCK_CONFIG                 0x43140
244 
245 /*
246  * HALO_AHBM_WINDOW_DEBUG_1
247  */
248 #define HALO_AHBM_CORE_ERR_ADDR_MASK         0x0fffff00
249 #define HALO_AHBM_CORE_ERR_ADDR_SHIFT                 8
250 #define HALO_AHBM_FLAGS_ERR_MASK             0x000000ff
251 
252 /*
253  * HALO_CCM_CORE_CONTROL
254  */
255 #define HALO_CORE_RESET                     0x00000200
256 #define HALO_CORE_EN                        0x00000001
257 
258 /*
259  * HALO_CORE_SOFT_RESET
260  */
261 #define HALO_CORE_SOFT_RESET_MASK           0x00000001
262 
263 /*
264  * HALO_WDT_CONTROL
265  */
266 #define HALO_WDT_EN_MASK                    0x00000001
267 
268 /*
269  * HALO_MPU_?M_VIO_STATUS
270  */
271 #define HALO_MPU_VIO_STS_MASK               0x007e0000
272 #define HALO_MPU_VIO_STS_SHIFT                      17
273 #define HALO_MPU_VIO_ERR_WR_MASK            0x00008000
274 #define HALO_MPU_VIO_ERR_SRC_MASK           0x00007fff
275 #define HALO_MPU_VIO_ERR_SRC_SHIFT                   0
276 
277 struct cs_dsp_ops {
278 	bool (*validate_version)(struct cs_dsp *dsp, unsigned int version);
279 	unsigned int (*parse_sizes)(struct cs_dsp *dsp,
280 				    const char * const file,
281 				    unsigned int pos,
282 				    const struct firmware *firmware);
283 	int (*setup_algs)(struct cs_dsp *dsp);
284 	unsigned int (*region_to_reg)(struct cs_dsp_region const *mem,
285 				      unsigned int offset);
286 
287 	void (*show_fw_status)(struct cs_dsp *dsp);
288 	void (*stop_watchdog)(struct cs_dsp *dsp);
289 
290 	int (*enable_memory)(struct cs_dsp *dsp);
291 	void (*disable_memory)(struct cs_dsp *dsp);
292 	int (*lock_memory)(struct cs_dsp *dsp, unsigned int lock_regions);
293 
294 	int (*enable_core)(struct cs_dsp *dsp);
295 	void (*disable_core)(struct cs_dsp *dsp);
296 
297 	int (*start_core)(struct cs_dsp *dsp);
298 	void (*stop_core)(struct cs_dsp *dsp);
299 };
300 
301 static const struct cs_dsp_ops cs_dsp_adsp1_ops;
302 static const struct cs_dsp_ops cs_dsp_adsp2_ops[];
303 static const struct cs_dsp_ops cs_dsp_halo_ops;
304 
305 struct cs_dsp_buf {
306 	struct list_head list;
307 	void *buf;
308 };
309 
310 static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len,
311 					   struct list_head *list)
312 {
313 	struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
314 
315 	if (buf == NULL)
316 		return NULL;
317 
318 	buf->buf = vmalloc(len);
319 	if (!buf->buf) {
320 		kfree(buf);
321 		return NULL;
322 	}
323 	memcpy(buf->buf, src, len);
324 
325 	if (list)
326 		list_add_tail(&buf->list, list);
327 
328 	return buf;
329 }
330 
331 static void cs_dsp_buf_free(struct list_head *list)
332 {
333 	while (!list_empty(list)) {
334 		struct cs_dsp_buf *buf = list_first_entry(list,
335 							  struct cs_dsp_buf,
336 							  list);
337 		list_del(&buf->list);
338 		vfree(buf->buf);
339 		kfree(buf);
340 	}
341 }
342 
343 /**
344  * cs_dsp_mem_region_name() - Return a name string for a memory type
345  * @type: the memory type to match
346  *
347  * Return: A const string identifying the memory region.
348  */
349 const char *cs_dsp_mem_region_name(unsigned int type)
350 {
351 	switch (type) {
352 	case WMFW_ADSP1_PM:
353 		return "PM";
354 	case WMFW_HALO_PM_PACKED:
355 		return "PM_PACKED";
356 	case WMFW_ADSP1_DM:
357 		return "DM";
358 	case WMFW_ADSP2_XM:
359 		return "XM";
360 	case WMFW_HALO_XM_PACKED:
361 		return "XM_PACKED";
362 	case WMFW_ADSP2_YM:
363 		return "YM";
364 	case WMFW_HALO_YM_PACKED:
365 		return "YM_PACKED";
366 	case WMFW_ADSP1_ZM:
367 		return "ZM";
368 	default:
369 		return NULL;
370 	}
371 }
372 EXPORT_SYMBOL_GPL(cs_dsp_mem_region_name);
373 
374 #ifdef CONFIG_DEBUG_FS
375 static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s)
376 {
377 	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
378 
379 	kfree(dsp->wmfw_file_name);
380 	dsp->wmfw_file_name = tmp;
381 }
382 
383 static void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, const char *s)
384 {
385 	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
386 
387 	kfree(dsp->bin_file_name);
388 	dsp->bin_file_name = tmp;
389 }
390 
391 static void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
392 {
393 	kfree(dsp->wmfw_file_name);
394 	kfree(dsp->bin_file_name);
395 	dsp->wmfw_file_name = NULL;
396 	dsp->bin_file_name = NULL;
397 }
398 
399 static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file,
400 					char __user *user_buf,
401 					size_t count, loff_t *ppos)
402 {
403 	struct cs_dsp *dsp = file->private_data;
404 	ssize_t ret;
405 
406 	mutex_lock(&dsp->pwr_lock);
407 
408 	if (!dsp->wmfw_file_name || !dsp->booted)
409 		ret = 0;
410 	else
411 		ret = simple_read_from_buffer(user_buf, count, ppos,
412 					      dsp->wmfw_file_name,
413 					      strlen(dsp->wmfw_file_name));
414 
415 	mutex_unlock(&dsp->pwr_lock);
416 	return ret;
417 }
418 
419 static ssize_t cs_dsp_debugfs_bin_read(struct file *file,
420 				       char __user *user_buf,
421 				       size_t count, loff_t *ppos)
422 {
423 	struct cs_dsp *dsp = file->private_data;
424 	ssize_t ret;
425 
426 	mutex_lock(&dsp->pwr_lock);
427 
428 	if (!dsp->bin_file_name || !dsp->booted)
429 		ret = 0;
430 	else
431 		ret = simple_read_from_buffer(user_buf, count, ppos,
432 					      dsp->bin_file_name,
433 					      strlen(dsp->bin_file_name));
434 
435 	mutex_unlock(&dsp->pwr_lock);
436 	return ret;
437 }
438 
439 static const struct {
440 	const char *name;
441 	const struct file_operations fops;
442 } cs_dsp_debugfs_fops[] = {
443 	{
444 		.name = "wmfw_file_name",
445 		.fops = {
446 			.open = simple_open,
447 			.read = cs_dsp_debugfs_wmfw_read,
448 		},
449 	},
450 	{
451 		.name = "bin_file_name",
452 		.fops = {
453 			.open = simple_open,
454 			.read = cs_dsp_debugfs_bin_read,
455 		},
456 	},
457 };
458 
459 /**
460  * cs_dsp_init_debugfs() - Create and populate DSP representation in debugfs
461  * @dsp: pointer to DSP structure
462  * @debugfs_root: pointer to debugfs directory in which to create this DSP
463  *                representation
464  */
465 void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
466 {
467 	struct dentry *root = NULL;
468 	int i;
469 
470 	root = debugfs_create_dir(dsp->name, debugfs_root);
471 
472 	debugfs_create_bool("booted", 0444, root, &dsp->booted);
473 	debugfs_create_bool("running", 0444, root, &dsp->running);
474 	debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
475 	debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
476 
477 	for (i = 0; i < ARRAY_SIZE(cs_dsp_debugfs_fops); ++i)
478 		debugfs_create_file(cs_dsp_debugfs_fops[i].name, 0444, root,
479 				    dsp, &cs_dsp_debugfs_fops[i].fops);
480 
481 	dsp->debugfs_root = root;
482 }
483 EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs);
484 
485 /**
486  * cs_dsp_cleanup_debugfs() - Removes DSP representation from debugfs
487  * @dsp: pointer to DSP structure
488  */
489 void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
490 {
491 	cs_dsp_debugfs_clear(dsp);
492 	debugfs_remove_recursive(dsp->debugfs_root);
493 	dsp->debugfs_root = NULL;
494 }
495 EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs);
496 #else
497 void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
498 {
499 }
500 EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs);
501 
502 void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
503 {
504 }
505 EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs);
506 
507 static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp,
508 						const char *s)
509 {
510 }
511 
512 static inline void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp,
513 					       const char *s)
514 {
515 }
516 
517 static inline void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
518 {
519 }
520 #endif
521 
522 static const struct cs_dsp_region *cs_dsp_find_region(struct cs_dsp *dsp,
523 						      int type)
524 {
525 	int i;
526 
527 	for (i = 0; i < dsp->num_mems; i++)
528 		if (dsp->mem[i].type == type)
529 			return &dsp->mem[i];
530 
531 	return NULL;
532 }
533 
534 static unsigned int cs_dsp_region_to_reg(struct cs_dsp_region const *mem,
535 					 unsigned int offset)
536 {
537 	switch (mem->type) {
538 	case WMFW_ADSP1_PM:
539 		return mem->base + (offset * 3);
540 	case WMFW_ADSP1_DM:
541 	case WMFW_ADSP2_XM:
542 	case WMFW_ADSP2_YM:
543 	case WMFW_ADSP1_ZM:
544 		return mem->base + (offset * 2);
545 	default:
546 		WARN(1, "Unknown memory region type");
547 		return offset;
548 	}
549 }
550 
551 static unsigned int cs_dsp_halo_region_to_reg(struct cs_dsp_region const *mem,
552 					      unsigned int offset)
553 {
554 	switch (mem->type) {
555 	case WMFW_ADSP2_XM:
556 	case WMFW_ADSP2_YM:
557 		return mem->base + (offset * 4);
558 	case WMFW_HALO_XM_PACKED:
559 	case WMFW_HALO_YM_PACKED:
560 		return (mem->base + (offset * 3)) & ~0x3;
561 	case WMFW_HALO_PM_PACKED:
562 		return mem->base + (offset * 5);
563 	default:
564 		WARN(1, "Unknown memory region type");
565 		return offset;
566 	}
567 }
568 
569 static void cs_dsp_read_fw_status(struct cs_dsp *dsp,
570 				  int noffs, unsigned int *offs)
571 {
572 	unsigned int i;
573 	int ret;
574 
575 	for (i = 0; i < noffs; ++i) {
576 		ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
577 		if (ret) {
578 			cs_dsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
579 			return;
580 		}
581 	}
582 }
583 
584 static void cs_dsp_adsp2_show_fw_status(struct cs_dsp *dsp)
585 {
586 	unsigned int offs[] = {
587 		ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
588 	};
589 
590 	cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
591 
592 	cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
593 		   offs[0], offs[1], offs[2], offs[3]);
594 }
595 
596 static void cs_dsp_adsp2v2_show_fw_status(struct cs_dsp *dsp)
597 {
598 	unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
599 
600 	cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
601 
602 	cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
603 		   offs[0] & 0xFFFF, offs[0] >> 16,
604 		   offs[1] & 0xFFFF, offs[1] >> 16);
605 }
606 
607 static void cs_dsp_halo_show_fw_status(struct cs_dsp *dsp)
608 {
609 	unsigned int offs[] = {
610 		HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
611 	};
612 
613 	cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
614 
615 	cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
616 		   offs[0], offs[1], offs[2], offs[3]);
617 }
618 
619 static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg,
620 				 unsigned int off)
621 {
622 	const struct cs_dsp_alg_region *alg_region = &ctl->alg_region;
623 	struct cs_dsp *dsp = ctl->dsp;
624 	const struct cs_dsp_region *mem;
625 
626 	mem = cs_dsp_find_region(dsp, alg_region->type);
627 	if (!mem) {
628 		cs_dsp_err(dsp, "No base for region %x\n",
629 			   alg_region->type);
630 		return -EINVAL;
631 	}
632 
633 	*reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset + off);
634 
635 	return 0;
636 }
637 
638 /**
639  * cs_dsp_coeff_write_acked_control() - Sends event_id to the acked control
640  * @ctl: pointer to acked coefficient control
641  * @event_id: the value to write to the given acked control
642  *
643  * Once the value has been written to the control the function shall block
644  * until the running firmware acknowledges the write or timeout is exceeded.
645  *
646  * Must be called with pwr_lock held.
647  *
648  * Return: Zero for success, a negative number on error.
649  */
650 int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int event_id)
651 {
652 	struct cs_dsp *dsp = ctl->dsp;
653 	__be32 val = cpu_to_be32(event_id);
654 	unsigned int reg;
655 	int i, ret;
656 
657 	lockdep_assert_held(&dsp->pwr_lock);
658 
659 	if (!dsp->running)
660 		return -EPERM;
661 
662 	ret = cs_dsp_coeff_base_reg(ctl, &reg, 0);
663 	if (ret)
664 		return ret;
665 
666 	cs_dsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
667 		   event_id, ctl->alg_region.alg,
668 		   cs_dsp_mem_region_name(ctl->alg_region.type), ctl->offset);
669 
670 	ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
671 	if (ret) {
672 		cs_dsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
673 		return ret;
674 	}
675 
676 	/*
677 	 * Poll for ack, we initially poll at ~1ms intervals for firmwares
678 	 * that respond quickly, then go to ~10ms polls. A firmware is unlikely
679 	 * to ack instantly so we do the first 1ms delay before reading the
680 	 * control to avoid a pointless bus transaction
681 	 */
682 	for (i = 0; i < CS_DSP_ACKED_CTL_TIMEOUT_MS;) {
683 		switch (i) {
684 		case 0 ... CS_DSP_ACKED_CTL_N_QUICKPOLLS - 1:
685 			usleep_range(1000, 2000);
686 			i++;
687 			break;
688 		default:
689 			usleep_range(10000, 20000);
690 			i += 10;
691 			break;
692 		}
693 
694 		ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
695 		if (ret) {
696 			cs_dsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
697 			return ret;
698 		}
699 
700 		if (val == 0) {
701 			cs_dsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
702 			return 0;
703 		}
704 	}
705 
706 	cs_dsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
707 		    reg, ctl->alg_region.alg,
708 		    cs_dsp_mem_region_name(ctl->alg_region.type),
709 		    ctl->offset);
710 
711 	return -ETIMEDOUT;
712 }
713 EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_acked_control);
714 
715 static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
716 				       unsigned int off, const void *buf, size_t len)
717 {
718 	struct cs_dsp *dsp = ctl->dsp;
719 	void *scratch;
720 	int ret;
721 	unsigned int reg;
722 
723 	ret = cs_dsp_coeff_base_reg(ctl, &reg, off);
724 	if (ret)
725 		return ret;
726 
727 	scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
728 	if (!scratch)
729 		return -ENOMEM;
730 
731 	ret = regmap_raw_write(dsp->regmap, reg, scratch,
732 			       len);
733 	if (ret) {
734 		cs_dsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
735 			   len, reg, ret);
736 		kfree(scratch);
737 		return ret;
738 	}
739 	cs_dsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
740 
741 	kfree(scratch);
742 
743 	return 0;
744 }
745 
746 /**
747  * cs_dsp_coeff_write_ctrl() - Writes the given buffer to the given coefficient control
748  * @ctl: pointer to coefficient control
749  * @off: word offset at which data should be written
750  * @buf: the buffer to write to the given control
751  * @len: the length of the buffer in bytes
752  *
753  * Must be called with pwr_lock held.
754  *
755  * Return: Zero for success, a negative number on error.
756  */
757 int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
758 			    unsigned int off, const void *buf, size_t len)
759 {
760 	int ret = 0;
761 
762 	if (!ctl)
763 		return -ENOENT;
764 
765 	lockdep_assert_held(&ctl->dsp->pwr_lock);
766 
767 	if (len + off * sizeof(u32) > ctl->len)
768 		return -EINVAL;
769 
770 	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
771 		ret = -EPERM;
772 	else if (buf != ctl->cache)
773 		memcpy(ctl->cache + off * sizeof(u32), buf, len);
774 
775 	ctl->set = 1;
776 	if (ctl->enabled && ctl->dsp->running)
777 		ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len);
778 
779 	return ret;
780 }
781 EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_ctrl);
782 
783 static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
784 				      unsigned int off, void *buf, size_t len)
785 {
786 	struct cs_dsp *dsp = ctl->dsp;
787 	void *scratch;
788 	int ret;
789 	unsigned int reg;
790 
791 	ret = cs_dsp_coeff_base_reg(ctl, &reg, off);
792 	if (ret)
793 		return ret;
794 
795 	scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
796 	if (!scratch)
797 		return -ENOMEM;
798 
799 	ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
800 	if (ret) {
801 		cs_dsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
802 			   len, reg, ret);
803 		kfree(scratch);
804 		return ret;
805 	}
806 	cs_dsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
807 
808 	memcpy(buf, scratch, len);
809 	kfree(scratch);
810 
811 	return 0;
812 }
813 
814 /**
815  * cs_dsp_coeff_read_ctrl() - Reads the given coefficient control into the given buffer
816  * @ctl: pointer to coefficient control
817  * @off: word offset at which data should be read
818  * @buf: the buffer to store to the given control
819  * @len: the length of the buffer in bytes
820  *
821  * Must be called with pwr_lock held.
822  *
823  * Return: Zero for success, a negative number on error.
824  */
825 int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl,
826 			   unsigned int off, void *buf, size_t len)
827 {
828 	int ret = 0;
829 
830 	if (!ctl)
831 		return -ENOENT;
832 
833 	lockdep_assert_held(&ctl->dsp->pwr_lock);
834 
835 	if (len + off * sizeof(u32) > ctl->len)
836 		return -EINVAL;
837 
838 	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
839 		if (ctl->enabled && ctl->dsp->running)
840 			return cs_dsp_coeff_read_ctrl_raw(ctl, off, buf, len);
841 		else
842 			return -EPERM;
843 	} else {
844 		if (!ctl->flags && ctl->enabled && ctl->dsp->running)
845 			ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len);
846 
847 		if (buf != ctl->cache)
848 			memcpy(buf, ctl->cache + off * sizeof(u32), len);
849 	}
850 
851 	return ret;
852 }
853 EXPORT_SYMBOL_GPL(cs_dsp_coeff_read_ctrl);
854 
855 static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp)
856 {
857 	struct cs_dsp_coeff_ctl *ctl;
858 	int ret;
859 
860 	list_for_each_entry(ctl, &dsp->ctl_list, list) {
861 		if (!ctl->enabled || ctl->set)
862 			continue;
863 		if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
864 			continue;
865 
866 		/*
867 		 * For readable controls populate the cache from the DSP memory.
868 		 * For non-readable controls the cache was zero-filled when
869 		 * created so we don't need to do anything.
870 		 */
871 		if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
872 			ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len);
873 			if (ret < 0)
874 				return ret;
875 		}
876 	}
877 
878 	return 0;
879 }
880 
881 static int cs_dsp_coeff_sync_controls(struct cs_dsp *dsp)
882 {
883 	struct cs_dsp_coeff_ctl *ctl;
884 	int ret;
885 
886 	list_for_each_entry(ctl, &dsp->ctl_list, list) {
887 		if (!ctl->enabled)
888 			continue;
889 		if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
890 			ret = cs_dsp_coeff_write_ctrl_raw(ctl, 0, ctl->cache,
891 							  ctl->len);
892 			if (ret < 0)
893 				return ret;
894 		}
895 	}
896 
897 	return 0;
898 }
899 
900 static void cs_dsp_signal_event_controls(struct cs_dsp *dsp,
901 					 unsigned int event)
902 {
903 	struct cs_dsp_coeff_ctl *ctl;
904 	int ret;
905 
906 	list_for_each_entry(ctl, &dsp->ctl_list, list) {
907 		if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
908 			continue;
909 
910 		if (!ctl->enabled)
911 			continue;
912 
913 		ret = cs_dsp_coeff_write_acked_control(ctl, event);
914 		if (ret)
915 			cs_dsp_warn(dsp,
916 				    "Failed to send 0x%x event to alg 0x%x (%d)\n",
917 				    event, ctl->alg_region.alg, ret);
918 	}
919 }
920 
921 static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl)
922 {
923 	kfree(ctl->cache);
924 	kfree(ctl->subname);
925 	kfree(ctl);
926 }
927 
928 static int cs_dsp_create_control(struct cs_dsp *dsp,
929 				 const struct cs_dsp_alg_region *alg_region,
930 				 unsigned int offset, unsigned int len,
931 				 const char *subname, unsigned int subname_len,
932 				 unsigned int flags, unsigned int type)
933 {
934 	struct cs_dsp_coeff_ctl *ctl;
935 	int ret;
936 
937 	list_for_each_entry(ctl, &dsp->ctl_list, list) {
938 		if (ctl->fw_name == dsp->fw_name &&
939 		    ctl->alg_region.alg == alg_region->alg &&
940 		    ctl->alg_region.type == alg_region->type) {
941 			if ((!subname && !ctl->subname) ||
942 			    (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) {
943 				if (!ctl->enabled)
944 					ctl->enabled = 1;
945 				return 0;
946 			}
947 		}
948 	}
949 
950 	ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
951 	if (!ctl)
952 		return -ENOMEM;
953 
954 	ctl->fw_name = dsp->fw_name;
955 	ctl->alg_region = *alg_region;
956 	if (subname && dsp->fw_ver >= 2) {
957 		ctl->subname_len = subname_len;
958 		ctl->subname = kmemdup(subname,
959 				       strlen(subname) + 1, GFP_KERNEL);
960 		if (!ctl->subname) {
961 			ret = -ENOMEM;
962 			goto err_ctl;
963 		}
964 	}
965 	ctl->enabled = 1;
966 	ctl->set = 0;
967 	ctl->dsp = dsp;
968 
969 	ctl->flags = flags;
970 	ctl->type = type;
971 	ctl->offset = offset;
972 	ctl->len = len;
973 	ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
974 	if (!ctl->cache) {
975 		ret = -ENOMEM;
976 		goto err_ctl_subname;
977 	}
978 
979 	list_add(&ctl->list, &dsp->ctl_list);
980 
981 	if (dsp->client_ops->control_add) {
982 		ret = dsp->client_ops->control_add(ctl);
983 		if (ret)
984 			goto err_list_del;
985 	}
986 
987 	return 0;
988 
989 err_list_del:
990 	list_del(&ctl->list);
991 	kfree(ctl->cache);
992 err_ctl_subname:
993 	kfree(ctl->subname);
994 err_ctl:
995 	kfree(ctl);
996 
997 	return ret;
998 }
999 
1000 struct cs_dsp_coeff_parsed_alg {
1001 	int id;
1002 	const u8 *name;
1003 	int name_len;
1004 	int ncoeff;
1005 };
1006 
1007 struct cs_dsp_coeff_parsed_coeff {
1008 	int offset;
1009 	int mem_type;
1010 	const u8 *name;
1011 	int name_len;
1012 	unsigned int ctl_type;
1013 	int flags;
1014 	int len;
1015 };
1016 
1017 static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
1018 {
1019 	int length;
1020 
1021 	switch (bytes) {
1022 	case 1:
1023 		length = **pos;
1024 		break;
1025 	case 2:
1026 		length = le16_to_cpu(*((__le16 *)*pos));
1027 		break;
1028 	default:
1029 		return 0;
1030 	}
1031 
1032 	if (str)
1033 		*str = *pos + bytes;
1034 
1035 	*pos += ((length + bytes) + 3) & ~0x03;
1036 
1037 	return length;
1038 }
1039 
1040 static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos)
1041 {
1042 	int val = 0;
1043 
1044 	switch (bytes) {
1045 	case 2:
1046 		val = le16_to_cpu(*((__le16 *)*pos));
1047 		break;
1048 	case 4:
1049 		val = le32_to_cpu(*((__le32 *)*pos));
1050 		break;
1051 	default:
1052 		break;
1053 	}
1054 
1055 	*pos += bytes;
1056 
1057 	return val;
1058 }
1059 
1060 static inline void cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, const u8 **data,
1061 					  struct cs_dsp_coeff_parsed_alg *blk)
1062 {
1063 	const struct wmfw_adsp_alg_data *raw;
1064 
1065 	switch (dsp->fw_ver) {
1066 	case 0:
1067 	case 1:
1068 		raw = (const struct wmfw_adsp_alg_data *)*data;
1069 		*data = raw->data;
1070 
1071 		blk->id = le32_to_cpu(raw->id);
1072 		blk->name = raw->name;
1073 		blk->name_len = strlen(raw->name);
1074 		blk->ncoeff = le32_to_cpu(raw->ncoeff);
1075 		break;
1076 	default:
1077 		blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data);
1078 		blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data,
1079 							  &blk->name);
1080 		cs_dsp_coeff_parse_string(sizeof(u16), data, NULL);
1081 		blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data);
1082 		break;
1083 	}
1084 
1085 	cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
1086 	cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
1087 	cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
1088 }
1089 
1090 static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data,
1091 					    struct cs_dsp_coeff_parsed_coeff *blk)
1092 {
1093 	const struct wmfw_adsp_coeff_data *raw;
1094 	const u8 *tmp;
1095 	int length;
1096 
1097 	switch (dsp->fw_ver) {
1098 	case 0:
1099 	case 1:
1100 		raw = (const struct wmfw_adsp_coeff_data *)*data;
1101 		*data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
1102 
1103 		blk->offset = le16_to_cpu(raw->hdr.offset);
1104 		blk->mem_type = le16_to_cpu(raw->hdr.type);
1105 		blk->name = raw->name;
1106 		blk->name_len = strlen(raw->name);
1107 		blk->ctl_type = le16_to_cpu(raw->ctl_type);
1108 		blk->flags = le16_to_cpu(raw->flags);
1109 		blk->len = le32_to_cpu(raw->len);
1110 		break;
1111 	default:
1112 		tmp = *data;
1113 		blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
1114 		blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
1115 		length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
1116 		blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp,
1117 							  &blk->name);
1118 		cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL);
1119 		cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL);
1120 		blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
1121 		blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp);
1122 		blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp);
1123 
1124 		*data = *data + sizeof(raw->hdr) + length;
1125 		break;
1126 	}
1127 
1128 	cs_dsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
1129 	cs_dsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
1130 	cs_dsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
1131 	cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
1132 	cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
1133 	cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
1134 }
1135 
1136 static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp,
1137 				    const struct cs_dsp_coeff_parsed_coeff *coeff_blk,
1138 				    unsigned int f_required,
1139 				    unsigned int f_illegal)
1140 {
1141 	if ((coeff_blk->flags & f_illegal) ||
1142 	    ((coeff_blk->flags & f_required) != f_required)) {
1143 		cs_dsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
1144 			   coeff_blk->flags, coeff_blk->ctl_type);
1145 		return -EINVAL;
1146 	}
1147 
1148 	return 0;
1149 }
1150 
1151 static int cs_dsp_parse_coeff(struct cs_dsp *dsp,
1152 			      const struct wmfw_region *region)
1153 {
1154 	struct cs_dsp_alg_region alg_region = {};
1155 	struct cs_dsp_coeff_parsed_alg alg_blk;
1156 	struct cs_dsp_coeff_parsed_coeff coeff_blk;
1157 	const u8 *data = region->data;
1158 	int i, ret;
1159 
1160 	cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk);
1161 	for (i = 0; i < alg_blk.ncoeff; i++) {
1162 		cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk);
1163 
1164 		switch (coeff_blk.ctl_type) {
1165 		case WMFW_CTL_TYPE_BYTES:
1166 			break;
1167 		case WMFW_CTL_TYPE_ACKED:
1168 			if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
1169 				continue;	/* ignore */
1170 
1171 			ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1172 						       WMFW_CTL_FLAG_VOLATILE |
1173 						       WMFW_CTL_FLAG_WRITEABLE |
1174 						       WMFW_CTL_FLAG_READABLE,
1175 						       0);
1176 			if (ret)
1177 				return -EINVAL;
1178 			break;
1179 		case WMFW_CTL_TYPE_HOSTEVENT:
1180 		case WMFW_CTL_TYPE_FWEVENT:
1181 			ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1182 						       WMFW_CTL_FLAG_SYS |
1183 						       WMFW_CTL_FLAG_VOLATILE |
1184 						       WMFW_CTL_FLAG_WRITEABLE |
1185 						       WMFW_CTL_FLAG_READABLE,
1186 						       0);
1187 			if (ret)
1188 				return -EINVAL;
1189 			break;
1190 		case WMFW_CTL_TYPE_HOST_BUFFER:
1191 			ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1192 						       WMFW_CTL_FLAG_SYS |
1193 						       WMFW_CTL_FLAG_VOLATILE |
1194 						       WMFW_CTL_FLAG_READABLE,
1195 						       0);
1196 			if (ret)
1197 				return -EINVAL;
1198 			break;
1199 		default:
1200 			cs_dsp_err(dsp, "Unknown control type: %d\n",
1201 				   coeff_blk.ctl_type);
1202 			return -EINVAL;
1203 		}
1204 
1205 		alg_region.type = coeff_blk.mem_type;
1206 		alg_region.alg = alg_blk.id;
1207 
1208 		ret = cs_dsp_create_control(dsp, &alg_region,
1209 					    coeff_blk.offset,
1210 					    coeff_blk.len,
1211 					    coeff_blk.name,
1212 					    coeff_blk.name_len,
1213 					    coeff_blk.flags,
1214 					    coeff_blk.ctl_type);
1215 		if (ret < 0)
1216 			cs_dsp_err(dsp, "Failed to create control: %.*s, %d\n",
1217 				   coeff_blk.name_len, coeff_blk.name, ret);
1218 	}
1219 
1220 	return 0;
1221 }
1222 
1223 static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp,
1224 					     const char * const file,
1225 					     unsigned int pos,
1226 					     const struct firmware *firmware)
1227 {
1228 	const struct wmfw_adsp1_sizes *adsp1_sizes;
1229 
1230 	adsp1_sizes = (void *)&firmware->data[pos];
1231 
1232 	cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
1233 		   le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
1234 		   le32_to_cpu(adsp1_sizes->zm));
1235 
1236 	return pos + sizeof(*adsp1_sizes);
1237 }
1238 
1239 static unsigned int cs_dsp_adsp2_parse_sizes(struct cs_dsp *dsp,
1240 					     const char * const file,
1241 					     unsigned int pos,
1242 					     const struct firmware *firmware)
1243 {
1244 	const struct wmfw_adsp2_sizes *adsp2_sizes;
1245 
1246 	adsp2_sizes = (void *)&firmware->data[pos];
1247 
1248 	cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
1249 		   le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
1250 		   le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
1251 
1252 	return pos + sizeof(*adsp2_sizes);
1253 }
1254 
1255 static bool cs_dsp_validate_version(struct cs_dsp *dsp, unsigned int version)
1256 {
1257 	switch (version) {
1258 	case 0:
1259 		cs_dsp_warn(dsp, "Deprecated file format %d\n", version);
1260 		return true;
1261 	case 1:
1262 	case 2:
1263 		return true;
1264 	default:
1265 		return false;
1266 	}
1267 }
1268 
1269 static bool cs_dsp_halo_validate_version(struct cs_dsp *dsp, unsigned int version)
1270 {
1271 	switch (version) {
1272 	case 3:
1273 		return true;
1274 	default:
1275 		return false;
1276 	}
1277 }
1278 
1279 static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
1280 		       const char *file)
1281 {
1282 	LIST_HEAD(buf_list);
1283 	struct regmap *regmap = dsp->regmap;
1284 	unsigned int pos = 0;
1285 	const struct wmfw_header *header;
1286 	const struct wmfw_adsp1_sizes *adsp1_sizes;
1287 	const struct wmfw_footer *footer;
1288 	const struct wmfw_region *region;
1289 	const struct cs_dsp_region *mem;
1290 	const char *region_name;
1291 	char *text = NULL;
1292 	struct cs_dsp_buf *buf;
1293 	unsigned int reg;
1294 	int regions = 0;
1295 	int ret, offset, type;
1296 
1297 	ret = -EINVAL;
1298 
1299 	pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1300 	if (pos >= firmware->size) {
1301 		cs_dsp_err(dsp, "%s: file too short, %zu bytes\n",
1302 			   file, firmware->size);
1303 		goto out_fw;
1304 	}
1305 
1306 	header = (void *)&firmware->data[0];
1307 
1308 	if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
1309 		cs_dsp_err(dsp, "%s: invalid magic\n", file);
1310 		goto out_fw;
1311 	}
1312 
1313 	if (!dsp->ops->validate_version(dsp, header->ver)) {
1314 		cs_dsp_err(dsp, "%s: unknown file format %d\n",
1315 			   file, header->ver);
1316 		goto out_fw;
1317 	}
1318 
1319 	cs_dsp_info(dsp, "Firmware version: %d\n", header->ver);
1320 	dsp->fw_ver = header->ver;
1321 
1322 	if (header->core != dsp->type) {
1323 		cs_dsp_err(dsp, "%s: invalid core %d != %d\n",
1324 			   file, header->core, dsp->type);
1325 		goto out_fw;
1326 	}
1327 
1328 	pos = sizeof(*header);
1329 	pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
1330 
1331 	footer = (void *)&firmware->data[pos];
1332 	pos += sizeof(*footer);
1333 
1334 	if (le32_to_cpu(header->len) != pos) {
1335 		cs_dsp_err(dsp, "%s: unexpected header length %d\n",
1336 			   file, le32_to_cpu(header->len));
1337 		goto out_fw;
1338 	}
1339 
1340 	cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file,
1341 		   le64_to_cpu(footer->timestamp));
1342 
1343 	while (pos < firmware->size &&
1344 	       sizeof(*region) < firmware->size - pos) {
1345 		region = (void *)&(firmware->data[pos]);
1346 		region_name = "Unknown";
1347 		reg = 0;
1348 		text = NULL;
1349 		offset = le32_to_cpu(region->offset) & 0xffffff;
1350 		type = be32_to_cpu(region->type) & 0xff;
1351 
1352 		switch (type) {
1353 		case WMFW_NAME_TEXT:
1354 			region_name = "Firmware name";
1355 			text = kzalloc(le32_to_cpu(region->len) + 1,
1356 				       GFP_KERNEL);
1357 			break;
1358 		case WMFW_ALGORITHM_DATA:
1359 			region_name = "Algorithm";
1360 			ret = cs_dsp_parse_coeff(dsp, region);
1361 			if (ret != 0)
1362 				goto out_fw;
1363 			break;
1364 		case WMFW_INFO_TEXT:
1365 			region_name = "Information";
1366 			text = kzalloc(le32_to_cpu(region->len) + 1,
1367 				       GFP_KERNEL);
1368 			break;
1369 		case WMFW_ABSOLUTE:
1370 			region_name = "Absolute";
1371 			reg = offset;
1372 			break;
1373 		case WMFW_ADSP1_PM:
1374 		case WMFW_ADSP1_DM:
1375 		case WMFW_ADSP2_XM:
1376 		case WMFW_ADSP2_YM:
1377 		case WMFW_ADSP1_ZM:
1378 		case WMFW_HALO_PM_PACKED:
1379 		case WMFW_HALO_XM_PACKED:
1380 		case WMFW_HALO_YM_PACKED:
1381 			mem = cs_dsp_find_region(dsp, type);
1382 			if (!mem) {
1383 				cs_dsp_err(dsp, "No region of type: %x\n", type);
1384 				ret = -EINVAL;
1385 				goto out_fw;
1386 			}
1387 
1388 			region_name = cs_dsp_mem_region_name(type);
1389 			reg = dsp->ops->region_to_reg(mem, offset);
1390 			break;
1391 		default:
1392 			cs_dsp_warn(dsp,
1393 				    "%s.%d: Unknown region type %x at %d(%x)\n",
1394 				    file, regions, type, pos, pos);
1395 			break;
1396 		}
1397 
1398 		cs_dsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
1399 			   regions, le32_to_cpu(region->len), offset,
1400 			   region_name);
1401 
1402 		if (le32_to_cpu(region->len) >
1403 		    firmware->size - pos - sizeof(*region)) {
1404 			cs_dsp_err(dsp,
1405 				   "%s.%d: %s region len %d bytes exceeds file length %zu\n",
1406 				   file, regions, region_name,
1407 				   le32_to_cpu(region->len), firmware->size);
1408 			ret = -EINVAL;
1409 			goto out_fw;
1410 		}
1411 
1412 		if (text) {
1413 			memcpy(text, region->data, le32_to_cpu(region->len));
1414 			cs_dsp_info(dsp, "%s: %s\n", file, text);
1415 			kfree(text);
1416 			text = NULL;
1417 		}
1418 
1419 		if (reg) {
1420 			buf = cs_dsp_buf_alloc(region->data,
1421 					       le32_to_cpu(region->len),
1422 					       &buf_list);
1423 			if (!buf) {
1424 				cs_dsp_err(dsp, "Out of memory\n");
1425 				ret = -ENOMEM;
1426 				goto out_fw;
1427 			}
1428 
1429 			ret = regmap_raw_write_async(regmap, reg, buf->buf,
1430 						     le32_to_cpu(region->len));
1431 			if (ret != 0) {
1432 				cs_dsp_err(dsp,
1433 					   "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
1434 					   file, regions,
1435 					   le32_to_cpu(region->len), offset,
1436 					   region_name, ret);
1437 				goto out_fw;
1438 			}
1439 		}
1440 
1441 		pos += le32_to_cpu(region->len) + sizeof(*region);
1442 		regions++;
1443 	}
1444 
1445 	ret = regmap_async_complete(regmap);
1446 	if (ret != 0) {
1447 		cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
1448 		goto out_fw;
1449 	}
1450 
1451 	if (pos > firmware->size)
1452 		cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
1453 			    file, regions, pos - firmware->size);
1454 
1455 	cs_dsp_debugfs_save_wmfwname(dsp, file);
1456 
1457 out_fw:
1458 	regmap_async_complete(regmap);
1459 	cs_dsp_buf_free(&buf_list);
1460 	kfree(text);
1461 
1462 	return ret;
1463 }
1464 
1465 /**
1466  * cs_dsp_get_ctl() - Finds a matching coefficient control
1467  * @dsp: pointer to DSP structure
1468  * @name: pointer to string to match with a control's subname
1469  * @type: the algorithm type to match
1470  * @alg: the algorithm id to match
1471  *
1472  * Find cs_dsp_coeff_ctl with input name as its subname
1473  *
1474  * Return: pointer to the control on success, NULL if not found
1475  */
1476 struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, int type,
1477 					unsigned int alg)
1478 {
1479 	struct cs_dsp_coeff_ctl *pos, *rslt = NULL;
1480 
1481 	lockdep_assert_held(&dsp->pwr_lock);
1482 
1483 	list_for_each_entry(pos, &dsp->ctl_list, list) {
1484 		if (!pos->subname)
1485 			continue;
1486 		if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
1487 		    pos->fw_name == dsp->fw_name &&
1488 		    pos->alg_region.alg == alg &&
1489 		    pos->alg_region.type == type) {
1490 			rslt = pos;
1491 			break;
1492 		}
1493 	}
1494 
1495 	return rslt;
1496 }
1497 EXPORT_SYMBOL_GPL(cs_dsp_get_ctl);
1498 
1499 static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp,
1500 				  const struct cs_dsp_alg_region *alg_region)
1501 {
1502 	struct cs_dsp_coeff_ctl *ctl;
1503 
1504 	list_for_each_entry(ctl, &dsp->ctl_list, list) {
1505 		if (ctl->fw_name == dsp->fw_name &&
1506 		    alg_region->alg == ctl->alg_region.alg &&
1507 		    alg_region->type == ctl->alg_region.type) {
1508 			ctl->alg_region.base = alg_region->base;
1509 		}
1510 	}
1511 }
1512 
1513 static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs,
1514 			      const struct cs_dsp_region *mem,
1515 			      unsigned int pos, unsigned int len)
1516 {
1517 	void *alg;
1518 	unsigned int reg;
1519 	int ret;
1520 	__be32 val;
1521 
1522 	if (n_algs == 0) {
1523 		cs_dsp_err(dsp, "No algorithms\n");
1524 		return ERR_PTR(-EINVAL);
1525 	}
1526 
1527 	if (n_algs > 1024) {
1528 		cs_dsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
1529 		return ERR_PTR(-EINVAL);
1530 	}
1531 
1532 	/* Read the terminator first to validate the length */
1533 	reg = dsp->ops->region_to_reg(mem, pos + len);
1534 
1535 	ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
1536 	if (ret != 0) {
1537 		cs_dsp_err(dsp, "Failed to read algorithm list end: %d\n",
1538 			   ret);
1539 		return ERR_PTR(ret);
1540 	}
1541 
1542 	if (be32_to_cpu(val) != 0xbedead)
1543 		cs_dsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
1544 			    reg, be32_to_cpu(val));
1545 
1546 	/* Convert length from DSP words to bytes */
1547 	len *= sizeof(u32);
1548 
1549 	alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
1550 	if (!alg)
1551 		return ERR_PTR(-ENOMEM);
1552 
1553 	reg = dsp->ops->region_to_reg(mem, pos);
1554 
1555 	ret = regmap_raw_read(dsp->regmap, reg, alg, len);
1556 	if (ret != 0) {
1557 		cs_dsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
1558 		kfree(alg);
1559 		return ERR_PTR(ret);
1560 	}
1561 
1562 	return alg;
1563 }
1564 
1565 /**
1566  * cs_dsp_find_alg_region() - Finds a matching algorithm region
1567  * @dsp: pointer to DSP structure
1568  * @type: the algorithm type to match
1569  * @id: the algorithm id to match
1570  *
1571  * Return: Pointer to matching algorithm region, or NULL if not found.
1572  */
1573 struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp,
1574 						 int type, unsigned int id)
1575 {
1576 	struct cs_dsp_alg_region *alg_region;
1577 
1578 	lockdep_assert_held(&dsp->pwr_lock);
1579 
1580 	list_for_each_entry(alg_region, &dsp->alg_regions, list) {
1581 		if (id == alg_region->alg && type == alg_region->type)
1582 			return alg_region;
1583 	}
1584 
1585 	return NULL;
1586 }
1587 EXPORT_SYMBOL_GPL(cs_dsp_find_alg_region);
1588 
1589 static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp,
1590 						      int type, __be32 id,
1591 						      __be32 ver, __be32 base)
1592 {
1593 	struct cs_dsp_alg_region *alg_region;
1594 
1595 	alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
1596 	if (!alg_region)
1597 		return ERR_PTR(-ENOMEM);
1598 
1599 	alg_region->type = type;
1600 	alg_region->alg = be32_to_cpu(id);
1601 	alg_region->ver = be32_to_cpu(ver);
1602 	alg_region->base = be32_to_cpu(base);
1603 
1604 	list_add_tail(&alg_region->list, &dsp->alg_regions);
1605 
1606 	if (dsp->fw_ver > 0)
1607 		cs_dsp_ctl_fixup_base(dsp, alg_region);
1608 
1609 	return alg_region;
1610 }
1611 
1612 static void cs_dsp_free_alg_regions(struct cs_dsp *dsp)
1613 {
1614 	struct cs_dsp_alg_region *alg_region;
1615 
1616 	while (!list_empty(&dsp->alg_regions)) {
1617 		alg_region = list_first_entry(&dsp->alg_regions,
1618 					      struct cs_dsp_alg_region,
1619 					      list);
1620 		list_del(&alg_region->list);
1621 		kfree(alg_region);
1622 	}
1623 }
1624 
1625 static void cs_dsp_parse_wmfw_id_header(struct cs_dsp *dsp,
1626 					struct wmfw_id_hdr *fw, int nalgs)
1627 {
1628 	dsp->fw_id = be32_to_cpu(fw->id);
1629 	dsp->fw_id_version = be32_to_cpu(fw->ver);
1630 
1631 	cs_dsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n",
1632 		    dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16,
1633 		    (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
1634 		    nalgs);
1635 }
1636 
1637 static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp,
1638 					   struct wmfw_v3_id_hdr *fw, int nalgs)
1639 {
1640 	dsp->fw_id = be32_to_cpu(fw->id);
1641 	dsp->fw_id_version = be32_to_cpu(fw->ver);
1642 	dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id);
1643 
1644 	cs_dsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n",
1645 		    dsp->fw_id, dsp->fw_vendor_id,
1646 		    (dsp->fw_id_version & 0xff0000) >> 16,
1647 		    (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
1648 		    nalgs);
1649 }
1650 
1651 static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver,
1652 				 int nregions, const int *type, __be32 *base)
1653 {
1654 	struct cs_dsp_alg_region *alg_region;
1655 	int i;
1656 
1657 	for (i = 0; i < nregions; i++) {
1658 		alg_region = cs_dsp_create_region(dsp, type[i], id, ver, base[i]);
1659 		if (IS_ERR(alg_region))
1660 			return PTR_ERR(alg_region);
1661 	}
1662 
1663 	return 0;
1664 }
1665 
1666 static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp)
1667 {
1668 	struct wmfw_adsp1_id_hdr adsp1_id;
1669 	struct wmfw_adsp1_alg_hdr *adsp1_alg;
1670 	struct cs_dsp_alg_region *alg_region;
1671 	const struct cs_dsp_region *mem;
1672 	unsigned int pos, len;
1673 	size_t n_algs;
1674 	int i, ret;
1675 
1676 	mem = cs_dsp_find_region(dsp, WMFW_ADSP1_DM);
1677 	if (WARN_ON(!mem))
1678 		return -EINVAL;
1679 
1680 	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
1681 			      sizeof(adsp1_id));
1682 	if (ret != 0) {
1683 		cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
1684 			   ret);
1685 		return ret;
1686 	}
1687 
1688 	n_algs = be32_to_cpu(adsp1_id.n_algs);
1689 
1690 	cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs);
1691 
1692 	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM,
1693 					  adsp1_id.fw.id, adsp1_id.fw.ver,
1694 					  adsp1_id.zm);
1695 	if (IS_ERR(alg_region))
1696 		return PTR_ERR(alg_region);
1697 
1698 	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM,
1699 					  adsp1_id.fw.id, adsp1_id.fw.ver,
1700 					  adsp1_id.dm);
1701 	if (IS_ERR(alg_region))
1702 		return PTR_ERR(alg_region);
1703 
1704 	/* Calculate offset and length in DSP words */
1705 	pos = sizeof(adsp1_id) / sizeof(u32);
1706 	len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
1707 
1708 	adsp1_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
1709 	if (IS_ERR(adsp1_alg))
1710 		return PTR_ERR(adsp1_alg);
1711 
1712 	for (i = 0; i < n_algs; i++) {
1713 		cs_dsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
1714 			    i, be32_to_cpu(adsp1_alg[i].alg.id),
1715 			    (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
1716 			    (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
1717 			    be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
1718 			    be32_to_cpu(adsp1_alg[i].dm),
1719 			    be32_to_cpu(adsp1_alg[i].zm));
1720 
1721 		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM,
1722 						  adsp1_alg[i].alg.id,
1723 						  adsp1_alg[i].alg.ver,
1724 						  adsp1_alg[i].dm);
1725 		if (IS_ERR(alg_region)) {
1726 			ret = PTR_ERR(alg_region);
1727 			goto out;
1728 		}
1729 		if (dsp->fw_ver == 0) {
1730 			if (i + 1 < n_algs) {
1731 				len = be32_to_cpu(adsp1_alg[i + 1].dm);
1732 				len -= be32_to_cpu(adsp1_alg[i].dm);
1733 				len *= 4;
1734 				cs_dsp_create_control(dsp, alg_region, 0,
1735 						      len, NULL, 0, 0,
1736 						      WMFW_CTL_TYPE_BYTES);
1737 			} else {
1738 				cs_dsp_warn(dsp, "Missing length info for region DM with ID %x\n",
1739 					    be32_to_cpu(adsp1_alg[i].alg.id));
1740 			}
1741 		}
1742 
1743 		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM,
1744 						  adsp1_alg[i].alg.id,
1745 						  adsp1_alg[i].alg.ver,
1746 						  adsp1_alg[i].zm);
1747 		if (IS_ERR(alg_region)) {
1748 			ret = PTR_ERR(alg_region);
1749 			goto out;
1750 		}
1751 		if (dsp->fw_ver == 0) {
1752 			if (i + 1 < n_algs) {
1753 				len = be32_to_cpu(adsp1_alg[i + 1].zm);
1754 				len -= be32_to_cpu(adsp1_alg[i].zm);
1755 				len *= 4;
1756 				cs_dsp_create_control(dsp, alg_region, 0,
1757 						      len, NULL, 0, 0,
1758 						      WMFW_CTL_TYPE_BYTES);
1759 			} else {
1760 				cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1761 					    be32_to_cpu(adsp1_alg[i].alg.id));
1762 			}
1763 		}
1764 	}
1765 
1766 out:
1767 	kfree(adsp1_alg);
1768 	return ret;
1769 }
1770 
1771 static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp)
1772 {
1773 	struct wmfw_adsp2_id_hdr adsp2_id;
1774 	struct wmfw_adsp2_alg_hdr *adsp2_alg;
1775 	struct cs_dsp_alg_region *alg_region;
1776 	const struct cs_dsp_region *mem;
1777 	unsigned int pos, len;
1778 	size_t n_algs;
1779 	int i, ret;
1780 
1781 	mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM);
1782 	if (WARN_ON(!mem))
1783 		return -EINVAL;
1784 
1785 	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
1786 			      sizeof(adsp2_id));
1787 	if (ret != 0) {
1788 		cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
1789 			   ret);
1790 		return ret;
1791 	}
1792 
1793 	n_algs = be32_to_cpu(adsp2_id.n_algs);
1794 
1795 	cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs);
1796 
1797 	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
1798 					  adsp2_id.fw.id, adsp2_id.fw.ver,
1799 					  adsp2_id.xm);
1800 	if (IS_ERR(alg_region))
1801 		return PTR_ERR(alg_region);
1802 
1803 	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
1804 					  adsp2_id.fw.id, adsp2_id.fw.ver,
1805 					  adsp2_id.ym);
1806 	if (IS_ERR(alg_region))
1807 		return PTR_ERR(alg_region);
1808 
1809 	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
1810 					  adsp2_id.fw.id, adsp2_id.fw.ver,
1811 					  adsp2_id.zm);
1812 	if (IS_ERR(alg_region))
1813 		return PTR_ERR(alg_region);
1814 
1815 	/* Calculate offset and length in DSP words */
1816 	pos = sizeof(adsp2_id) / sizeof(u32);
1817 	len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
1818 
1819 	adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
1820 	if (IS_ERR(adsp2_alg))
1821 		return PTR_ERR(adsp2_alg);
1822 
1823 	for (i = 0; i < n_algs; i++) {
1824 		cs_dsp_info(dsp,
1825 			    "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
1826 			    i, be32_to_cpu(adsp2_alg[i].alg.id),
1827 			    (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
1828 			    (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
1829 			    be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
1830 			    be32_to_cpu(adsp2_alg[i].xm),
1831 			    be32_to_cpu(adsp2_alg[i].ym),
1832 			    be32_to_cpu(adsp2_alg[i].zm));
1833 
1834 		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
1835 						  adsp2_alg[i].alg.id,
1836 						  adsp2_alg[i].alg.ver,
1837 						  adsp2_alg[i].xm);
1838 		if (IS_ERR(alg_region)) {
1839 			ret = PTR_ERR(alg_region);
1840 			goto out;
1841 		}
1842 		if (dsp->fw_ver == 0) {
1843 			if (i + 1 < n_algs) {
1844 				len = be32_to_cpu(adsp2_alg[i + 1].xm);
1845 				len -= be32_to_cpu(adsp2_alg[i].xm);
1846 				len *= 4;
1847 				cs_dsp_create_control(dsp, alg_region, 0,
1848 						      len, NULL, 0, 0,
1849 						      WMFW_CTL_TYPE_BYTES);
1850 			} else {
1851 				cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n",
1852 					    be32_to_cpu(adsp2_alg[i].alg.id));
1853 			}
1854 		}
1855 
1856 		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
1857 						  adsp2_alg[i].alg.id,
1858 						  adsp2_alg[i].alg.ver,
1859 						  adsp2_alg[i].ym);
1860 		if (IS_ERR(alg_region)) {
1861 			ret = PTR_ERR(alg_region);
1862 			goto out;
1863 		}
1864 		if (dsp->fw_ver == 0) {
1865 			if (i + 1 < n_algs) {
1866 				len = be32_to_cpu(adsp2_alg[i + 1].ym);
1867 				len -= be32_to_cpu(adsp2_alg[i].ym);
1868 				len *= 4;
1869 				cs_dsp_create_control(dsp, alg_region, 0,
1870 						      len, NULL, 0, 0,
1871 						      WMFW_CTL_TYPE_BYTES);
1872 			} else {
1873 				cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n",
1874 					    be32_to_cpu(adsp2_alg[i].alg.id));
1875 			}
1876 		}
1877 
1878 		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
1879 						  adsp2_alg[i].alg.id,
1880 						  adsp2_alg[i].alg.ver,
1881 						  adsp2_alg[i].zm);
1882 		if (IS_ERR(alg_region)) {
1883 			ret = PTR_ERR(alg_region);
1884 			goto out;
1885 		}
1886 		if (dsp->fw_ver == 0) {
1887 			if (i + 1 < n_algs) {
1888 				len = be32_to_cpu(adsp2_alg[i + 1].zm);
1889 				len -= be32_to_cpu(adsp2_alg[i].zm);
1890 				len *= 4;
1891 				cs_dsp_create_control(dsp, alg_region, 0,
1892 						      len, NULL, 0, 0,
1893 						      WMFW_CTL_TYPE_BYTES);
1894 			} else {
1895 				cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1896 					    be32_to_cpu(adsp2_alg[i].alg.id));
1897 			}
1898 		}
1899 	}
1900 
1901 out:
1902 	kfree(adsp2_alg);
1903 	return ret;
1904 }
1905 
1906 static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver,
1907 				      __be32 xm_base, __be32 ym_base)
1908 {
1909 	static const int types[] = {
1910 		WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED,
1911 		WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED
1912 	};
1913 	__be32 bases[] = { xm_base, xm_base, ym_base, ym_base };
1914 
1915 	return cs_dsp_create_regions(dsp, id, ver, ARRAY_SIZE(types), types, bases);
1916 }
1917 
1918 static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp)
1919 {
1920 	struct wmfw_halo_id_hdr halo_id;
1921 	struct wmfw_halo_alg_hdr *halo_alg;
1922 	const struct cs_dsp_region *mem;
1923 	unsigned int pos, len;
1924 	size_t n_algs;
1925 	int i, ret;
1926 
1927 	mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM);
1928 	if (WARN_ON(!mem))
1929 		return -EINVAL;
1930 
1931 	ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id,
1932 			      sizeof(halo_id));
1933 	if (ret != 0) {
1934 		cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
1935 			   ret);
1936 		return ret;
1937 	}
1938 
1939 	n_algs = be32_to_cpu(halo_id.n_algs);
1940 
1941 	cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs);
1942 
1943 	ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, halo_id.fw.ver,
1944 					 halo_id.xm_base, halo_id.ym_base);
1945 	if (ret)
1946 		return ret;
1947 
1948 	/* Calculate offset and length in DSP words */
1949 	pos = sizeof(halo_id) / sizeof(u32);
1950 	len = (sizeof(*halo_alg) * n_algs) / sizeof(u32);
1951 
1952 	halo_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
1953 	if (IS_ERR(halo_alg))
1954 		return PTR_ERR(halo_alg);
1955 
1956 	for (i = 0; i < n_algs; i++) {
1957 		cs_dsp_info(dsp,
1958 			    "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
1959 			    i, be32_to_cpu(halo_alg[i].alg.id),
1960 			    (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
1961 			    (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
1962 			    be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
1963 			    be32_to_cpu(halo_alg[i].xm_base),
1964 			    be32_to_cpu(halo_alg[i].ym_base));
1965 
1966 		ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id,
1967 						 halo_alg[i].alg.ver,
1968 						 halo_alg[i].xm_base,
1969 						 halo_alg[i].ym_base);
1970 		if (ret)
1971 			goto out;
1972 	}
1973 
1974 out:
1975 	kfree(halo_alg);
1976 	return ret;
1977 }
1978 
1979 static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware,
1980 			     const char *file)
1981 {
1982 	LIST_HEAD(buf_list);
1983 	struct regmap *regmap = dsp->regmap;
1984 	struct wmfw_coeff_hdr *hdr;
1985 	struct wmfw_coeff_item *blk;
1986 	const struct cs_dsp_region *mem;
1987 	struct cs_dsp_alg_region *alg_region;
1988 	const char *region_name;
1989 	int ret, pos, blocks, type, offset, reg, version;
1990 	char *text = NULL;
1991 	struct cs_dsp_buf *buf;
1992 
1993 	if (!firmware)
1994 		return 0;
1995 
1996 	ret = -EINVAL;
1997 
1998 	if (sizeof(*hdr) >= firmware->size) {
1999 		cs_dsp_err(dsp, "%s: coefficient file too short, %zu bytes\n",
2000 			   file, firmware->size);
2001 		goto out_fw;
2002 	}
2003 
2004 	hdr = (void *)&firmware->data[0];
2005 	if (memcmp(hdr->magic, "WMDR", 4) != 0) {
2006 		cs_dsp_err(dsp, "%s: invalid coefficient magic\n", file);
2007 		goto out_fw;
2008 	}
2009 
2010 	switch (be32_to_cpu(hdr->rev) & 0xff) {
2011 	case 1:
2012 	case 2:
2013 		break;
2014 	default:
2015 		cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
2016 			   file, be32_to_cpu(hdr->rev) & 0xff);
2017 		ret = -EINVAL;
2018 		goto out_fw;
2019 	}
2020 
2021 	cs_dsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
2022 		   (le32_to_cpu(hdr->ver) >> 16) & 0xff,
2023 		   (le32_to_cpu(hdr->ver) >>  8) & 0xff,
2024 		   le32_to_cpu(hdr->ver) & 0xff);
2025 
2026 	pos = le32_to_cpu(hdr->len);
2027 
2028 	blocks = 0;
2029 	while (pos < firmware->size &&
2030 	       sizeof(*blk) < firmware->size - pos) {
2031 		blk = (void *)(&firmware->data[pos]);
2032 
2033 		type = le16_to_cpu(blk->type);
2034 		offset = le16_to_cpu(blk->offset);
2035 		version = le32_to_cpu(blk->ver) >> 8;
2036 
2037 		cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
2038 			   file, blocks, le32_to_cpu(blk->id),
2039 			   (le32_to_cpu(blk->ver) >> 16) & 0xff,
2040 			   (le32_to_cpu(blk->ver) >>  8) & 0xff,
2041 			   le32_to_cpu(blk->ver) & 0xff);
2042 		cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
2043 			   file, blocks, le32_to_cpu(blk->len), offset, type);
2044 
2045 		reg = 0;
2046 		region_name = "Unknown";
2047 		switch (type) {
2048 		case (WMFW_NAME_TEXT << 8):
2049 			text = kzalloc(le32_to_cpu(blk->len) + 1, GFP_KERNEL);
2050 			break;
2051 		case (WMFW_INFO_TEXT << 8):
2052 		case (WMFW_METADATA << 8):
2053 			break;
2054 		case (WMFW_ABSOLUTE << 8):
2055 			/*
2056 			 * Old files may use this for global
2057 			 * coefficients.
2058 			 */
2059 			if (le32_to_cpu(blk->id) == dsp->fw_id &&
2060 			    offset == 0) {
2061 				region_name = "global coefficients";
2062 				mem = cs_dsp_find_region(dsp, type);
2063 				if (!mem) {
2064 					cs_dsp_err(dsp, "No ZM\n");
2065 					break;
2066 				}
2067 				reg = dsp->ops->region_to_reg(mem, 0);
2068 
2069 			} else {
2070 				region_name = "register";
2071 				reg = offset;
2072 			}
2073 			break;
2074 
2075 		case WMFW_ADSP1_DM:
2076 		case WMFW_ADSP1_ZM:
2077 		case WMFW_ADSP2_XM:
2078 		case WMFW_ADSP2_YM:
2079 		case WMFW_HALO_XM_PACKED:
2080 		case WMFW_HALO_YM_PACKED:
2081 		case WMFW_HALO_PM_PACKED:
2082 			cs_dsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
2083 				   file, blocks, le32_to_cpu(blk->len),
2084 				   type, le32_to_cpu(blk->id));
2085 
2086 			mem = cs_dsp_find_region(dsp, type);
2087 			if (!mem) {
2088 				cs_dsp_err(dsp, "No base for region %x\n", type);
2089 				break;
2090 			}
2091 
2092 			alg_region = cs_dsp_find_alg_region(dsp, type,
2093 							    le32_to_cpu(blk->id));
2094 			if (alg_region) {
2095 				if (version != alg_region->ver)
2096 					cs_dsp_warn(dsp,
2097 						    "Algorithm coefficient version %d.%d.%d but expected %d.%d.%d\n",
2098 						   (version >> 16) & 0xFF,
2099 						   (version >> 8) & 0xFF,
2100 						   version & 0xFF,
2101 						   (alg_region->ver >> 16) & 0xFF,
2102 						   (alg_region->ver >> 8) & 0xFF,
2103 						   alg_region->ver & 0xFF);
2104 
2105 				reg = alg_region->base;
2106 				reg = dsp->ops->region_to_reg(mem, reg);
2107 				reg += offset;
2108 			} else {
2109 				cs_dsp_err(dsp, "No %x for algorithm %x\n",
2110 					   type, le32_to_cpu(blk->id));
2111 			}
2112 			break;
2113 
2114 		default:
2115 			cs_dsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
2116 				   file, blocks, type, pos);
2117 			break;
2118 		}
2119 
2120 		if (text) {
2121 			memcpy(text, blk->data, le32_to_cpu(blk->len));
2122 			cs_dsp_info(dsp, "%s: %s\n", dsp->fw_name, text);
2123 			kfree(text);
2124 			text = NULL;
2125 		}
2126 
2127 		if (reg) {
2128 			if (le32_to_cpu(blk->len) >
2129 			    firmware->size - pos - sizeof(*blk)) {
2130 				cs_dsp_err(dsp,
2131 					   "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2132 					   file, blocks, region_name,
2133 					   le32_to_cpu(blk->len),
2134 					   firmware->size);
2135 				ret = -EINVAL;
2136 				goto out_fw;
2137 			}
2138 
2139 			buf = cs_dsp_buf_alloc(blk->data,
2140 					       le32_to_cpu(blk->len),
2141 					       &buf_list);
2142 			if (!buf) {
2143 				cs_dsp_err(dsp, "Out of memory\n");
2144 				ret = -ENOMEM;
2145 				goto out_fw;
2146 			}
2147 
2148 			cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
2149 				   file, blocks, le32_to_cpu(blk->len),
2150 				   reg);
2151 			ret = regmap_raw_write_async(regmap, reg, buf->buf,
2152 						     le32_to_cpu(blk->len));
2153 			if (ret != 0) {
2154 				cs_dsp_err(dsp,
2155 					   "%s.%d: Failed to write to %x in %s: %d\n",
2156 					   file, blocks, reg, region_name, ret);
2157 			}
2158 		}
2159 
2160 		pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
2161 		blocks++;
2162 	}
2163 
2164 	ret = regmap_async_complete(regmap);
2165 	if (ret != 0)
2166 		cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
2167 
2168 	if (pos > firmware->size)
2169 		cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2170 			    file, blocks, pos - firmware->size);
2171 
2172 	cs_dsp_debugfs_save_binname(dsp, file);
2173 
2174 out_fw:
2175 	regmap_async_complete(regmap);
2176 	cs_dsp_buf_free(&buf_list);
2177 	kfree(text);
2178 	return ret;
2179 }
2180 
2181 static int cs_dsp_create_name(struct cs_dsp *dsp)
2182 {
2183 	if (!dsp->name) {
2184 		dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
2185 					   dsp->num);
2186 		if (!dsp->name)
2187 			return -ENOMEM;
2188 	}
2189 
2190 	return 0;
2191 }
2192 
2193 static int cs_dsp_common_init(struct cs_dsp *dsp)
2194 {
2195 	int ret;
2196 
2197 	ret = cs_dsp_create_name(dsp);
2198 	if (ret)
2199 		return ret;
2200 
2201 	INIT_LIST_HEAD(&dsp->alg_regions);
2202 	INIT_LIST_HEAD(&dsp->ctl_list);
2203 
2204 	mutex_init(&dsp->pwr_lock);
2205 
2206 	return 0;
2207 }
2208 
2209 /**
2210  * cs_dsp_adsp1_init() - Initialise a cs_dsp structure representing a ADSP1 device
2211  * @dsp: pointer to DSP structure
2212  *
2213  * Return: Zero for success, a negative number on error.
2214  */
2215 int cs_dsp_adsp1_init(struct cs_dsp *dsp)
2216 {
2217 	dsp->ops = &cs_dsp_adsp1_ops;
2218 
2219 	return cs_dsp_common_init(dsp);
2220 }
2221 EXPORT_SYMBOL_GPL(cs_dsp_adsp1_init);
2222 
2223 /**
2224  * cs_dsp_adsp1_power_up() - Load and start the named firmware
2225  * @dsp: pointer to DSP structure
2226  * @wmfw_firmware: the firmware to be sent
2227  * @wmfw_filename: file name of firmware to be sent
2228  * @coeff_firmware: the coefficient data to be sent
2229  * @coeff_filename: file name of coefficient to data be sent
2230  * @fw_name: the user-friendly firmware name
2231  *
2232  * Return: Zero for success, a negative number on error.
2233  */
2234 int cs_dsp_adsp1_power_up(struct cs_dsp *dsp,
2235 			  const struct firmware *wmfw_firmware, char *wmfw_filename,
2236 			  const struct firmware *coeff_firmware, char *coeff_filename,
2237 			  const char *fw_name)
2238 {
2239 	unsigned int val;
2240 	int ret;
2241 
2242 	mutex_lock(&dsp->pwr_lock);
2243 
2244 	dsp->fw_name = fw_name;
2245 
2246 	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2247 			   ADSP1_SYS_ENA, ADSP1_SYS_ENA);
2248 
2249 	/*
2250 	 * For simplicity set the DSP clock rate to be the
2251 	 * SYSCLK rate rather than making it configurable.
2252 	 */
2253 	if (dsp->sysclk_reg) {
2254 		ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
2255 		if (ret != 0) {
2256 			cs_dsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
2257 			goto err_mutex;
2258 		}
2259 
2260 		val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
2261 
2262 		ret = regmap_update_bits(dsp->regmap,
2263 					 dsp->base + ADSP1_CONTROL_31,
2264 					 ADSP1_CLK_SEL_MASK, val);
2265 		if (ret != 0) {
2266 			cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret);
2267 			goto err_mutex;
2268 		}
2269 	}
2270 
2271 	ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename);
2272 	if (ret != 0)
2273 		goto err_ena;
2274 
2275 	ret = cs_dsp_adsp1_setup_algs(dsp);
2276 	if (ret != 0)
2277 		goto err_ena;
2278 
2279 	ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename);
2280 	if (ret != 0)
2281 		goto err_ena;
2282 
2283 	/* Initialize caches for enabled and unset controls */
2284 	ret = cs_dsp_coeff_init_control_caches(dsp);
2285 	if (ret != 0)
2286 		goto err_ena;
2287 
2288 	/* Sync set controls */
2289 	ret = cs_dsp_coeff_sync_controls(dsp);
2290 	if (ret != 0)
2291 		goto err_ena;
2292 
2293 	dsp->booted = true;
2294 
2295 	/* Start the core running */
2296 	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2297 			   ADSP1_CORE_ENA | ADSP1_START,
2298 			   ADSP1_CORE_ENA | ADSP1_START);
2299 
2300 	dsp->running = true;
2301 
2302 	mutex_unlock(&dsp->pwr_lock);
2303 
2304 	return 0;
2305 
2306 err_ena:
2307 	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2308 			   ADSP1_SYS_ENA, 0);
2309 err_mutex:
2310 	mutex_unlock(&dsp->pwr_lock);
2311 	return ret;
2312 }
2313 EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_up);
2314 
2315 /**
2316  * cs_dsp_adsp1_power_down() - Halts the DSP
2317  * @dsp: pointer to DSP structure
2318  */
2319 void cs_dsp_adsp1_power_down(struct cs_dsp *dsp)
2320 {
2321 	struct cs_dsp_coeff_ctl *ctl;
2322 
2323 	mutex_lock(&dsp->pwr_lock);
2324 
2325 	dsp->running = false;
2326 	dsp->booted = false;
2327 
2328 	/* Halt the core */
2329 	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2330 			   ADSP1_CORE_ENA | ADSP1_START, 0);
2331 
2332 	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
2333 			   ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
2334 
2335 	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2336 			   ADSP1_SYS_ENA, 0);
2337 
2338 	list_for_each_entry(ctl, &dsp->ctl_list, list)
2339 		ctl->enabled = 0;
2340 
2341 	cs_dsp_free_alg_regions(dsp);
2342 
2343 	mutex_unlock(&dsp->pwr_lock);
2344 }
2345 EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_down);
2346 
2347 static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp)
2348 {
2349 	unsigned int val;
2350 	int ret, count;
2351 
2352 	/* Wait for the RAM to start, should be near instantaneous */
2353 	for (count = 0; count < 10; ++count) {
2354 		ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
2355 		if (ret != 0)
2356 			return ret;
2357 
2358 		if (val & ADSP2_RAM_RDY)
2359 			break;
2360 
2361 		usleep_range(250, 500);
2362 	}
2363 
2364 	if (!(val & ADSP2_RAM_RDY)) {
2365 		cs_dsp_err(dsp, "Failed to start DSP RAM\n");
2366 		return -EBUSY;
2367 	}
2368 
2369 	cs_dsp_dbg(dsp, "RAM ready after %d polls\n", count);
2370 
2371 	return 0;
2372 }
2373 
2374 static int cs_dsp_adsp2_enable_core(struct cs_dsp *dsp)
2375 {
2376 	int ret;
2377 
2378 	ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
2379 				       ADSP2_SYS_ENA, ADSP2_SYS_ENA);
2380 	if (ret != 0)
2381 		return ret;
2382 
2383 	return cs_dsp_adsp2v2_enable_core(dsp);
2384 }
2385 
2386 static int cs_dsp_adsp2_lock(struct cs_dsp *dsp, unsigned int lock_regions)
2387 {
2388 	struct regmap *regmap = dsp->regmap;
2389 	unsigned int code0, code1, lock_reg;
2390 
2391 	if (!(lock_regions & CS_ADSP2_REGION_ALL))
2392 		return 0;
2393 
2394 	lock_regions &= CS_ADSP2_REGION_ALL;
2395 	lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
2396 
2397 	while (lock_regions) {
2398 		code0 = code1 = 0;
2399 		if (lock_regions & BIT(0)) {
2400 			code0 = ADSP2_LOCK_CODE_0;
2401 			code1 = ADSP2_LOCK_CODE_1;
2402 		}
2403 		if (lock_regions & BIT(1)) {
2404 			code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
2405 			code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
2406 		}
2407 		regmap_write(regmap, lock_reg, code0);
2408 		regmap_write(regmap, lock_reg, code1);
2409 		lock_regions >>= 2;
2410 		lock_reg += 2;
2411 	}
2412 
2413 	return 0;
2414 }
2415 
2416 static int cs_dsp_adsp2_enable_memory(struct cs_dsp *dsp)
2417 {
2418 	return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2419 				  ADSP2_MEM_ENA, ADSP2_MEM_ENA);
2420 }
2421 
2422 static void cs_dsp_adsp2_disable_memory(struct cs_dsp *dsp)
2423 {
2424 	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2425 			   ADSP2_MEM_ENA, 0);
2426 }
2427 
2428 static void cs_dsp_adsp2_disable_core(struct cs_dsp *dsp)
2429 {
2430 	regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2431 	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2432 	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
2433 
2434 	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2435 			   ADSP2_SYS_ENA, 0);
2436 }
2437 
2438 static void cs_dsp_adsp2v2_disable_core(struct cs_dsp *dsp)
2439 {
2440 	regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2441 	regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2442 	regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
2443 }
2444 
2445 static int cs_dsp_halo_configure_mpu(struct cs_dsp *dsp, unsigned int lock_regions)
2446 {
2447 	struct reg_sequence config[] = {
2448 		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0x5555 },
2449 		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0xAAAA },
2450 		{ dsp->base + HALO_MPU_XMEM_ACCESS_0,   0xFFFFFFFF },
2451 		{ dsp->base + HALO_MPU_YMEM_ACCESS_0,   0xFFFFFFFF },
2452 		{ dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions },
2453 		{ dsp->base + HALO_MPU_XREG_ACCESS_0,   lock_regions },
2454 		{ dsp->base + HALO_MPU_YREG_ACCESS_0,   lock_regions },
2455 		{ dsp->base + HALO_MPU_XMEM_ACCESS_1,   0xFFFFFFFF },
2456 		{ dsp->base + HALO_MPU_YMEM_ACCESS_1,   0xFFFFFFFF },
2457 		{ dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions },
2458 		{ dsp->base + HALO_MPU_XREG_ACCESS_1,   lock_regions },
2459 		{ dsp->base + HALO_MPU_YREG_ACCESS_1,   lock_regions },
2460 		{ dsp->base + HALO_MPU_XMEM_ACCESS_2,   0xFFFFFFFF },
2461 		{ dsp->base + HALO_MPU_YMEM_ACCESS_2,   0xFFFFFFFF },
2462 		{ dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions },
2463 		{ dsp->base + HALO_MPU_XREG_ACCESS_2,   lock_regions },
2464 		{ dsp->base + HALO_MPU_YREG_ACCESS_2,   lock_regions },
2465 		{ dsp->base + HALO_MPU_XMEM_ACCESS_3,   0xFFFFFFFF },
2466 		{ dsp->base + HALO_MPU_YMEM_ACCESS_3,   0xFFFFFFFF },
2467 		{ dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions },
2468 		{ dsp->base + HALO_MPU_XREG_ACCESS_3,   lock_regions },
2469 		{ dsp->base + HALO_MPU_YREG_ACCESS_3,   lock_regions },
2470 		{ dsp->base + HALO_MPU_LOCK_CONFIG,     0 },
2471 	};
2472 
2473 	return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config));
2474 }
2475 
2476 /**
2477  * cs_dsp_set_dspclk() - Applies the given frequency to the given cs_dsp
2478  * @dsp: pointer to DSP structure
2479  * @freq: clock rate to set
2480  *
2481  * This is only for use on ADSP2 cores.
2482  *
2483  * Return: Zero for success, a negative number on error.
2484  */
2485 int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq)
2486 {
2487 	int ret;
2488 
2489 	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING,
2490 				 ADSP2_CLK_SEL_MASK,
2491 				 freq << ADSP2_CLK_SEL_SHIFT);
2492 	if (ret)
2493 		cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret);
2494 
2495 	return ret;
2496 }
2497 EXPORT_SYMBOL_GPL(cs_dsp_set_dspclk);
2498 
2499 static void cs_dsp_stop_watchdog(struct cs_dsp *dsp)
2500 {
2501 	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
2502 			   ADSP2_WDT_ENA_MASK, 0);
2503 }
2504 
2505 static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp)
2506 {
2507 	regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL,
2508 			   HALO_WDT_EN_MASK, 0);
2509 }
2510 
2511 /**
2512  * cs_dsp_power_up() - Downloads firmware to the DSP
2513  * @dsp: pointer to DSP structure
2514  * @wmfw_firmware: the firmware to be sent
2515  * @wmfw_filename: file name of firmware to be sent
2516  * @coeff_firmware: the coefficient data to be sent
2517  * @coeff_filename: file name of coefficient to data be sent
2518  * @fw_name: the user-friendly firmware name
2519  *
2520  * This function is used on ADSP2 and Halo DSP cores, it powers-up the DSP core
2521  * and downloads the firmware but does not start the firmware running. The
2522  * cs_dsp booted flag will be set once completed and if the core has a low-power
2523  * memory retention mode it will be put into this state after the firmware is
2524  * downloaded.
2525  *
2526  * Return: Zero for success, a negative number on error.
2527  */
2528 int cs_dsp_power_up(struct cs_dsp *dsp,
2529 		    const struct firmware *wmfw_firmware, char *wmfw_filename,
2530 		    const struct firmware *coeff_firmware, char *coeff_filename,
2531 		    const char *fw_name)
2532 {
2533 	int ret;
2534 
2535 	mutex_lock(&dsp->pwr_lock);
2536 
2537 	dsp->fw_name = fw_name;
2538 
2539 	if (dsp->ops->enable_memory) {
2540 		ret = dsp->ops->enable_memory(dsp);
2541 		if (ret != 0)
2542 			goto err_mutex;
2543 	}
2544 
2545 	if (dsp->ops->enable_core) {
2546 		ret = dsp->ops->enable_core(dsp);
2547 		if (ret != 0)
2548 			goto err_mem;
2549 	}
2550 
2551 	ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename);
2552 	if (ret != 0)
2553 		goto err_ena;
2554 
2555 	ret = dsp->ops->setup_algs(dsp);
2556 	if (ret != 0)
2557 		goto err_ena;
2558 
2559 	ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename);
2560 	if (ret != 0)
2561 		goto err_ena;
2562 
2563 	/* Initialize caches for enabled and unset controls */
2564 	ret = cs_dsp_coeff_init_control_caches(dsp);
2565 	if (ret != 0)
2566 		goto err_ena;
2567 
2568 	if (dsp->ops->disable_core)
2569 		dsp->ops->disable_core(dsp);
2570 
2571 	dsp->booted = true;
2572 
2573 	mutex_unlock(&dsp->pwr_lock);
2574 
2575 	return 0;
2576 err_ena:
2577 	if (dsp->ops->disable_core)
2578 		dsp->ops->disable_core(dsp);
2579 err_mem:
2580 	if (dsp->ops->disable_memory)
2581 		dsp->ops->disable_memory(dsp);
2582 err_mutex:
2583 	mutex_unlock(&dsp->pwr_lock);
2584 
2585 	return ret;
2586 }
2587 EXPORT_SYMBOL_GPL(cs_dsp_power_up);
2588 
2589 /**
2590  * cs_dsp_power_down() - Powers-down the DSP
2591  * @dsp: pointer to DSP structure
2592  *
2593  * cs_dsp_stop() must have been called before this function. The core will be
2594  * fully powered down and so the memory will not be retained.
2595  */
2596 void cs_dsp_power_down(struct cs_dsp *dsp)
2597 {
2598 	struct cs_dsp_coeff_ctl *ctl;
2599 
2600 	mutex_lock(&dsp->pwr_lock);
2601 
2602 	cs_dsp_debugfs_clear(dsp);
2603 
2604 	dsp->fw_id = 0;
2605 	dsp->fw_id_version = 0;
2606 
2607 	dsp->booted = false;
2608 
2609 	if (dsp->ops->disable_memory)
2610 		dsp->ops->disable_memory(dsp);
2611 
2612 	list_for_each_entry(ctl, &dsp->ctl_list, list)
2613 		ctl->enabled = 0;
2614 
2615 	cs_dsp_free_alg_regions(dsp);
2616 
2617 	mutex_unlock(&dsp->pwr_lock);
2618 
2619 	cs_dsp_dbg(dsp, "Shutdown complete\n");
2620 }
2621 EXPORT_SYMBOL_GPL(cs_dsp_power_down);
2622 
2623 static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp)
2624 {
2625 	return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2626 				  ADSP2_CORE_ENA | ADSP2_START,
2627 				  ADSP2_CORE_ENA | ADSP2_START);
2628 }
2629 
2630 static void cs_dsp_adsp2_stop_core(struct cs_dsp *dsp)
2631 {
2632 	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2633 			   ADSP2_CORE_ENA | ADSP2_START, 0);
2634 }
2635 
2636 /**
2637  * cs_dsp_run() - Starts the firmware running
2638  * @dsp: pointer to DSP structure
2639  *
2640  * cs_dsp_power_up() must have previously been called successfully.
2641  *
2642  * Return: Zero for success, a negative number on error.
2643  */
2644 int cs_dsp_run(struct cs_dsp *dsp)
2645 {
2646 	int ret;
2647 
2648 	mutex_lock(&dsp->pwr_lock);
2649 
2650 	if (!dsp->booted) {
2651 		ret = -EIO;
2652 		goto err;
2653 	}
2654 
2655 	if (dsp->ops->enable_core) {
2656 		ret = dsp->ops->enable_core(dsp);
2657 		if (ret != 0)
2658 			goto err;
2659 	}
2660 
2661 	if (dsp->client_ops->pre_run) {
2662 		ret = dsp->client_ops->pre_run(dsp);
2663 		if (ret)
2664 			goto err;
2665 	}
2666 
2667 	/* Sync set controls */
2668 	ret = cs_dsp_coeff_sync_controls(dsp);
2669 	if (ret != 0)
2670 		goto err;
2671 
2672 	if (dsp->ops->lock_memory) {
2673 		ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
2674 		if (ret != 0) {
2675 			cs_dsp_err(dsp, "Error configuring MPU: %d\n", ret);
2676 			goto err;
2677 		}
2678 	}
2679 
2680 	if (dsp->ops->start_core) {
2681 		ret = dsp->ops->start_core(dsp);
2682 		if (ret != 0)
2683 			goto err;
2684 	}
2685 
2686 	dsp->running = true;
2687 
2688 	if (dsp->client_ops->post_run) {
2689 		ret = dsp->client_ops->post_run(dsp);
2690 		if (ret)
2691 			goto err;
2692 	}
2693 
2694 	mutex_unlock(&dsp->pwr_lock);
2695 
2696 	return 0;
2697 
2698 err:
2699 	if (dsp->ops->stop_core)
2700 		dsp->ops->stop_core(dsp);
2701 	if (dsp->ops->disable_core)
2702 		dsp->ops->disable_core(dsp);
2703 	mutex_unlock(&dsp->pwr_lock);
2704 
2705 	return ret;
2706 }
2707 EXPORT_SYMBOL_GPL(cs_dsp_run);
2708 
2709 /**
2710  * cs_dsp_stop() - Stops the firmware
2711  * @dsp: pointer to DSP structure
2712  *
2713  * Memory will not be disabled so firmware will remain loaded.
2714  */
2715 void cs_dsp_stop(struct cs_dsp *dsp)
2716 {
2717 	/* Tell the firmware to cleanup */
2718 	cs_dsp_signal_event_controls(dsp, CS_DSP_FW_EVENT_SHUTDOWN);
2719 
2720 	if (dsp->ops->stop_watchdog)
2721 		dsp->ops->stop_watchdog(dsp);
2722 
2723 	/* Log firmware state, it can be useful for analysis */
2724 	if (dsp->ops->show_fw_status)
2725 		dsp->ops->show_fw_status(dsp);
2726 
2727 	mutex_lock(&dsp->pwr_lock);
2728 
2729 	dsp->running = false;
2730 
2731 	if (dsp->ops->stop_core)
2732 		dsp->ops->stop_core(dsp);
2733 	if (dsp->ops->disable_core)
2734 		dsp->ops->disable_core(dsp);
2735 
2736 	if (dsp->client_ops->post_stop)
2737 		dsp->client_ops->post_stop(dsp);
2738 
2739 	mutex_unlock(&dsp->pwr_lock);
2740 
2741 	cs_dsp_dbg(dsp, "Execution stopped\n");
2742 }
2743 EXPORT_SYMBOL_GPL(cs_dsp_stop);
2744 
2745 static int cs_dsp_halo_start_core(struct cs_dsp *dsp)
2746 {
2747 	int ret;
2748 
2749 	ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2750 				 HALO_CORE_RESET | HALO_CORE_EN,
2751 				 HALO_CORE_RESET | HALO_CORE_EN);
2752 	if (ret)
2753 		return ret;
2754 
2755 	return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2756 				  HALO_CORE_RESET, 0);
2757 }
2758 
2759 static void cs_dsp_halo_stop_core(struct cs_dsp *dsp)
2760 {
2761 	regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2762 			   HALO_CORE_EN, 0);
2763 
2764 	/* reset halo core with CORE_SOFT_RESET */
2765 	regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
2766 			   HALO_CORE_SOFT_RESET_MASK, 1);
2767 }
2768 
2769 /**
2770  * cs_dsp_adsp2_init() - Initialise a cs_dsp structure representing a ADSP2 core
2771  * @dsp: pointer to DSP structure
2772  *
2773  * Return: Zero for success, a negative number on error.
2774  */
2775 int cs_dsp_adsp2_init(struct cs_dsp *dsp)
2776 {
2777 	int ret;
2778 
2779 	switch (dsp->rev) {
2780 	case 0:
2781 		/*
2782 		 * Disable the DSP memory by default when in reset for a small
2783 		 * power saving.
2784 		 */
2785 		ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2786 					 ADSP2_MEM_ENA, 0);
2787 		if (ret) {
2788 			cs_dsp_err(dsp,
2789 				   "Failed to clear memory retention: %d\n", ret);
2790 			return ret;
2791 		}
2792 
2793 		dsp->ops = &cs_dsp_adsp2_ops[0];
2794 		break;
2795 	case 1:
2796 		dsp->ops = &cs_dsp_adsp2_ops[1];
2797 		break;
2798 	default:
2799 		dsp->ops = &cs_dsp_adsp2_ops[2];
2800 		break;
2801 	}
2802 
2803 	return cs_dsp_common_init(dsp);
2804 }
2805 EXPORT_SYMBOL_GPL(cs_dsp_adsp2_init);
2806 
2807 /**
2808  * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP
2809  * @dsp: pointer to DSP structure
2810  *
2811  * Return: Zero for success, a negative number on error.
2812  */
2813 int cs_dsp_halo_init(struct cs_dsp *dsp)
2814 {
2815 	dsp->ops = &cs_dsp_halo_ops;
2816 
2817 	return cs_dsp_common_init(dsp);
2818 }
2819 EXPORT_SYMBOL_GPL(cs_dsp_halo_init);
2820 
2821 /**
2822  * cs_dsp_remove() - Clean a cs_dsp before deletion
2823  * @dsp: pointer to DSP structure
2824  */
2825 void cs_dsp_remove(struct cs_dsp *dsp)
2826 {
2827 	struct cs_dsp_coeff_ctl *ctl;
2828 
2829 	while (!list_empty(&dsp->ctl_list)) {
2830 		ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
2831 
2832 		if (dsp->client_ops->control_remove)
2833 			dsp->client_ops->control_remove(ctl);
2834 
2835 		list_del(&ctl->list);
2836 		cs_dsp_free_ctl_blk(ctl);
2837 	}
2838 }
2839 EXPORT_SYMBOL_GPL(cs_dsp_remove);
2840 
2841 /**
2842  * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory
2843  * @dsp: pointer to DSP structure
2844  * @mem_type: the type of DSP memory containing the data to be read
2845  * @mem_addr: the address of the data within the memory region
2846  * @num_words: the length of the data to read
2847  * @data: a buffer to store the fetched data
2848  *
2849  * If this is used to read unpacked 24-bit memory, each 24-bit DSP word will
2850  * occupy 32-bits in data (MSbyte will be 0). This padding can be removed using
2851  * cs_dsp_remove_padding()
2852  *
2853  * Return: Zero for success, a negative number on error.
2854  */
2855 int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr,
2856 			       unsigned int num_words, __be32 *data)
2857 {
2858 	struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
2859 	unsigned int reg;
2860 	int ret;
2861 
2862 	lockdep_assert_held(&dsp->pwr_lock);
2863 
2864 	if (!mem)
2865 		return -EINVAL;
2866 
2867 	reg = dsp->ops->region_to_reg(mem, mem_addr);
2868 
2869 	ret = regmap_raw_read(dsp->regmap, reg, data,
2870 			      sizeof(*data) * num_words);
2871 	if (ret < 0)
2872 		return ret;
2873 
2874 	return 0;
2875 }
2876 EXPORT_SYMBOL_GPL(cs_dsp_read_raw_data_block);
2877 
2878 /**
2879  * cs_dsp_read_data_word() - Reads a word from DSP memory
2880  * @dsp: pointer to DSP structure
2881  * @mem_type: the type of DSP memory containing the data to be read
2882  * @mem_addr: the address of the data within the memory region
2883  * @data: a buffer to store the fetched data
2884  *
2885  * Return: Zero for success, a negative number on error.
2886  */
2887 int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 *data)
2888 {
2889 	__be32 raw;
2890 	int ret;
2891 
2892 	ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw);
2893 	if (ret < 0)
2894 		return ret;
2895 
2896 	*data = be32_to_cpu(raw) & 0x00ffffffu;
2897 
2898 	return 0;
2899 }
2900 EXPORT_SYMBOL_GPL(cs_dsp_read_data_word);
2901 
2902 /**
2903  * cs_dsp_write_data_word() - Writes a word to DSP memory
2904  * @dsp: pointer to DSP structure
2905  * @mem_type: the type of DSP memory containing the data to be written
2906  * @mem_addr: the address of the data within the memory region
2907  * @data: the data to be written
2908  *
2909  * Return: Zero for success, a negative number on error.
2910  */
2911 int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 data)
2912 {
2913 	struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
2914 	__be32 val = cpu_to_be32(data & 0x00ffffffu);
2915 	unsigned int reg;
2916 
2917 	lockdep_assert_held(&dsp->pwr_lock);
2918 
2919 	if (!mem)
2920 		return -EINVAL;
2921 
2922 	reg = dsp->ops->region_to_reg(mem, mem_addr);
2923 
2924 	return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
2925 }
2926 EXPORT_SYMBOL_GPL(cs_dsp_write_data_word);
2927 
2928 /**
2929  * cs_dsp_remove_padding() - Convert unpacked words to packed bytes
2930  * @buf: buffer containing DSP words read from DSP memory
2931  * @nwords: number of words to convert
2932  *
2933  * DSP words from the register map have pad bytes and the data bytes
2934  * are in swapped order. This swaps to the native endian order and
2935  * strips the pad bytes.
2936  */
2937 void cs_dsp_remove_padding(u32 *buf, int nwords)
2938 {
2939 	const __be32 *pack_in = (__be32 *)buf;
2940 	u8 *pack_out = (u8 *)buf;
2941 	int i;
2942 
2943 	for (i = 0; i < nwords; i++) {
2944 		u32 word = be32_to_cpu(*pack_in++);
2945 		*pack_out++ = (u8)word;
2946 		*pack_out++ = (u8)(word >> 8);
2947 		*pack_out++ = (u8)(word >> 16);
2948 	}
2949 }
2950 EXPORT_SYMBOL_GPL(cs_dsp_remove_padding);
2951 
2952 /**
2953  * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt
2954  * @dsp: pointer to DSP structure
2955  *
2956  * The firmware and DSP state will be logged for future analysis.
2957  */
2958 void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp)
2959 {
2960 	unsigned int val;
2961 	struct regmap *regmap = dsp->regmap;
2962 	int ret = 0;
2963 
2964 	mutex_lock(&dsp->pwr_lock);
2965 
2966 	ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
2967 	if (ret) {
2968 		cs_dsp_err(dsp,
2969 			   "Failed to read Region Lock Ctrl register: %d\n", ret);
2970 		goto error;
2971 	}
2972 
2973 	if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
2974 		cs_dsp_err(dsp, "watchdog timeout error\n");
2975 		dsp->ops->stop_watchdog(dsp);
2976 		if (dsp->client_ops->watchdog_expired)
2977 			dsp->client_ops->watchdog_expired(dsp);
2978 	}
2979 
2980 	if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
2981 		if (val & ADSP2_ADDR_ERR_MASK)
2982 			cs_dsp_err(dsp, "bus error: address error\n");
2983 		else
2984 			cs_dsp_err(dsp, "bus error: region lock error\n");
2985 
2986 		ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
2987 		if (ret) {
2988 			cs_dsp_err(dsp,
2989 				   "Failed to read Bus Err Addr register: %d\n",
2990 				   ret);
2991 			goto error;
2992 		}
2993 
2994 		cs_dsp_err(dsp, "bus error address = 0x%x\n",
2995 			   val & ADSP2_BUS_ERR_ADDR_MASK);
2996 
2997 		ret = regmap_read(regmap,
2998 				  dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
2999 				  &val);
3000 		if (ret) {
3001 			cs_dsp_err(dsp,
3002 				   "Failed to read Pmem Xmem Err Addr register: %d\n",
3003 				   ret);
3004 			goto error;
3005 		}
3006 
3007 		cs_dsp_err(dsp, "xmem error address = 0x%x\n",
3008 			   val & ADSP2_XMEM_ERR_ADDR_MASK);
3009 		cs_dsp_err(dsp, "pmem error address = 0x%x\n",
3010 			   (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
3011 			   ADSP2_PMEM_ERR_ADDR_SHIFT);
3012 	}
3013 
3014 	regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
3015 			   ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
3016 
3017 error:
3018 	mutex_unlock(&dsp->pwr_lock);
3019 }
3020 EXPORT_SYMBOL_GPL(cs_dsp_adsp2_bus_error);
3021 
3022 /**
3023  * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt
3024  * @dsp: pointer to DSP structure
3025  *
3026  * The firmware and DSP state will be logged for future analysis.
3027  */
3028 void cs_dsp_halo_bus_error(struct cs_dsp *dsp)
3029 {
3030 	struct regmap *regmap = dsp->regmap;
3031 	unsigned int fault[6];
3032 	struct reg_sequence clear[] = {
3033 		{ dsp->base + HALO_MPU_XM_VIO_STATUS,     0x0 },
3034 		{ dsp->base + HALO_MPU_YM_VIO_STATUS,     0x0 },
3035 		{ dsp->base + HALO_MPU_PM_VIO_STATUS,     0x0 },
3036 	};
3037 	int ret;
3038 
3039 	mutex_lock(&dsp->pwr_lock);
3040 
3041 	ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
3042 			  fault);
3043 	if (ret) {
3044 		cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
3045 		goto exit_unlock;
3046 	}
3047 
3048 	cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
3049 		    *fault & HALO_AHBM_FLAGS_ERR_MASK,
3050 		    (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
3051 		    HALO_AHBM_CORE_ERR_ADDR_SHIFT);
3052 
3053 	ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
3054 			  fault);
3055 	if (ret) {
3056 		cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
3057 		goto exit_unlock;
3058 	}
3059 
3060 	cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
3061 
3062 	ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
3063 			       fault, ARRAY_SIZE(fault));
3064 	if (ret) {
3065 		cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
3066 		goto exit_unlock;
3067 	}
3068 
3069 	cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
3070 	cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
3071 	cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
3072 
3073 	ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
3074 	if (ret)
3075 		cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
3076 
3077 exit_unlock:
3078 	mutex_unlock(&dsp->pwr_lock);
3079 }
3080 EXPORT_SYMBOL_GPL(cs_dsp_halo_bus_error);
3081 
3082 /**
3083  * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry
3084  * @dsp: pointer to DSP structure
3085  *
3086  * This is logged for future analysis.
3087  */
3088 void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp)
3089 {
3090 	mutex_lock(&dsp->pwr_lock);
3091 
3092 	cs_dsp_warn(dsp, "WDT Expiry Fault\n");
3093 
3094 	dsp->ops->stop_watchdog(dsp);
3095 	if (dsp->client_ops->watchdog_expired)
3096 		dsp->client_ops->watchdog_expired(dsp);
3097 
3098 	mutex_unlock(&dsp->pwr_lock);
3099 }
3100 EXPORT_SYMBOL_GPL(cs_dsp_halo_wdt_expire);
3101 
3102 static const struct cs_dsp_ops cs_dsp_adsp1_ops = {
3103 	.validate_version = cs_dsp_validate_version,
3104 	.parse_sizes = cs_dsp_adsp1_parse_sizes,
3105 	.region_to_reg = cs_dsp_region_to_reg,
3106 };
3107 
3108 static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = {
3109 	{
3110 		.parse_sizes = cs_dsp_adsp2_parse_sizes,
3111 		.validate_version = cs_dsp_validate_version,
3112 		.setup_algs = cs_dsp_adsp2_setup_algs,
3113 		.region_to_reg = cs_dsp_region_to_reg,
3114 
3115 		.show_fw_status = cs_dsp_adsp2_show_fw_status,
3116 
3117 		.enable_memory = cs_dsp_adsp2_enable_memory,
3118 		.disable_memory = cs_dsp_adsp2_disable_memory,
3119 
3120 		.enable_core = cs_dsp_adsp2_enable_core,
3121 		.disable_core = cs_dsp_adsp2_disable_core,
3122 
3123 		.start_core = cs_dsp_adsp2_start_core,
3124 		.stop_core = cs_dsp_adsp2_stop_core,
3125 
3126 	},
3127 	{
3128 		.parse_sizes = cs_dsp_adsp2_parse_sizes,
3129 		.validate_version = cs_dsp_validate_version,
3130 		.setup_algs = cs_dsp_adsp2_setup_algs,
3131 		.region_to_reg = cs_dsp_region_to_reg,
3132 
3133 		.show_fw_status = cs_dsp_adsp2v2_show_fw_status,
3134 
3135 		.enable_memory = cs_dsp_adsp2_enable_memory,
3136 		.disable_memory = cs_dsp_adsp2_disable_memory,
3137 		.lock_memory = cs_dsp_adsp2_lock,
3138 
3139 		.enable_core = cs_dsp_adsp2v2_enable_core,
3140 		.disable_core = cs_dsp_adsp2v2_disable_core,
3141 
3142 		.start_core = cs_dsp_adsp2_start_core,
3143 		.stop_core = cs_dsp_adsp2_stop_core,
3144 	},
3145 	{
3146 		.parse_sizes = cs_dsp_adsp2_parse_sizes,
3147 		.validate_version = cs_dsp_validate_version,
3148 		.setup_algs = cs_dsp_adsp2_setup_algs,
3149 		.region_to_reg = cs_dsp_region_to_reg,
3150 
3151 		.show_fw_status = cs_dsp_adsp2v2_show_fw_status,
3152 		.stop_watchdog = cs_dsp_stop_watchdog,
3153 
3154 		.enable_memory = cs_dsp_adsp2_enable_memory,
3155 		.disable_memory = cs_dsp_adsp2_disable_memory,
3156 		.lock_memory = cs_dsp_adsp2_lock,
3157 
3158 		.enable_core = cs_dsp_adsp2v2_enable_core,
3159 		.disable_core = cs_dsp_adsp2v2_disable_core,
3160 
3161 		.start_core = cs_dsp_adsp2_start_core,
3162 		.stop_core = cs_dsp_adsp2_stop_core,
3163 	},
3164 };
3165 
3166 static const struct cs_dsp_ops cs_dsp_halo_ops = {
3167 	.parse_sizes = cs_dsp_adsp2_parse_sizes,
3168 	.validate_version = cs_dsp_halo_validate_version,
3169 	.setup_algs = cs_dsp_halo_setup_algs,
3170 	.region_to_reg = cs_dsp_halo_region_to_reg,
3171 
3172 	.show_fw_status = cs_dsp_halo_show_fw_status,
3173 	.stop_watchdog = cs_dsp_halo_stop_watchdog,
3174 
3175 	.lock_memory = cs_dsp_halo_configure_mpu,
3176 
3177 	.start_core = cs_dsp_halo_start_core,
3178 	.stop_core = cs_dsp_halo_stop_core,
3179 };
3180 
3181 MODULE_DESCRIPTION("Cirrus Logic DSP Support");
3182 MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
3183 MODULE_LICENSE("GPL v2");
3184