Path: blob/master/drivers/firmware/cirrus/test/cs_dsp_mock_bin.c
53055 views
// SPDX-License-Identifier: GPL-2.0-only1//2// bin file builder for cs_dsp KUnit tests.3//4// Copyright (C) 2024 Cirrus Logic, Inc. and5// Cirrus Logic International Semiconductor Ltd.67#include <kunit/resource.h>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/firmware.h>13#include <linux/math.h>14#include <linux/overflow.h>15#include <linux/string.h>16#include <linux/vmalloc.h>1718/* Buffer large enough for bin file content */19#define CS_DSP_MOCK_BIN_BUF_SIZE 327682021KUNIT_DEFINE_ACTION_WRAPPER(vfree_action_wrapper, vfree, void *)2223struct cs_dsp_mock_bin_builder {24struct cs_dsp_test *test_priv;25void *buf;26void *write_p;27size_t bytes_used;28};2930/**31* cs_dsp_mock_bin_get_firmware() - Get struct firmware wrapper for data.32*33* @builder: Pointer to struct cs_dsp_mock_bin_builder.34*35* Return: Pointer to a struct firmware wrapper for the data.36*/37struct firmware *cs_dsp_mock_bin_get_firmware(struct cs_dsp_mock_bin_builder *builder)38{39struct firmware *fw;4041fw = kunit_kzalloc(builder->test_priv->test, sizeof(*fw), GFP_KERNEL);42KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, fw);4344fw->data = builder->buf;45fw->size = builder->bytes_used;4647return fw;48}49EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_get_firmware, "FW_CS_DSP_KUNIT_TEST_UTILS");5051/**52* cs_dsp_mock_bin_add_raw_block() - Add a data block to the bin file.53*54* @builder: Pointer to struct cs_dsp_mock_bin_builder.55* @alg_id: Algorithm ID.56* @alg_ver: Algorithm version.57* @type: Type of the block.58* @offset: 16-bit offset.59* @offset32: 32-bit offset (sample rate on V1 and V2 file formats).60* @payload_data: Pointer to buffer containing the payload data.61* @payload_len_bytes: Length of payload data in bytes.62*/63void cs_dsp_mock_bin_add_raw_block(struct cs_dsp_mock_bin_builder *builder,64unsigned int alg_id, unsigned int alg_ver,65int type, u16 offset, u32 offset32,66const void *payload_data, size_t payload_len_bytes)67{68struct wmfw_coeff_item *item;69size_t bytes_needed = struct_size_t(struct wmfw_coeff_item, data, payload_len_bytes);7071KUNIT_ASSERT_TRUE(builder->test_priv->test,72(builder->write_p + bytes_needed) <73(builder->buf + CS_DSP_MOCK_BIN_BUF_SIZE));7475item = builder->write_p;7677item->offset = cpu_to_le16(offset);78item->offset32 = cpu_to_le32(offset32);79item->type = cpu_to_le16(type);80item->id = cpu_to_le32(alg_id);81item->ver = cpu_to_le32(alg_ver << 8);82item->len = cpu_to_le32(payload_len_bytes);8384if (payload_len_bytes)85memcpy(item->data, payload_data, payload_len_bytes);8687builder->write_p += bytes_needed;88builder->bytes_used += bytes_needed;89}90EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_raw_block, "FW_CS_DSP_KUNIT_TEST_UTILS");9192static void cs_dsp_mock_bin_add_name_or_info(struct cs_dsp_mock_bin_builder *builder,93const char *info, int type)94{95size_t info_len = strlen(info);96char *tmp = NULL;9798if (info_len % 4) {99/* Create a padded string with length a multiple of 4 */100size_t copy_len = info_len;101info_len = round_up(info_len, 4);102tmp = kunit_kzalloc(builder->test_priv->test, info_len, GFP_KERNEL);103KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, tmp);104memcpy(tmp, info, copy_len);105info = tmp;106}107108cs_dsp_mock_bin_add_raw_block(builder, 0, 0, WMFW_INFO_TEXT, 0, 0, info, info_len);109kunit_kfree(builder->test_priv->test, tmp);110}111112/**113* cs_dsp_mock_bin_add_info() - Add an info block to the bin file.114*115* @builder: Pointer to struct cs_dsp_mock_bin_builder.116* @info: Pointer to info string to be copied into the file.117*118* The string will be padded to a length that is a multiple of 4 bytes.119*/120void cs_dsp_mock_bin_add_info(struct cs_dsp_mock_bin_builder *builder,121const char *info)122{123cs_dsp_mock_bin_add_name_or_info(builder, info, WMFW_INFO_TEXT);124}125EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_info, "FW_CS_DSP_KUNIT_TEST_UTILS");126127/**128* cs_dsp_mock_bin_add_name() - Add a name block to the bin file.129*130* @builder: Pointer to struct cs_dsp_mock_bin_builder.131* @name: Pointer to name string to be copied into the file.132*/133void cs_dsp_mock_bin_add_name(struct cs_dsp_mock_bin_builder *builder,134const char *name)135{136cs_dsp_mock_bin_add_name_or_info(builder, name, WMFW_NAME_TEXT);137}138EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_name, "FW_CS_DSP_KUNIT_TEST_UTILS");139140/**141* cs_dsp_mock_bin_add_patch() - Add a patch data block to the bin file.142*143* @builder: Pointer to struct cs_dsp_mock_bin_builder.144* @alg_id: Algorithm ID for the patch.145* @alg_ver: Algorithm version for the patch.146* @mem_region: Memory region for the patch.147* @reg_addr_offset: Offset to start of data in register addresses.148* @payload_data: Pointer to buffer containing the payload data.149* @payload_len_bytes: Length of payload data in bytes.150*/151void cs_dsp_mock_bin_add_patch(struct cs_dsp_mock_bin_builder *builder,152unsigned int alg_id, unsigned int alg_ver,153int mem_region, unsigned int reg_addr_offset,154const void *payload_data, size_t payload_len_bytes)155{156/* Payload length must be a multiple of 4 */157KUNIT_ASSERT_EQ(builder->test_priv->test, payload_len_bytes % 4, 0);158159cs_dsp_mock_bin_add_raw_block(builder, alg_id, alg_ver,160mem_region, (u16)reg_addr_offset, 0,161payload_data, payload_len_bytes);162}163EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_patch, "FW_CS_DSP_KUNIT_TEST_UTILS");164165/**166* cs_dsp_mock_bin_add_patch_off32() - Add a patch data block with 32-bit offset.167*168* @builder: Pointer to struct cs_dsp_mock_bin_builder.169* @alg_id: Algorithm ID for the patch.170* @alg_ver: Algorithm version for the patch.171* @mem_region: Memory region for the patch.172* @reg_addr_offset: Offset to start of data in register addresses.173* @payload_data: Pointer to buffer containing the payload data.174* @payload_len_bytes: Length of payload data in bytes.175*/176void cs_dsp_mock_bin_add_patch_off32(struct cs_dsp_mock_bin_builder *builder,177unsigned int alg_id, unsigned int alg_ver,178int mem_region, unsigned int reg_addr_offset,179const void *payload_data, size_t payload_len_bytes)180{181/* Payload length must be a multiple of 4 */182KUNIT_ASSERT_EQ(builder->test_priv->test, payload_len_bytes % 4, 0);183184/* Mark the block as using the 32-bit offset */185mem_region |= 0xf400;186187cs_dsp_mock_bin_add_raw_block(builder, alg_id, alg_ver,188mem_region, 0, reg_addr_offset,189payload_data, payload_len_bytes);190}191EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_patch_off32, "FW_CS_DSP_KUNIT_TEST_UTILS");192193/**194* cs_dsp_mock_bin_init() - Initialize a struct cs_dsp_mock_bin_builder.195*196* @priv: Pointer to struct cs_dsp_test.197* @format_version: Required bin format version.198* @fw_version: Firmware version to put in bin file.199*200* Return: Pointer to created struct cs_dsp_mock_bin_builder.201*/202struct cs_dsp_mock_bin_builder *cs_dsp_mock_bin_init(struct cs_dsp_test *priv,203int format_version,204unsigned int fw_version)205{206struct cs_dsp_mock_bin_builder *builder;207struct wmfw_coeff_hdr *hdr;208209KUNIT_ASSERT_LE(priv->test, format_version, 0xff);210KUNIT_ASSERT_LE(priv->test, fw_version, 0xffffff);211212builder = kunit_kzalloc(priv->test, sizeof(*builder), GFP_KERNEL);213KUNIT_ASSERT_NOT_ERR_OR_NULL(priv->test, builder);214builder->test_priv = priv;215216builder->buf = vmalloc(CS_DSP_MOCK_BIN_BUF_SIZE);217KUNIT_ASSERT_NOT_NULL(priv->test, builder->buf);218kunit_add_action_or_reset(priv->test, vfree_action_wrapper, builder->buf);219220/* Create header */221hdr = builder->buf;222memcpy(hdr->magic, "WMDR", sizeof(hdr->magic));223hdr->len = cpu_to_le32(offsetof(struct wmfw_coeff_hdr, data));224hdr->ver = cpu_to_le32(fw_version | (format_version << 24));225hdr->core_ver = cpu_to_le32(((u32)priv->dsp->type << 24) | priv->dsp->rev);226227builder->write_p = hdr->data;228builder->bytes_used = offsetof(struct wmfw_coeff_hdr, data);229230return builder;231}232EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_init, "FW_CS_DSP_KUNIT_TEST_UTILS");233234235