xref: /linux/drivers/firmware/cirrus/test/cs_dsp_mock_wmfw.c (revision af477f4d5a6c183e2dd44f49dd9a7950bfa7bd50)
15cf1b7b4SRichard Fitzgerald // SPDX-License-Identifier: GPL-2.0-only
25cf1b7b4SRichard Fitzgerald //
35cf1b7b4SRichard Fitzgerald // wmfw file builder for cs_dsp KUnit tests.
45cf1b7b4SRichard Fitzgerald //
55cf1b7b4SRichard Fitzgerald // Copyright (C) 2024 Cirrus Logic, Inc. and
65cf1b7b4SRichard Fitzgerald //                    Cirrus Logic International Semiconductor Ltd.
75cf1b7b4SRichard Fitzgerald 
85cf1b7b4SRichard Fitzgerald #include <kunit/resource.h>
95cf1b7b4SRichard Fitzgerald #include <kunit/test.h>
105cf1b7b4SRichard Fitzgerald #include <linux/firmware/cirrus/cs_dsp.h>
115cf1b7b4SRichard Fitzgerald #include <linux/firmware/cirrus/cs_dsp_test_utils.h>
125cf1b7b4SRichard Fitzgerald #include <linux/firmware/cirrus/wmfw.h>
135cf1b7b4SRichard Fitzgerald #include <linux/firmware.h>
145cf1b7b4SRichard Fitzgerald #include <linux/math.h>
155cf1b7b4SRichard Fitzgerald #include <linux/overflow.h>
165cf1b7b4SRichard Fitzgerald #include <linux/string.h>
175cf1b7b4SRichard Fitzgerald #include <linux/vmalloc.h>
185cf1b7b4SRichard Fitzgerald 
195cf1b7b4SRichard Fitzgerald /* Buffer large enough for bin file content */
205cf1b7b4SRichard Fitzgerald #define CS_DSP_MOCK_WMFW_BUF_SIZE	131072
215cf1b7b4SRichard Fitzgerald 
225cf1b7b4SRichard Fitzgerald struct cs_dsp_mock_wmfw_builder {
235cf1b7b4SRichard Fitzgerald 	struct cs_dsp_test *test_priv;
245cf1b7b4SRichard Fitzgerald 	int format_version;
255cf1b7b4SRichard Fitzgerald 	void *buf;
265cf1b7b4SRichard Fitzgerald 	size_t buf_size_bytes;
275cf1b7b4SRichard Fitzgerald 	void *write_p;
285cf1b7b4SRichard Fitzgerald 	size_t bytes_used;
295cf1b7b4SRichard Fitzgerald 
305cf1b7b4SRichard Fitzgerald 	void *alg_data_header;
315cf1b7b4SRichard Fitzgerald 	unsigned int num_coeffs;
325cf1b7b4SRichard Fitzgerald };
335cf1b7b4SRichard Fitzgerald 
345cf1b7b4SRichard Fitzgerald struct wmfw_adsp2_halo_header {
355cf1b7b4SRichard Fitzgerald 	struct wmfw_header header;
365cf1b7b4SRichard Fitzgerald 	struct wmfw_adsp2_sizes sizes;
375cf1b7b4SRichard Fitzgerald 	struct wmfw_footer footer;
385cf1b7b4SRichard Fitzgerald } __packed;
395cf1b7b4SRichard Fitzgerald 
405cf1b7b4SRichard Fitzgerald struct wmfw_long_string {
415cf1b7b4SRichard Fitzgerald 	__le16 len;
425cf1b7b4SRichard Fitzgerald 	u8 data[] __nonstring __counted_by(len);
435cf1b7b4SRichard Fitzgerald } __packed;
445cf1b7b4SRichard Fitzgerald 
455cf1b7b4SRichard Fitzgerald struct wmfw_short_string {
465cf1b7b4SRichard Fitzgerald 	u8 len;
475cf1b7b4SRichard Fitzgerald 	u8 data[] __nonstring __counted_by(len);
485cf1b7b4SRichard Fitzgerald } __packed;
495cf1b7b4SRichard Fitzgerald 
KUNIT_DEFINE_ACTION_WRAPPER(vfree_action_wrapper,vfree,void *)505cf1b7b4SRichard Fitzgerald KUNIT_DEFINE_ACTION_WRAPPER(vfree_action_wrapper, vfree, void *)
515cf1b7b4SRichard Fitzgerald 
525cf1b7b4SRichard Fitzgerald /**
535cf1b7b4SRichard Fitzgerald  * cs_dsp_mock_wmfw_format_version() - Return format version.
545cf1b7b4SRichard Fitzgerald  *
555cf1b7b4SRichard Fitzgerald  * @builder:	Pointer to struct cs_dsp_mock_wmfw_builder.
565cf1b7b4SRichard Fitzgerald  *
575cf1b7b4SRichard Fitzgerald  * Return: Format version.
585cf1b7b4SRichard Fitzgerald  */
595cf1b7b4SRichard Fitzgerald int cs_dsp_mock_wmfw_format_version(struct cs_dsp_mock_wmfw_builder *builder)
605cf1b7b4SRichard Fitzgerald {
615cf1b7b4SRichard Fitzgerald 	return builder->format_version;
625cf1b7b4SRichard Fitzgerald }
635cf1b7b4SRichard Fitzgerald EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_wmfw_format_version, "FW_CS_DSP_KUNIT_TEST_UTILS");
645cf1b7b4SRichard Fitzgerald 
655cf1b7b4SRichard Fitzgerald /**
665cf1b7b4SRichard Fitzgerald  * cs_dsp_mock_wmfw_get_firmware() - Get struct firmware wrapper for data.
675cf1b7b4SRichard Fitzgerald  *
685cf1b7b4SRichard Fitzgerald  * @builder:	Pointer to struct cs_dsp_mock_wmfw_builder.
695cf1b7b4SRichard Fitzgerald  *
705cf1b7b4SRichard Fitzgerald  * Return: Pointer to a struct firmware wrapper for the data.
715cf1b7b4SRichard Fitzgerald  */
cs_dsp_mock_wmfw_get_firmware(struct cs_dsp_mock_wmfw_builder * builder)725cf1b7b4SRichard Fitzgerald struct firmware *cs_dsp_mock_wmfw_get_firmware(struct cs_dsp_mock_wmfw_builder *builder)
735cf1b7b4SRichard Fitzgerald {
745cf1b7b4SRichard Fitzgerald 	struct firmware *fw;
755cf1b7b4SRichard Fitzgerald 
765cf1b7b4SRichard Fitzgerald 	if (!builder)
775cf1b7b4SRichard Fitzgerald 		return NULL;
785cf1b7b4SRichard Fitzgerald 
795cf1b7b4SRichard Fitzgerald 	fw = kunit_kzalloc(builder->test_priv->test, sizeof(*fw), GFP_KERNEL);
805cf1b7b4SRichard Fitzgerald 	KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, fw);
815cf1b7b4SRichard Fitzgerald 
825cf1b7b4SRichard Fitzgerald 	fw->data = builder->buf;
835cf1b7b4SRichard Fitzgerald 	fw->size = builder->bytes_used;
845cf1b7b4SRichard Fitzgerald 
855cf1b7b4SRichard Fitzgerald 	return fw;
865cf1b7b4SRichard Fitzgerald }
875cf1b7b4SRichard Fitzgerald EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_wmfw_get_firmware, "FW_CS_DSP_KUNIT_TEST_UTILS");
885cf1b7b4SRichard Fitzgerald 
895cf1b7b4SRichard Fitzgerald /**
905cf1b7b4SRichard Fitzgerald  * cs_dsp_mock_wmfw_add_raw_block() - Add a block to the wmfw file.
915cf1b7b4SRichard Fitzgerald  *
925cf1b7b4SRichard Fitzgerald  * @builder:		Pointer to struct cs_dsp_mock_bin_builder.
935cf1b7b4SRichard Fitzgerald  * @block_type:		Block type.
945cf1b7b4SRichard Fitzgerald  * @offset:		Offset.
955cf1b7b4SRichard Fitzgerald  * @payload_data:	Pointer to buffer containing the payload data,
965cf1b7b4SRichard Fitzgerald  *			or NULL if no data.
975cf1b7b4SRichard Fitzgerald  * @payload_len_bytes:	Length of payload data in bytes, or zero.
985cf1b7b4SRichard Fitzgerald  */
cs_dsp_mock_wmfw_add_raw_block(struct cs_dsp_mock_wmfw_builder * builder,int block_type,unsigned int offset,const void * payload_data,size_t payload_len_bytes)995cf1b7b4SRichard Fitzgerald void cs_dsp_mock_wmfw_add_raw_block(struct cs_dsp_mock_wmfw_builder *builder,
1005cf1b7b4SRichard Fitzgerald 				    int block_type, unsigned int offset,
1015cf1b7b4SRichard Fitzgerald 				    const void *payload_data, size_t payload_len_bytes)
1025cf1b7b4SRichard Fitzgerald {
1035cf1b7b4SRichard Fitzgerald 	struct wmfw_region *header = builder->write_p;
1045cf1b7b4SRichard Fitzgerald 	unsigned int bytes_needed = struct_size_t(struct wmfw_region, data, payload_len_bytes);
1055cf1b7b4SRichard Fitzgerald 
1065cf1b7b4SRichard Fitzgerald 	KUNIT_ASSERT_TRUE(builder->test_priv->test,
1075cf1b7b4SRichard Fitzgerald 			  (builder->write_p + bytes_needed) <
1085cf1b7b4SRichard Fitzgerald 			  (builder->buf + CS_DSP_MOCK_WMFW_BUF_SIZE));
1095cf1b7b4SRichard Fitzgerald 
1105cf1b7b4SRichard Fitzgerald 	header->offset = cpu_to_le32(offset | (block_type << 24));
1115cf1b7b4SRichard Fitzgerald 	header->len = cpu_to_le32(payload_len_bytes);
1125cf1b7b4SRichard Fitzgerald 	if (payload_len_bytes > 0)
1135cf1b7b4SRichard Fitzgerald 		memcpy(header->data, payload_data, payload_len_bytes);
1145cf1b7b4SRichard Fitzgerald 
1155cf1b7b4SRichard Fitzgerald 	builder->write_p += bytes_needed;
1165cf1b7b4SRichard Fitzgerald 	builder->bytes_used += bytes_needed;
1175cf1b7b4SRichard Fitzgerald }
1185cf1b7b4SRichard Fitzgerald EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_wmfw_add_raw_block, "FW_CS_DSP_KUNIT_TEST_UTILS");
1195cf1b7b4SRichard Fitzgerald 
1205cf1b7b4SRichard Fitzgerald /**
1215cf1b7b4SRichard Fitzgerald  * cs_dsp_mock_wmfw_add_info() - Add an info block to the wmfw file.
1225cf1b7b4SRichard Fitzgerald  *
1235cf1b7b4SRichard Fitzgerald  * @builder:	Pointer to struct cs_dsp_mock_bin_builder.
1245cf1b7b4SRichard Fitzgerald  * @info:	Pointer to info string to be copied into the file.
1255cf1b7b4SRichard Fitzgerald  *
1265cf1b7b4SRichard Fitzgerald  * The string will be padded to a length that is a multiple of 4 bytes.
1275cf1b7b4SRichard Fitzgerald  */
cs_dsp_mock_wmfw_add_info(struct cs_dsp_mock_wmfw_builder * builder,const char * info)1285cf1b7b4SRichard Fitzgerald void cs_dsp_mock_wmfw_add_info(struct cs_dsp_mock_wmfw_builder *builder,
1295cf1b7b4SRichard Fitzgerald 			       const char *info)
1305cf1b7b4SRichard Fitzgerald {
1315cf1b7b4SRichard Fitzgerald 	size_t info_len = strlen(info);
1325cf1b7b4SRichard Fitzgerald 	char *tmp = NULL;
1335cf1b7b4SRichard Fitzgerald 
1345cf1b7b4SRichard Fitzgerald 	if (info_len % 4) {
1355cf1b7b4SRichard Fitzgerald 		/* Create a padded string with length a multiple of 4 */
136*d979b783SJaroslav Kysela 		size_t copy_len = info_len;
1375cf1b7b4SRichard Fitzgerald 		info_len = round_up(info_len, 4);
1385cf1b7b4SRichard Fitzgerald 		tmp = kunit_kzalloc(builder->test_priv->test, info_len, GFP_KERNEL);
1395cf1b7b4SRichard Fitzgerald 		KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, tmp);
140*d979b783SJaroslav Kysela 		memcpy(tmp, info, copy_len);
1415cf1b7b4SRichard Fitzgerald 		info = tmp;
1425cf1b7b4SRichard Fitzgerald 	}
1435cf1b7b4SRichard Fitzgerald 
1445cf1b7b4SRichard Fitzgerald 	cs_dsp_mock_wmfw_add_raw_block(builder, WMFW_INFO_TEXT, 0, info, info_len);
1455cf1b7b4SRichard Fitzgerald 	kunit_kfree(builder->test_priv->test, tmp);
1465cf1b7b4SRichard Fitzgerald }
1475cf1b7b4SRichard Fitzgerald EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_wmfw_add_info, "FW_CS_DSP_KUNIT_TEST_UTILS");
1485cf1b7b4SRichard Fitzgerald 
1495cf1b7b4SRichard Fitzgerald /**
1505cf1b7b4SRichard Fitzgerald  * cs_dsp_mock_wmfw_add_data_block() - Add a data block to the wmfw file.
1515cf1b7b4SRichard Fitzgerald  *
1525cf1b7b4SRichard Fitzgerald  * @builder:		  Pointer to struct cs_dsp_mock_bin_builder.
1535cf1b7b4SRichard Fitzgerald  * @mem_region:		  Memory region for the block.
1545cf1b7b4SRichard Fitzgerald  * @mem_offset_dsp_words: Offset to start of destination in DSP words.
1555cf1b7b4SRichard Fitzgerald  * @payload_data:	  Pointer to buffer containing the payload data.
1565cf1b7b4SRichard Fitzgerald  * @payload_len_bytes:	  Length of payload data in bytes.
1575cf1b7b4SRichard Fitzgerald  */
cs_dsp_mock_wmfw_add_data_block(struct cs_dsp_mock_wmfw_builder * builder,int mem_region,unsigned int mem_offset_dsp_words,const void * payload_data,size_t payload_len_bytes)1585cf1b7b4SRichard Fitzgerald void cs_dsp_mock_wmfw_add_data_block(struct cs_dsp_mock_wmfw_builder *builder,
1595cf1b7b4SRichard Fitzgerald 				     int mem_region, unsigned int mem_offset_dsp_words,
1605cf1b7b4SRichard Fitzgerald 				     const void *payload_data, size_t payload_len_bytes)
1615cf1b7b4SRichard Fitzgerald {
1625cf1b7b4SRichard Fitzgerald 	/* Blob payload length must be a multiple of 4 */
1635cf1b7b4SRichard Fitzgerald 	KUNIT_ASSERT_EQ(builder->test_priv->test, payload_len_bytes % 4, 0);
1645cf1b7b4SRichard Fitzgerald 
1655cf1b7b4SRichard Fitzgerald 	cs_dsp_mock_wmfw_add_raw_block(builder, mem_region, mem_offset_dsp_words,
1665cf1b7b4SRichard Fitzgerald 				       payload_data, payload_len_bytes);
1675cf1b7b4SRichard Fitzgerald }
1685cf1b7b4SRichard Fitzgerald EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_wmfw_add_data_block, "FW_CS_DSP_KUNIT_TEST_UTILS");
1695cf1b7b4SRichard Fitzgerald 
cs_dsp_mock_wmfw_start_alg_info_block(struct cs_dsp_mock_wmfw_builder * builder,unsigned int alg_id,const char * name,const char * description)1705cf1b7b4SRichard Fitzgerald void cs_dsp_mock_wmfw_start_alg_info_block(struct cs_dsp_mock_wmfw_builder *builder,
1715cf1b7b4SRichard Fitzgerald 					   unsigned int alg_id,
1725cf1b7b4SRichard Fitzgerald 					   const char *name,
1735cf1b7b4SRichard Fitzgerald 					   const char *description)
1745cf1b7b4SRichard Fitzgerald {
1755cf1b7b4SRichard Fitzgerald 	struct wmfw_region *rgn = builder->write_p;
1765cf1b7b4SRichard Fitzgerald 	struct wmfw_adsp_alg_data *v1;
1775cf1b7b4SRichard Fitzgerald 	struct wmfw_short_string *shortstring;
1785cf1b7b4SRichard Fitzgerald 	struct wmfw_long_string *longstring;
1795cf1b7b4SRichard Fitzgerald 	size_t bytes_needed, name_len, description_len;
1805cf1b7b4SRichard Fitzgerald 	int offset;
1815cf1b7b4SRichard Fitzgerald 
1824308487bSRichard Fitzgerald 	KUNIT_ASSERT_LE(builder->test_priv->test, alg_id, 0xffffff);
1834308487bSRichard Fitzgerald 
1845cf1b7b4SRichard Fitzgerald 	/* Bytes needed for region header */
1855cf1b7b4SRichard Fitzgerald 	bytes_needed = offsetof(struct wmfw_region, data);
1865cf1b7b4SRichard Fitzgerald 
1875cf1b7b4SRichard Fitzgerald 	builder->alg_data_header = builder->write_p;
1885cf1b7b4SRichard Fitzgerald 	builder->num_coeffs = 0;
1895cf1b7b4SRichard Fitzgerald 
1905cf1b7b4SRichard Fitzgerald 	switch (builder->format_version) {
1915cf1b7b4SRichard Fitzgerald 	case 0:
1925cf1b7b4SRichard Fitzgerald 		KUNIT_FAIL(builder->test_priv->test, "wmfwV0 does not have alg blocks\n");
1935cf1b7b4SRichard Fitzgerald 		return;
1945cf1b7b4SRichard Fitzgerald 	case 1:
1955cf1b7b4SRichard Fitzgerald 		bytes_needed += offsetof(struct wmfw_adsp_alg_data, data);
1965cf1b7b4SRichard Fitzgerald 		KUNIT_ASSERT_TRUE(builder->test_priv->test,
1975cf1b7b4SRichard Fitzgerald 				  (builder->write_p + bytes_needed) <
1985cf1b7b4SRichard Fitzgerald 				  (builder->buf + CS_DSP_MOCK_WMFW_BUF_SIZE));
1995cf1b7b4SRichard Fitzgerald 
2005cf1b7b4SRichard Fitzgerald 		memset(builder->write_p, 0, bytes_needed);
2015cf1b7b4SRichard Fitzgerald 
2025cf1b7b4SRichard Fitzgerald 		/* Create region header */
2035cf1b7b4SRichard Fitzgerald 		rgn->offset = cpu_to_le32(WMFW_ALGORITHM_DATA << 24);
2045cf1b7b4SRichard Fitzgerald 
2055cf1b7b4SRichard Fitzgerald 		/* Create algorithm entry */
2065cf1b7b4SRichard Fitzgerald 		v1 = (struct wmfw_adsp_alg_data *)&rgn->data[0];
2075cf1b7b4SRichard Fitzgerald 		v1->id = cpu_to_le32(alg_id);
2085cf1b7b4SRichard Fitzgerald 		if (name)
2095cf1b7b4SRichard Fitzgerald 			strscpy(v1->name, name, sizeof(v1->name));
2105cf1b7b4SRichard Fitzgerald 
2115cf1b7b4SRichard Fitzgerald 		if (description)
2125cf1b7b4SRichard Fitzgerald 			strscpy(v1->descr, description, sizeof(v1->descr));
2135cf1b7b4SRichard Fitzgerald 		break;
2145cf1b7b4SRichard Fitzgerald 	default:
2155cf1b7b4SRichard Fitzgerald 		name_len = 0;
2165cf1b7b4SRichard Fitzgerald 		description_len = 0;
2175cf1b7b4SRichard Fitzgerald 
2185cf1b7b4SRichard Fitzgerald 		if (name)
2195cf1b7b4SRichard Fitzgerald 			name_len = strlen(name);
2205cf1b7b4SRichard Fitzgerald 
2215cf1b7b4SRichard Fitzgerald 		if (description)
2225cf1b7b4SRichard Fitzgerald 			description_len = strlen(description);
2235cf1b7b4SRichard Fitzgerald 
2245cf1b7b4SRichard Fitzgerald 		bytes_needed += sizeof(__le32); /* alg id */
2255cf1b7b4SRichard Fitzgerald 		bytes_needed += round_up(name_len + sizeof(u8), sizeof(__le32));
2265cf1b7b4SRichard Fitzgerald 		bytes_needed += round_up(description_len + sizeof(__le16), sizeof(__le32));
2275cf1b7b4SRichard Fitzgerald 		bytes_needed += sizeof(__le32); /* coeff count */
2285cf1b7b4SRichard Fitzgerald 
2295cf1b7b4SRichard Fitzgerald 		KUNIT_ASSERT_TRUE(builder->test_priv->test,
2305cf1b7b4SRichard Fitzgerald 				  (builder->write_p + bytes_needed) <
2315cf1b7b4SRichard Fitzgerald 				  (builder->buf + CS_DSP_MOCK_WMFW_BUF_SIZE));
2325cf1b7b4SRichard Fitzgerald 
2335cf1b7b4SRichard Fitzgerald 		memset(builder->write_p, 0, bytes_needed);
2345cf1b7b4SRichard Fitzgerald 
2355cf1b7b4SRichard Fitzgerald 		/* Create region header */
2365cf1b7b4SRichard Fitzgerald 		rgn->offset = cpu_to_le32(WMFW_ALGORITHM_DATA << 24);
2375cf1b7b4SRichard Fitzgerald 
2385cf1b7b4SRichard Fitzgerald 		/* Create algorithm entry */
2395cf1b7b4SRichard Fitzgerald 		*(__force __le32 *)&rgn->data[0] = cpu_to_le32(alg_id);
2405cf1b7b4SRichard Fitzgerald 
2415cf1b7b4SRichard Fitzgerald 		shortstring = (struct wmfw_short_string *)&rgn->data[4];
2425cf1b7b4SRichard Fitzgerald 		shortstring->len = name_len;
2435cf1b7b4SRichard Fitzgerald 
2445cf1b7b4SRichard Fitzgerald 		if (name_len)
2455cf1b7b4SRichard Fitzgerald 			memcpy(shortstring->data, name, name_len);
2465cf1b7b4SRichard Fitzgerald 
2475cf1b7b4SRichard Fitzgerald 		/* Round up to next __le32 */
2485cf1b7b4SRichard Fitzgerald 		offset = round_up(4 + struct_size_t(struct wmfw_short_string, data, name_len),
2495cf1b7b4SRichard Fitzgerald 				  sizeof(__le32));
2505cf1b7b4SRichard Fitzgerald 
2515cf1b7b4SRichard Fitzgerald 		longstring = (struct wmfw_long_string *)&rgn->data[offset];
2525cf1b7b4SRichard Fitzgerald 		longstring->len = cpu_to_le16(description_len);
2535cf1b7b4SRichard Fitzgerald 
2545cf1b7b4SRichard Fitzgerald 		if (description_len)
2555cf1b7b4SRichard Fitzgerald 			memcpy(longstring->data, description, description_len);
2565cf1b7b4SRichard Fitzgerald 		break;
2575cf1b7b4SRichard Fitzgerald 	}
2585cf1b7b4SRichard Fitzgerald 
2595cf1b7b4SRichard Fitzgerald 	builder->write_p += bytes_needed;
2605cf1b7b4SRichard Fitzgerald 	builder->bytes_used += bytes_needed;
2615cf1b7b4SRichard Fitzgerald }
2625cf1b7b4SRichard Fitzgerald EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_wmfw_start_alg_info_block, "FW_CS_DSP_KUNIT_TEST_UTILS");
2635cf1b7b4SRichard Fitzgerald 
cs_dsp_mock_wmfw_add_coeff_desc(struct cs_dsp_mock_wmfw_builder * builder,const struct cs_dsp_mock_coeff_def * def)2645cf1b7b4SRichard Fitzgerald void cs_dsp_mock_wmfw_add_coeff_desc(struct cs_dsp_mock_wmfw_builder *builder,
2655cf1b7b4SRichard Fitzgerald 				     const struct cs_dsp_mock_coeff_def *def)
2665cf1b7b4SRichard Fitzgerald {
2675cf1b7b4SRichard Fitzgerald 	struct wmfw_adsp_coeff_data *v1;
2685cf1b7b4SRichard Fitzgerald 	struct wmfw_short_string *shortstring;
2695cf1b7b4SRichard Fitzgerald 	struct wmfw_long_string *longstring;
2705cf1b7b4SRichard Fitzgerald 	size_t bytes_needed, shortname_len, fullname_len, description_len;
2715cf1b7b4SRichard Fitzgerald 	__le32 *ple32;
2725cf1b7b4SRichard Fitzgerald 
2735cf1b7b4SRichard Fitzgerald 	KUNIT_ASSERT_NOT_NULL(builder->test_priv->test, builder->alg_data_header);
2745cf1b7b4SRichard Fitzgerald 
2755cf1b7b4SRichard Fitzgerald 	switch (builder->format_version) {
2765cf1b7b4SRichard Fitzgerald 	case 0:
2775cf1b7b4SRichard Fitzgerald 		return;
2785cf1b7b4SRichard Fitzgerald 	case 1:
2795cf1b7b4SRichard Fitzgerald 		bytes_needed = offsetof(struct wmfw_adsp_coeff_data, data);
2805cf1b7b4SRichard Fitzgerald 		KUNIT_ASSERT_TRUE(builder->test_priv->test,
2815cf1b7b4SRichard Fitzgerald 				  (builder->write_p + bytes_needed) <
2825cf1b7b4SRichard Fitzgerald 				  (builder->buf + CS_DSP_MOCK_WMFW_BUF_SIZE));
2835cf1b7b4SRichard Fitzgerald 
2845cf1b7b4SRichard Fitzgerald 		v1 = (struct wmfw_adsp_coeff_data *)builder->write_p;
2855cf1b7b4SRichard Fitzgerald 		memset(v1, 0, sizeof(*v1));
2865cf1b7b4SRichard Fitzgerald 		v1->hdr.offset = cpu_to_le16(def->offset_dsp_words);
2875cf1b7b4SRichard Fitzgerald 		v1->hdr.type = cpu_to_le16(def->mem_type);
2885cf1b7b4SRichard Fitzgerald 		v1->hdr.size = cpu_to_le32(bytes_needed - sizeof(v1->hdr));
2895cf1b7b4SRichard Fitzgerald 		v1->ctl_type = cpu_to_le16(def->type);
2905cf1b7b4SRichard Fitzgerald 		v1->flags = cpu_to_le16(def->flags);
2915cf1b7b4SRichard Fitzgerald 		v1->len = cpu_to_le32(def->length_bytes);
2925cf1b7b4SRichard Fitzgerald 
2935cf1b7b4SRichard Fitzgerald 		if (def->fullname)
2945cf1b7b4SRichard Fitzgerald 			strscpy(v1->name, def->fullname, sizeof(v1->name));
2955cf1b7b4SRichard Fitzgerald 
2965cf1b7b4SRichard Fitzgerald 		if (def->description)
2975cf1b7b4SRichard Fitzgerald 			strscpy(v1->descr, def->description, sizeof(v1->descr));
2985cf1b7b4SRichard Fitzgerald 		break;
2995cf1b7b4SRichard Fitzgerald 	default:
3005cf1b7b4SRichard Fitzgerald 		fullname_len = 0;
3015cf1b7b4SRichard Fitzgerald 		description_len = 0;
3025cf1b7b4SRichard Fitzgerald 		shortname_len = strlen(def->shortname);
3035cf1b7b4SRichard Fitzgerald 
3045cf1b7b4SRichard Fitzgerald 		if (def->fullname)
3055cf1b7b4SRichard Fitzgerald 			fullname_len = strlen(def->fullname);
3065cf1b7b4SRichard Fitzgerald 
3075cf1b7b4SRichard Fitzgerald 		if (def->description)
3085cf1b7b4SRichard Fitzgerald 			description_len = strlen(def->description);
3095cf1b7b4SRichard Fitzgerald 
3105cf1b7b4SRichard Fitzgerald 		bytes_needed = sizeof(__le32) * 2; /* type, offset and size */
3115cf1b7b4SRichard Fitzgerald 		bytes_needed += round_up(shortname_len + sizeof(u8), sizeof(__le32));
3125cf1b7b4SRichard Fitzgerald 		bytes_needed += round_up(fullname_len + sizeof(u8), sizeof(__le32));
3135cf1b7b4SRichard Fitzgerald 		bytes_needed += round_up(description_len + sizeof(__le16), sizeof(__le32));
3145cf1b7b4SRichard Fitzgerald 		bytes_needed += sizeof(__le32) * 2; /* flags, type and length */
3155cf1b7b4SRichard Fitzgerald 		KUNIT_ASSERT_TRUE(builder->test_priv->test,
3165cf1b7b4SRichard Fitzgerald 				  (builder->write_p + bytes_needed) <
3175cf1b7b4SRichard Fitzgerald 				  (builder->buf + CS_DSP_MOCK_WMFW_BUF_SIZE));
3185cf1b7b4SRichard Fitzgerald 
3195cf1b7b4SRichard Fitzgerald 		ple32 = (__force __le32 *)builder->write_p;
3205cf1b7b4SRichard Fitzgerald 		*ple32++ = cpu_to_le32(def->offset_dsp_words | (def->mem_type << 16));
3215cf1b7b4SRichard Fitzgerald 		*ple32++ = cpu_to_le32(bytes_needed - sizeof(__le32) - sizeof(__le32));
3225cf1b7b4SRichard Fitzgerald 
3235cf1b7b4SRichard Fitzgerald 		shortstring = (__force struct wmfw_short_string *)ple32;
3245cf1b7b4SRichard Fitzgerald 		shortstring->len = shortname_len;
3255cf1b7b4SRichard Fitzgerald 		memcpy(shortstring->data, def->shortname, shortname_len);
3265cf1b7b4SRichard Fitzgerald 
3275cf1b7b4SRichard Fitzgerald 		/* Round up to next __le32 multiple */
3285cf1b7b4SRichard Fitzgerald 		ple32 += round_up(struct_size_t(struct wmfw_short_string, data, shortname_len),
3295cf1b7b4SRichard Fitzgerald 				  sizeof(*ple32)) / sizeof(*ple32);
3305cf1b7b4SRichard Fitzgerald 
3315cf1b7b4SRichard Fitzgerald 		shortstring = (__force struct wmfw_short_string *)ple32;
3325cf1b7b4SRichard Fitzgerald 		shortstring->len = fullname_len;
3335cf1b7b4SRichard Fitzgerald 		memcpy(shortstring->data, def->fullname, fullname_len);
3345cf1b7b4SRichard Fitzgerald 
3355cf1b7b4SRichard Fitzgerald 		/* Round up to next __le32 multiple */
3365cf1b7b4SRichard Fitzgerald 		ple32 += round_up(struct_size_t(struct wmfw_short_string, data, fullname_len),
3375cf1b7b4SRichard Fitzgerald 				  sizeof(*ple32)) / sizeof(*ple32);
3385cf1b7b4SRichard Fitzgerald 
3395cf1b7b4SRichard Fitzgerald 		longstring = (__force struct wmfw_long_string *)ple32;
340644115e8SRichard Fitzgerald 		longstring->len = cpu_to_le16(description_len);
3415cf1b7b4SRichard Fitzgerald 		memcpy(longstring->data, def->description, description_len);
3425cf1b7b4SRichard Fitzgerald 
3435cf1b7b4SRichard Fitzgerald 		/* Round up to next __le32 multiple */
3445cf1b7b4SRichard Fitzgerald 		ple32 += round_up(struct_size_t(struct wmfw_long_string, data, description_len),
3455cf1b7b4SRichard Fitzgerald 				  sizeof(*ple32)) / sizeof(*ple32);
3465cf1b7b4SRichard Fitzgerald 
3475cf1b7b4SRichard Fitzgerald 		*ple32++ = cpu_to_le32(def->type | (def->flags << 16));
3485cf1b7b4SRichard Fitzgerald 		*ple32 = cpu_to_le32(def->length_bytes);
3495cf1b7b4SRichard Fitzgerald 		break;
3505cf1b7b4SRichard Fitzgerald 	}
3515cf1b7b4SRichard Fitzgerald 
3525cf1b7b4SRichard Fitzgerald 	builder->write_p += bytes_needed;
3535cf1b7b4SRichard Fitzgerald 	builder->bytes_used += bytes_needed;
3545cf1b7b4SRichard Fitzgerald 	builder->num_coeffs++;
3555cf1b7b4SRichard Fitzgerald }
3565cf1b7b4SRichard Fitzgerald EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_wmfw_add_coeff_desc, "FW_CS_DSP_KUNIT_TEST_UTILS");
3575cf1b7b4SRichard Fitzgerald 
cs_dsp_mock_wmfw_end_alg_info_block(struct cs_dsp_mock_wmfw_builder * builder)3585cf1b7b4SRichard Fitzgerald void cs_dsp_mock_wmfw_end_alg_info_block(struct cs_dsp_mock_wmfw_builder *builder)
3595cf1b7b4SRichard Fitzgerald {
3605cf1b7b4SRichard Fitzgerald 	struct wmfw_region *rgn = builder->alg_data_header;
3615cf1b7b4SRichard Fitzgerald 	struct wmfw_adsp_alg_data *v1;
3625cf1b7b4SRichard Fitzgerald 	const struct wmfw_short_string *shortstring;
3635cf1b7b4SRichard Fitzgerald 	const struct wmfw_long_string *longstring;
3645cf1b7b4SRichard Fitzgerald 	size_t offset;
3655cf1b7b4SRichard Fitzgerald 
3665cf1b7b4SRichard Fitzgerald 	KUNIT_ASSERT_NOT_NULL(builder->test_priv->test, rgn);
3675cf1b7b4SRichard Fitzgerald 
3685cf1b7b4SRichard Fitzgerald 	/* Fill in data size */
3695cf1b7b4SRichard Fitzgerald 	rgn->len = cpu_to_le32((u8 *)builder->write_p - (u8 *)rgn->data);
3705cf1b7b4SRichard Fitzgerald 
3715cf1b7b4SRichard Fitzgerald 	/* Fill in coefficient count */
3725cf1b7b4SRichard Fitzgerald 	switch (builder->format_version) {
3735cf1b7b4SRichard Fitzgerald 	case 0:
3745cf1b7b4SRichard Fitzgerald 		return;
3755cf1b7b4SRichard Fitzgerald 	case 1:
3765cf1b7b4SRichard Fitzgerald 		v1 = (struct wmfw_adsp_alg_data *)&rgn->data[0];
3775cf1b7b4SRichard Fitzgerald 		v1->ncoeff = cpu_to_le32(builder->num_coeffs);
3785cf1b7b4SRichard Fitzgerald 		break;
3795cf1b7b4SRichard Fitzgerald 	default:
3805cf1b7b4SRichard Fitzgerald 		offset = 4; /* skip alg id */
3815cf1b7b4SRichard Fitzgerald 
3825cf1b7b4SRichard Fitzgerald 		/* Get name length and round up to __le32 multiple */
3835cf1b7b4SRichard Fitzgerald 		shortstring = (const struct wmfw_short_string *)&rgn->data[offset];
3845cf1b7b4SRichard Fitzgerald 		offset += round_up(struct_size_t(struct wmfw_short_string, data, shortstring->len),
3855cf1b7b4SRichard Fitzgerald 				   sizeof(__le32));
3865cf1b7b4SRichard Fitzgerald 
3875cf1b7b4SRichard Fitzgerald 		/* Get description length and round up to __le32 multiple */
3885cf1b7b4SRichard Fitzgerald 		longstring = (const struct wmfw_long_string *)&rgn->data[offset];
3895cf1b7b4SRichard Fitzgerald 		offset += round_up(struct_size_t(struct wmfw_long_string, data,
3905cf1b7b4SRichard Fitzgerald 				   le16_to_cpu(longstring->len)),
3915cf1b7b4SRichard Fitzgerald 				   sizeof(__le32));
3925cf1b7b4SRichard Fitzgerald 
3935cf1b7b4SRichard Fitzgerald 		*(__force __le32 *)&rgn->data[offset] = cpu_to_le32(builder->num_coeffs);
3945cf1b7b4SRichard Fitzgerald 		break;
3955cf1b7b4SRichard Fitzgerald 	}
3965cf1b7b4SRichard Fitzgerald 
3975cf1b7b4SRichard Fitzgerald 	builder->alg_data_header = NULL;
3985cf1b7b4SRichard Fitzgerald }
3995cf1b7b4SRichard Fitzgerald EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_wmfw_end_alg_info_block, "FW_CS_DSP_KUNIT_TEST_UTILS");
4005cf1b7b4SRichard Fitzgerald 
cs_dsp_init_adsp2_halo_wmfw(struct cs_dsp_mock_wmfw_builder * builder)4015cf1b7b4SRichard Fitzgerald static void cs_dsp_init_adsp2_halo_wmfw(struct cs_dsp_mock_wmfw_builder *builder)
4025cf1b7b4SRichard Fitzgerald {
4035cf1b7b4SRichard Fitzgerald 	struct wmfw_adsp2_halo_header *hdr = builder->buf;
4045cf1b7b4SRichard Fitzgerald 	const struct cs_dsp *dsp = builder->test_priv->dsp;
4055cf1b7b4SRichard Fitzgerald 
4065cf1b7b4SRichard Fitzgerald 	memcpy(hdr->header.magic, "WMFW", sizeof(hdr->header.magic));
4075cf1b7b4SRichard Fitzgerald 	hdr->header.len = cpu_to_le32(sizeof(*hdr));
4085cf1b7b4SRichard Fitzgerald 	hdr->header.ver = builder->format_version;
4095cf1b7b4SRichard Fitzgerald 	hdr->header.core = dsp->type;
4105cf1b7b4SRichard Fitzgerald 	hdr->header.rev = cpu_to_le16(dsp->rev);
4115cf1b7b4SRichard Fitzgerald 
4125cf1b7b4SRichard Fitzgerald 	hdr->sizes.pm = cpu_to_le32(cs_dsp_mock_size_of_region(dsp, WMFW_ADSP2_PM));
4135cf1b7b4SRichard Fitzgerald 	hdr->sizes.xm = cpu_to_le32(cs_dsp_mock_size_of_region(dsp, WMFW_ADSP2_XM));
4145cf1b7b4SRichard Fitzgerald 	hdr->sizes.ym = cpu_to_le32(cs_dsp_mock_size_of_region(dsp, WMFW_ADSP2_YM));
4155cf1b7b4SRichard Fitzgerald 
4165cf1b7b4SRichard Fitzgerald 	switch (dsp->type) {
4175cf1b7b4SRichard Fitzgerald 	case WMFW_ADSP2:
4185cf1b7b4SRichard Fitzgerald 		hdr->sizes.zm = cpu_to_le32(cs_dsp_mock_size_of_region(dsp, WMFW_ADSP2_ZM));
4195cf1b7b4SRichard Fitzgerald 		break;
4205cf1b7b4SRichard Fitzgerald 	default:
4215cf1b7b4SRichard Fitzgerald 		break;
4225cf1b7b4SRichard Fitzgerald 	}
4235cf1b7b4SRichard Fitzgerald 
4245cf1b7b4SRichard Fitzgerald 	builder->write_p = &hdr[1];
4255cf1b7b4SRichard Fitzgerald 	builder->bytes_used += sizeof(*hdr);
4265cf1b7b4SRichard Fitzgerald }
4275cf1b7b4SRichard Fitzgerald 
4285cf1b7b4SRichard Fitzgerald /**
4295cf1b7b4SRichard Fitzgerald  * cs_dsp_mock_wmfw_init() - Initialize a struct cs_dsp_mock_wmfw_builder.
4305cf1b7b4SRichard Fitzgerald  *
4315cf1b7b4SRichard Fitzgerald  * @priv:		Pointer to struct cs_dsp_test.
4325cf1b7b4SRichard Fitzgerald  * @format_version:	Required wmfw format version.
4335cf1b7b4SRichard Fitzgerald  *
4345cf1b7b4SRichard Fitzgerald  * Return: Pointer to created struct cs_dsp_mock_wmfw_builder.
4355cf1b7b4SRichard Fitzgerald  */
cs_dsp_mock_wmfw_init(struct cs_dsp_test * priv,int format_version)4365cf1b7b4SRichard Fitzgerald struct cs_dsp_mock_wmfw_builder *cs_dsp_mock_wmfw_init(struct cs_dsp_test *priv,
4375cf1b7b4SRichard Fitzgerald 						       int format_version)
4385cf1b7b4SRichard Fitzgerald {
4395cf1b7b4SRichard Fitzgerald 	struct cs_dsp_mock_wmfw_builder *builder;
4405cf1b7b4SRichard Fitzgerald 
4414308487bSRichard Fitzgerald 	KUNIT_ASSERT_LE(priv->test, format_version, 0xff);
4424308487bSRichard Fitzgerald 
4435cf1b7b4SRichard Fitzgerald 	/* If format version isn't given use the default for the target core */
4445cf1b7b4SRichard Fitzgerald 	if (format_version < 0) {
4455cf1b7b4SRichard Fitzgerald 		switch (priv->dsp->type) {
4465cf1b7b4SRichard Fitzgerald 		case WMFW_ADSP2:
4475cf1b7b4SRichard Fitzgerald 			format_version = 2;
4485cf1b7b4SRichard Fitzgerald 			break;
4495cf1b7b4SRichard Fitzgerald 		default:
4505cf1b7b4SRichard Fitzgerald 			format_version = 3;
4515cf1b7b4SRichard Fitzgerald 			break;
4525cf1b7b4SRichard Fitzgerald 		}
4535cf1b7b4SRichard Fitzgerald 	}
4545cf1b7b4SRichard Fitzgerald 
4555cf1b7b4SRichard Fitzgerald 	builder = kunit_kzalloc(priv->test, sizeof(*builder), GFP_KERNEL);
4565cf1b7b4SRichard Fitzgerald 	KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder);
4575cf1b7b4SRichard Fitzgerald 
4585cf1b7b4SRichard Fitzgerald 	builder->test_priv = priv;
4595cf1b7b4SRichard Fitzgerald 	builder->format_version = format_version;
4605cf1b7b4SRichard Fitzgerald 
4615cf1b7b4SRichard Fitzgerald 	builder->buf = vmalloc(CS_DSP_MOCK_WMFW_BUF_SIZE);
4625cf1b7b4SRichard Fitzgerald 	KUNIT_ASSERT_NOT_NULL(priv->test, builder->buf);
4635cf1b7b4SRichard Fitzgerald 	kunit_add_action_or_reset(priv->test, vfree_action_wrapper, builder->buf);
4645cf1b7b4SRichard Fitzgerald 
4655cf1b7b4SRichard Fitzgerald 	builder->buf_size_bytes = CS_DSP_MOCK_WMFW_BUF_SIZE;
4665cf1b7b4SRichard Fitzgerald 
4675cf1b7b4SRichard Fitzgerald 	switch (priv->dsp->type) {
4685cf1b7b4SRichard Fitzgerald 	case WMFW_ADSP2:
4695cf1b7b4SRichard Fitzgerald 	case WMFW_HALO:
4705cf1b7b4SRichard Fitzgerald 		cs_dsp_init_adsp2_halo_wmfw(builder);
4715cf1b7b4SRichard Fitzgerald 		break;
4725cf1b7b4SRichard Fitzgerald 	default:
4735cf1b7b4SRichard Fitzgerald 		break;
4745cf1b7b4SRichard Fitzgerald 	}
4755cf1b7b4SRichard Fitzgerald 
4765cf1b7b4SRichard Fitzgerald 	return builder;
4775cf1b7b4SRichard Fitzgerald }
4785cf1b7b4SRichard Fitzgerald EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_wmfw_init, "FW_CS_DSP_KUNIT_TEST_UTILS");
479