wm_adsp.c (2dd044641ec3672433b9fe3ec47b236621757aa8) wm_adsp.c (f6bc909e7673c30abcbdb329e7d0aa2e83c103d7)
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * wm_adsp.c -- Wolfson ADSP support
4 *
5 * Copyright 2012 Wolfson Microelectronics plc
6 *
7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8 */

--- 5 unchanged lines hidden (view full) ---

14#include <linux/delay.h>
15#include <linux/firmware.h>
16#include <linux/list.h>
17#include <linux/pm.h>
18#include <linux/pm_runtime.h>
19#include <linux/regmap.h>
20#include <linux/regulator/consumer.h>
21#include <linux/slab.h>
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * wm_adsp.c -- Wolfson ADSP support
4 *
5 * Copyright 2012 Wolfson Microelectronics plc
6 *
7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8 */

--- 5 unchanged lines hidden (view full) ---

14#include <linux/delay.h>
15#include <linux/firmware.h>
16#include <linux/list.h>
17#include <linux/pm.h>
18#include <linux/pm_runtime.h>
19#include <linux/regmap.h>
20#include <linux/regulator/consumer.h>
21#include <linux/slab.h>
22#include <linux/vmalloc.h>
23#include <linux/workqueue.h>
24#include <linux/debugfs.h>
25#include <sound/core.h>
26#include <sound/pcm.h>
27#include <sound/pcm_params.h>
28#include <sound/soc.h>
29#include <sound/jack.h>
30#include <sound/initval.h>

--- 8 unchanged lines hidden (view full) ---

