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