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