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