1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // Mock DSP memory maps 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/math.h>
13
14 const struct cs_dsp_region cs_dsp_mock_halo_dsp1_regions[] = {
15 { .type = WMFW_HALO_PM_PACKED, .base = 0x3800000 },
16 { .type = WMFW_HALO_XM_PACKED, .base = 0x2000000 },
17 { .type = WMFW_HALO_YM_PACKED, .base = 0x2C00000 },
18 { .type = WMFW_ADSP2_XM, .base = 0x2800000 },
19 { .type = WMFW_ADSP2_YM, .base = 0x3400000 },
20 };
21 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_halo_dsp1_regions, "FW_CS_DSP_KUNIT_TEST_UTILS");
22
23 /* List of sizes in bytes, for each entry above */
24 const unsigned int cs_dsp_mock_halo_dsp1_region_sizes[] = {
25 0x5000, /* PM_PACKED */
26 0x6000, /* XM_PACKED */
27 0x47F4, /* YM_PACKED */
28 0x8000, /* XM_UNPACKED_24 */
29 0x5FF8, /* YM_UNPACKED_24 */
30
31 0 /* terminator */
32 };
33 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_halo_dsp1_region_sizes, "FW_CS_DSP_KUNIT_TEST_UTILS");
34
35 const struct cs_dsp_region cs_dsp_mock_adsp2_32bit_dsp1_regions[] = {
36 { .type = WMFW_ADSP2_PM, .base = 0x080000 },
37 { .type = WMFW_ADSP2_XM, .base = 0x0a0000 },
38 { .type = WMFW_ADSP2_YM, .base = 0x0c0000 },
39 { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 },
40 };
41 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_adsp2_32bit_dsp1_regions, "FW_CS_DSP_KUNIT_TEST_UTILS");
42
43 /* List of sizes in bytes, for each entry above */
44 const unsigned int cs_dsp_mock_adsp2_32bit_dsp1_region_sizes[] = {
45 0x9000, /* PM */
46 0xa000, /* ZM */
47 0x2000, /* XM */
48 0x2000, /* YM */
49
50 0 /* terminator */
51 };
52 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_adsp2_32bit_dsp1_region_sizes, "FW_CS_DSP_KUNIT_TEST_UTILS");
53
54 const struct cs_dsp_region cs_dsp_mock_adsp2_16bit_dsp1_regions[] = {
55 { .type = WMFW_ADSP2_PM, .base = 0x100000 },
56 { .type = WMFW_ADSP2_ZM, .base = 0x180000 },
57 { .type = WMFW_ADSP2_XM, .base = 0x190000 },
58 { .type = WMFW_ADSP2_YM, .base = 0x1a8000 },
59 };
60 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_adsp2_16bit_dsp1_regions, "FW_CS_DSP_KUNIT_TEST_UTILS");
61
62 /* List of sizes in bytes, for each entry above */
63 const unsigned int cs_dsp_mock_adsp2_16bit_dsp1_region_sizes[] = {
64 0x6000, /* PM */
65 0x800, /* ZM */
66 0x800, /* XM */
67 0x800, /* YM */
68
69 0 /* terminator */
70 };
71 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_adsp2_16bit_dsp1_region_sizes, "FW_CS_DSP_KUNIT_TEST_UTILS");
72
cs_dsp_mock_count_regions(const unsigned int * region_sizes)73 int cs_dsp_mock_count_regions(const unsigned int *region_sizes)
74 {
75 int i;
76
77 for (i = 0; region_sizes[i]; ++i)
78 ;
79
80 return i;
81 }
82 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_count_regions, "FW_CS_DSP_KUNIT_TEST_UTILS");
83
84 /**
85 * cs_dsp_mock_size_of_region() - Return size of given memory region.
86 *
87 * @dsp: Pointer to struct cs_dsp.
88 * @mem_type: Memory region type.
89 *
90 * Return: Size of region in bytes.
91 */
cs_dsp_mock_size_of_region(const struct cs_dsp * dsp,int mem_type)92 unsigned int cs_dsp_mock_size_of_region(const struct cs_dsp *dsp, int mem_type)
93 {
94 const unsigned int *sizes;
95 int i;
96
97 if (dsp->mem == cs_dsp_mock_halo_dsp1_regions)
98 sizes = cs_dsp_mock_halo_dsp1_region_sizes;
99 else if (dsp->mem == cs_dsp_mock_adsp2_32bit_dsp1_regions)
100 sizes = cs_dsp_mock_adsp2_32bit_dsp1_region_sizes;
101 else if (dsp->mem == cs_dsp_mock_adsp2_16bit_dsp1_regions)
102 sizes = cs_dsp_mock_adsp2_16bit_dsp1_region_sizes;
103 else
104 return 0;
105
106 for (i = 0; i < dsp->num_mems; ++i) {
107 if (dsp->mem[i].type == mem_type)
108 return sizes[i];
109 }
110
111 return 0;
112 }
113 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_size_of_region, "FW_CS_DSP_KUNIT_TEST_UTILS");
114
115 /**
116 * cs_dsp_mock_base_addr_for_mem() - Base register address for memory region.
117 *
118 * @priv: Pointer to struct cs_dsp_test.
119 * @mem_type: Memory region type.
120 *
121 * Return: Base register address of region.
122 */
cs_dsp_mock_base_addr_for_mem(struct cs_dsp_test * priv,int mem_type)123 unsigned int cs_dsp_mock_base_addr_for_mem(struct cs_dsp_test *priv, int mem_type)
124 {
125 int num_mems = priv->dsp->num_mems;
126 const struct cs_dsp_region *region = priv->dsp->mem;
127 int i;
128
129 for (i = 0; i < num_mems; ++i) {
130 if (region[i].type == mem_type)
131 return region[i].base;
132 }
133
134 KUNIT_FAIL(priv->test, "Unexpected region %d\n", mem_type);
135
136 return 0;
137 }
138 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_base_addr_for_mem, "FW_CS_DSP_KUNIT_TEST_UTILS");
139
140 /**
141 * cs_dsp_mock_reg_addr_inc_per_unpacked_word() - Unpacked register address increment per DSP word.
142 *
143 * @priv: Pointer to struct cs_dsp_test.
144 *
145 * Return: Amount by which register address increments to move to the next
146 * DSP word in unpacked XM/YM/ZM.
147 */
cs_dsp_mock_reg_addr_inc_per_unpacked_word(struct cs_dsp_test * priv)148 unsigned int cs_dsp_mock_reg_addr_inc_per_unpacked_word(struct cs_dsp_test *priv)
149 {
150 switch (priv->dsp->type) {
151 case WMFW_ADSP2:
152 return 2; /* two 16-bit register indexes per XM/YM/ZM word */
153 case WMFW_HALO:
154 return 4; /* one byte-addressed 32-bit register per XM/YM/ZM word */
155 default:
156 KUNIT_FAIL(priv->test, "Unexpected DSP type\n");
157 return -1;
158 }
159 }
160 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_reg_addr_inc_per_unpacked_word, "FW_CS_DSP_KUNIT_TEST_UTILS");
161
162 /**
163 * cs_dsp_mock_reg_block_length_bytes() - Number of bytes in an access block.
164 *
165 * @priv: Pointer to struct cs_dsp_test.
166 * @mem_type: Memory region type.
167 *
168 * Return: Total number of bytes in a group of registers forming the
169 * smallest bus access size (including any padding bits). For unpacked
170 * memory this is the number of registers containing one DSP word.
171 * For packed memory this is the number of registers in one packed
172 * access block.
173 */
cs_dsp_mock_reg_block_length_bytes(struct cs_dsp_test * priv,int mem_type)174 unsigned int cs_dsp_mock_reg_block_length_bytes(struct cs_dsp_test *priv, int mem_type)
175 {
176 switch (priv->dsp->type) {
177 case WMFW_ADSP2:
178 switch (mem_type) {
179 case WMFW_ADSP2_PM:
180 return 3 * regmap_get_val_bytes(priv->dsp->regmap);
181 case WMFW_ADSP2_XM:
182 case WMFW_ADSP2_YM:
183 case WMFW_ADSP2_ZM:
184 return sizeof(u32);
185 default:
186 break;
187 }
188 break;
189 case WMFW_HALO:
190 switch (mem_type) {
191 case WMFW_ADSP2_XM:
192 case WMFW_ADSP2_YM:
193 return sizeof(u32);
194 case WMFW_HALO_PM_PACKED:
195 return 5 * sizeof(u32);
196 case WMFW_HALO_XM_PACKED:
197 case WMFW_HALO_YM_PACKED:
198 return 3 * sizeof(u32);
199 default:
200 break;
201 }
202 break;
203 default:
204 KUNIT_FAIL(priv->test, "Unexpected DSP type\n");
205 return 0;
206 }
207
208 KUNIT_FAIL(priv->test, "Unexpected mem type\n");
209
210 return 0;
211 }
212 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_reg_block_length_bytes, "FW_CS_DSP_KUNIT_TEST_UTILS");
213
214 /**
215 * cs_dsp_mock_reg_block_length_registers() - Number of registers in an access block.
216 *
217 * @priv: Pointer to struct cs_dsp_test.
218 * @mem_type: Memory region type.
219 *
220 * Return: Total number of register forming the smallest bus access size.
221 * For unpacked memory this is the number of registers containing one
222 * DSP word. For packed memory this is the number of registers in one
223 * packed access block.
224 */
cs_dsp_mock_reg_block_length_registers(struct cs_dsp_test * priv,int mem_type)225 unsigned int cs_dsp_mock_reg_block_length_registers(struct cs_dsp_test *priv, int mem_type)
226 {
227 return cs_dsp_mock_reg_block_length_bytes(priv, mem_type) /
228 regmap_get_val_bytes(priv->dsp->regmap);
229 }
230 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_reg_block_length_registers, "FW_CS_DSP_KUNIT_TEST_UTILS");
231
232 /**
233 * cs_dsp_mock_reg_block_length_dsp_words() - Number of dsp_words in an access block.
234 *
235 * @priv: Pointer to struct cs_dsp_test.
236 * @mem_type: Memory region type.
237 *
238 * Return: Total number of DSP words in a group of registers forming the
239 * smallest bus access size.
240 */
cs_dsp_mock_reg_block_length_dsp_words(struct cs_dsp_test * priv,int mem_type)241 unsigned int cs_dsp_mock_reg_block_length_dsp_words(struct cs_dsp_test *priv, int mem_type)
242 {
243 switch (priv->dsp->type) {
244 case WMFW_ADSP2:
245 switch (mem_type) {
246 case WMFW_ADSP2_PM:
247 return regmap_get_val_bytes(priv->dsp->regmap) / 2;
248 case WMFW_ADSP2_XM:
249 case WMFW_ADSP2_YM:
250 case WMFW_ADSP2_ZM:
251 return 1;
252 default:
253 break;
254 }
255 break;
256 case WMFW_HALO:
257 switch (mem_type) {
258 case WMFW_ADSP2_XM:
259 case WMFW_ADSP2_YM:
260 return 1;
261 case WMFW_HALO_PM_PACKED:
262 case WMFW_HALO_XM_PACKED:
263 case WMFW_HALO_YM_PACKED:
264 return 4;
265 default:
266 break;
267 }
268 break;
269 default:
270 KUNIT_FAIL(priv->test, "Unexpected DSP type\n");
271 return 0;
272 }
273
274 KUNIT_FAIL(priv->test, "Unexpected mem type\n");
275
276 return 0;
277 }
278 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_reg_block_length_dsp_words, "FW_CS_DSP_KUNIT_TEST_UTILS");
279
280 /**
281 * cs_dsp_mock_has_zm() - DSP has ZM
282 *
283 * @priv: Pointer to struct cs_dsp_test.
284 *
285 * Return: True if DSP has ZM.
286 */
cs_dsp_mock_has_zm(struct cs_dsp_test * priv)287 bool cs_dsp_mock_has_zm(struct cs_dsp_test *priv)
288 {
289 switch (priv->dsp->type) {
290 case WMFW_ADSP2:
291 return true;
292 default:
293 return false;
294 }
295 }
296 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_has_zm, "FW_CS_DSP_KUNIT_TEST_UTILS");
297
298 /**
299 * cs_dsp_mock_packed_to_unpacked_mem_type() - Unpacked region that is
300 * the same memory as a packed region.
301 *
302 * @packed_mem_type: Type of packed memory region.
303 *
304 * Return: unpacked type that is the same memory as packed_mem_type.
305 */
cs_dsp_mock_packed_to_unpacked_mem_type(int packed_mem_type)306 int cs_dsp_mock_packed_to_unpacked_mem_type(int packed_mem_type)
307 {
308 switch (packed_mem_type) {
309 case WMFW_HALO_XM_PACKED:
310 return WMFW_ADSP2_XM;
311 case WMFW_HALO_YM_PACKED:
312 return WMFW_ADSP2_YM;
313 default:
314 return -1;
315 }
316 }
317 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_packed_to_unpacked_mem_type, "FW_CS_DSP_KUNIT_TEST_UTILS");
318
319 /**
320 * cs_dsp_mock_num_dsp_words_to_num_packed_regs() - Number of DSP words
321 * to number of packed registers.
322 *
323 * @num_dsp_words: Number of DSP words.
324 *
325 * Convert number of DSP words to number of packed registers rounded
326 * down to the nearest register.
327 *
328 * Return: Number of packed registers.
329 */
cs_dsp_mock_num_dsp_words_to_num_packed_regs(unsigned int num_dsp_words)330 unsigned int cs_dsp_mock_num_dsp_words_to_num_packed_regs(unsigned int num_dsp_words)
331 {
332 /* There are 3 registers for every 4 packed words */
333 return (num_dsp_words * 3) / 4;
334 }
335 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_num_dsp_words_to_num_packed_regs, "FW_CS_DSP_KUNIT_TEST_UTILS");
336
337 static const struct wmfw_halo_id_hdr cs_dsp_mock_halo_xm_hdr = {
338 .fw = {
339 .core_id = cpu_to_be32(WMFW_HALO << 16),
340 .block_rev = cpu_to_be32(3 << 16),
341 .vendor_id = cpu_to_be32(0x2),
342 .id = cpu_to_be32(0xabcdef),
343 .ver = cpu_to_be32(0x090101),
344 },
345
346 /*
347 * Leave enough space for this header and 40 algorithm descriptors.
348 * base and size are counted in DSP words.
349 */
350 .xm_base = cpu_to_be32(((sizeof(struct wmfw_halo_id_hdr) +
351 (40 * sizeof(struct wmfw_halo_alg_hdr)))
352 / 4) * 3),
353 .xm_size = cpu_to_be32(0x20),
354
355 /* Allocate a dummy word of YM */
356 .ym_base = cpu_to_be32(0),
357 .ym_size = cpu_to_be32(1),
358
359 .n_algs = 0,
360 };
361
362 static const struct wmfw_adsp2_id_hdr cs_dsp_mock_adsp2_xm_hdr = {
363 .fw = {
364 .core_id = cpu_to_be32(WMFW_ADSP2 << 16),
365 .core_rev = cpu_to_be32(2 << 16),
366 .id = cpu_to_be32(0xabcdef),
367 .ver = cpu_to_be32(0x090101),
368 },
369
370 /*
371 * Leave enough space for this header and 40 algorithm descriptors.
372 * base and size are counted in DSP words.
373 */
374 .xm = cpu_to_be32(((sizeof(struct wmfw_adsp2_id_hdr) +
375 (40 * sizeof(struct wmfw_adsp2_alg_hdr)))
376 / 4) * 3),
377
378 .ym = cpu_to_be32(0),
379 .zm = cpu_to_be32(0),
380
381 .n_algs = 0,
382 };
383
384 /**
385 * cs_dsp_mock_xm_header_get_alg_base_in_words() - Algorithm base offset in DSP words.
386 *
387 * @priv: Pointer to struct cs_dsp_test.
388 * @alg_id: Algorithm ID.
389 * @mem_type: Memory region type.
390 *
391 * Lookup an algorithm in the XM header and return the base offset in
392 * DSP words of the algorithm data in the requested memory region.
393 *
394 * Return: Offset in DSP words.
395 */
cs_dsp_mock_xm_header_get_alg_base_in_words(struct cs_dsp_test * priv,unsigned int alg_id,int mem_type)396 unsigned int cs_dsp_mock_xm_header_get_alg_base_in_words(struct cs_dsp_test *priv,
397 unsigned int alg_id,
398 int mem_type)
399 {
400 unsigned int xm = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_XM);
401 union {
402 struct wmfw_adsp2_alg_hdr adsp2;
403 struct wmfw_halo_alg_hdr halo;
404 } alg;
405 unsigned int alg_hdr_addr;
406 unsigned int val, xm_base = 0, ym_base = 0, zm_base = 0;
407 int ret;
408
409 switch (priv->dsp->type) {
410 case WMFW_ADSP2:
411 alg_hdr_addr = xm + (sizeof(struct wmfw_adsp2_id_hdr) / 2);
412 for (;; alg_hdr_addr += sizeof(alg.adsp2) / 2) {
413 ret = regmap_read(priv->dsp->regmap, alg_hdr_addr, &val);
414 KUNIT_ASSERT_GE(priv->test, ret, 0);
415 KUNIT_ASSERT_NE(priv->test, val, 0xbedead);
416 ret = regmap_raw_read(priv->dsp->regmap, alg_hdr_addr,
417 &alg.adsp2, sizeof(alg.adsp2));
418 KUNIT_ASSERT_GE(priv->test, ret, 0);
419 if (be32_to_cpu(alg.adsp2.alg.id) == alg_id) {
420 xm_base = be32_to_cpu(alg.adsp2.xm);
421 ym_base = be32_to_cpu(alg.adsp2.ym);
422 zm_base = be32_to_cpu(alg.adsp2.zm);
423 break;
424 }
425 }
426 break;
427 case WMFW_HALO:
428 alg_hdr_addr = xm + sizeof(struct wmfw_halo_id_hdr);
429 for (;; alg_hdr_addr += sizeof(alg.halo)) {
430 ret = regmap_read(priv->dsp->regmap, alg_hdr_addr, &val);
431 KUNIT_ASSERT_GE(priv->test, ret, 0);
432 KUNIT_ASSERT_NE(priv->test, val, 0xbedead);
433 ret = regmap_raw_read(priv->dsp->regmap, alg_hdr_addr,
434 &alg.halo, sizeof(alg.halo));
435 KUNIT_ASSERT_GE(priv->test, ret, 0);
436 if (be32_to_cpu(alg.halo.alg.id) == alg_id) {
437 xm_base = be32_to_cpu(alg.halo.xm_base);
438 ym_base = be32_to_cpu(alg.halo.ym_base);
439 break;
440 }
441 }
442 break;
443 default:
444 KUNIT_FAIL(priv->test, "Unexpected DSP type %d\n", priv->dsp->type);
445 return 0;
446 }
447
448 switch (mem_type) {
449 case WMFW_ADSP2_XM:
450 case WMFW_HALO_XM_PACKED:
451 return xm_base;
452 case WMFW_ADSP2_YM:
453 case WMFW_HALO_YM_PACKED:
454 return ym_base;
455 case WMFW_ADSP2_ZM:
456 return zm_base;
457 default:
458 KUNIT_FAIL(priv->test, "Bad mem_type\n");
459 return 0;
460 }
461 }
462 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_xm_header_get_alg_base_in_words, "FW_CS_DSP_KUNIT_TEST_UTILS");
463
464 /**
465 * cs_dsp_mock_xm_header_get_fw_version() - Firmware version.
466 *
467 * @header: Pointer to struct cs_dsp_mock_xm_header.
468 *
469 * Return: Firmware version word value.
470 */
cs_dsp_mock_xm_header_get_fw_version(struct cs_dsp_mock_xm_header * header)471 unsigned int cs_dsp_mock_xm_header_get_fw_version(struct cs_dsp_mock_xm_header *header)
472 {
473 const struct wmfw_id_hdr *adsp2_hdr;
474 const struct wmfw_v3_id_hdr *halo_hdr;
475
476 switch (header->test_priv->dsp->type) {
477 case WMFW_ADSP2:
478 adsp2_hdr = header->blob_data;
479 return be32_to_cpu(adsp2_hdr->ver);
480 case WMFW_HALO:
481 halo_hdr = header->blob_data;
482 return be32_to_cpu(halo_hdr->ver);
483 default:
484 KUNIT_FAIL(header->test_priv->test, NULL);
485 return 0;
486 }
487 }
488 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_xm_header_get_fw_version, "FW_CS_DSP_KUNIT_TEST_UTILS");
489
490 /**
491 * cs_dsp_mock_xm_header_drop_from_regmap_cache() - Drop XM header from regmap cache.
492 *
493 * @priv: Pointer to struct cs_dsp_test.
494 */
cs_dsp_mock_xm_header_drop_from_regmap_cache(struct cs_dsp_test * priv)495 void cs_dsp_mock_xm_header_drop_from_regmap_cache(struct cs_dsp_test *priv)
496 {
497 unsigned int xm = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_XM);
498 unsigned int bytes;
499 __be32 num_algs_be32;
500 unsigned int num_algs;
501
502 switch (priv->dsp->type) {
503 case WMFW_ADSP2:
504 /*
505 * Could be one 32-bit register or two 16-bit registers.
506 * A raw read will read the requested number of bytes.
507 */
508 regmap_raw_read(priv->dsp->regmap,
509 xm + (offsetof(struct wmfw_adsp2_id_hdr, n_algs) / 2),
510 &num_algs_be32, sizeof(num_algs_be32));
511 num_algs = be32_to_cpu(num_algs_be32);
512 bytes = sizeof(struct wmfw_adsp2_id_hdr) +
513 (num_algs * sizeof(struct wmfw_adsp2_alg_hdr)) +
514 4 /* terminator word */;
515
516 regcache_drop_region(priv->dsp->regmap, xm, xm + (bytes / 2) - 1);
517 break;
518 case WMFW_HALO:
519 regmap_read(priv->dsp->regmap,
520 xm + offsetof(struct wmfw_halo_id_hdr, n_algs),
521 &num_algs);
522 bytes = sizeof(struct wmfw_halo_id_hdr) +
523 (num_algs * sizeof(struct wmfw_halo_alg_hdr)) +
524 4 /* terminator word */;
525
526 regcache_drop_region(priv->dsp->regmap, xm, xm + bytes - 4);
527 break;
528 default:
529 break;
530 }
531 }
532 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_xm_header_drop_from_regmap_cache, "FW_CS_DSP_KUNIT_TEST_UTILS");
533
cs_dsp_mock_xm_header_add_adsp2_algs(struct cs_dsp_mock_xm_header * builder,const struct cs_dsp_mock_alg_def * algs,size_t num_algs)534 static void cs_dsp_mock_xm_header_add_adsp2_algs(struct cs_dsp_mock_xm_header *builder,
535 const struct cs_dsp_mock_alg_def *algs,
536 size_t num_algs)
537 {
538 struct wmfw_adsp2_id_hdr *hdr = builder->blob_data;
539 unsigned int next_free_xm_word, next_free_ym_word, next_free_zm_word;
540
541 next_free_xm_word = be32_to_cpu(hdr->xm);
542 next_free_ym_word = be32_to_cpu(hdr->ym);
543 next_free_zm_word = be32_to_cpu(hdr->zm);
544
545 /* Set num_algs in XM header. */
546 hdr->n_algs = cpu_to_be32(num_algs);
547
548 /* Create algorithm descriptor list */
549 struct wmfw_adsp2_alg_hdr *alg_info =
550 (struct wmfw_adsp2_alg_hdr *)(&hdr[1]);
551
552 for (; num_algs > 0; num_algs--, algs++, alg_info++) {
553 unsigned int alg_xm_last, alg_ym_last, alg_zm_last;
554
555 alg_info->alg.id = cpu_to_be32(algs->id);
556 alg_info->alg.ver = cpu_to_be32(algs->ver);
557 alg_info->xm = cpu_to_be32(algs->xm_base_words);
558 alg_info->ym = cpu_to_be32(algs->ym_base_words);
559 alg_info->zm = cpu_to_be32(algs->zm_base_words);
560
561 /* Check if we need to auto-allocate base addresses */
562 if (!alg_info->xm && algs->xm_size_words)
563 alg_info->xm = cpu_to_be32(next_free_xm_word);
564
565 if (!alg_info->ym && algs->ym_size_words)
566 alg_info->ym = cpu_to_be32(next_free_ym_word);
567
568 if (!alg_info->zm && algs->zm_size_words)
569 alg_info->zm = cpu_to_be32(next_free_zm_word);
570
571 alg_xm_last = be32_to_cpu(alg_info->xm) + algs->xm_size_words - 1;
572 if (alg_xm_last > next_free_xm_word)
573 next_free_xm_word = alg_xm_last;
574
575 alg_ym_last = be32_to_cpu(alg_info->ym) + algs->ym_size_words - 1;
576 if (alg_ym_last > next_free_ym_word)
577 next_free_ym_word = alg_ym_last;
578
579 alg_zm_last = be32_to_cpu(alg_info->zm) + algs->zm_size_words - 1;
580 if (alg_zm_last > next_free_zm_word)
581 next_free_zm_word = alg_zm_last;
582 }
583
584 /* Write list terminator */
585 *(__be32 *)(alg_info) = cpu_to_be32(0xbedead);
586 }
587
cs_dsp_mock_xm_header_add_halo_algs(struct cs_dsp_mock_xm_header * builder,const struct cs_dsp_mock_alg_def * algs,size_t num_algs)588 static void cs_dsp_mock_xm_header_add_halo_algs(struct cs_dsp_mock_xm_header *builder,
589 const struct cs_dsp_mock_alg_def *algs,
590 size_t num_algs)
591 {
592 struct wmfw_halo_id_hdr *hdr = builder->blob_data;
593 unsigned int next_free_xm_word, next_free_ym_word;
594
595 /* Assume we're starting with bare header */
596 next_free_xm_word = be32_to_cpu(hdr->xm_base) + be32_to_cpu(hdr->xm_size) - 1;
597 next_free_ym_word = be32_to_cpu(hdr->ym_base) + be32_to_cpu(hdr->ym_size) - 1;
598
599 /* Set num_algs in XM header */
600 hdr->n_algs = cpu_to_be32(num_algs);
601
602 /* Create algorithm descriptor list */
603 struct wmfw_halo_alg_hdr *alg_info =
604 (struct wmfw_halo_alg_hdr *)(&hdr[1]);
605
606 for (; num_algs > 0; num_algs--, algs++, alg_info++) {
607 unsigned int alg_xm_last, alg_ym_last;
608
609 alg_info->alg.id = cpu_to_be32(algs->id);
610 alg_info->alg.ver = cpu_to_be32(algs->ver);
611 alg_info->xm_base = cpu_to_be32(algs->xm_base_words);
612 alg_info->xm_size = cpu_to_be32(algs->xm_size_words);
613 alg_info->ym_base = cpu_to_be32(algs->ym_base_words);
614 alg_info->ym_size = cpu_to_be32(algs->ym_size_words);
615
616 /* Check if we need to auto-allocate base addresses */
617 if (!alg_info->xm_base && alg_info->xm_size)
618 alg_info->xm_base = cpu_to_be32(next_free_xm_word);
619
620 if (!alg_info->ym_base && alg_info->ym_size)
621 alg_info->ym_base = cpu_to_be32(next_free_ym_word);
622
623 alg_xm_last = be32_to_cpu(alg_info->xm_base) + be32_to_cpu(alg_info->xm_size) - 1;
624 if (alg_xm_last > next_free_xm_word)
625 next_free_xm_word = alg_xm_last;
626
627 alg_ym_last = be32_to_cpu(alg_info->ym_base) + be32_to_cpu(alg_info->ym_size) - 1;
628 if (alg_ym_last > next_free_ym_word)
629 next_free_ym_word = alg_ym_last;
630 }
631
632 /* Write list terminator */
633 *(__be32 *)(alg_info) = cpu_to_be32(0xbedead);
634 }
635
636 /**
637 * cs_dsp_mock_xm_header_write_to_regmap() - Write XM header to regmap.
638 *
639 * @header: Pointer to struct cs_dsp_mock_xm_header.
640 *
641 * The data in header is written to the XM addresses in the regmap.
642 *
643 * Return: 0 on success, else negative error code.
644 */
cs_dsp_mock_xm_header_write_to_regmap(struct cs_dsp_mock_xm_header * header)645 int cs_dsp_mock_xm_header_write_to_regmap(struct cs_dsp_mock_xm_header *header)
646 {
647 struct cs_dsp_test *priv = header->test_priv;
648 unsigned int reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_XM);
649
650 /*
651 * One 32-bit word corresponds to one 32-bit unpacked XM word so the
652 * blob can be written directly to the regmap.
653 */
654 return regmap_raw_write(priv->dsp->regmap, reg_addr,
655 header->blob_data, header->blob_size_bytes);
656 }
657 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_xm_header_write_to_regmap, "FW_CS_DSP_KUNIT_TEST_UTILS");
658
659 /**
660 * cs_dsp_create_mock_xm_header() - Create a dummy XM header.
661 *
662 * @priv: Pointer to struct cs_dsp_test.
663 * @algs: Pointer to array of struct cs_dsp_mock_alg_def listing the
664 * dummy algorithm entries to include in the XM header.
665 * @num_algs: Number of entries in the algs array.
666 *
667 * Return: Pointer to created struct cs_dsp_mock_xm_header.
668 */
cs_dsp_create_mock_xm_header(struct cs_dsp_test * priv,const struct cs_dsp_mock_alg_def * algs,size_t num_algs)669 struct cs_dsp_mock_xm_header *cs_dsp_create_mock_xm_header(struct cs_dsp_test *priv,
670 const struct cs_dsp_mock_alg_def *algs,
671 size_t num_algs)
672 {
673 struct cs_dsp_mock_xm_header *builder;
674 size_t total_bytes_required;
675 const void *header;
676 size_t header_size_bytes;
677
678 builder = kunit_kzalloc(priv->test, sizeof(*builder), GFP_KERNEL);
679 KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder);
680 builder->test_priv = priv;
681
682 switch (priv->dsp->type) {
683 case WMFW_ADSP2:
684 header = &cs_dsp_mock_adsp2_xm_hdr;
685 header_size_bytes = sizeof(cs_dsp_mock_adsp2_xm_hdr);
686 total_bytes_required = header_size_bytes +
687 (num_algs * sizeof(struct wmfw_adsp2_alg_hdr))
688 + 4; /* terminator word */
689 break;
690 case WMFW_HALO:
691 header = &cs_dsp_mock_halo_xm_hdr,
692 header_size_bytes = sizeof(cs_dsp_mock_halo_xm_hdr);
693 total_bytes_required = header_size_bytes +
694 (num_algs * sizeof(struct wmfw_halo_alg_hdr))
695 + 4; /* terminator word */
696 break;
697 default:
698 KUNIT_FAIL(priv->test, "%s unexpected DSP type %d\n",
699 __func__, priv->dsp->type);
700 return NULL;
701 }
702
703 builder->blob_data = kunit_kzalloc(priv->test, total_bytes_required, GFP_KERNEL);
704 KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder->blob_data);
705 builder->blob_size_bytes = total_bytes_required;
706
707 memcpy(builder->blob_data, header, header_size_bytes);
708
709 switch (priv->dsp->type) {
710 case WMFW_ADSP2:
711 cs_dsp_mock_xm_header_add_adsp2_algs(builder, algs, num_algs);
712 break;
713 case WMFW_HALO:
714 cs_dsp_mock_xm_header_add_halo_algs(builder, algs, num_algs);
715 break;
716 default:
717 break;
718 }
719
720 return builder;
721 }
722 EXPORT_SYMBOL_NS_GPL(cs_dsp_create_mock_xm_header, "FW_CS_DSP_KUNIT_TEST_UTILS");
723