]> Git Repo - linux.git/blob - drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c
Linux 6.14-rc3
[linux.git] / drivers / firmware / cirrus / test / cs_dsp_mock_regmap.c
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");
This page took 0.055319 seconds and 4 git commands to generate.