39 dev_err(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
40#define adsp_warn(_dsp, fmt, ...) \
41 dev_warn(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
42#define adsp_info(_dsp, fmt, ...) \
43 dev_info(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
44#define adsp_dbg(_dsp, fmt, ...) \
45 dev_dbg(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
46
22#include <linux/workqueue.h>
23#include <linux/debugfs.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28#include <sound/jack.h>
29#include <sound/initval.h>

--- 8 unchanged lines hidden (view full) ---

38 dev_err(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
39#define adsp_warn(_dsp, fmt, ...) \
40 dev_warn(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
41#define adsp_info(_dsp, fmt, ...) \
42 dev_info(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
43#define adsp_dbg(_dsp, fmt, ...) \
44 dev_dbg(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__)
45
47#define cs_dsp_err(_dsp, fmt, ...) \
48 dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
49#define cs_dsp_warn(_dsp, fmt, ...) \
50 dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
51#define cs_dsp_info(_dsp, fmt, ...) \
52 dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
53#define cs_dsp_dbg(_dsp, fmt, ...) \
54 dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
55
56#define compr_err(_obj, fmt, ...) \
57 adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
58 ##__VA_ARGS__)
59#define compr_dbg(_obj, fmt, ...) \
60 adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
61 ##__VA_ARGS__)
62
46#define compr_err(_obj, fmt, ...) \
47 adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
48 ##__VA_ARGS__)
49#define compr_dbg(_obj, fmt, ...) \
50 adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
51 ##__VA_ARGS__)
52
63#define ADSP1_CONTROL_1 0x00
64#define ADSP1_CONTROL_2 0x02
65#define ADSP1_CONTROL_3 0x03
66#define ADSP1_CONTROL_4 0x04
67#define ADSP1_CONTROL_5 0x06
68#define ADSP1_CONTROL_6 0x07
69#define ADSP1_CONTROL_7 0x08
70#define ADSP1_CONTROL_8 0x09
71#define ADSP1_CONTROL_9 0x0A
72#define ADSP1_CONTROL_10 0x0B
73#define ADSP1_CONTROL_11 0x0C
74#define ADSP1_CONTROL_12 0x0D
75#define ADSP1_CONTROL_13 0x0F
76#define ADSP1_CONTROL_14 0x10
77#define ADSP1_CONTROL_15 0x11
78#define ADSP1_CONTROL_16 0x12
79#define ADSP1_CONTROL_17 0x13
80#define ADSP1_CONTROL_18 0x14
81#define ADSP1_CONTROL_19 0x16
82#define ADSP1_CONTROL_20 0x17
83#define ADSP1_CONTROL_21 0x18
84#define ADSP1_CONTROL_22 0x1A
85#define ADSP1_CONTROL_23 0x1B
86#define ADSP1_CONTROL_24 0x1C
87#define ADSP1_CONTROL_25 0x1E
88#define ADSP1_CONTROL_26 0x20
89#define ADSP1_CONTROL_27 0x21
90#define ADSP1_CONTROL_28 0x22
91#define ADSP1_CONTROL_29 0x23
92#define ADSP1_CONTROL_30 0x24
93#define ADSP1_CONTROL_31 0x26
94
95/*
96 * ADSP1 Control 19
97 */
98#define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
99#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
100#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
101
102
103/*
104 * ADSP1 Control 30
105 */
106#define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */
107#define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */
108#define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */
109#define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */
110#define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
111#define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
112#define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
113#define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
114#define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
115#define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
116#define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
117#define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
118#define ADSP1_START 0x0001 /* DSP1_START */
119#define ADSP1_START_MASK 0x0001 /* DSP1_START */
120#define ADSP1_START_SHIFT 0 /* DSP1_START */
121#define ADSP1_START_WIDTH 1 /* DSP1_START */
122
123/*
124 * ADSP1 Control 31
125 */
126#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
127#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
128#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
129
130#define ADSP2_CONTROL 0x0
131#define ADSP2_CLOCKING 0x1
132#define ADSP2V2_CLOCKING 0x2
133#define ADSP2_STATUS1 0x4
134#define ADSP2_WDMA_CONFIG_1 0x30
135#define ADSP2_WDMA_CONFIG_2 0x31
136#define ADSP2V2_WDMA_CONFIG_2 0x32
137#define ADSP2_RDMA_CONFIG_1 0x34
138
139#define ADSP2_SCRATCH0 0x40
140#define ADSP2_SCRATCH1 0x41
141#define ADSP2_SCRATCH2 0x42
142#define ADSP2_SCRATCH3 0x43
143
144#define ADSP2V2_SCRATCH0_1 0x40
145#define ADSP2V2_SCRATCH2_3 0x42
146
147/*
148 * ADSP2 Control
149 */
150
151#define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */
152#define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */
153#define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */
154#define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */
155#define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
156#define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
157#define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
158#define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
159#define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
160#define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
161#define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
162#define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
163#define ADSP2_START 0x0001 /* DSP1_START */
164#define ADSP2_START_MASK 0x0001 /* DSP1_START */
165#define ADSP2_START_SHIFT 0 /* DSP1_START */
166#define ADSP2_START_WIDTH 1 /* DSP1_START */
167
168/*
169 * ADSP2 clocking
170 */
171#define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
172#define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
173#define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
174
175/*
176 * ADSP2V2 clocking
177 */
178#define ADSP2V2_CLK_SEL_MASK 0x70000 /* CLK_SEL_ENA */
179#define ADSP2V2_CLK_SEL_SHIFT 16 /* CLK_SEL_ENA */
180#define ADSP2V2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
181
182#define ADSP2V2_RATE_MASK 0x7800 /* DSP_RATE */
183#define ADSP2V2_RATE_SHIFT 11 /* DSP_RATE */
184#define ADSP2V2_RATE_WIDTH 4 /* DSP_RATE */
185
186/*
187 * ADSP2 Status 1
188 */
189#define ADSP2_RAM_RDY 0x0001
190#define ADSP2_RAM_RDY_MASK 0x0001
191#define ADSP2_RAM_RDY_SHIFT 0
192#define ADSP2_RAM_RDY_WIDTH 1
193
194/*
195 * ADSP2 Lock support
196 */
197#define ADSP2_LOCK_CODE_0 0x5555
198#define ADSP2_LOCK_CODE_1 0xAAAA
199
200#define ADSP2_WATCHDOG 0x0A
201#define ADSP2_BUS_ERR_ADDR 0x52
202#define ADSP2_REGION_LOCK_STATUS 0x64
203#define ADSP2_LOCK_REGION_1_LOCK_REGION_0 0x66
204#define ADSP2_LOCK_REGION_3_LOCK_REGION_2 0x68
205#define ADSP2_LOCK_REGION_5_LOCK_REGION_4 0x6A
206#define ADSP2_LOCK_REGION_7_LOCK_REGION_6 0x6C
207#define ADSP2_LOCK_REGION_9_LOCK_REGION_8 0x6E
208#define ADSP2_LOCK_REGION_CTRL 0x7A
209#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR 0x7C
210
211#define ADSP2_REGION_LOCK_ERR_MASK 0x8000
212#define ADSP2_ADDR_ERR_MASK 0x4000
213#define ADSP2_WDT_TIMEOUT_STS_MASK 0x2000
214#define ADSP2_CTRL_ERR_PAUSE_ENA 0x0002
215#define ADSP2_CTRL_ERR_EINT 0x0001
216
217#define ADSP2_BUS_ERR_ADDR_MASK 0x00FFFFFF
218#define ADSP2_XMEM_ERR_ADDR_MASK 0x0000FFFF
219#define ADSP2_PMEM_ERR_ADDR_MASK 0x7FFF0000
220#define ADSP2_PMEM_ERR_ADDR_SHIFT 16
221#define ADSP2_WDT_ENA_MASK 0xFFFFFFFD
222
223#define ADSP2_LOCK_REGION_SHIFT 16
224
225#define ADSP_MAX_STD_CTRL_SIZE 512
226
53#define ADSP_MAX_STD_CTRL_SIZE 512
54
227#define CS_DSP_ACKED_CTL_TIMEOUT_MS 100
228#define CS_DSP_ACKED_CTL_N_QUICKPOLLS 10
229#define CS_DSP_ACKED_CTL_MIN_VALUE 0
230#define CS_DSP_ACKED_CTL_MAX_VALUE 0xFFFFFF
231
232/*
233 * Event control messages
234 */
235#define CS_DSP_FW_EVENT_SHUTDOWN 0x000001
236
237/*
238 * HALO system info
239 */
240#define HALO_AHBM_WINDOW_DEBUG_0 0x02040
241#define HALO_AHBM_WINDOW_DEBUG_1 0x02044
242
243/*
244 * HALO core
245 */
246#define HALO_SCRATCH1 0x005c0
247#define HALO_SCRATCH2 0x005c8
248#define HALO_SCRATCH3 0x005d0
249#define HALO_SCRATCH4 0x005d8
250#define HALO_CCM_CORE_CONTROL 0x41000
251#define HALO_CORE_SOFT_RESET 0x00010
252#define HALO_WDT_CONTROL 0x47000
253
254/*
255 * HALO MPU banks
256 */
257#define HALO_MPU_XMEM_ACCESS_0 0x43000
258#define HALO_MPU_YMEM_ACCESS_0 0x43004
259#define HALO_MPU_WINDOW_ACCESS_0 0x43008
260#define HALO_MPU_XREG_ACCESS_0 0x4300C
261#define HALO_MPU_YREG_ACCESS_0 0x43014
262#define HALO_MPU_XMEM_ACCESS_1 0x43018
263#define HALO_MPU_YMEM_ACCESS_1 0x4301C
264#define HALO_MPU_WINDOW_ACCESS_1 0x43020
265#define HALO_MPU_XREG_ACCESS_1 0x43024
266#define HALO_MPU_YREG_ACCESS_1 0x4302C
267#define HALO_MPU_XMEM_ACCESS_2 0x43030
268#define HALO_MPU_YMEM_ACCESS_2 0x43034
269#define HALO_MPU_WINDOW_ACCESS_2 0x43038
270#define HALO_MPU_XREG_ACCESS_2 0x4303C
271#define HALO_MPU_YREG_ACCESS_2 0x43044
272#define HALO_MPU_XMEM_ACCESS_3 0x43048
273#define HALO_MPU_YMEM_ACCESS_3 0x4304C
274#define HALO_MPU_WINDOW_ACCESS_3 0x43050
275#define HALO_MPU_XREG_ACCESS_3 0x43054
276#define HALO_MPU_YREG_ACCESS_3 0x4305C
277#define HALO_MPU_XM_VIO_ADDR 0x43100
278#define HALO_MPU_XM_VIO_STATUS 0x43104
279#define HALO_MPU_YM_VIO_ADDR 0x43108
280#define HALO_MPU_YM_VIO_STATUS 0x4310C
281#define HALO_MPU_PM_VIO_ADDR 0x43110
282#define HALO_MPU_PM_VIO_STATUS 0x43114
283#define HALO_MPU_LOCK_CONFIG 0x43140
284
285/*
286 * HALO_AHBM_WINDOW_DEBUG_1
287 */
288#define HALO_AHBM_CORE_ERR_ADDR_MASK 0x0fffff00
289#define HALO_AHBM_CORE_ERR_ADDR_SHIFT 8
290#define HALO_AHBM_FLAGS_ERR_MASK 0x000000ff
291
292/*
293 * HALO_CCM_CORE_CONTROL
294 */
295#define HALO_CORE_RESET 0x00000200
296#define HALO_CORE_EN 0x00000001
297
298/*
299 * HALO_CORE_SOFT_RESET
300 */
301#define HALO_CORE_SOFT_RESET_MASK 0x00000001
302
303/*
304 * HALO_WDT_CONTROL
305 */
306#define HALO_WDT_EN_MASK 0x00000001
307
308/*
309 * HALO_MPU_?M_VIO_STATUS
310 */
311#define HALO_MPU_VIO_STS_MASK 0x007e0000
312#define HALO_MPU_VIO_STS_SHIFT 17
313#define HALO_MPU_VIO_ERR_WR_MASK 0x00008000
314#define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff
315#define HALO_MPU_VIO_ERR_SRC_SHIFT 0
316
317static const struct cs_dsp_ops cs_dsp_adsp1_ops;
318static const struct cs_dsp_ops cs_dsp_adsp2_ops[];
319static const struct cs_dsp_ops cs_dsp_halo_ops;
320
321static const struct cs_dsp_client_ops wm_adsp1_client_ops;
322static const struct cs_dsp_client_ops wm_adsp2_client_ops;
323
55static const struct cs_dsp_client_ops wm_adsp1_client_ops;
56static const struct cs_dsp_client_ops wm_adsp2_client_ops;
57
324struct cs_dsp_buf {
325 struct list_head list;
326 void *buf;
327};
328
329static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len,
330 struct list_head *list)
331{
332 struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
333
334 if (buf == NULL)
335 return NULL;
336
337 buf->buf = vmalloc(len);
338 if (!buf->buf) {
339 kfree(buf);
340 return NULL;
341 }
342 memcpy(buf->buf, src, len);
343
344 if (list)
345 list_add_tail(&buf->list, list);
346
347 return buf;
348}
349
350static void cs_dsp_buf_free(struct list_head *list)
351{
352 while (!list_empty(list)) {
353 struct cs_dsp_buf *buf = list_first_entry(list,
354 struct cs_dsp_buf,
355 list);
356 list_del(&buf->list);
357 vfree(buf->buf);
358 kfree(buf);
359 }
360}
361
362#define WM_ADSP_FW_MBC_VSS 0
363#define WM_ADSP_FW_HIFI 1
364#define WM_ADSP_FW_TX 2
365#define WM_ADSP_FW_TX_SPK 3
366#define WM_ADSP_FW_RX 4
367#define WM_ADSP_FW_RX_ANC 5
368#define WM_ADSP_FW_CTRL 6
369#define WM_ADSP_FW_ASR 7

--- 108 unchanged lines hidden (view full) ---

478 u32 *raw_buf;
479 unsigned int copied_total;
480
481 unsigned int sample_rate;
482
483 const char *name;
484};
485
58#define WM_ADSP_FW_MBC_VSS 0
59#define WM_ADSP_FW_HIFI 1
60#define WM_ADSP_FW_TX 2
61#define WM_ADSP_FW_TX_SPK 3
62#define WM_ADSP_FW_RX 4
63#define WM_ADSP_FW_RX_ANC 5
64#define WM_ADSP_FW_CTRL 6
65#define WM_ADSP_FW_ASR 7

--- 108 unchanged lines hidden (view full) ---

174 u32 *raw_buf;
175 unsigned int copied_total;
176
177 unsigned int sample_rate;
178
179 const char *name;
180};
181
486#define CS_DSP_DATA_WORD_SIZE 3
487
488#define WM_ADSP_MIN_FRAGMENTS 1
489#define WM_ADSP_MAX_FRAGMENTS 256
490#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * CS_DSP_DATA_WORD_SIZE)
491#define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * CS_DSP_DATA_WORD_SIZE)
492
493#define WM_ADSP_ALG_XM_STRUCT_MAGIC 0x49aec7
494
495#define HOST_BUFFER_FIELD(field) \

--- 115 unchanged lines hidden (view full) ---

611
612struct wm_coeff_ctl {
613 const char *name;
614 struct cs_dsp_coeff_ctl *cs_ctl;
615 struct soc_bytes_ext bytes_ext;
616 struct work_struct work;
617};
618
182#define WM_ADSP_MIN_FRAGMENTS 1
183#define WM_ADSP_MAX_FRAGMENTS 256
184#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * CS_DSP_DATA_WORD_SIZE)
185#define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * CS_DSP_DATA_WORD_SIZE)
186
187#define WM_ADSP_ALG_XM_STRUCT_MAGIC 0x49aec7
188
189#define HOST_BUFFER_FIELD(field) \

--- 115 unchanged lines hidden (view full) ---

305
306struct wm_coeff_ctl {
307 const char *name;
308 struct cs_dsp_coeff_ctl *cs_ctl;
309 struct soc_bytes_ext bytes_ext;
310 struct work_struct work;
311};
312
619static const char *cs_dsp_mem_region_name(unsigned int type)
620{
621 switch (type) {
622 case WMFW_ADSP1_PM:
623 return "PM";
624 case WMFW_HALO_PM_PACKED:
625 return "PM_PACKED";
626 case WMFW_ADSP1_DM:
627 return "DM";
628 case WMFW_ADSP2_XM:
629 return "XM";
630 case WMFW_HALO_XM_PACKED:
631 return "XM_PACKED";
632 case WMFW_ADSP2_YM:
633 return "YM";
634 case WMFW_HALO_YM_PACKED:
635 return "YM_PACKED";
636 case WMFW_ADSP1_ZM:
637 return "ZM";
638 default:
639 return NULL;
640 }
641}
642
643#ifdef CONFIG_DEBUG_FS
644static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s)
645{
646 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
647
648 kfree(dsp->wmfw_file_name);
649 dsp->wmfw_file_name = tmp;
650}
651
652static void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, const char *s)
653{
654 char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
655
656 kfree(dsp->bin_file_name);
657 dsp->bin_file_name = tmp;
658}
659
660static void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
661{
662 kfree(dsp->wmfw_file_name);
663 kfree(dsp->bin_file_name);
664 dsp->wmfw_file_name = NULL;
665 dsp->bin_file_name = NULL;
666}
667
668static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file,
669 char __user *user_buf,
670 size_t count, loff_t *ppos)
671{
672 struct cs_dsp *dsp = file->private_data;
673 ssize_t ret;
674
675 mutex_lock(&dsp->pwr_lock);
676
677 if (!dsp->wmfw_file_name || !dsp->booted)
678 ret = 0;
679 else
680 ret = simple_read_from_buffer(user_buf, count, ppos,
681 dsp->wmfw_file_name,
682 strlen(dsp->wmfw_file_name));
683
684 mutex_unlock(&dsp->pwr_lock);
685 return ret;
686}
687
688static ssize_t cs_dsp_debugfs_bin_read(struct file *file,
689 char __user *user_buf,
690 size_t count, loff_t *ppos)
691{
692 struct cs_dsp *dsp = file->private_data;
693 ssize_t ret;
694
695 mutex_lock(&dsp->pwr_lock);
696
697 if (!dsp->bin_file_name || !dsp->booted)
698 ret = 0;
699 else
700 ret = simple_read_from_buffer(user_buf, count, ppos,
701 dsp->bin_file_name,
702 strlen(dsp->bin_file_name));
703
704 mutex_unlock(&dsp->pwr_lock);
705 return ret;
706}
707
708static const struct {
709 const char *name;
710 const struct file_operations fops;
711} cs_dsp_debugfs_fops[] = {
712 {
713 .name = "wmfw_file_name",
714 .fops = {
715 .open = simple_open,
716 .read = cs_dsp_debugfs_wmfw_read,
717 },
718 },
719 {
720 .name = "bin_file_name",
721 .fops = {
722 .open = simple_open,
723 .read = cs_dsp_debugfs_bin_read,
724 },
725 },
726};
727
728static void cs_dsp_init_debugfs(struct cs_dsp *dsp,
729 struct dentry *debugfs_root)
730{
731 struct dentry *root = NULL;
732 int i;
733
734 root = debugfs_create_dir(dsp->name, debugfs_root);
735
736 debugfs_create_bool("booted", 0444, root, &dsp->booted);
737 debugfs_create_bool("running", 0444, root, &dsp->running);
738 debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
739 debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
740
741 for (i = 0; i < ARRAY_SIZE(cs_dsp_debugfs_fops); ++i)
742 debugfs_create_file(cs_dsp_debugfs_fops[i].name, 0444, root,
743 dsp, &cs_dsp_debugfs_fops[i].fops);
744
745 dsp->debugfs_root = root;
746}
747
748static void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
749{
750 cs_dsp_debugfs_clear(dsp);
751 debugfs_remove_recursive(dsp->debugfs_root);
752 dsp->debugfs_root = NULL;
753}
754#else
755static inline void cs_dsp_init_debugfs(struct cs_dsp *dsp,
756 struct dentry *debugfs_root)
757{
758}
759
760static inline void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
761{
762}
763
764static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp,
765 const char *s)
766{
767}
768
769static inline void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp,
770 const char *s)
771{
772}
773
774static inline void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
775{
776}
777#endif
778
779int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
780 struct snd_ctl_elem_value *ucontrol)
781{
782 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
783 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
784 struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
785
786 ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;

--- 35 unchanged lines hidden (view full) ---

822 SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
823 SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
824 SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
825 SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
826 SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
827};
828EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
829
313int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
314 struct snd_ctl_elem_value *ucontrol)
315{
316 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
317 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
318 struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
319
320 ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;

--- 35 unchanged lines hidden (view full) ---

356 SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
357 SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
358 SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
359 SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
360 SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
361};
362EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
363
830static const struct cs_dsp_region *cs_dsp_find_region(struct cs_dsp *dsp,
831 int type)
832{
833 int i;
834
835 for (i = 0; i < dsp->num_mems; i++)
836 if (dsp->mem[i].type == type)
837 return &dsp->mem[i];
838
839 return NULL;
840}
841
842static unsigned int cs_dsp_region_to_reg(struct cs_dsp_region const *mem,
843 unsigned int offset)
844{
845 switch (mem->type) {
846 case WMFW_ADSP1_PM:
847 return mem->base + (offset * 3);
848 case WMFW_ADSP1_DM:
849 case WMFW_ADSP2_XM:
850 case WMFW_ADSP2_YM:
851 case WMFW_ADSP1_ZM:
852 return mem->base + (offset * 2);
853 default:
854 WARN(1, "Unknown memory region type");
855 return offset;
856 }
857}
858
859static unsigned int cs_dsp_halo_region_to_reg(struct cs_dsp_region const *mem,
860 unsigned int offset)
861{
862 switch (mem->type) {
863 case WMFW_ADSP2_XM:
864 case WMFW_ADSP2_YM:
865 return mem->base + (offset * 4);
866 case WMFW_HALO_XM_PACKED:
867 case WMFW_HALO_YM_PACKED:
868 return (mem->base + (offset * 3)) & ~0x3;
869 case WMFW_HALO_PM_PACKED:
870 return mem->base + (offset * 5);
871 default:
872 WARN(1, "Unknown memory region type");
873 return offset;
874 }
875}
876
877static void cs_dsp_read_fw_status(struct cs_dsp *dsp,
878 int noffs, unsigned int *offs)
879{
880 unsigned int i;
881 int ret;
882
883 for (i = 0; i < noffs; ++i) {
884 ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
885 if (ret) {
886 cs_dsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
887 return;
888 }
889 }
890}
891
892static void cs_dsp_adsp2_show_fw_status(struct cs_dsp *dsp)
893{
894 unsigned int offs[] = {
895 ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
896 };
897
898 cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
899
900 cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
901 offs[0], offs[1], offs[2], offs[3]);
902}
903
904static void cs_dsp_adsp2v2_show_fw_status(struct cs_dsp *dsp)
905{
906 unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
907
908 cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
909
910 cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
911 offs[0] & 0xFFFF, offs[0] >> 16,
912 offs[1] & 0xFFFF, offs[1] >> 16);
913}
914
915static void cs_dsp_halo_show_fw_status(struct cs_dsp *dsp)
916{
917 unsigned int offs[] = {
918 HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
919 };
920
921 cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
922
923 cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
924 offs[0], offs[1], offs[2], offs[3]);
925}
926
927static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
928{
929 return container_of(ext, struct wm_coeff_ctl, bytes_ext);
930}
931
364static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
365{
366 return container_of(ext, struct wm_coeff_ctl, bytes_ext);
367}
368
932static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg)
933{
934 const struct cs_dsp_alg_region *alg_region = &ctl->alg_region;
935 struct cs_dsp *dsp = ctl->dsp;
936 const struct cs_dsp_region *mem;
937
938 mem = cs_dsp_find_region(dsp, alg_region->type);
939 if (!mem) {
940 cs_dsp_err(dsp, "No base for region %x\n",
941 alg_region->type);
942 return -EINVAL;
943 }
944
945 *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset);
946
947 return 0;
948}
949
950static int wm_coeff_info(struct snd_kcontrol *kctl,
951 struct snd_ctl_elem_info *uinfo)
952{
953 struct soc_bytes_ext *bytes_ext =
954 (struct soc_bytes_ext *)kctl->private_value;
955 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
956 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
957

--- 9 unchanged lines hidden (view full) ---

967 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
968 uinfo->count = cs_ctl->len;
969 break;
970 }
971
972 return 0;
973}
974
369static int wm_coeff_info(struct snd_kcontrol *kctl,
370 struct snd_ctl_elem_info *uinfo)
371{
372 struct soc_bytes_ext *bytes_ext =
373 (struct soc_bytes_ext *)kctl->private_value;
374 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
375 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
376

--- 9 unchanged lines hidden (view full) ---

386 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
387 uinfo->count = cs_ctl->len;
388 break;
389 }
390
391 return 0;
392}
393
975static int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl,
976 unsigned int event_id)
977{
978 struct cs_dsp *dsp = ctl->dsp;
979 __be32 val = cpu_to_be32(event_id);
980 unsigned int reg;
981 int i, ret;
982
983 if (!dsp->running)
984 return -EPERM;
985
986 ret = cs_dsp_coeff_base_reg(ctl, &reg);
987 if (ret)
988 return ret;
989
990 cs_dsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
991 event_id, ctl->alg_region.alg,
992 cs_dsp_mem_region_name(ctl->alg_region.type), ctl->offset);
993
994 ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
995 if (ret) {
996 cs_dsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
997 return ret;
998 }
999
1000 /*
1001 * Poll for ack, we initially poll at ~1ms intervals for firmwares
1002 * that respond quickly, then go to ~10ms polls. A firmware is unlikely
1003 * to ack instantly so we do the first 1ms delay before reading the
1004 * control to avoid a pointless bus transaction
1005 */
1006 for (i = 0; i < CS_DSP_ACKED_CTL_TIMEOUT_MS;) {
1007 switch (i) {
1008 case 0 ... CS_DSP_ACKED_CTL_N_QUICKPOLLS - 1:
1009 usleep_range(1000, 2000);
1010 i++;
1011 break;
1012 default:
1013 usleep_range(10000, 20000);
1014 i += 10;
1015 break;
1016 }
1017
1018 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
1019 if (ret) {
1020 cs_dsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
1021 return ret;
1022 }
1023
1024 if (val == 0) {
1025 cs_dsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
1026 return 0;
1027 }
1028 }
1029
1030 cs_dsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
1031 reg, ctl->alg_region.alg,
1032 cs_dsp_mem_region_name(ctl->alg_region.type),
1033 ctl->offset);
1034
1035 return -ETIMEDOUT;
1036}
1037
1038static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
1039 const void *buf, size_t len)
1040{
1041 struct cs_dsp *dsp = ctl->dsp;
1042 void *scratch;
1043 int ret;
1044 unsigned int reg;
1045
1046 ret = cs_dsp_coeff_base_reg(ctl, &reg);
1047 if (ret)
1048 return ret;
1049
1050 scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
1051 if (!scratch)
1052 return -ENOMEM;
1053
1054 ret = regmap_raw_write(dsp->regmap, reg, scratch,
1055 len);
1056 if (ret) {
1057 cs_dsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
1058 len, reg, ret);
1059 kfree(scratch);
1060 return ret;
1061 }
1062 cs_dsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
1063
1064 kfree(scratch);
1065
1066 return 0;
1067}
1068
1069static int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
1070 const void *buf, size_t len)
1071{
1072 int ret = 0;
1073
1074 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1075 ret = -EPERM;
1076 else if (buf != ctl->cache)
1077 memcpy(ctl->cache, buf, len);
1078
1079 ctl->set = 1;
1080 if (ctl->enabled && ctl->dsp->running)
1081 ret = cs_dsp_coeff_write_ctrl_raw(ctl, buf, len);
1082
1083 return ret;
1084}
1085
1086static int wm_coeff_put(struct snd_kcontrol *kctl,
1087 struct snd_ctl_elem_value *ucontrol)
1088{
1089 struct soc_bytes_ext *bytes_ext =
1090 (struct soc_bytes_ext *)kctl->private_value;
1091 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1092 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
1093 char *p = ucontrol->value.bytes.data;

--- 47 unchanged lines hidden (view full) ---

1141 else
1142 ret = -EPERM;
1143
1144 mutex_unlock(&cs_ctl->dsp->pwr_lock);
1145
1146 return ret;
1147}
1148
394static int wm_coeff_put(struct snd_kcontrol *kctl,
395 struct snd_ctl_elem_value *ucontrol)
396{
397 struct soc_bytes_ext *bytes_ext =
398 (struct soc_bytes_ext *)kctl->private_value;
399 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
400 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
401 char *p = ucontrol->value.bytes.data;

--- 47 unchanged lines hidden (view full) ---

449 else
450 ret = -EPERM;
451
452 mutex_unlock(&cs_ctl->dsp->pwr_lock);
453
454 return ret;
455}
456
1149static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
1150 void *buf, size_t len)
1151{
1152 struct cs_dsp *dsp = ctl->dsp;
1153 void *scratch;
1154 int ret;
1155 unsigned int reg;
1156
1157 ret = cs_dsp_coeff_base_reg(ctl, &reg);
1158 if (ret)
1159 return ret;
1160
1161 scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
1162 if (!scratch)
1163 return -ENOMEM;
1164
1165 ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
1166 if (ret) {
1167 cs_dsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
1168 len, reg, ret);
1169 kfree(scratch);
1170 return ret;
1171 }
1172 cs_dsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
1173
1174 memcpy(buf, scratch, len);
1175 kfree(scratch);
1176
1177 return 0;
1178}
1179
1180static int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len)
1181{
1182 int ret = 0;
1183
1184 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
1185 if (ctl->enabled && ctl->dsp->running)
1186 return cs_dsp_coeff_read_ctrl_raw(ctl, buf, len);
1187 else
1188 return -EPERM;
1189 } else {
1190 if (!ctl->flags && ctl->enabled && ctl->dsp->running)
1191 ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1192
1193 if (buf != ctl->cache)
1194 memcpy(buf, ctl->cache, len);
1195 }
1196
1197 return ret;
1198}
1199
1200static int wm_coeff_get(struct snd_kcontrol *kctl,
1201 struct snd_ctl_elem_value *ucontrol)
1202{
1203 struct soc_bytes_ext *bytes_ext =
1204 (struct soc_bytes_ext *)kctl->private_value;
1205 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
1206 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
1207 char *p = ucontrol->value.bytes.data;

--- 115 unchanged lines hidden (view full) ---

1323
1324 return 0;
1325
1326err_kcontrol:
1327 kfree(kcontrol);
1328 return ret;
1329}
1330
457static int wm_coeff_get(struct snd_kcontrol *kctl,
458 struct snd_ctl_elem_value *ucontrol)
459{
460 struct soc_bytes_ext *bytes_ext =
461 (struct soc_bytes_ext *)kctl->private_value;
462 struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
463 struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
464 char *p = ucontrol->value.bytes.data;

--- 115 unchanged lines hidden (view full) ---

580
581 return 0;
582
583err_kcontrol:
584 kfree(kcontrol);
585 return ret;
586}
587
1331static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp)
1332{
1333 struct cs_dsp_coeff_ctl *ctl;
1334 int ret;
1335
1336 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1337 if (!ctl->enabled || ctl->set)
1338 continue;
1339 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
1340 continue;
1341
1342 /*
1343 * For readable controls populate the cache from the DSP memory.
1344 * For non-readable controls the cache was zero-filled when
1345 * created so we don't need to do anything.
1346 */
1347 if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
1348 ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
1349 if (ret < 0)
1350 return ret;
1351 }
1352 }
1353
1354 return 0;
1355}
1356
1357static int cs_dsp_coeff_sync_controls(struct cs_dsp *dsp)
1358{
1359 struct cs_dsp_coeff_ctl *ctl;
1360 int ret;
1361
1362 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1363 if (!ctl->enabled)
1364 continue;
1365 if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
1366 ret = cs_dsp_coeff_write_ctrl_raw(ctl, ctl->cache,
1367 ctl->len);
1368 if (ret < 0)
1369 return ret;
1370 }
1371 }
1372
1373 return 0;
1374}
1375
1376static void cs_dsp_signal_event_controls(struct cs_dsp *dsp,
1377 unsigned int event)
1378{
1379 struct cs_dsp_coeff_ctl *ctl;
1380 int ret;
1381
1382 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1383 if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
1384 continue;
1385
1386 if (!ctl->enabled)
1387 continue;
1388
1389 ret = cs_dsp_coeff_write_acked_control(ctl, event);
1390 if (ret)
1391 cs_dsp_warn(dsp,
1392 "Failed to send 0x%x event to alg 0x%x (%d)\n",
1393 event, ctl->alg_region.alg, ret);
1394 }
1395}
1396
1397static void wm_adsp_ctl_work(struct work_struct *work)
1398{
1399 struct wm_coeff_ctl *ctl = container_of(work,
1400 struct wm_coeff_ctl,
1401 work);
1402 struct wm_adsp *dsp = container_of(ctl->cs_ctl->dsp,
1403 struct wm_adsp,
1404 cs_dsp);
1405
1406 wmfw_add_ctl(dsp, ctl);
1407}
1408
588static void wm_adsp_ctl_work(struct work_struct *work)
589{
590 struct wm_coeff_ctl *ctl = container_of(work,
591 struct wm_coeff_ctl,
592 work);
593 struct wm_adsp *dsp = container_of(ctl->cs_ctl->dsp,
594 struct wm_adsp,
595 cs_dsp);
596
597 wmfw_add_ctl(dsp, ctl);
598}
599
1409static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl)
1410{
1411 kfree(ctl->cache);
1412 kfree(ctl->subname);
1413 kfree(ctl);
1414}
1415
1416static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
1417{
1418 struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
1419 struct cs_dsp *cs_dsp = &dsp->cs_dsp;
1420 struct wm_coeff_ctl *ctl;
1421 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1422 const char *region_name;
1423 int ret;

--- 69 unchanged lines hidden (view full) ---

1493 struct wm_coeff_ctl *ctl = cs_ctl->priv;
1494
1495 cancel_work_sync(&ctl->work);
1496
1497 kfree(ctl->name);
1498 kfree(ctl);
1499}
1500
600static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
601{
602 struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
603 struct cs_dsp *cs_dsp = &dsp->cs_dsp;
604 struct wm_coeff_ctl *ctl;
605 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
606 const char *region_name;
607 int ret;

--- 69 unchanged lines hidden (view full) ---

677 struct wm_coeff_ctl *ctl = cs_ctl->priv;
678
679 cancel_work_sync(&ctl->work);
680
681 kfree(ctl->name);
682 kfree(ctl);
683}
684
1501static int cs_dsp_create_control(struct cs_dsp *dsp,
1502 const struct cs_dsp_alg_region *alg_region,
1503 unsigned int offset, unsigned int len,
1504 const char *subname, unsigned int subname_len,
1505 unsigned int flags, unsigned int type)
1506{
1507 struct cs_dsp_coeff_ctl *ctl;
1508 int ret;
1509
1510 list_for_each_entry(ctl, &dsp->ctl_list, list) {
1511 if (ctl->fw_name == dsp->fw_name &&
1512 ctl->alg_region.alg == alg_region->alg &&
1513 ctl->alg_region.type == alg_region->type) {
1514 if ((!subname && !ctl->subname) ||
1515 (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) {
1516 if (!ctl->enabled)
1517 ctl->enabled = 1;
1518 return 0;
1519 }
1520 }
1521 }
1522
1523 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
1524 if (!ctl)
1525 return -ENOMEM;
1526
1527 ctl->fw_name = dsp->fw_name;
1528 ctl->alg_region = *alg_region;
1529 if (subname && dsp->fw_ver >= 2) {
1530 ctl->subname_len = subname_len;
1531 ctl->subname = kmemdup(subname,
1532 strlen(subname) + 1, GFP_KERNEL);
1533 if (!ctl->subname) {
1534 ret = -ENOMEM;
1535 goto err_ctl;
1536 }
1537 }
1538 ctl->enabled = 1;
1539 ctl->set = 0;
1540 ctl->dsp = dsp;
1541
1542 ctl->flags = flags;
1543 ctl->type = type;
1544 ctl->offset = offset;
1545 ctl->len = len;
1546 ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
1547 if (!ctl->cache) {
1548 ret = -ENOMEM;
1549 goto err_ctl_subname;
1550 }
1551
1552 list_add(&ctl->list, &dsp->ctl_list);
1553
1554 if (dsp->client_ops->control_add) {
1555 ret = dsp->client_ops->control_add(ctl);
1556 if (ret)
1557 goto err_list_del;
1558 }
1559
1560 return 0;
1561
1562err_list_del:
1563 list_del(&ctl->list);
1564 kfree(ctl->cache);
1565err_ctl_subname:
1566 kfree(ctl->subname);
1567err_ctl:
1568 kfree(ctl);
1569
1570 return ret;
1571}
1572
1573struct cs_dsp_coeff_parsed_alg {
1574 int id;
1575 const u8 *name;
1576 int name_len;
1577 int ncoeff;
1578};
1579
1580struct cs_dsp_coeff_parsed_coeff {
1581 int offset;
1582 int mem_type;
1583 const u8 *name;
1584 int name_len;
1585 unsigned int ctl_type;
1586 int flags;
1587 int len;
1588};
1589
1590static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
1591{
1592 int length;
1593
1594 switch (bytes) {
1595 case 1:
1596 length = **pos;
1597 break;
1598 case 2:
1599 length = le16_to_cpu(*((__le16 *)*pos));
1600 break;
1601 default:
1602 return 0;
1603 }
1604
1605 if (str)
1606 *str = *pos + bytes;
1607
1608 *pos += ((length + bytes) + 3) & ~0x03;
1609
1610 return length;
1611}
1612
1613static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos)
1614{
1615 int val = 0;
1616
1617 switch (bytes) {
1618 case 2:
1619 val = le16_to_cpu(*((__le16 *)*pos));
1620 break;
1621 case 4:
1622 val = le32_to_cpu(*((__le32 *)*pos));
1623 break;
1624 default:
1625 break;
1626 }
1627
1628 *pos += bytes;
1629
1630 return val;
1631}
1632
1633static inline void cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, const u8 **data,
1634 struct cs_dsp_coeff_parsed_alg *blk)
1635{
1636 const struct wmfw_adsp_alg_data *raw;
1637
1638 switch (dsp->fw_ver) {
1639 case 0:
1640 case 1:
1641 raw = (const struct wmfw_adsp_alg_data *)*data;
1642 *data = raw->data;
1643
1644 blk->id = le32_to_cpu(raw->id);
1645 blk->name = raw->name;
1646 blk->name_len = strlen(raw->name);
1647 blk->ncoeff = le32_to_cpu(raw->ncoeff);
1648 break;
1649 default:
1650 blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data);
1651 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data,
1652 &blk->name);
1653 cs_dsp_coeff_parse_string(sizeof(u16), data, NULL);
1654 blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data);
1655 break;
1656 }
1657
1658 cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
1659 cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
1660 cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
1661}
1662
1663static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data,
1664 struct cs_dsp_coeff_parsed_coeff *blk)
1665{
1666 const struct wmfw_adsp_coeff_data *raw;
1667 const u8 *tmp;
1668 int length;
1669
1670 switch (dsp->fw_ver) {
1671 case 0:
1672 case 1:
1673 raw = (const struct wmfw_adsp_coeff_data *)*data;
1674 *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
1675
1676 blk->offset = le16_to_cpu(raw->hdr.offset);
1677 blk->mem_type = le16_to_cpu(raw->hdr.type);
1678 blk->name = raw->name;
1679 blk->name_len = strlen(raw->name);
1680 blk->ctl_type = le16_to_cpu(raw->ctl_type);
1681 blk->flags = le16_to_cpu(raw->flags);
1682 blk->len = le32_to_cpu(raw->len);
1683 break;
1684 default:
1685 tmp = *data;
1686 blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
1687 blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
1688 length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
1689 blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp,
1690 &blk->name);
1691 cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL);
1692 cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL);
1693 blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
1694 blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp);
1695 blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp);
1696
1697 *data = *data + sizeof(raw->hdr) + length;
1698 break;
1699 }
1700
1701 cs_dsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
1702 cs_dsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
1703 cs_dsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
1704 cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
1705 cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
1706 cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
1707}
1708
1709static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp,
1710 const struct cs_dsp_coeff_parsed_coeff *coeff_blk,
1711 unsigned int f_required,
1712 unsigned int f_illegal)
1713{
1714 if ((coeff_blk->flags & f_illegal) ||
1715 ((coeff_blk->flags & f_required) != f_required)) {
1716 cs_dsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
1717 coeff_blk->flags, coeff_blk->ctl_type);
1718 return -EINVAL;
1719 }
1720
1721 return 0;
1722}
1723
1724static int cs_dsp_parse_coeff(struct cs_dsp *dsp,
1725 const struct wmfw_region *region)
1726{
1727 struct cs_dsp_alg_region alg_region = {};
1728 struct cs_dsp_coeff_parsed_alg alg_blk;
1729 struct cs_dsp_coeff_parsed_coeff coeff_blk;
1730 const u8 *data = region->data;
1731 int i, ret;
1732
1733 cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk);
1734 for (i = 0; i < alg_blk.ncoeff; i++) {
1735 cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk);
1736
1737 switch (coeff_blk.ctl_type) {
1738 case WMFW_CTL_TYPE_BYTES:
1739 break;
1740 case WMFW_CTL_TYPE_ACKED:
1741 if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
1742 continue; /* ignore */
1743
1744 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1745 WMFW_CTL_FLAG_VOLATILE |
1746 WMFW_CTL_FLAG_WRITEABLE |
1747 WMFW_CTL_FLAG_READABLE,
1748 0);
1749 if (ret)
1750 return -EINVAL;
1751 break;
1752 case WMFW_CTL_TYPE_HOSTEVENT:
1753 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1754 WMFW_CTL_FLAG_SYS |
1755 WMFW_CTL_FLAG_VOLATILE |
1756 WMFW_CTL_FLAG_WRITEABLE |
1757 WMFW_CTL_FLAG_READABLE,
1758 0);
1759 if (ret)
1760 return -EINVAL;
1761 break;
1762 case WMFW_CTL_TYPE_HOST_BUFFER:
1763 ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk,
1764 WMFW_CTL_FLAG_SYS |
1765 WMFW_CTL_FLAG_VOLATILE |
1766 WMFW_CTL_FLAG_READABLE,
1767 0);
1768 if (ret)
1769 return -EINVAL;
1770 break;
1771 default:
1772 cs_dsp_err(dsp, "Unknown control type: %d\n",
1773 coeff_blk.ctl_type);
1774 return -EINVAL;
1775 }
1776
1777 alg_region.type = coeff_blk.mem_type;
1778 alg_region.alg = alg_blk.id;
1779
1780 ret = cs_dsp_create_control(dsp, &alg_region,
1781 coeff_blk.offset,
1782 coeff_blk.len,
1783 coeff_blk.name,
1784 coeff_blk.name_len,
1785 coeff_blk.flags,
1786 coeff_blk.ctl_type);
1787 if (ret < 0)
1788 cs_dsp_err(dsp, "Failed to create control: %.*s, %d\n",
1789 coeff_blk.name_len, coeff_blk.name, ret);
1790 }
1791
1792 return 0;
1793}
1794
1795static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp,
1796 const char * const file,
1797 unsigned int pos,
1798 const struct firmware *firmware)
1799{
1800 const struct wmfw_adsp1_sizes *adsp1_sizes;
1801
1802 adsp1_sizes = (void *)&firmware->data[pos];
1803
1804 cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
1805 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
1806 le32_to_cpu(adsp1_sizes->zm));
1807
1808 return pos + sizeof(*adsp1_sizes);
1809}
1810
1811static void wm_adsp_release_firmware_files(struct wm_adsp *dsp,
1812 const struct firmware *wmfw_firmware,
1813 char *wmfw_filename,
1814 const struct firmware *coeff_firmware,
1815 char *coeff_filename)
1816{
1817 if (wmfw_firmware)
1818 release_firmware(wmfw_firmware);
1819 kfree(wmfw_filename);
1820
1821 if (coeff_firmware)
1822 release_firmware(coeff_firmware);
1823 kfree(coeff_filename);
1824}
1825
1826static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
1827 const struct firmware **firmware,
1828 char **filename,
1829 char *suffix)
1830{
1831 struct cs_dsp *cs_dsp = &dsp->cs_dsp;
1832 int ret = 0;
1833
1834 *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", dsp->part, dsp->fwf_name,
1835 wm_adsp_fw[dsp->fw].file, suffix);
1836 if (*filename == NULL)
1837 return -ENOMEM;
1838
1839 ret = request_firmware(firmware, *filename, cs_dsp->dev);
1840 if (ret != 0) {
1841 adsp_err(dsp, "Failed to request '%s'\n", *filename);
1842 kfree(*filename);
1843 *filename = NULL;
1844 }
1845
1846 return ret;
1847}
1848
1849static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
1850 const struct firmware **wmfw_firmware,
1851 char **wmfw_filename,
1852 const struct firmware **coeff_firmware,
1853 char **coeff_filename)
1854{
1855 int ret = 0;
1856
1857 ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, "wmfw");
1858 if (ret != 0)
1859 return ret;
1860
1861 wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, "bin");
1862
1863 return 0;
1864}
1865
1866static unsigned int cs_dsp_adsp2_parse_sizes(struct cs_dsp *dsp,
1867 const char * const file,
1868 unsigned int pos,
1869 const struct firmware *firmware)
1870{
1871 const struct wmfw_adsp2_sizes *adsp2_sizes;
1872
1873 adsp2_sizes = (void *)&firmware->data[pos];
1874
1875 cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
1876 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
1877 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
1878
1879 return pos + sizeof(*adsp2_sizes);
1880}
1881
1882static bool cs_dsp_validate_version(struct cs_dsp *dsp, unsigned int version)
1883{
1884 switch (version) {
1885 case 0:
1886 cs_dsp_warn(dsp, "Deprecated file format %d\n", version);
1887 return true;
1888 case 1:
1889 case 2:
1890 return true;
1891 default:
1892 return false;
1893 }
1894}
1895
1896static bool cs_dsp_halo_validate_version(struct cs_dsp *dsp, unsigned int version)
1897{
1898 switch (version) {
1899 case 3:
1900 return true;
1901 default:
1902 return false;
1903 }
1904}
1905
1906static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
1907 const char *file)
1908{
1909 LIST_HEAD(buf_list);
1910 struct regmap *regmap = dsp->regmap;
1911 unsigned int pos = 0;
1912 const struct wmfw_header *header;
1913 const struct wmfw_adsp1_sizes *adsp1_sizes;
1914 const struct wmfw_footer *footer;
1915 const struct wmfw_region *region;
1916 const struct cs_dsp_region *mem;
1917 const char *region_name;
1918 char *text = NULL;
1919 struct cs_dsp_buf *buf;
1920 unsigned int reg;
1921 int regions = 0;
1922 int ret, offset, type;
1923
1924 ret = -EINVAL;
1925
1926 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1927 if (pos >= firmware->size) {
1928 cs_dsp_err(dsp, "%s: file too short, %zu bytes\n",
1929 file, firmware->size);
1930 goto out_fw;
1931 }
1932
1933 header = (void *)&firmware->data[0];
1934
1935 if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
1936 cs_dsp_err(dsp, "%s: invalid magic\n", file);
1937 goto out_fw;
1938 }
1939
1940 if (!dsp->ops->validate_version(dsp, header->ver)) {
1941 cs_dsp_err(dsp, "%s: unknown file format %d\n",
1942 file, header->ver);
1943 goto out_fw;
1944 }
1945
1946 cs_dsp_info(dsp, "Firmware version: %d\n", header->ver);
1947 dsp->fw_ver = header->ver;
1948
1949 if (header->core != dsp->type) {
1950 cs_dsp_err(dsp, "%s: invalid core %d != %d\n",
1951 file, header->core, dsp->type);
1952 goto out_fw;
1953 }
1954
1955 pos = sizeof(*header);
1956 pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
1957
1958 footer = (void *)&firmware->data[pos];
1959 pos += sizeof(*footer);
1960
1961 if (le32_to_cpu(header->len) != pos) {
1962 cs_dsp_err(dsp, "%s: unexpected header length %d\n",
1963 file, le32_to_cpu(header->len));
1964 goto out_fw;
1965 }
1966
1967 cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file,
1968 le64_to_cpu(footer->timestamp));
1969
1970 while (pos < firmware->size &&
1971 sizeof(*region) < firmware->size - pos) {
1972 region = (void *)&(firmware->data[pos]);
1973 region_name = "Unknown";
1974 reg = 0;
1975 text = NULL;
1976 offset = le32_to_cpu(region->offset) & 0xffffff;
1977 type = be32_to_cpu(region->type) & 0xff;
1978
1979 switch (type) {
1980 case WMFW_NAME_TEXT:
1981 region_name = "Firmware name";
1982 text = kzalloc(le32_to_cpu(region->len) + 1,
1983 GFP_KERNEL);
1984 break;
1985 case WMFW_ALGORITHM_DATA:
1986 region_name = "Algorithm";
1987 ret = cs_dsp_parse_coeff(dsp, region);
1988 if (ret != 0)
1989 goto out_fw;
1990 break;
1991 case WMFW_INFO_TEXT:
1992 region_name = "Information";
1993 text = kzalloc(le32_to_cpu(region->len) + 1,
1994 GFP_KERNEL);
1995 break;
1996 case WMFW_ABSOLUTE:
1997 region_name = "Absolute";
1998 reg = offset;
1999 break;
2000 case WMFW_ADSP1_PM:
2001 case WMFW_ADSP1_DM:
2002 case WMFW_ADSP2_XM:
2003 case WMFW_ADSP2_YM:
2004 case WMFW_ADSP1_ZM:
2005 case WMFW_HALO_PM_PACKED:
2006 case WMFW_HALO_XM_PACKED:
2007 case WMFW_HALO_YM_PACKED:
2008 mem = cs_dsp_find_region(dsp, type);
2009 if (!mem) {
2010 cs_dsp_err(dsp, "No region of type: %x\n", type);
2011 ret = -EINVAL;
2012 goto out_fw;
2013 }
2014
2015 region_name = cs_dsp_mem_region_name(type);
2016 reg = dsp->ops->region_to_reg(mem, offset);
2017 break;
2018 default:
2019 cs_dsp_warn(dsp,
2020 "%s.%d: Unknown region type %x at %d(%x)\n",
2021 file, regions, type, pos, pos);
2022 break;
2023 }
2024
2025 cs_dsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
2026 regions, le32_to_cpu(region->len), offset,
2027 region_name);
2028
2029 if (le32_to_cpu(region->len) >
2030 firmware->size - pos - sizeof(*region)) {
2031 cs_dsp_err(dsp,
2032 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2033 file, regions, region_name,
2034 le32_to_cpu(region->len), firmware->size);
2035 ret = -EINVAL;
2036 goto out_fw;
2037 }
2038
2039 if (text) {
2040 memcpy(text, region->data, le32_to_cpu(region->len));
2041 cs_dsp_info(dsp, "%s: %s\n", file, text);
2042 kfree(text);
2043 text = NULL;
2044 }
2045
2046 if (reg) {
2047 buf = cs_dsp_buf_alloc(region->data,
2048 le32_to_cpu(region->len),
2049 &buf_list);
2050 if (!buf) {
2051 cs_dsp_err(dsp, "Out of memory\n");
2052 ret = -ENOMEM;
2053 goto out_fw;
2054 }
2055
2056 ret = regmap_raw_write_async(regmap, reg, buf->buf,
2057 le32_to_cpu(region->len));
2058 if (ret != 0) {
2059 cs_dsp_err(dsp,
2060 "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
2061 file, regions,
2062 le32_to_cpu(region->len), offset,
2063 region_name, ret);
2064 goto out_fw;
2065 }
2066 }
2067
2068 pos += le32_to_cpu(region->len) + sizeof(*region);
2069 regions++;
2070 }
2071
2072 ret = regmap_async_complete(regmap);
2073 if (ret != 0) {
2074 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
2075 goto out_fw;
2076 }
2077
2078 if (pos > firmware->size)
2079 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2080 file, regions, pos - firmware->size);
2081
2082 cs_dsp_debugfs_save_wmfwname(dsp, file);
2083
2084out_fw:
2085 regmap_async_complete(regmap);
2086 cs_dsp_buf_free(&buf_list);
2087 kfree(text);
2088
2089 return ret;
2090}
2091
2092/*
2093 * Find cs_dsp_coeff_ctl with input name as its subname
2094 * If not found, return NULL
2095 */
2096static struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp,
2097 const char *name, int type,
2098 unsigned int alg)
2099{
2100 struct cs_dsp_coeff_ctl *pos, *rslt = NULL;
2101
2102 list_for_each_entry(pos, &dsp->ctl_list, list) {
2103 if (!pos->subname)
2104 continue;
2105 if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
2106 pos->fw_name == dsp->fw_name &&
2107 pos->alg_region.alg == alg &&
2108 pos->alg_region.type == type) {
2109 rslt = pos;
2110 break;
2111 }
2112 }
2113
2114 return rslt;
2115}
2116
2117int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
2118 unsigned int alg, void *buf, size_t len)
2119{
2120 struct cs_dsp_coeff_ctl *cs_ctl;
2121 struct wm_coeff_ctl *ctl;
2122 struct snd_kcontrol *kcontrol;
2123 char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
2124 int ret;

--- 45 unchanged lines hidden (view full) ---

2170
2171 if (len > cs_ctl->len)
2172 return -EINVAL;
2173
2174 return cs_dsp_coeff_read_ctrl(cs_ctl, buf, len);
2175}
2176EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
2177
685int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
686 unsigned int alg, void *buf, size_t len)
687{
688 struct cs_dsp_coeff_ctl *cs_ctl;
689 struct wm_coeff_ctl *ctl;
690 struct snd_kcontrol *kcontrol;
691 char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
692 int ret;

--- 45 unchanged lines hidden (view full) ---

738
739 if (len > cs_ctl->len)
740 return -EINVAL;
741
742 return cs_dsp_coeff_read_ctrl(cs_ctl, buf, len);
743}
744EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
745
2178static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp,
2179 const struct cs_dsp_alg_region *alg_region)
746static void wm_adsp_release_firmware_files(struct wm_adsp *dsp,
747 const struct firmware *wmfw_firmware,
748 char *wmfw_filename,
749 const struct firmware *coeff_firmware,
750 char *coeff_filename)
2180{
751{
2181 struct cs_dsp_coeff_ctl *ctl;
752 if (wmfw_firmware)
753 release_firmware(wmfw_firmware);
754 kfree(wmfw_filename);
2182
755
2183 list_for_each_entry(ctl, &dsp->ctl_list, list) {
2184 if (ctl->fw_name == dsp->fw_name &&
2185 alg_region->alg == ctl->alg_region.alg &&
2186 alg_region->type == ctl->alg_region.type) {
2187 ctl->alg_region.base = alg_region->base;
2188 }
2189 }
756 if (coeff_firmware)
757 release_firmware(coeff_firmware);
758 kfree(coeff_filename);
2190}
2191
759}
760
2192static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs,
2193 const struct cs_dsp_region *mem,
2194 unsigned int pos, unsigned int len)
761static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
762 const struct firmware **firmware,
763 char **filename,
764 char *suffix)
2195{
765{
2196 void *alg;
2197 unsigned int reg;
2198 int ret;
2199 __be32 val;
766 struct cs_dsp *cs_dsp = &dsp->cs_dsp;
767 int ret = 0;
2200
768
2201 if (n_algs == 0) {
2202 cs_dsp_err(dsp, "No algorithms\n");
2203 return ERR_PTR(-EINVAL);
2204 }
769 *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", dsp->part, dsp->fwf_name,
770 wm_adsp_fw[dsp->fw].file, suffix);
771 if (*filename == NULL)
772 return -ENOMEM;
2205
773
2206 if (n_algs > 1024) {
2207 cs_dsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
2208 return ERR_PTR(-EINVAL);
2209 }
2210
2211 /* Read the terminator first to validate the length */
2212 reg = dsp->ops->region_to_reg(mem, pos + len);
2213
2214 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
774 ret = request_firmware(firmware, *filename, cs_dsp->dev);
2215 if (ret != 0) {
775 if (ret != 0) {
2216 cs_dsp_err(dsp, "Failed to read algorithm list end: %d\n",
2217 ret);
2218 return ERR_PTR(ret);
776 adsp_err(dsp, "Failed to request '%s'\n", *filename);
777 kfree(*filename);
778 *filename = NULL;
2219 }
2220
779 }
780
2221 if (be32_to_cpu(val) != 0xbedead)
2222 cs_dsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
2223 reg, be32_to_cpu(val));
2224
2225 /* Convert length from DSP words to bytes */
2226 len *= sizeof(u32);
2227
2228 alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
2229 if (!alg)
2230 return ERR_PTR(-ENOMEM);
2231
2232 reg = dsp->ops->region_to_reg(mem, pos);
2233
2234 ret = regmap_raw_read(dsp->regmap, reg, alg, len);
2235 if (ret != 0) {
2236 cs_dsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
2237 kfree(alg);
2238 return ERR_PTR(ret);
2239 }
2240
2241 return alg;
2242}
2243
2244static struct cs_dsp_alg_region *
2245 cs_dsp_find_alg_region(struct cs_dsp *dsp, int type, unsigned int id)
2246{
2247 struct cs_dsp_alg_region *alg_region;
2248
2249 list_for_each_entry(alg_region, &dsp->alg_regions, list) {
2250 if (id == alg_region->alg && type == alg_region->type)
2251 return alg_region;
2252 }
2253
2254 return NULL;
2255}
2256
2257static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp,
2258 int type, __be32 id,
2259 __be32 base)
2260{
2261 struct cs_dsp_alg_region *alg_region;
2262
2263 alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
2264 if (!alg_region)
2265 return ERR_PTR(-ENOMEM);
2266
2267 alg_region->type = type;
2268 alg_region->alg = be32_to_cpu(id);
2269 alg_region->base = be32_to_cpu(base);
2270
2271 list_add_tail(&alg_region->list, &dsp->alg_regions);
2272
2273 if (dsp->fw_ver > 0)
2274 cs_dsp_ctl_fixup_base(dsp, alg_region);
2275
2276 return alg_region;
2277}
2278
2279static void cs_dsp_free_alg_regions(struct cs_dsp *dsp)
2280{
2281 struct cs_dsp_alg_region *alg_region;
2282
2283 while (!list_empty(&dsp->alg_regions)) {
2284 alg_region = list_first_entry(&dsp->alg_regions,
2285 struct cs_dsp_alg_region,
2286 list);
2287 list_del(&alg_region->list);
2288 kfree(alg_region);
2289 }
2290}
2291
2292static void cs_dsp_parse_wmfw_id_header(struct cs_dsp *dsp,
2293 struct wmfw_id_hdr *fw, int nalgs)
2294{
2295 dsp->fw_id = be32_to_cpu(fw->id);
2296 dsp->fw_id_version = be32_to_cpu(fw->ver);
2297
2298 cs_dsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n",
2299 dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16,
2300 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2301 nalgs);
2302}
2303
2304static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp,
2305 struct wmfw_v3_id_hdr *fw, int nalgs)
2306{
2307 dsp->fw_id = be32_to_cpu(fw->id);
2308 dsp->fw_id_version = be32_to_cpu(fw->ver);
2309 dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id);
2310
2311 cs_dsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n",
2312 dsp->fw_id, dsp->fw_vendor_id,
2313 (dsp->fw_id_version & 0xff0000) >> 16,
2314 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2315 nalgs);
2316}
2317
2318static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, int nregions,
2319 const int *type, __be32 *base)
2320{
2321 struct cs_dsp_alg_region *alg_region;
2322 int i;
2323
2324 for (i = 0; i < nregions; i++) {
2325 alg_region = cs_dsp_create_region(dsp, type[i], id, base[i]);
2326 if (IS_ERR(alg_region))
2327 return PTR_ERR(alg_region);
2328 }
2329
2330 return 0;
2331}
2332
2333static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp)
2334{
2335 struct wmfw_adsp1_id_hdr adsp1_id;
2336 struct wmfw_adsp1_alg_hdr *adsp1_alg;
2337 struct cs_dsp_alg_region *alg_region;
2338 const struct cs_dsp_region *mem;
2339 unsigned int pos, len;
2340 size_t n_algs;
2341 int i, ret;
2342
2343 mem = cs_dsp_find_region(dsp, WMFW_ADSP1_DM);
2344 if (WARN_ON(!mem))
2345 return -EINVAL;
2346
2347 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
2348 sizeof(adsp1_id));
2349 if (ret != 0) {
2350 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
2351 ret);
2352 return ret;
2353 }
2354
2355 n_algs = be32_to_cpu(adsp1_id.n_algs);
2356
2357 cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs);
2358
2359 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM,
2360 adsp1_id.fw.id, adsp1_id.zm);
2361 if (IS_ERR(alg_region))
2362 return PTR_ERR(alg_region);
2363
2364 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM,
2365 adsp1_id.fw.id, adsp1_id.dm);
2366 if (IS_ERR(alg_region))
2367 return PTR_ERR(alg_region);
2368
2369 /* Calculate offset and length in DSP words */
2370 pos = sizeof(adsp1_id) / sizeof(u32);
2371 len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
2372
2373 adsp1_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
2374 if (IS_ERR(adsp1_alg))
2375 return PTR_ERR(adsp1_alg);
2376
2377 for (i = 0; i < n_algs; i++) {
2378 cs_dsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
2379 i, be32_to_cpu(adsp1_alg[i].alg.id),
2380 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
2381 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
2382 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
2383 be32_to_cpu(adsp1_alg[i].dm),
2384 be32_to_cpu(adsp1_alg[i].zm));
2385
2386 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM,
2387 adsp1_alg[i].alg.id,
2388 adsp1_alg[i].dm);
2389 if (IS_ERR(alg_region)) {
2390 ret = PTR_ERR(alg_region);
2391 goto out;
2392 }
2393 if (dsp->fw_ver == 0) {
2394 if (i + 1 < n_algs) {
2395 len = be32_to_cpu(adsp1_alg[i + 1].dm);
2396 len -= be32_to_cpu(adsp1_alg[i].dm);
2397 len *= 4;
2398 cs_dsp_create_control(dsp, alg_region, 0,
2399 len, NULL, 0, 0,
2400 WMFW_CTL_TYPE_BYTES);
2401 } else {
2402 cs_dsp_warn(dsp, "Missing length info for region DM with ID %x\n",
2403 be32_to_cpu(adsp1_alg[i].alg.id));
2404 }
2405 }
2406
2407 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM,
2408 adsp1_alg[i].alg.id,
2409 adsp1_alg[i].zm);
2410 if (IS_ERR(alg_region)) {
2411 ret = PTR_ERR(alg_region);
2412 goto out;
2413 }
2414 if (dsp->fw_ver == 0) {
2415 if (i + 1 < n_algs) {
2416 len = be32_to_cpu(adsp1_alg[i + 1].zm);
2417 len -= be32_to_cpu(adsp1_alg[i].zm);
2418 len *= 4;
2419 cs_dsp_create_control(dsp, alg_region, 0,
2420 len, NULL, 0, 0,
2421 WMFW_CTL_TYPE_BYTES);
2422 } else {
2423 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2424 be32_to_cpu(adsp1_alg[i].alg.id));
2425 }
2426 }
2427 }
2428
2429out:
2430 kfree(adsp1_alg);
2431 return ret;
2432}
2433
781 return ret;
782}
783
2434static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp)
784static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
785 const struct firmware **wmfw_firmware,
786 char **wmfw_filename,
787 const struct firmware **coeff_firmware,
788 char **coeff_filename)
2435{
789{
2436 struct wmfw_adsp2_id_hdr adsp2_id;
2437 struct wmfw_adsp2_alg_hdr *adsp2_alg;
2438 struct cs_dsp_alg_region *alg_region;
2439 const struct cs_dsp_region *mem;
2440 unsigned int pos, len;
2441 size_t n_algs;
2442 int i, ret;
790 int ret = 0;
2443
791
2444 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM);
2445 if (WARN_ON(!mem))
2446 return -EINVAL;
2447
2448 ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
2449 sizeof(adsp2_id));
2450 if (ret != 0) {
2451 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
2452 ret);
2453 return ret;
2454 }
2455
2456 n_algs = be32_to_cpu(adsp2_id.n_algs);
2457
2458 cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs);
2459
2460 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
2461 adsp2_id.fw.id, adsp2_id.xm);
2462 if (IS_ERR(alg_region))
2463 return PTR_ERR(alg_region);
2464
2465 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
2466 adsp2_id.fw.id, adsp2_id.ym);
2467 if (IS_ERR(alg_region))
2468 return PTR_ERR(alg_region);
2469
2470 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
2471 adsp2_id.fw.id, adsp2_id.zm);
2472 if (IS_ERR(alg_region))
2473 return PTR_ERR(alg_region);
2474
2475 /* Calculate offset and length in DSP words */
2476 pos = sizeof(adsp2_id) / sizeof(u32);
2477 len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
2478
2479 adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
2480 if (IS_ERR(adsp2_alg))
2481 return PTR_ERR(adsp2_alg);
2482
2483 for (i = 0; i < n_algs; i++) {
2484 cs_dsp_info(dsp,
2485 "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
2486 i, be32_to_cpu(adsp2_alg[i].alg.id),
2487 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
2488 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
2489 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
2490 be32_to_cpu(adsp2_alg[i].xm),
2491 be32_to_cpu(adsp2_alg[i].ym),
2492 be32_to_cpu(adsp2_alg[i].zm));
2493
2494 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
2495 adsp2_alg[i].alg.id,
2496 adsp2_alg[i].xm);
2497 if (IS_ERR(alg_region)) {
2498 ret = PTR_ERR(alg_region);
2499 goto out;
2500 }
2501 if (dsp->fw_ver == 0) {
2502 if (i + 1 < n_algs) {
2503 len = be32_to_cpu(adsp2_alg[i + 1].xm);
2504 len -= be32_to_cpu(adsp2_alg[i].xm);
2505 len *= 4;
2506 cs_dsp_create_control(dsp, alg_region, 0,
2507 len, NULL, 0, 0,
2508 WMFW_CTL_TYPE_BYTES);
2509 } else {
2510 cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n",
2511 be32_to_cpu(adsp2_alg[i].alg.id));
2512 }
2513 }
2514
2515 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
2516 adsp2_alg[i].alg.id,
2517 adsp2_alg[i].ym);
2518 if (IS_ERR(alg_region)) {
2519 ret = PTR_ERR(alg_region);
2520 goto out;
2521 }
2522 if (dsp->fw_ver == 0) {
2523 if (i + 1 < n_algs) {
2524 len = be32_to_cpu(adsp2_alg[i + 1].ym);
2525 len -= be32_to_cpu(adsp2_alg[i].ym);
2526 len *= 4;
2527 cs_dsp_create_control(dsp, alg_region, 0,
2528 len, NULL, 0, 0,
2529 WMFW_CTL_TYPE_BYTES);
2530 } else {
2531 cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n",
2532 be32_to_cpu(adsp2_alg[i].alg.id));
2533 }
2534 }
2535
2536 alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
2537 adsp2_alg[i].alg.id,
2538 adsp2_alg[i].zm);
2539 if (IS_ERR(alg_region)) {
2540 ret = PTR_ERR(alg_region);
2541 goto out;
2542 }
2543 if (dsp->fw_ver == 0) {
2544 if (i + 1 < n_algs) {
2545 len = be32_to_cpu(adsp2_alg[i + 1].zm);
2546 len -= be32_to_cpu(adsp2_alg[i].zm);
2547 len *= 4;
2548 cs_dsp_create_control(dsp, alg_region, 0,
2549 len, NULL, 0, 0,
2550 WMFW_CTL_TYPE_BYTES);
2551 } else {
2552 cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
2553 be32_to_cpu(adsp2_alg[i].alg.id));
2554 }
2555 }
2556 }
2557
2558out:
2559 kfree(adsp2_alg);
2560 return ret;
2561}
2562
2563static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id,
2564 __be32 xm_base, __be32 ym_base)
2565{
2566 static const int types[] = {
2567 WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED,
2568 WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED
2569 };
2570 __be32 bases[] = { xm_base, xm_base, ym_base, ym_base };
2571
2572 return cs_dsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases);
2573}
2574
2575static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp)
2576{
2577 struct wmfw_halo_id_hdr halo_id;
2578 struct wmfw_halo_alg_hdr *halo_alg;
2579 const struct cs_dsp_region *mem;
2580 unsigned int pos, len;
2581 size_t n_algs;
2582 int i, ret;
2583
2584 mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM);
2585 if (WARN_ON(!mem))
2586 return -EINVAL;
2587
2588 ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id,
2589 sizeof(halo_id));
2590 if (ret != 0) {
2591 cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
2592 ret);
2593 return ret;
2594 }
2595
2596 n_algs = be32_to_cpu(halo_id.n_algs);
2597
2598 cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs);
2599
2600 ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id,
2601 halo_id.xm_base, halo_id.ym_base);
2602 if (ret)
2603 return ret;
2604
2605 /* Calculate offset and length in DSP words */
2606 pos = sizeof(halo_id) / sizeof(u32);
2607 len = (sizeof(*halo_alg) * n_algs) / sizeof(u32);
2608
2609 halo_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
2610 if (IS_ERR(halo_alg))
2611 return PTR_ERR(halo_alg);
2612
2613 for (i = 0; i < n_algs; i++) {
2614 cs_dsp_info(dsp,
2615 "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
2616 i, be32_to_cpu(halo_alg[i].alg.id),
2617 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
2618 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
2619 be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
2620 be32_to_cpu(halo_alg[i].xm_base),
2621 be32_to_cpu(halo_alg[i].ym_base));
2622
2623 ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id,
2624 halo_alg[i].xm_base,
2625 halo_alg[i].ym_base);
2626 if (ret)
2627 goto out;
2628 }
2629
2630out:
2631 kfree(halo_alg);
2632 return ret;
2633}
2634
2635static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware,
2636 const char *file)
2637{
2638 LIST_HEAD(buf_list);
2639 struct regmap *regmap = dsp->regmap;
2640 struct wmfw_coeff_hdr *hdr;
2641 struct wmfw_coeff_item *blk;
2642 const struct cs_dsp_region *mem;
2643 struct cs_dsp_alg_region *alg_region;
2644 const char *region_name;
2645 int ret, pos, blocks, type, offset, reg;
2646 struct cs_dsp_buf *buf;
2647
2648 if (!firmware)
2649 return 0;
2650
2651 ret = -EINVAL;
2652
2653 if (sizeof(*hdr) >= firmware->size) {
2654 cs_dsp_err(dsp, "%s: coefficient file too short, %zu bytes\n",
2655 file, firmware->size);
2656 goto out_fw;
2657 }
2658
2659 hdr = (void *)&firmware->data[0];
2660 if (memcmp(hdr->magic, "WMDR", 4) != 0) {
2661 cs_dsp_err(dsp, "%s: invalid coefficient magic\n", file);
2662 goto out_fw;
2663 }
2664
2665 switch (be32_to_cpu(hdr->rev) & 0xff) {
2666 case 1:
2667 break;
2668 default:
2669 cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
2670 file, be32_to_cpu(hdr->rev) & 0xff);
2671 ret = -EINVAL;
2672 goto out_fw;
2673 }
2674
2675 cs_dsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
2676 (le32_to_cpu(hdr->ver) >> 16) & 0xff,
2677 (le32_to_cpu(hdr->ver) >> 8) & 0xff,
2678 le32_to_cpu(hdr->ver) & 0xff);
2679
2680 pos = le32_to_cpu(hdr->len);
2681
2682 blocks = 0;
2683 while (pos < firmware->size &&
2684 sizeof(*blk) < firmware->size - pos) {
2685 blk = (void *)(&firmware->data[pos]);
2686
2687 type = le16_to_cpu(blk->type);
2688 offset = le16_to_cpu(blk->offset);
2689
2690 cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
2691 file, blocks, le32_to_cpu(blk->id),
2692 (le32_to_cpu(blk->ver) >> 16) & 0xff,
2693 (le32_to_cpu(blk->ver) >> 8) & 0xff,
2694 le32_to_cpu(blk->ver) & 0xff);
2695 cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
2696 file, blocks, le32_to_cpu(blk->len), offset, type);
2697
2698 reg = 0;
2699 region_name = "Unknown";
2700 switch (type) {
2701 case (WMFW_NAME_TEXT << 8):
2702 case (WMFW_INFO_TEXT << 8):
2703 case (WMFW_METADATA << 8):
2704 break;
2705 case (WMFW_ABSOLUTE << 8):
2706 /*
2707 * Old files may use this for global
2708 * coefficients.
2709 */
2710 if (le32_to_cpu(blk->id) == dsp->fw_id &&
2711 offset == 0) {
2712 region_name = "global coefficients";
2713 mem = cs_dsp_find_region(dsp, type);
2714 if (!mem) {
2715 cs_dsp_err(dsp, "No ZM\n");
2716 break;
2717 }
2718 reg = dsp->ops->region_to_reg(mem, 0);
2719
2720 } else {
2721 region_name = "register";
2722 reg = offset;
2723 }
2724 break;
2725
2726 case WMFW_ADSP1_DM:
2727 case WMFW_ADSP1_ZM:
2728 case WMFW_ADSP2_XM:
2729 case WMFW_ADSP2_YM:
2730 case WMFW_HALO_XM_PACKED:
2731 case WMFW_HALO_YM_PACKED:
2732 case WMFW_HALO_PM_PACKED:
2733 cs_dsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
2734 file, blocks, le32_to_cpu(blk->len),
2735 type, le32_to_cpu(blk->id));
2736
2737 mem = cs_dsp_find_region(dsp, type);
2738 if (!mem) {
2739 cs_dsp_err(dsp, "No base for region %x\n", type);
2740 break;
2741 }
2742
2743 alg_region = cs_dsp_find_alg_region(dsp, type,
2744 le32_to_cpu(blk->id));
2745 if (alg_region) {
2746 reg = alg_region->base;
2747 reg = dsp->ops->region_to_reg(mem, reg);
2748 reg += offset;
2749 } else {
2750 cs_dsp_err(dsp, "No %x for algorithm %x\n",
2751 type, le32_to_cpu(blk->id));
2752 }
2753 break;
2754
2755 default:
2756 cs_dsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
2757 file, blocks, type, pos);
2758 break;
2759 }
2760
2761 if (reg) {
2762 if (le32_to_cpu(blk->len) >
2763 firmware->size - pos - sizeof(*blk)) {
2764 cs_dsp_err(dsp,
2765 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2766 file, blocks, region_name,
2767 le32_to_cpu(blk->len),
2768 firmware->size);
2769 ret = -EINVAL;
2770 goto out_fw;
2771 }
2772
2773 buf = cs_dsp_buf_alloc(blk->data,
2774 le32_to_cpu(blk->len),
2775 &buf_list);
2776 if (!buf) {
2777 cs_dsp_err(dsp, "Out of memory\n");
2778 ret = -ENOMEM;
2779 goto out_fw;
2780 }
2781
2782 cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
2783 file, blocks, le32_to_cpu(blk->len),
2784 reg);
2785 ret = regmap_raw_write_async(regmap, reg, buf->buf,
2786 le32_to_cpu(blk->len));
2787 if (ret != 0) {
2788 cs_dsp_err(dsp,
2789 "%s.%d: Failed to write to %x in %s: %d\n",
2790 file, blocks, reg, region_name, ret);
2791 }
2792 }
2793
2794 pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
2795 blocks++;
2796 }
2797
2798 ret = regmap_async_complete(regmap);
792 ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, "wmfw");
2799 if (ret != 0)
793 if (ret != 0)
2800 cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
2801
2802 if (pos > firmware->size)
2803 cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
2804 file, blocks, pos - firmware->size);
2805
2806 cs_dsp_debugfs_save_binname(dsp, file);
2807
2808out_fw:
2809 regmap_async_complete(regmap);
2810 cs_dsp_buf_free(&buf_list);
2811 return ret;
2812}
2813
2814static int cs_dsp_create_name(struct cs_dsp *dsp)
2815{
2816 if (!dsp->name) {
2817 dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
2818 dsp->num);
2819 if (!dsp->name)
2820 return -ENOMEM;
2821 }
2822
2823 return 0;
2824}
2825
2826static int cs_dsp_common_init(struct cs_dsp *dsp)
2827{
2828 int ret;
2829
2830 ret = cs_dsp_create_name(dsp);
2831 if (ret)
2832 return ret;
2833
794 return ret;
795
2834 INIT_LIST_HEAD(&dsp->alg_regions);
2835 INIT_LIST_HEAD(&dsp->ctl_list);
796 wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, "bin");
2836
797
2837 mutex_init(&dsp->pwr_lock);
2838
2839 return 0;
2840}
2841
2842static int wm_adsp_common_init(struct wm_adsp *dsp)
2843{
2844 char *p;
2845
2846 INIT_LIST_HEAD(&dsp->compr_list);

--- 7 unchanged lines hidden (view full) ---

2854 dsp->fwf_name = p;
2855 for (; *p != 0; ++p)
2856 *p = tolower(*p);
2857 }
2858
2859 return 0;
2860}
2861
798 return 0;
799}
800
801static int wm_adsp_common_init(struct wm_adsp *dsp)
802{
803 char *p;
804
805 INIT_LIST_HEAD(&dsp->compr_list);

--- 7 unchanged lines hidden (view full) ---

813 dsp->fwf_name = p;
814 for (; *p != 0; ++p)
815 *p = tolower(*p);
816 }
817
818 return 0;
819}
820
2862static int cs_dsp_adsp1_init(struct cs_dsp *dsp)
2863{
2864 dsp->ops = &cs_dsp_adsp1_ops;
2865
2866 return cs_dsp_common_init(dsp);
2867}
2868
2869int wm_adsp1_init(struct wm_adsp *dsp)
2870{
2871 int ret;
2872
2873 dsp->cs_dsp.client_ops = &wm_adsp1_client_ops;
2874
2875 ret = cs_dsp_adsp1_init(&dsp->cs_dsp);
2876 if (ret)
2877 return ret;
2878
2879 return wm_adsp_common_init(dsp);
2880}
2881EXPORT_SYMBOL_GPL(wm_adsp1_init);
2882
821int wm_adsp1_init(struct wm_adsp *dsp)
822{
823 int ret;
824
825 dsp->cs_dsp.client_ops = &wm_adsp1_client_ops;
826
827 ret = cs_dsp_adsp1_init(&dsp->cs_dsp);
828 if (ret)
829 return ret;
830
831 return wm_adsp_common_init(dsp);
832}
833EXPORT_SYMBOL_GPL(wm_adsp1_init);
834
2883static int cs_dsp_adsp1_power_up(struct cs_dsp *dsp,
2884 const struct firmware *wmfw_firmware, char *wmfw_filename,
2885 const struct firmware *coeff_firmware, char *coeff_filename,
2886 const char *fw_name)
2887{
2888 unsigned int val;
2889 int ret;
2890
2891 mutex_lock(&dsp->pwr_lock);
2892
2893 dsp->fw_name = fw_name;
2894
2895 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2896 ADSP1_SYS_ENA, ADSP1_SYS_ENA);
2897
2898 /*
2899 * For simplicity set the DSP clock rate to be the
2900 * SYSCLK rate rather than making it configurable.
2901 */
2902 if (dsp->sysclk_reg) {
2903 ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
2904 if (ret != 0) {
2905 cs_dsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
2906 goto err_mutex;
2907 }
2908
2909 val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
2910
2911 ret = regmap_update_bits(dsp->regmap,
2912 dsp->base + ADSP1_CONTROL_31,
2913 ADSP1_CLK_SEL_MASK, val);
2914 if (ret != 0) {
2915 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret);
2916 goto err_mutex;
2917 }
2918 }
2919
2920 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename);
2921 if (ret != 0)
2922 goto err_ena;
2923
2924 ret = cs_dsp_adsp1_setup_algs(dsp);
2925 if (ret != 0)
2926 goto err_ena;
2927
2928 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename);
2929 if (ret != 0)
2930 goto err_ena;
2931
2932 /* Initialize caches for enabled and unset controls */
2933 ret = cs_dsp_coeff_init_control_caches(dsp);
2934 if (ret != 0)
2935 goto err_ena;
2936
2937 /* Sync set controls */
2938 ret = cs_dsp_coeff_sync_controls(dsp);
2939 if (ret != 0)
2940 goto err_ena;
2941
2942 dsp->booted = true;
2943
2944 /* Start the core running */
2945 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2946 ADSP1_CORE_ENA | ADSP1_START,
2947 ADSP1_CORE_ENA | ADSP1_START);
2948
2949 dsp->running = true;
2950
2951 mutex_unlock(&dsp->pwr_lock);
2952
2953 return 0;
2954
2955err_ena:
2956 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2957 ADSP1_SYS_ENA, 0);
2958err_mutex:
2959 mutex_unlock(&dsp->pwr_lock);
2960 return ret;
2961}
2962
2963static void cs_dsp_adsp1_power_down(struct cs_dsp *dsp)
2964{
2965 struct cs_dsp_coeff_ctl *ctl;
2966
2967 mutex_lock(&dsp->pwr_lock);
2968
2969 dsp->running = false;
2970 dsp->booted = false;
2971
2972 /* Halt the core */
2973 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2974 ADSP1_CORE_ENA | ADSP1_START, 0);
2975
2976 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
2977 ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
2978
2979 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
2980 ADSP1_SYS_ENA, 0);
2981
2982 list_for_each_entry(ctl, &dsp->ctl_list, list)
2983 ctl->enabled = 0;
2984
2985 cs_dsp_free_alg_regions(dsp);
2986
2987 mutex_unlock(&dsp->pwr_lock);
2988}
2989
2990int wm_adsp1_event(struct snd_soc_dapm_widget *w,
2991 struct snd_kcontrol *kcontrol,
2992 int event)
2993{
2994 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
2995 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
2996 struct wm_adsp *dsp = &dsps[w->shift];
2997 int ret = 0;

--- 27 unchanged lines hidden (view full) ---

3025 default:
3026 break;
3027 }
3028
3029 return ret;
3030}
3031EXPORT_SYMBOL_GPL(wm_adsp1_event);
3032
835int wm_adsp1_event(struct snd_soc_dapm_widget *w,
836 struct snd_kcontrol *kcontrol,
837 int event)
838{
839 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
840 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
841 struct wm_adsp *dsp = &dsps[w->shift];
842 int ret = 0;

--- 27 unchanged lines hidden (view full) ---

870 default:
871 break;
872 }
873
874 return ret;
875}
876EXPORT_SYMBOL_GPL(wm_adsp1_event);
877
3033static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp)
3034{
3035 unsigned int val;
3036 int ret, count;
3037
3038 /* Wait for the RAM to start, should be near instantaneous */
3039 for (count = 0; count < 10; ++count) {
3040 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
3041 if (ret != 0)
3042 return ret;
3043
3044 if (val & ADSP2_RAM_RDY)
3045 break;
3046
3047 usleep_range(250, 500);
3048 }
3049
3050 if (!(val & ADSP2_RAM_RDY)) {
3051 cs_dsp_err(dsp, "Failed to start DSP RAM\n");
3052 return -EBUSY;
3053 }
3054
3055 cs_dsp_dbg(dsp, "RAM ready after %d polls\n", count);
3056
3057 return 0;
3058}
3059
3060static int cs_dsp_adsp2_enable_core(struct cs_dsp *dsp)
3061{
3062 int ret;
3063
3064 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
3065 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
3066 if (ret != 0)
3067 return ret;
3068
3069 return cs_dsp_adsp2v2_enable_core(dsp);
3070}
3071
3072static int cs_dsp_adsp2_lock(struct cs_dsp *dsp, unsigned int lock_regions)
3073{
3074 struct regmap *regmap = dsp->regmap;
3075 unsigned int code0, code1, lock_reg;
3076
3077 if (!(lock_regions & CS_ADSP2_REGION_ALL))
3078 return 0;
3079
3080 lock_regions &= CS_ADSP2_REGION_ALL;
3081 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
3082
3083 while (lock_regions) {
3084 code0 = code1 = 0;
3085 if (lock_regions & BIT(0)) {
3086 code0 = ADSP2_LOCK_CODE_0;
3087 code1 = ADSP2_LOCK_CODE_1;
3088 }
3089 if (lock_regions & BIT(1)) {
3090 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
3091 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
3092 }
3093 regmap_write(regmap, lock_reg, code0);
3094 regmap_write(regmap, lock_reg, code1);
3095 lock_regions >>= 2;
3096 lock_reg += 2;
3097 }
3098
3099 return 0;
3100}
3101
3102static int cs_dsp_adsp2_enable_memory(struct cs_dsp *dsp)
3103{
3104 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3105 ADSP2_MEM_ENA, ADSP2_MEM_ENA);
3106}
3107
3108static void cs_dsp_adsp2_disable_memory(struct cs_dsp *dsp)
3109{
3110 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3111 ADSP2_MEM_ENA, 0);
3112}
3113
3114static void cs_dsp_adsp2_disable_core(struct cs_dsp *dsp)
3115{
3116 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
3117 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
3118 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
3119
3120 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3121 ADSP2_SYS_ENA, 0);
3122}
3123
3124static void cs_dsp_adsp2v2_disable_core(struct cs_dsp *dsp)
3125{
3126 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
3127 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
3128 regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
3129}
3130
3131static int cs_dsp_halo_configure_mpu(struct cs_dsp *dsp, unsigned int lock_regions)
3132{
3133 struct reg_sequence config[] = {
3134 { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 },
3135 { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA },
3136 { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF },
3137 { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF },
3138 { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions },
3139 { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions },
3140 { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions },
3141 { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF },
3142 { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF },
3143 { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions },
3144 { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions },
3145 { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions },
3146 { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF },
3147 { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF },
3148 { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions },
3149 { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions },
3150 { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions },
3151 { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF },
3152 { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF },
3153 { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions },
3154 { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions },
3155 { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions },
3156 { dsp->base + HALO_MPU_LOCK_CONFIG, 0 },
3157 };
3158
3159 return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config));
3160}
3161
3162static int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq)
3163{
3164 int ret;
3165
3166 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING,
3167 ADSP2_CLK_SEL_MASK,
3168 freq << ADSP2_CLK_SEL_SHIFT);
3169 if (ret)
3170 cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret);
3171
3172 return ret;
3173}
3174
3175int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
3176{
3177 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3178 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3179 struct wm_adsp *dsp = &dsps[w->shift];
3180
3181 return cs_dsp_set_dspclk(&dsp->cs_dsp, freq);
3182}

