1 // SPDX-License-Identifier: GPL-2.0-only
3 // bin file builder for cs_dsp KUnit tests.
5 // Copyright (C) 2024 Cirrus Logic, Inc. and
6 // Cirrus Logic International Semiconductor Ltd.
8 #include <kunit/resource.h>
9 #include <kunit/test.h>
10 #include <linux/firmware/cirrus/cs_dsp.h>
11 #include <linux/firmware/cirrus/cs_dsp_test_utils.h>
12 #include <linux/firmware/cirrus/wmfw.h>
13 #include <linux/firmware.h>
14 #include <linux/math.h>
15 #include <linux/overflow.h>
16 #include <linux/string.h>
17 #include <linux/vmalloc.h>
19 /* Buffer large enough for bin file content */
20 #define CS_DSP_MOCK_BIN_BUF_SIZE 32768
22 KUNIT_DEFINE_ACTION_WRAPPER(vfree_action_wrapper, vfree, void *)
24 struct cs_dsp_mock_bin_builder {
25 struct cs_dsp_test *test_priv;
32 * cs_dsp_mock_bin_get_firmware() - Get struct firmware wrapper for data.
34 * @builder: Pointer to struct cs_dsp_mock_bin_builder.
36 * Return: Pointer to a struct firmware wrapper for the data.
38 struct firmware *cs_dsp_mock_bin_get_firmware(struct cs_dsp_mock_bin_builder *builder)
42 fw = kunit_kzalloc(builder->test_priv->test, sizeof(*fw), GFP_KERNEL);
43 KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, fw);
45 fw->data = builder->buf;
46 fw->size = builder->bytes_used;
50 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_get_firmware, "FW_CS_DSP_KUNIT_TEST_UTILS");
53 * cs_dsp_mock_bin_add_raw_block() - Add a data block to the bin file.
55 * @builder: Pointer to struct cs_dsp_mock_bin_builder.
56 * @alg_id: Algorithm ID.
57 * @alg_ver: Algorithm version.
58 * @type: Type of the block.
60 * @payload_data: Pointer to buffer containing the payload data.
61 * @payload_len_bytes: Length of payload data in bytes.
63 void cs_dsp_mock_bin_add_raw_block(struct cs_dsp_mock_bin_builder *builder,
64 unsigned int alg_id, unsigned int alg_ver,
65 int type, unsigned int offset,
66 const void *payload_data, size_t payload_len_bytes)
68 struct wmfw_coeff_item *item;
69 size_t bytes_needed = struct_size_t(struct wmfw_coeff_item, data, payload_len_bytes);
71 KUNIT_ASSERT_TRUE(builder->test_priv->test,
72 (builder->write_p + bytes_needed) <
73 (builder->buf + CS_DSP_MOCK_BIN_BUF_SIZE));
75 item = builder->write_p;
77 item->offset = cpu_to_le16(offset);
78 item->type = cpu_to_le16(type);
79 item->id = cpu_to_le32(alg_id);
80 item->ver = cpu_to_le32(alg_ver << 8);
81 item->len = cpu_to_le32(payload_len_bytes);
83 if (payload_len_bytes)
84 memcpy(item->data, payload_data, payload_len_bytes);
86 builder->write_p += bytes_needed;
87 builder->bytes_used += bytes_needed;
89 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_raw_block, "FW_CS_DSP_KUNIT_TEST_UTILS");
91 static void cs_dsp_mock_bin_add_name_or_info(struct cs_dsp_mock_bin_builder *builder,
92 const char *info, int type)
94 size_t info_len = strlen(info);
98 /* Create a padded string with length a multiple of 4 */
99 info_len = round_up(info_len, 4);
100 tmp = kunit_kzalloc(builder->test_priv->test, info_len, GFP_KERNEL);
101 KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, tmp);
102 memcpy(tmp, info, info_len);
106 cs_dsp_mock_bin_add_raw_block(builder, 0, 0, WMFW_INFO_TEXT, 0, info, info_len);
107 kunit_kfree(builder->test_priv->test, tmp);
111 * cs_dsp_mock_bin_add_info() - Add an info block to the bin file.
113 * @builder: Pointer to struct cs_dsp_mock_bin_builder.
114 * @info: Pointer to info string to be copied into the file.
116 * The string will be padded to a length that is a multiple of 4 bytes.
118 void cs_dsp_mock_bin_add_info(struct cs_dsp_mock_bin_builder *builder,
121 cs_dsp_mock_bin_add_name_or_info(builder, info, WMFW_INFO_TEXT);
123 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_info, "FW_CS_DSP_KUNIT_TEST_UTILS");
126 * cs_dsp_mock_bin_add_name() - Add a name block to the bin file.
128 * @builder: Pointer to struct cs_dsp_mock_bin_builder.
129 * @name: Pointer to name string to be copied into the file.
131 void cs_dsp_mock_bin_add_name(struct cs_dsp_mock_bin_builder *builder,
134 cs_dsp_mock_bin_add_name_or_info(builder, name, WMFW_NAME_TEXT);
136 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_name, "FW_CS_DSP_KUNIT_TEST_UTILS");
139 * cs_dsp_mock_bin_add_patch() - Add a patch data block to the bin file.
141 * @builder: Pointer to struct cs_dsp_mock_bin_builder.
142 * @alg_id: Algorithm ID for the patch.
143 * @alg_ver: Algorithm version for the patch.
144 * @mem_region: Memory region for the patch.
145 * @reg_addr_offset: Offset to start of data in register addresses.
146 * @payload_data: Pointer to buffer containing the payload data.
147 * @payload_len_bytes: Length of payload data in bytes.
149 void cs_dsp_mock_bin_add_patch(struct cs_dsp_mock_bin_builder *builder,
150 unsigned int alg_id, unsigned int alg_ver,
151 int mem_region, unsigned int reg_addr_offset,
152 const void *payload_data, size_t payload_len_bytes)
154 /* Payload length must be a multiple of 4 */
155 KUNIT_ASSERT_EQ(builder->test_priv->test, payload_len_bytes % 4, 0);
157 cs_dsp_mock_bin_add_raw_block(builder, alg_id, alg_ver,
158 mem_region, reg_addr_offset,
159 payload_data, payload_len_bytes);
161 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_patch, "FW_CS_DSP_KUNIT_TEST_UTILS");
164 * cs_dsp_mock_bin_init() - Initialize a struct cs_dsp_mock_bin_builder.
166 * @priv: Pointer to struct cs_dsp_test.
167 * @format_version: Required bin format version.
168 * @fw_version: Firmware version to put in bin file.
170 * Return: Pointer to created struct cs_dsp_mock_bin_builder.
172 struct cs_dsp_mock_bin_builder *cs_dsp_mock_bin_init(struct cs_dsp_test *priv,
174 unsigned int fw_version)
176 struct cs_dsp_mock_bin_builder *builder;
177 struct wmfw_coeff_hdr *hdr;
179 builder = kunit_kzalloc(priv->test, sizeof(*builder), GFP_KERNEL);
180 KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder);
181 builder->test_priv = priv;
183 builder->buf = vmalloc(CS_DSP_MOCK_BIN_BUF_SIZE);
184 KUNIT_ASSERT_NOT_NULL(priv->test, builder->buf);
185 kunit_add_action_or_reset(priv->test, vfree_action_wrapper, builder->buf);
189 memcpy(hdr->magic, "WMDR", sizeof(hdr->magic));
190 hdr->len = cpu_to_le32(offsetof(struct wmfw_coeff_hdr, data));
191 hdr->ver = cpu_to_le32(fw_version | (format_version << 24));
192 hdr->core_ver = cpu_to_le32(((u32)priv->dsp->type << 24) | priv->dsp->rev);
194 builder->write_p = hdr->data;
195 builder->bytes_used = offsetof(struct wmfw_coeff_hdr, data);
199 EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_init, "FW_CS_DSP_KUNIT_TEST_UTILS");