Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
//
3
// Mock regmap for cs_dsp KUnit tests.
4
//
5
// Copyright (C) 2024 Cirrus Logic, Inc. and
6
// Cirrus Logic International Semiconductor Ltd.
7
8
#include <kunit/test.h>
9
#include <linux/firmware/cirrus/cs_dsp.h>
10
#include <linux/firmware/cirrus/cs_dsp_test_utils.h>
11
#include <linux/firmware/cirrus/wmfw.h>
12
#include <linux/regmap.h>
13
14
static int cs_dsp_mock_regmap_read(void *context, const void *reg_buf,
15
const size_t reg_size, void *val_buf,
16
size_t val_size)
17
{
18
struct cs_dsp_test *priv = context;
19
20
/* Should never get here because the regmap is cache-only */
21
KUNIT_FAIL(priv->test, "Unexpected bus read @%#x", *(u32 *)reg_buf);
22
23
return -EIO;
24
}
25
26
static int cs_dsp_mock_regmap_gather_write(void *context,
27
const void *reg_buf, size_t reg_size,
28
const void *val_buf, size_t val_size)
29
{
30
struct cs_dsp_test *priv = context;
31
32
priv->saw_bus_write = true;
33
34
/* Should never get here because the regmap is cache-only */
35
KUNIT_FAIL(priv->test, "Unexpected bus gather_write @%#x", *(u32 *)reg_buf);
36
37
return -EIO;
38
}
39
40
static int cs_dsp_mock_regmap_write(void *context, const void *val_buf, size_t val_size)
41
{
42
struct cs_dsp_test *priv = context;
43
44
priv->saw_bus_write = true;
45
46
/* Should never get here because the regmap is cache-only */
47
KUNIT_FAIL(priv->test, "Unexpected bus write @%#x", *(u32 *)val_buf);
48
49
return -EIO;
50
}
51
52
static const struct regmap_bus cs_dsp_mock_regmap_bus = {
53
.read = cs_dsp_mock_regmap_read,
54
.write = cs_dsp_mock_regmap_write,
55
.gather_write = cs_dsp_mock_regmap_gather_write,
56
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
57
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
58
};
59
60
static const struct reg_default adsp2_32bit_register_defaults[] = {
61
{ 0xffe00, 0x0000 }, /* CONTROL */
62
{ 0xffe02, 0x0000 }, /* CLOCKING */
63
{ 0xffe04, 0x0001 }, /* STATUS1: RAM_RDY=1 */
64
{ 0xffe30, 0x0000 }, /* WDMW_CONFIG_1 */
65
{ 0xffe32, 0x0000 }, /* WDMA_CONFIG_2 */
66
{ 0xffe34, 0x0000 }, /* RDMA_CONFIG_1 */
67
{ 0xffe40, 0x0000 }, /* SCRATCH_0_1 */
68
{ 0xffe42, 0x0000 }, /* SCRATCH_2_3 */
69
};
70
71
static const struct regmap_range adsp2_32bit_registers[] = {
72
regmap_reg_range(0x80000, 0x88ffe), /* PM */
73
regmap_reg_range(0xa0000, 0xa9ffe), /* XM */
74
regmap_reg_range(0xc0000, 0xc1ffe), /* YM */
75
regmap_reg_range(0xe0000, 0xe1ffe), /* ZM */
76
regmap_reg_range(0xffe00, 0xffe7c), /* CORE CTRL */
77
};
78
79
const unsigned int cs_dsp_mock_adsp2_32bit_sysbase = 0xffe00;
80
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_adsp2_32bit_sysbase, "FW_CS_DSP_KUNIT_TEST_UTILS");
81
82
static const struct regmap_access_table adsp2_32bit_rw = {
83
.yes_ranges = adsp2_32bit_registers,
84
.n_yes_ranges = ARRAY_SIZE(adsp2_32bit_registers),
85
};
86
87
static const struct regmap_config cs_dsp_mock_regmap_adsp2_32bit = {
88
.reg_bits = 32,
89
.val_bits = 32,
90
.reg_stride = 2,
91
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
92
.val_format_endian = REGMAP_ENDIAN_BIG,
93
.wr_table = &adsp2_32bit_rw,
94
.rd_table = &adsp2_32bit_rw,
95
.max_register = 0xffe7c,
96
.reg_defaults = adsp2_32bit_register_defaults,
97
.num_reg_defaults = ARRAY_SIZE(adsp2_32bit_register_defaults),
98
.cache_type = REGCACHE_MAPLE,
99
};
100
101
static const struct reg_default adsp2_16bit_register_defaults[] = {
102
{ 0x1100, 0x0000 }, /* CONTROL */
103
{ 0x1101, 0x0000 }, /* CLOCKING */
104
{ 0x1104, 0x0001 }, /* STATUS1: RAM_RDY=1 */
105
{ 0x1130, 0x0000 }, /* WDMW_CONFIG_1 */
106
{ 0x1131, 0x0000 }, /* WDMA_CONFIG_2 */
107
{ 0x1134, 0x0000 }, /* RDMA_CONFIG_1 */
108
{ 0x1140, 0x0000 }, /* SCRATCH_0 */
109
{ 0x1141, 0x0000 }, /* SCRATCH_1 */
110
{ 0x1142, 0x0000 }, /* SCRATCH_2 */
111
{ 0x1143, 0x0000 }, /* SCRATCH_3 */
112
};
113
114
static const struct regmap_range adsp2_16bit_registers[] = {
115
regmap_reg_range(0x001100, 0x001143), /* CORE CTRL */
116
regmap_reg_range(0x100000, 0x105fff), /* PM */
117
regmap_reg_range(0x180000, 0x1807ff), /* ZM */
118
regmap_reg_range(0x190000, 0x1947ff), /* XM */
119
regmap_reg_range(0x1a8000, 0x1a97ff), /* YM */
120
};
121
122
const unsigned int cs_dsp_mock_adsp2_16bit_sysbase = 0x001100;
123
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_adsp2_16bit_sysbase, "FW_CS_DSP_KUNIT_TEST_UTILS");
124
125
static const struct regmap_access_table adsp2_16bit_rw = {
126
.yes_ranges = adsp2_16bit_registers,
127
.n_yes_ranges = ARRAY_SIZE(adsp2_16bit_registers),
128
};
129
130
static const struct regmap_config cs_dsp_mock_regmap_adsp2_16bit = {
131
.reg_bits = 32,
132
.val_bits = 16,
133
.reg_stride = 1,
134
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
135
.val_format_endian = REGMAP_ENDIAN_BIG,
136
.wr_table = &adsp2_16bit_rw,
137
.rd_table = &adsp2_16bit_rw,
138
.max_register = 0x1a97ff,
139
.reg_defaults = adsp2_16bit_register_defaults,
140
.num_reg_defaults = ARRAY_SIZE(adsp2_16bit_register_defaults),
141
.cache_type = REGCACHE_MAPLE,
142
};
143
144
static const struct reg_default halo_register_defaults[] = {
145
/* CORE */
146
{ 0x2b80010, 0 }, /* HALO_CORE_SOFT_RESET */
147
{ 0x2b805c0, 0 }, /* HALO_SCRATCH1 */
148
{ 0x2b805c8, 0 }, /* HALO_SCRATCH2 */
149
{ 0x2b805d0, 0 }, /* HALO_SCRATCH3 */
150
{ 0x2b805c8, 0 }, /* HALO_SCRATCH4 */
151
{ 0x2bc1000, 0 }, /* HALO_CCM_CORE_CONTROL */
152
{ 0x2bc7000, 0 }, /* HALO_WDT_CONTROL */
153
154
/* SYSINFO */
155
{ 0x25e2040, 0 }, /* HALO_AHBM_WINDOW_DEBUG_0 */
156
{ 0x25e2044, 0 }, /* HALO_AHBM_WINDOW_DEBUG_1 */
157
};
158
159
static const struct regmap_range halo_readable_registers[] = {
160
regmap_reg_range(0x2000000, 0x2005fff), /* XM_PACKED */
161
regmap_reg_range(0x25e0000, 0x25e004f), /* SYSINFO */
162
regmap_reg_range(0x25e2000, 0x25e2047), /* SYSINFO */
163
regmap_reg_range(0x2800000, 0x2807fff), /* XM */
164
regmap_reg_range(0x2b80000, 0x2bc700b), /* CORE CTRL */
165
regmap_reg_range(0x2c00000, 0x2c047f3), /* YM_PACKED */
166
regmap_reg_range(0x3400000, 0x3405ff7), /* YM */
167
regmap_reg_range(0x3800000, 0x3804fff), /* PM_PACKED */
168
};
169
170
static const struct regmap_range halo_writeable_registers[] = {
171
regmap_reg_range(0x2000000, 0x2005fff), /* XM_PACKED */
172
regmap_reg_range(0x2800000, 0x2807fff), /* XM */
173
regmap_reg_range(0x2b80000, 0x2bc700b), /* CORE CTRL */
174
regmap_reg_range(0x2c00000, 0x2c047f3), /* YM_PACKED */
175
regmap_reg_range(0x3400000, 0x3405ff7), /* YM */
176
regmap_reg_range(0x3800000, 0x3804fff), /* PM_PACKED */
177
};
178
179
const unsigned int cs_dsp_mock_halo_core_base = 0x2b80000;
180
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_halo_core_base, "FW_CS_DSP_KUNIT_TEST_UTILS");
181
182
const unsigned int cs_dsp_mock_halo_sysinfo_base = 0x25e0000;
183
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_halo_sysinfo_base, "FW_CS_DSP_KUNIT_TEST_UTILS");
184
185
static const struct regmap_access_table halo_readable = {
186
.yes_ranges = halo_readable_registers,
187
.n_yes_ranges = ARRAY_SIZE(halo_readable_registers),
188
};
189
190
static const struct regmap_access_table halo_writeable = {
191
.yes_ranges = halo_writeable_registers,
192
.n_yes_ranges = ARRAY_SIZE(halo_writeable_registers),
193
};
194
195
static const struct regmap_config cs_dsp_mock_regmap_halo = {
196
.reg_bits = 32,
197
.val_bits = 32,
198
.reg_stride = 4,
199
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
200
.val_format_endian = REGMAP_ENDIAN_BIG,
201
.wr_table = &halo_writeable,
202
.rd_table = &halo_readable,
203
.max_register = 0x3804ffc,
204
.reg_defaults = halo_register_defaults,
205
.num_reg_defaults = ARRAY_SIZE(halo_register_defaults),
206
.cache_type = REGCACHE_MAPLE,
207
};
208
209
/**
210
* cs_dsp_mock_regmap_drop_range() - drop a range of registers from the cache.
211
*
212
* @priv: Pointer to struct cs_dsp_test object.
213
* @first_reg: Address of first register to drop.
214
* @last_reg: Address of last register to drop.
215
*/
216
void cs_dsp_mock_regmap_drop_range(struct cs_dsp_test *priv,
217
unsigned int first_reg, unsigned int last_reg)
218
{
219
regcache_drop_region(priv->dsp->regmap, first_reg, last_reg);
220
}
221
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_regmap_drop_range, "FW_CS_DSP_KUNIT_TEST_UTILS");
222
223
/**
224
* cs_dsp_mock_regmap_drop_regs() - drop a number of registers from the cache.
225
*
226
* @priv: Pointer to struct cs_dsp_test object.
227
* @first_reg: Address of first register to drop.
228
* @num_regs: Number of registers to drop.
229
*/
230
void cs_dsp_mock_regmap_drop_regs(struct cs_dsp_test *priv,
231
unsigned int first_reg, size_t num_regs)
232
{
233
int stride = regmap_get_reg_stride(priv->dsp->regmap);
234
unsigned int last = first_reg + (stride * (num_regs - 1));
235
236
cs_dsp_mock_regmap_drop_range(priv, first_reg, last);
237
}
238
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_regmap_drop_regs, "FW_CS_DSP_KUNIT_TEST_UTILS");
239
240
/**
241
* cs_dsp_mock_regmap_drop_bytes() - drop a number of bytes from the cache.
242
*
243
* @priv: Pointer to struct cs_dsp_test object.
244
* @first_reg: Address of first register to drop.
245
* @num_bytes: Number of bytes to drop from the cache. Will be rounded
246
* down to a whole number of registers. Trailing bytes that
247
* are not a multiple of the register size will not be dropped.
248
* (This is intended to help detect math errors in test code.)
249
*/
250
void cs_dsp_mock_regmap_drop_bytes(struct cs_dsp_test *priv,
251
unsigned int first_reg, size_t num_bytes)
252
{
253
size_t num_regs = num_bytes / regmap_get_val_bytes(priv->dsp->regmap);
254
255
cs_dsp_mock_regmap_drop_regs(priv, first_reg, num_regs);
256
}
257
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_regmap_drop_bytes, "FW_CS_DSP_KUNIT_TEST_UTILS");
258
259
/**
260
* cs_dsp_mock_regmap_drop_system_regs() - Drop DSP system registers from the cache.
261
*
262
* @priv: Pointer to struct cs_dsp_test object.
263
*
264
* Drops all DSP system registers from the regmap cache.
265
*/
266
void cs_dsp_mock_regmap_drop_system_regs(struct cs_dsp_test *priv)
267
{
268
switch (priv->dsp->type) {
269
case WMFW_ADSP2:
270
if (priv->dsp->base) {
271
regcache_drop_region(priv->dsp->regmap,
272
priv->dsp->base,
273
priv->dsp->base + 0x7c);
274
}
275
return;
276
case WMFW_HALO:
277
if (priv->dsp->base) {
278
regcache_drop_region(priv->dsp->regmap,
279
priv->dsp->base,
280
priv->dsp->base + 0x47000);
281
}
282
283
/* sysinfo registers are read-only so don't drop them */
284
return;
285
default:
286
return;
287
}
288
}
289
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_regmap_drop_system_regs, "FW_CS_DSP_KUNIT_TEST_UTILS");
290
291
/**
292
* cs_dsp_mock_regmap_is_dirty() - Test for dirty registers in the cache.
293
*
294
* @priv: Pointer to struct cs_dsp_test object.
295
* @drop_system_regs: If true the DSP system regs will be dropped from
296
* the cache before checking for dirty.
297
*
298
* All registers that are expected to be written must have been dropped
299
* from the cache (DSP system registers can be dropped by passing
300
* drop_system_regs == true). If any unexpected registers were written
301
* there will still be dirty entries in the cache and a cache sync will
302
* cause a write.
303
*
304
* Returns: true if there were dirty entries, false if not.
305
*/
306
bool cs_dsp_mock_regmap_is_dirty(struct cs_dsp_test *priv, bool drop_system_regs)
307
{
308
if (drop_system_regs)
309
cs_dsp_mock_regmap_drop_system_regs(priv);
310
311
priv->saw_bus_write = false;
312
regcache_cache_only(priv->dsp->regmap, false);
313
regcache_sync(priv->dsp->regmap);
314
regcache_cache_only(priv->dsp->regmap, true);
315
316
return priv->saw_bus_write;
317
}
318
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_regmap_is_dirty, "FW_CS_DSP_KUNIT_TEST_UTILS");
319
320
/**
321
* cs_dsp_mock_regmap_init() - Initialize a mock regmap.
322
*
323
* @priv: Pointer to struct cs_dsp_test object. This must have a
324
* valid pointer to a struct cs_dsp in which the type and
325
* rev fields are set to the type of DSP to be simulated.
326
*
327
* On success the priv->dsp->regmap will point to the created
328
* regmap instance.
329
*
330
* Return: zero on success, else negative error code.
331
*/
332
int cs_dsp_mock_regmap_init(struct cs_dsp_test *priv)
333
{
334
const struct regmap_config *config;
335
int ret;
336
337
switch (priv->dsp->type) {
338
case WMFW_HALO:
339
config = &cs_dsp_mock_regmap_halo;
340
break;
341
case WMFW_ADSP2:
342
if (priv->dsp->rev == 0)
343
config = &cs_dsp_mock_regmap_adsp2_16bit;
344
else
345
config = &cs_dsp_mock_regmap_adsp2_32bit;
346
break;
347
default:
348
config = NULL;
349
break;
350
}
351
352
priv->dsp->regmap = devm_regmap_init(priv->dsp->dev,
353
&cs_dsp_mock_regmap_bus,
354
priv,
355
config);
356
if (IS_ERR(priv->dsp->regmap)) {
357
ret = PTR_ERR(priv->dsp->regmap);
358
kunit_err(priv->test, "Failed to allocate register map: %d\n", ret);
359
return ret;
360
}
361
362
/* Put regmap in cache-only so it accumulates the writes done by cs_dsp */
363
regcache_cache_only(priv->dsp->regmap, true);
364
365
return 0;
366
}
367
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_regmap_init, "FW_CS_DSP_KUNIT_TEST_UTILS");
368
369