File Index
Files and directories
Sign in
FILE

cs_dsp_mock_regmap.c

File preview with syntax highlighting.

linux-6.19.14/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c 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
 14static 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
 26static 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
 40static 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
 52static 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
 60static 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
 71static 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
 79const unsigned int cs_dsp_mock_adsp2_32bit_sysbase = 0xffe00;
 80EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_adsp2_32bit_sysbase, "FW_CS_DSP_KUNIT_TEST_UTILS");
 81
 82static 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
 87static 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
101static 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
114static 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
122const unsigned int cs_dsp_mock_adsp2_16bit_sysbase = 0x001100;
123EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_adsp2_16bit_sysbase, "FW_CS_DSP_KUNIT_TEST_UTILS");
124
125static 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
130static 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
144static 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
159static 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
170static 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
179const unsigned int cs_dsp_mock_halo_core_base = 0x2b80000;
180EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_halo_core_base, "FW_CS_DSP_KUNIT_TEST_UTILS");
181
182const unsigned int cs_dsp_mock_halo_sysinfo_base = 0x25e0000;
183EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_halo_sysinfo_base, "FW_CS_DSP_KUNIT_TEST_UTILS");
184
185static const struct regmap_access_table halo_readable = {
186	.yes_ranges = halo_readable_registers,
187	.n_yes_ranges = ARRAY_SIZE(halo_readable_registers),
188};
189
190static const struct regmap_access_table halo_writeable = {
191	.yes_ranges = halo_writeable_registers,
192	.n_yes_ranges = ARRAY_SIZE(halo_writeable_registers),
193};
194
195static 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 */
216void 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}
221EXPORT_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 */
230void 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}
238EXPORT_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 */
250void 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}
257EXPORT_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 */
266void 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}
289EXPORT_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 */
306bool 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}
318EXPORT_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 */
332int 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}
367EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_regmap_init, "FW_CS_DSP_KUNIT_TEST_UTILS");
~/ Read-only file preview.