--- 37 unchanged lines hidden (view full) ---

3220 snd_soc_dapm_sync(dapm);
3221
3222 flush_work(&dsp->boot_work);
3223
3224 return 0;
3225}
3226EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
3227
878int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
879{
880 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
881 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
882 struct wm_adsp *dsp = &dsps[w->shift];
883
884 return cs_dsp_set_dspclk(&dsp->cs_dsp, freq);
885}

--- 37 unchanged lines hidden (view full) ---

923 snd_soc_dapm_sync(dapm);
924
925 flush_work(&dsp->boot_work);
926
927 return 0;
928}
929EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
930
3228static void cs_dsp_stop_watchdog(struct cs_dsp *dsp)
3229{
3230 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
3231 ADSP2_WDT_ENA_MASK, 0);
3232}
3233
3234static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp)
3235{
3236 regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL,
3237 HALO_WDT_EN_MASK, 0);
3238}
3239
3240static int cs_dsp_power_up(struct cs_dsp *dsp,
3241 const struct firmware *wmfw_firmware, char *wmfw_filename,
3242 const struct firmware *coeff_firmware, char *coeff_filename,
3243 const char *fw_name)
3244{
3245 int ret;
3246
3247 mutex_lock(&dsp->pwr_lock);
3248
3249 dsp->fw_name = fw_name;
3250
3251 if (dsp->ops->enable_memory) {
3252 ret = dsp->ops->enable_memory(dsp);
3253 if (ret != 0)
3254 goto err_mutex;
3255 }
3256
3257 if (dsp->ops->enable_core) {
3258 ret = dsp->ops->enable_core(dsp);
3259 if (ret != 0)
3260 goto err_mem;
3261 }
3262
3263 ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename);
3264 if (ret != 0)
3265 goto err_ena;
3266
3267 ret = dsp->ops->setup_algs(dsp);
3268 if (ret != 0)
3269 goto err_ena;
3270
3271 ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename);
3272 if (ret != 0)
3273 goto err_ena;
3274
3275 /* Initialize caches for enabled and unset controls */
3276 ret = cs_dsp_coeff_init_control_caches(dsp);
3277 if (ret != 0)
3278 goto err_ena;
3279
3280 if (dsp->ops->disable_core)
3281 dsp->ops->disable_core(dsp);
3282
3283 dsp->booted = true;
3284
3285 mutex_unlock(&dsp->pwr_lock);
3286
3287 return 0;
3288err_ena:
3289 if (dsp->ops->disable_core)
3290 dsp->ops->disable_core(dsp);
3291err_mem:
3292 if (dsp->ops->disable_memory)
3293 dsp->ops->disable_memory(dsp);
3294err_mutex:
3295 mutex_unlock(&dsp->pwr_lock);
3296
3297 return ret;
3298}
3299
3300static void cs_dsp_power_down(struct cs_dsp *dsp)
3301{
3302 struct cs_dsp_coeff_ctl *ctl;
3303
3304 mutex_lock(&dsp->pwr_lock);
3305
3306 cs_dsp_debugfs_clear(dsp);
3307
3308 dsp->fw_id = 0;
3309 dsp->fw_id_version = 0;
3310
3311 dsp->booted = false;
3312
3313 if (dsp->ops->disable_memory)
3314 dsp->ops->disable_memory(dsp);
3315
3316 list_for_each_entry(ctl, &dsp->ctl_list, list)
3317 ctl->enabled = 0;
3318
3319 cs_dsp_free_alg_regions(dsp);
3320
3321 mutex_unlock(&dsp->pwr_lock);
3322
3323 cs_dsp_dbg(dsp, "Shutdown complete\n");
3324}
3325
3326static void wm_adsp_boot_work(struct work_struct *work)
3327{
3328 struct wm_adsp *dsp = container_of(work,
3329 struct wm_adsp,
3330 boot_work);
3331 int ret = 0;
3332 char *wmfw_filename = NULL;
3333 const struct firmware *wmfw_firmware = NULL;

--- 33 unchanged lines hidden (view full) ---

3367 default:
3368 break;
3369 }
3370
3371 return 0;
3372}
3373EXPORT_SYMBOL_GPL(wm_adsp_early_event);
3374
931static void wm_adsp_boot_work(struct work_struct *work)
932{
933 struct wm_adsp *dsp = container_of(work,
934 struct wm_adsp,
935 boot_work);
936 int ret = 0;
937 char *wmfw_filename = NULL;
938 const struct firmware *wmfw_firmware = NULL;

--- 33 unchanged lines hidden (view full) ---

972 default:
973 break;
974 }
975
976 return 0;
977}
978EXPORT_SYMBOL_GPL(wm_adsp_early_event);
979
3375static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp)
3376{
3377 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3378 ADSP2_CORE_ENA | ADSP2_START,
3379 ADSP2_CORE_ENA | ADSP2_START);
3380}
3381
3382static void cs_dsp_adsp2_stop_core(struct cs_dsp *dsp)
3383{
3384 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3385 ADSP2_CORE_ENA | ADSP2_START, 0);
3386}
3387
3388static int wm_adsp_event_post_run(struct cs_dsp *cs_dsp)
3389{
3390 struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
3391
3392 if (wm_adsp_fw[dsp->fw].num_caps != 0)
3393 return wm_adsp_buffer_init(dsp);
3394
3395 return 0;

--- 4 unchanged lines hidden (view full) ---

3400 struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
3401
3402 if (wm_adsp_fw[dsp->fw].num_caps != 0)
3403 wm_adsp_buffer_free(dsp);
3404
3405 dsp->fatal_error = false;
3406}
3407
980static int wm_adsp_event_post_run(struct cs_dsp *cs_dsp)
981{
982 struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
983
984 if (wm_adsp_fw[dsp->fw].num_caps != 0)
985 return wm_adsp_buffer_init(dsp);
986
987 return 0;

--- 4 unchanged lines hidden (view full) ---

992 struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
993
994 if (wm_adsp_fw[dsp->fw].num_caps != 0)
995 wm_adsp_buffer_free(dsp);
996
997 dsp->fatal_error = false;
998}
999
3408static int cs_dsp_run(struct cs_dsp *dsp)
3409{
3410 int ret;
3411
3412 mutex_lock(&dsp->pwr_lock);
3413
3414 if (!dsp->booted) {
3415 ret = -EIO;
3416 goto err;
3417 }
3418
3419 if (dsp->ops->enable_core) {
3420 ret = dsp->ops->enable_core(dsp);
3421 if (ret != 0)
3422 goto err;
3423 }
3424
3425 /* Sync set controls */
3426 ret = cs_dsp_coeff_sync_controls(dsp);
3427 if (ret != 0)
3428 goto err;
3429
3430 if (dsp->ops->lock_memory) {
3431 ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
3432 if (ret != 0) {
3433 cs_dsp_err(dsp, "Error configuring MPU: %d\n", ret);
3434 goto err;
3435 }
3436 }
3437
3438 if (dsp->ops->start_core) {
3439 ret = dsp->ops->start_core(dsp);
3440 if (ret != 0)
3441 goto err;
3442 }
3443
3444 dsp->running = true;
3445
3446 if (dsp->client_ops->post_run) {
3447 ret = dsp->client_ops->post_run(dsp);
3448 if (ret)
3449 goto err;
3450 }
3451
3452 mutex_unlock(&dsp->pwr_lock);
3453
3454 return 0;
3455
3456err:
3457 if (dsp->ops->stop_core)
3458 dsp->ops->stop_core(dsp);
3459 if (dsp->ops->disable_core)
3460 dsp->ops->disable_core(dsp);
3461 mutex_unlock(&dsp->pwr_lock);
3462
3463 return ret;
3464}
3465
3466static void cs_dsp_stop(struct cs_dsp *dsp)
3467{
3468 /* Tell the firmware to cleanup */
3469 cs_dsp_signal_event_controls(dsp, CS_DSP_FW_EVENT_SHUTDOWN);
3470
3471 if (dsp->ops->stop_watchdog)
3472 dsp->ops->stop_watchdog(dsp);
3473
3474 /* Log firmware state, it can be useful for analysis */
3475 if (dsp->ops->show_fw_status)
3476 dsp->ops->show_fw_status(dsp);
3477
3478 mutex_lock(&dsp->pwr_lock);
3479
3480 dsp->running = false;
3481
3482 if (dsp->ops->stop_core)
3483 dsp->ops->stop_core(dsp);
3484 if (dsp->ops->disable_core)
3485 dsp->ops->disable_core(dsp);
3486
3487 if (dsp->client_ops->post_stop)
3488 dsp->client_ops->post_stop(dsp);
3489
3490 mutex_unlock(&dsp->pwr_lock);
3491
3492 cs_dsp_dbg(dsp, "Execution stopped\n");
3493}
3494
3495int wm_adsp_event(struct snd_soc_dapm_widget *w,
3496 struct snd_kcontrol *kcontrol, int event)
3497{
3498 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3499 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3500 struct wm_adsp *dsp = &dsps[w->shift];
3501 int ret = 0;
3502

--- 8 unchanged lines hidden (view full) ---

3511 default:
3512 break;
3513 }
3514
3515 return ret;
3516}
3517EXPORT_SYMBOL_GPL(wm_adsp_event);
3518
1000int wm_adsp_event(struct snd_soc_dapm_widget *w,
1001 struct snd_kcontrol *kcontrol, int event)
1002{
1003 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
1004 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
1005 struct wm_adsp *dsp = &dsps[w->shift];
1006 int ret = 0;
1007

--- 8 unchanged lines hidden (view full) ---

1016 default:
1017 break;
1018 }
1019
1020 return ret;
1021}
1022EXPORT_SYMBOL_GPL(wm_adsp_event);
1023
3519static int cs_dsp_halo_start_core(struct cs_dsp *dsp)
3520{
3521 return regmap_update_bits(dsp->regmap,
3522 dsp->base + HALO_CCM_CORE_CONTROL,
3523 HALO_CORE_RESET | HALO_CORE_EN,
3524 HALO_CORE_RESET | HALO_CORE_EN);
3525}
3526
3527static void cs_dsp_halo_stop_core(struct cs_dsp *dsp)
3528{
3529 regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
3530 HALO_CORE_EN, 0);
3531
3532 /* reset halo core with CORE_SOFT_RESET */
3533 regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
3534 HALO_CORE_SOFT_RESET_MASK, 1);
3535}
3536
3537int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
3538{
3539 char preload[32];
3540
3541 snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
3542 snd_soc_component_disable_pin(component, preload);
3543
3544 cs_dsp_init_debugfs(&dsp->cs_dsp, component->debugfs_root);

--- 7 unchanged lines hidden (view full) ---

3552int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
3553{
3554 cs_dsp_cleanup_debugfs(&dsp->cs_dsp);
3555
3556 return 0;
3557}
3558EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
3559
1024int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
1025{
1026 char preload[32];
1027
1028 snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
1029 snd_soc_component_disable_pin(component, preload);
1030
1031 cs_dsp_init_debugfs(&dsp->cs_dsp, component->debugfs_root);

--- 7 unchanged lines hidden (view full) ---

1039int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
1040{
1041 cs_dsp_cleanup_debugfs(&dsp->cs_dsp);
1042
1043 return 0;
1044}
1045EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
1046
3560static int cs_dsp_adsp2_init(struct cs_dsp *dsp)
3561{
3562 int ret;
3563
3564 switch (dsp->rev) {
3565 case 0:
3566 /*
3567 * Disable the DSP memory by default when in reset for a small
3568 * power saving.
3569 */
3570 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3571 ADSP2_MEM_ENA, 0);
3572 if (ret) {
3573 cs_dsp_err(dsp,
3574 "Failed to clear memory retention: %d\n", ret);
3575 return ret;
3576 }
3577
3578 dsp->ops = &cs_dsp_adsp2_ops[0];
3579 break;
3580 case 1:
3581 dsp->ops = &cs_dsp_adsp2_ops[1];
3582 break;
3583 default:
3584 dsp->ops = &cs_dsp_adsp2_ops[2];
3585 break;
3586 }
3587
3588 return cs_dsp_common_init(dsp);
3589}
3590
3591int wm_adsp2_init(struct wm_adsp *dsp)
3592{
3593 int ret;
3594
3595 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3596
3597 dsp->sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr);
3598 dsp->cs_dsp.client_ops = &wm_adsp2_client_ops;
3599
3600 ret = cs_dsp_adsp2_init(&dsp->cs_dsp);
3601 if (ret)
3602 return ret;
3603
3604 return wm_adsp_common_init(dsp);
3605}
3606EXPORT_SYMBOL_GPL(wm_adsp2_init);
3607
1047int wm_adsp2_init(struct wm_adsp *dsp)
1048{
1049 int ret;
1050
1051 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
1052
1053 dsp->sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr);
1054 dsp->cs_dsp.client_ops = &wm_adsp2_client_ops;
1055
1056 ret = cs_dsp_adsp2_init(&dsp->cs_dsp);
1057 if (ret)
1058 return ret;
1059
1060 return wm_adsp_common_init(dsp);
1061}
1062EXPORT_SYMBOL_GPL(wm_adsp2_init);
1063
3608static int cs_dsp_halo_init(struct cs_dsp *dsp)
3609{
3610 dsp->ops = &cs_dsp_halo_ops;
3611
3612 return cs_dsp_common_init(dsp);
3613}
3614
3615int wm_halo_init(struct wm_adsp *dsp)
3616{
3617 int ret;
3618
3619 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3620
3621 dsp->sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr);
3622 dsp->cs_dsp.client_ops = &wm_adsp2_client_ops;
3623
3624 ret = cs_dsp_halo_init(&dsp->cs_dsp);
3625 if (ret)
3626 return ret;
3627
3628 return wm_adsp_common_init(dsp);
3629}
3630EXPORT_SYMBOL_GPL(wm_halo_init);
3631
1064int wm_halo_init(struct wm_adsp *dsp)
1065{
1066 int ret;
1067
1068 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
1069
1070 dsp->sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr);
1071 dsp->cs_dsp.client_ops = &wm_adsp2_client_ops;
1072
1073 ret = cs_dsp_halo_init(&dsp->cs_dsp);
1074 if (ret)
1075 return ret;
1076
1077 return wm_adsp_common_init(dsp);
1078}
1079EXPORT_SYMBOL_GPL(wm_halo_init);
1080
3632static void cs_dsp_remove(struct cs_dsp *dsp)
3633{
3634 struct cs_dsp_coeff_ctl *ctl;
3635
3636 while (!list_empty(&dsp->ctl_list)) {
3637 ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
3638
3639 if (dsp->client_ops->control_remove)
3640 dsp->client_ops->control_remove(ctl);
3641
3642 list_del(&ctl->list);
3643 cs_dsp_free_ctl_blk(ctl);
3644 }
3645}
3646
3647void wm_adsp2_remove(struct wm_adsp *dsp)
3648{
3649 cs_dsp_remove(&dsp->cs_dsp);
3650}
3651EXPORT_SYMBOL_GPL(wm_adsp2_remove);
3652
3653static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
3654{

--- 213 unchanged lines hidden (view full) ---

3868 caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
3869 caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
3870 }
3871
3872 return 0;
3873}
3874EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
3875
1081void wm_adsp2_remove(struct wm_adsp *dsp)
1082{
1083 cs_dsp_remove(&dsp->cs_dsp);
1084}
1085EXPORT_SYMBOL_GPL(wm_adsp2_remove);
1086
1087static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
1088{

--- 213 unchanged lines hidden (view full) ---

1302 caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
1303 caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
1304 }
1305
1306 return 0;
1307}
1308EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
1309
3876static int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type,
3877 unsigned int mem_addr,
3878 unsigned int num_words, __be32 *data)
3879{
3880 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
3881 unsigned int reg;
3882 int ret;
3883
3884 if (!mem)
3885 return -EINVAL;
3886
3887 reg = dsp->ops->region_to_reg(mem, mem_addr);
3888
3889 ret = regmap_raw_read(dsp->regmap, reg, data,
3890 sizeof(*data) * num_words);
3891 if (ret < 0)
3892 return ret;
3893
3894 return 0;
3895}
3896
3897static int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type,
3898 unsigned int mem_addr, u32 *data)
3899{
3900 __be32 raw;
3901 int ret;
3902
3903 ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw);
3904 if (ret < 0)
3905 return ret;
3906
3907 *data = be32_to_cpu(raw) & 0x00ffffffu;
3908
3909 return 0;
3910}
3911
3912static int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type,
3913 unsigned int mem_addr, u32 data)
3914{
3915 struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type);
3916 __be32 val = cpu_to_be32(data & 0x00ffffffu);
3917 unsigned int reg;
3918
3919 if (!mem)
3920 return -EINVAL;
3921
3922 reg = dsp->ops->region_to_reg(mem, mem_addr);
3923
3924 return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
3925}
3926
3927static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
3928 unsigned int field_offset, u32 *data)
3929{
3930 return cs_dsp_read_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type,
3931 buf->host_buf_ptr + field_offset, data);
3932}
3933
3934static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
3935 unsigned int field_offset, u32 data)
3936{
3937 return cs_dsp_write_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type,
3938 buf->host_buf_ptr + field_offset,
3939 data);
3940}
3941
1310static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
1311 unsigned int field_offset, u32 *data)
1312{
1313 return cs_dsp_read_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type,
1314 buf->host_buf_ptr + field_offset, data);
1315}
1316
1317static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
1318 unsigned int field_offset, u32 data)
1319{
1320 return cs_dsp_write_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type,
1321 buf->host_buf_ptr + field_offset,
1322 data);
1323}
1324
3942static void cs_dsp_remove_padding(u32 *buf, int nwords)
3943{
3944 const __be32 *pack_in = (__be32 *)buf;
3945 u8 *pack_out = (u8 *)buf;
3946 int i;
3947
3948 /*
3949 * DSP words from the register map have pad bytes and the data bytes
3950 * are in swapped order. This swaps back to the original little-endian
3951 * order and strips the pad bytes.
3952 */
3953 for (i = 0; i < nwords; i++) {
3954 u32 word = be32_to_cpu(*pack_in++);
3955 *pack_out++ = (u8)word;
3956 *pack_out++ = (u8)(word >> 8);
3957 *pack_out++ = (u8)(word >> 16);
3958 }
3959}
3960
3961static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
3962{
3963 const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
3964 struct wm_adsp_buffer_region *region;
3965 u32 offset = 0;
3966 int i, ret;
3967
3968 buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),

