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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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_from_regmap() - Firmware version. 466 * 467 * @priv: Pointer to struct cs_dsp_test. 468 * 469 * Return: Firmware version word value. 470 */ 471 unsigned int cs_dsp_mock_xm_header_get_fw_version_from_regmap(struct cs_dsp_test *priv) 472 { 473 unsigned int xm = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_XM); 474 union { 475 struct wmfw_id_hdr adsp2; 476 struct wmfw_v3_id_hdr halo; 477 } hdr; 478 479 switch (priv->dsp->type) { 480 case WMFW_ADSP2: 481 regmap_raw_read(priv->dsp->regmap, xm, &hdr.adsp2, sizeof(hdr.adsp2)); 482 return be32_to_cpu(hdr.adsp2.ver); 483 case WMFW_HALO: 484 regmap_raw_read(priv->dsp->regmap, xm, &hdr.halo, sizeof(hdr.halo)); 485 return be32_to_cpu(hdr.halo.ver); 486 default: 487 KUNIT_FAIL(priv->test, NULL); 488 return 0; 489 } 490 } 491 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_xm_header_get_fw_version_from_regmap, 492 "FW_CS_DSP_KUNIT_TEST_UTILS"); 493 494 /** 495 * cs_dsp_mock_xm_header_get_fw_version() - Firmware version. 496 * 497 * @header: Pointer to struct cs_dsp_mock_xm_header. 498 * 499 * Return: Firmware version word value. 500 */ 501 unsigned int cs_dsp_mock_xm_header_get_fw_version(struct cs_dsp_mock_xm_header *header) 502 { 503 const struct wmfw_id_hdr *adsp2_hdr; 504 const struct wmfw_v3_id_hdr *halo_hdr; 505 506 switch (header->test_priv->dsp->type) { 507 case WMFW_ADSP2: 508 adsp2_hdr = header->blob_data; 509 return be32_to_cpu(adsp2_hdr->ver); 510 case WMFW_HALO: 511 halo_hdr = header->blob_data; 512 return be32_to_cpu(halo_hdr->ver); 513 default: 514 KUNIT_FAIL(header->test_priv->test, NULL); 515 return 0; 516 } 517 } 518 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_xm_header_get_fw_version, "FW_CS_DSP_KUNIT_TEST_UTILS"); 519 520 /** 521 * cs_dsp_mock_xm_header_drop_from_regmap_cache() - Drop XM header from regmap cache. 522 * 523 * @priv: Pointer to struct cs_dsp_test. 524 */ 525 void cs_dsp_mock_xm_header_drop_from_regmap_cache(struct cs_dsp_test *priv) 526 { 527 unsigned int xm = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_XM); 528 unsigned int bytes; 529 __be32 num_algs_be32; 530 unsigned int num_algs; 531 532 switch (priv->dsp->type) { 533 case WMFW_ADSP2: 534 /* 535 * Could be one 32-bit register or two 16-bit registers. 536 * A raw read will read the requested number of bytes. 537 */ 538 regmap_raw_read(priv->dsp->regmap, 539 xm + (offsetof(struct wmfw_adsp2_id_hdr, n_algs) / 2), 540 &num_algs_be32, sizeof(num_algs_be32)); 541 num_algs = be32_to_cpu(num_algs_be32); 542 bytes = sizeof(struct wmfw_adsp2_id_hdr) + 543 (num_algs * sizeof(struct wmfw_adsp2_alg_hdr)) + 544 4 /* terminator word */; 545 546 regcache_drop_region(priv->dsp->regmap, xm, xm + (bytes / 2) - 1); 547 break; 548 case WMFW_HALO: 549 regmap_read(priv->dsp->regmap, 550 xm + offsetof(struct wmfw_halo_id_hdr, n_algs), 551 &num_algs); 552 bytes = sizeof(struct wmfw_halo_id_hdr) + 553 (num_algs * sizeof(struct wmfw_halo_alg_hdr)) + 554 4 /* terminator word */; 555 556 regcache_drop_region(priv->dsp->regmap, xm, xm + bytes - 4); 557 break; 558 default: 559 break; 560 } 561 } 562 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_xm_header_drop_from_regmap_cache, "FW_CS_DSP_KUNIT_TEST_UTILS"); 563 564 static void cs_dsp_mock_xm_header_add_adsp2_algs(struct cs_dsp_mock_xm_header *builder, 565 const struct cs_dsp_mock_alg_def *algs, 566 size_t num_algs) 567 { 568 struct wmfw_adsp2_id_hdr *hdr = builder->blob_data; 569 unsigned int next_free_xm_word, next_free_ym_word, next_free_zm_word; 570 571 next_free_xm_word = be32_to_cpu(hdr->xm); 572 next_free_ym_word = be32_to_cpu(hdr->ym); 573 next_free_zm_word = be32_to_cpu(hdr->zm); 574 575 /* Set num_algs in XM header. */ 576 hdr->n_algs = cpu_to_be32(num_algs); 577 578 /* Create algorithm descriptor list */ 579 struct wmfw_adsp2_alg_hdr *alg_info = 580 (struct wmfw_adsp2_alg_hdr *)(&hdr[1]); 581 582 for (; num_algs > 0; num_algs--, algs++, alg_info++) { 583 unsigned int alg_xm_last, alg_ym_last, alg_zm_last; 584 585 alg_info->alg.id = cpu_to_be32(algs->id); 586 alg_info->alg.ver = cpu_to_be32(algs->ver); 587 alg_info->xm = cpu_to_be32(algs->xm_base_words); 588 alg_info->ym = cpu_to_be32(algs->ym_base_words); 589 alg_info->zm = cpu_to_be32(algs->zm_base_words); 590 591 /* Check if we need to auto-allocate base addresses */ 592 if (!alg_info->xm && algs->xm_size_words) 593 alg_info->xm = cpu_to_be32(next_free_xm_word); 594 595 if (!alg_info->ym && algs->ym_size_words) 596 alg_info->ym = cpu_to_be32(next_free_ym_word); 597 598 if (!alg_info->zm && algs->zm_size_words) 599 alg_info->zm = cpu_to_be32(next_free_zm_word); 600 601 alg_xm_last = be32_to_cpu(alg_info->xm) + algs->xm_size_words - 1; 602 if (alg_xm_last > next_free_xm_word) 603 next_free_xm_word = alg_xm_last; 604 605 alg_ym_last = be32_to_cpu(alg_info->ym) + algs->ym_size_words - 1; 606 if (alg_ym_last > next_free_ym_word) 607 next_free_ym_word = alg_ym_last; 608 609 alg_zm_last = be32_to_cpu(alg_info->zm) + algs->zm_size_words - 1; 610 if (alg_zm_last > next_free_zm_word) 611 next_free_zm_word = alg_zm_last; 612 } 613 614 /* Write list terminator */ 615 *(__be32 *)(alg_info) = cpu_to_be32(0xbedead); 616 } 617 618 static void cs_dsp_mock_xm_header_add_halo_algs(struct cs_dsp_mock_xm_header *builder, 619 const struct cs_dsp_mock_alg_def *algs, 620 size_t num_algs) 621 { 622 struct wmfw_halo_id_hdr *hdr = builder->blob_data; 623 unsigned int next_free_xm_word, next_free_ym_word; 624 625 /* Assume we're starting with bare header */ 626 next_free_xm_word = be32_to_cpu(hdr->xm_base) + be32_to_cpu(hdr->xm_size) - 1; 627 next_free_ym_word = be32_to_cpu(hdr->ym_base) + be32_to_cpu(hdr->ym_size) - 1; 628 629 /* Set num_algs in XM header */ 630 hdr->n_algs = cpu_to_be32(num_algs); 631 632 /* Create algorithm descriptor list */ 633 struct wmfw_halo_alg_hdr *alg_info = 634 (struct wmfw_halo_alg_hdr *)(&hdr[1]); 635 636 for (; num_algs > 0; num_algs--, algs++, alg_info++) { 637 unsigned int alg_xm_last, alg_ym_last; 638 639 alg_info->alg.id = cpu_to_be32(algs->id); 640 alg_info->alg.ver = cpu_to_be32(algs->ver); 641 alg_info->xm_base = cpu_to_be32(algs->xm_base_words); 642 alg_info->xm_size = cpu_to_be32(algs->xm_size_words); 643 alg_info->ym_base = cpu_to_be32(algs->ym_base_words); 644 alg_info->ym_size = cpu_to_be32(algs->ym_size_words); 645 646 /* Check if we need to auto-allocate base addresses */ 647 if (!alg_info->xm_base && alg_info->xm_size) 648 alg_info->xm_base = cpu_to_be32(next_free_xm_word); 649 650 if (!alg_info->ym_base && alg_info->ym_size) 651 alg_info->ym_base = cpu_to_be32(next_free_ym_word); 652 653 alg_xm_last = be32_to_cpu(alg_info->xm_base) + be32_to_cpu(alg_info->xm_size) - 1; 654 if (alg_xm_last > next_free_xm_word) 655 next_free_xm_word = alg_xm_last; 656 657 alg_ym_last = be32_to_cpu(alg_info->ym_base) + be32_to_cpu(alg_info->ym_size) - 1; 658 if (alg_ym_last > next_free_ym_word) 659 next_free_ym_word = alg_ym_last; 660 } 661 662 /* Write list terminator */ 663 *(__be32 *)(alg_info) = cpu_to_be32(0xbedead); 664 } 665 666 /** 667 * cs_dsp_mock_xm_header_write_to_regmap() - Write XM header to regmap. 668 * 669 * @header: Pointer to struct cs_dsp_mock_xm_header. 670 * 671 * The data in header is written to the XM addresses in the regmap. 672 * 673 * Return: 0 on success, else negative error code. 674 */ 675 int cs_dsp_mock_xm_header_write_to_regmap(struct cs_dsp_mock_xm_header *header) 676 { 677 struct cs_dsp_test *priv = header->test_priv; 678 unsigned int reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_XM); 679 680 /* 681 * One 32-bit word corresponds to one 32-bit unpacked XM word so the 682 * blob can be written directly to the regmap. 683 */ 684 return regmap_raw_write(priv->dsp->regmap, reg_addr, 685 header->blob_data, header->blob_size_bytes); 686 } 687 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_xm_header_write_to_regmap, "FW_CS_DSP_KUNIT_TEST_UTILS"); 688 689 /** 690 * cs_dsp_create_mock_xm_header() - Create a dummy XM header. 691 * 692 * @priv: Pointer to struct cs_dsp_test. 693 * @algs: Pointer to array of struct cs_dsp_mock_alg_def listing the 694 * dummy algorithm entries to include in the XM header. 695 * @num_algs: Number of entries in the algs array. 696 * 697 * Return: Pointer to created struct cs_dsp_mock_xm_header. 698 */ 699 struct cs_dsp_mock_xm_header *cs_dsp_create_mock_xm_header(struct cs_dsp_test *priv, 700 const struct cs_dsp_mock_alg_def *algs, 701 size_t num_algs) 702 { 703 struct cs_dsp_mock_xm_header *builder; 704 size_t total_bytes_required; 705 const void *header; 706 size_t header_size_bytes; 707 708 builder = kunit_kzalloc(priv->test, sizeof(*builder), GFP_KERNEL); 709 KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder); 710 builder->test_priv = priv; 711 712 switch (priv->dsp->type) { 713 case WMFW_ADSP2: 714 header = &cs_dsp_mock_adsp2_xm_hdr; 715 header_size_bytes = sizeof(cs_dsp_mock_adsp2_xm_hdr); 716 total_bytes_required = header_size_bytes + 717 (num_algs * sizeof(struct wmfw_adsp2_alg_hdr)) 718 + 4; /* terminator word */ 719 break; 720 case WMFW_HALO: 721 header = &cs_dsp_mock_halo_xm_hdr, 722 header_size_bytes = sizeof(cs_dsp_mock_halo_xm_hdr); 723 total_bytes_required = header_size_bytes + 724 (num_algs * sizeof(struct wmfw_halo_alg_hdr)) 725 + 4; /* terminator word */ 726 break; 727 default: 728 KUNIT_FAIL(priv->test, "%s unexpected DSP type %d\n", 729 __func__, priv->dsp->type); 730 return NULL; 731 } 732 733 builder->blob_data = kunit_kzalloc(priv->test, total_bytes_required, GFP_KERNEL); 734 KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder->blob_data); 735 builder->blob_size_bytes = total_bytes_required; 736 737 memcpy(builder->blob_data, header, header_size_bytes); 738 739 switch (priv->dsp->type) { 740 case WMFW_ADSP2: 741 cs_dsp_mock_xm_header_add_adsp2_algs(builder, algs, num_algs); 742 break; 743 case WMFW_HALO: 744 cs_dsp_mock_xm_header_add_halo_algs(builder, algs, num_algs); 745 break; 746 default: 747 break; 748 } 749 750 return builder; 751 } 752 EXPORT_SYMBOL_NS_GPL(cs_dsp_create_mock_xm_header, "FW_CS_DSP_KUNIT_TEST_UTILS"); 753