--- 594 unchanged lines hidden (view full) ---

4563 dsp->fatal_error = true;
4564
4565 list_for_each_entry(compr, &dsp->compr_list, list) {
4566 if (compr->stream)
4567 snd_compr_fragment_elapsed(compr->stream);
4568 }
4569}
4570
1325static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
1326{
1327 const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
1328 struct wm_adsp_buffer_region *region;
1329 u32 offset = 0;
1330 int i, ret;
1331
1332 buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),

--- 594 unchanged lines hidden (view full) ---

1927 dsp->fatal_error = true;
1928
1929 list_for_each_entry(compr, &dsp->compr_list, list) {
1930 if (compr->stream)
1931 snd_compr_fragment_elapsed(compr->stream);
1932 }
1933}
1934
4571static void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp)
4572{
4573 unsigned int val;
4574 struct regmap *regmap = dsp->regmap;
4575 int ret = 0;
4576
4577 mutex_lock(&dsp->pwr_lock);
4578
4579 ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
4580 if (ret) {
4581 cs_dsp_err(dsp,
4582 "Failed to read Region Lock Ctrl register: %d\n", ret);
4583 goto error;
4584 }
4585
4586 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
4587 cs_dsp_err(dsp, "watchdog timeout error\n");
4588 dsp->ops->stop_watchdog(dsp);
4589 if (dsp->client_ops->watchdog_expired)
4590 dsp->client_ops->watchdog_expired(dsp);
4591 }
4592
4593 if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
4594 if (val & ADSP2_ADDR_ERR_MASK)
4595 cs_dsp_err(dsp, "bus error: address error\n");
4596 else
4597 cs_dsp_err(dsp, "bus error: region lock error\n");
4598
4599 ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
4600 if (ret) {
4601 cs_dsp_err(dsp,
4602 "Failed to read Bus Err Addr register: %d\n",
4603 ret);
4604 goto error;
4605 }
4606
4607 cs_dsp_err(dsp, "bus error address = 0x%x\n",
4608 val & ADSP2_BUS_ERR_ADDR_MASK);
4609
4610 ret = regmap_read(regmap,
4611 dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
4612 &val);
4613 if (ret) {
4614 cs_dsp_err(dsp,
4615 "Failed to read Pmem Xmem Err Addr register: %d\n",
4616 ret);
4617 goto error;
4618 }
4619
4620 cs_dsp_err(dsp, "xmem error address = 0x%x\n",
4621 val & ADSP2_XMEM_ERR_ADDR_MASK);
4622 cs_dsp_err(dsp, "pmem error address = 0x%x\n",
4623 (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
4624 ADSP2_PMEM_ERR_ADDR_SHIFT);
4625 }
4626
4627 regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
4628 ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
4629
4630error:
4631 mutex_unlock(&dsp->pwr_lock);
4632}
4633
4634irqreturn_t wm_adsp2_bus_error(int irq, void *data)
4635{
4636 struct wm_adsp *dsp = (struct wm_adsp *)data;
4637
4638 cs_dsp_adsp2_bus_error(&dsp->cs_dsp);
4639
4640 return IRQ_HANDLED;
4641}
4642EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
4643
1935irqreturn_t wm_adsp2_bus_error(int irq, void *data)
1936{
1937 struct wm_adsp *dsp = (struct wm_adsp *)data;
1938
1939 cs_dsp_adsp2_bus_error(&dsp->cs_dsp);
1940
1941 return IRQ_HANDLED;
1942}
1943EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
1944
4644static void cs_dsp_halo_bus_error(struct cs_dsp *dsp)
4645{
4646 struct regmap *regmap = dsp->regmap;
4647 unsigned int fault[6];
4648 struct reg_sequence clear[] = {
4649 { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 },
4650 { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 },
4651 { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 },
4652 };
4653 int ret;
4654
4655 mutex_lock(&dsp->pwr_lock);
4656
4657 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
4658 fault);
4659 if (ret) {
4660 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
4661 goto exit_unlock;
4662 }
4663
4664 cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
4665 *fault & HALO_AHBM_FLAGS_ERR_MASK,
4666 (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
4667 HALO_AHBM_CORE_ERR_ADDR_SHIFT);
4668
4669 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
4670 fault);
4671 if (ret) {
4672 cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
4673 goto exit_unlock;
4674 }
4675
4676 cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
4677
4678 ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
4679 fault, ARRAY_SIZE(fault));
4680 if (ret) {
4681 cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
4682 goto exit_unlock;
4683 }
4684
4685 cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
4686 cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
4687 cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
4688
4689 ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
4690 if (ret)
4691 cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
4692
4693exit_unlock:
4694 mutex_unlock(&dsp->pwr_lock);
4695}
4696
4697irqreturn_t wm_halo_bus_error(int irq, void *data)
4698{
4699 struct wm_adsp *dsp = (struct wm_adsp *)data;
4700
4701 cs_dsp_halo_bus_error(&dsp->cs_dsp);
4702
4703 return IRQ_HANDLED;
4704}
4705EXPORT_SYMBOL_GPL(wm_halo_bus_error);
4706
1945irqreturn_t wm_halo_bus_error(int irq, void *data)
1946{
1947 struct wm_adsp *dsp = (struct wm_adsp *)data;
1948
1949 cs_dsp_halo_bus_error(&dsp->cs_dsp);
1950
1951 return IRQ_HANDLED;
1952}
1953EXPORT_SYMBOL_GPL(wm_halo_bus_error);
1954
4707static void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp)
4708{
4709 mutex_lock(&dsp->pwr_lock);
4710
4711 cs_dsp_warn(dsp, "WDT Expiry Fault\n");
4712
4713 dsp->ops->stop_watchdog(dsp);
4714 if (dsp->client_ops->watchdog_expired)
4715 dsp->client_ops->watchdog_expired(dsp);
4716
4717 mutex_unlock(&dsp->pwr_lock);
4718}
4719
4720irqreturn_t wm_halo_wdt_expire(int irq, void *data)
4721{
4722 struct wm_adsp *dsp = data;
4723
4724 cs_dsp_halo_wdt_expire(&dsp->cs_dsp);
4725
4726 return IRQ_HANDLED;
4727}
4728EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
4729
1955irqreturn_t wm_halo_wdt_expire(int irq, void *data)
1956{
1957 struct wm_adsp *dsp = data;
1958
1959 cs_dsp_halo_wdt_expire(&dsp->cs_dsp);
1960
1961 return IRQ_HANDLED;
1962}
1963EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
1964
4730static const struct cs_dsp_ops cs_dsp_adsp1_ops = {
4731 .validate_version = cs_dsp_validate_version,
4732 .parse_sizes = cs_dsp_adsp1_parse_sizes,
4733 .region_to_reg = cs_dsp_region_to_reg,
4734};
4735
4736static const struct cs_dsp_client_ops wm_adsp1_client_ops = {
4737 .control_add = wm_adsp_control_add,
4738 .control_remove = wm_adsp_control_remove,
4739};
4740
1965static const struct cs_dsp_client_ops wm_adsp1_client_ops = {
1966 .control_add = wm_adsp_control_add,
1967 .control_remove = wm_adsp_control_remove,
1968};
1969
4741static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = {
4742 {
4743 .parse_sizes = cs_dsp_adsp2_parse_sizes,
4744 .validate_version = cs_dsp_validate_version,
4745 .setup_algs = cs_dsp_adsp2_setup_algs,
4746 .region_to_reg = cs_dsp_region_to_reg,
4747
4748 .show_fw_status = cs_dsp_adsp2_show_fw_status,
4749
4750 .enable_memory = cs_dsp_adsp2_enable_memory,
4751 .disable_memory = cs_dsp_adsp2_disable_memory,
4752
4753 .enable_core = cs_dsp_adsp2_enable_core,
4754 .disable_core = cs_dsp_adsp2_disable_core,
4755
4756 .start_core = cs_dsp_adsp2_start_core,
4757 .stop_core = cs_dsp_adsp2_stop_core,
4758
4759 },
4760 {
4761 .parse_sizes = cs_dsp_adsp2_parse_sizes,
4762 .validate_version = cs_dsp_validate_version,
4763 .setup_algs = cs_dsp_adsp2_setup_algs,
4764 .region_to_reg = cs_dsp_region_to_reg,
4765
4766 .show_fw_status = cs_dsp_adsp2v2_show_fw_status,
4767
4768 .enable_memory = cs_dsp_adsp2_enable_memory,
4769 .disable_memory = cs_dsp_adsp2_disable_memory,
4770 .lock_memory = cs_dsp_adsp2_lock,
4771
4772 .enable_core = cs_dsp_adsp2v2_enable_core,
4773 .disable_core = cs_dsp_adsp2v2_disable_core,
4774
4775 .start_core = cs_dsp_adsp2_start_core,
4776 .stop_core = cs_dsp_adsp2_stop_core,
4777 },
4778 {
4779 .parse_sizes = cs_dsp_adsp2_parse_sizes,
4780 .validate_version = cs_dsp_validate_version,
4781 .setup_algs = cs_dsp_adsp2_setup_algs,
4782 .region_to_reg = cs_dsp_region_to_reg,
4783
4784 .show_fw_status = cs_dsp_adsp2v2_show_fw_status,
4785 .stop_watchdog = cs_dsp_stop_watchdog,
4786
4787 .enable_memory = cs_dsp_adsp2_enable_memory,
4788 .disable_memory = cs_dsp_adsp2_disable_memory,
4789 .lock_memory = cs_dsp_adsp2_lock,
4790
4791 .enable_core = cs_dsp_adsp2v2_enable_core,
4792 .disable_core = cs_dsp_adsp2v2_disable_core,
4793
4794 .start_core = cs_dsp_adsp2_start_core,
4795 .stop_core = cs_dsp_adsp2_stop_core,
4796 },
4797};
4798
4799static const struct cs_dsp_ops cs_dsp_halo_ops = {
4800 .parse_sizes = cs_dsp_adsp2_parse_sizes,
4801 .validate_version = cs_dsp_halo_validate_version,
4802 .setup_algs = cs_dsp_halo_setup_algs,
4803 .region_to_reg = cs_dsp_halo_region_to_reg,
4804
4805 .show_fw_status = cs_dsp_halo_show_fw_status,
4806 .stop_watchdog = cs_dsp_halo_stop_watchdog,
4807
4808 .lock_memory = cs_dsp_halo_configure_mpu,
4809
4810 .start_core = cs_dsp_halo_start_core,
4811 .stop_core = cs_dsp_halo_stop_core,
4812};
4813
4814static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
4815 .control_add = wm_adsp_control_add,
4816 .control_remove = wm_adsp_control_remove,
4817 .post_run = wm_adsp_event_post_run,
4818 .post_stop = wm_adsp_event_post_stop,
4819 .watchdog_expired = wm_adsp_fatal_error,
4820};
4821
4822MODULE_LICENSE("GPL v2");
1970static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
1971 .control_add = wm_adsp_control_add,
1972 .control_remove = wm_adsp_control_remove,
1973 .post_run = wm_adsp_event_post_run,
1974 .post_stop = wm_adsp_event_post_stop,
1975 .watchdog_expired = wm_adsp_fatal_error,
1976};
1977
1978MODULE_LICENSE("GPL v2");