firmware: cirrus: cs_dsp: Add long-offset WMDR

Merge series from Richard Fitzgerald <rf@opensource.cirrus.com>:

Version 3 of the WMDR file format introduces a new block type that has a
32-bit address offset.

The first patch of this series adds the support to the cs_dsp driver.

The rest of the series is adding KUnit tests for this.
This commit is contained in:
Mark Brown
2026-01-06 18:48:31 +00:00
8 changed files with 731 additions and 394 deletions

View File

@@ -2138,7 +2138,8 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
const struct cs_dsp_region *mem;
struct cs_dsp_alg_region *alg_region;
const char *region_name;
int ret, pos, blocks, type, offset, reg, version;
int ret, pos, blocks, type, version;
unsigned int offset, reg;
u8 *buf = NULL;
size_t buf_len = 0;
size_t region_len;
@@ -2163,6 +2164,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
switch (be32_to_cpu(hdr->rev) & 0xff) {
case 1:
case 2:
case 3:
break;
default:
cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
@@ -2171,7 +2173,8 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
goto out_fw;
}
cs_dsp_info(dsp, "%s: v%d.%d.%d\n", file,
cs_dsp_info(dsp, "%s (v%d): v%d.%d.%d\n", file,
be32_to_cpu(hdr->rev) & 0xff,
(le32_to_cpu(hdr->ver) >> 16) & 0xff,
(le32_to_cpu(hdr->ver) >> 8) & 0xff,
le32_to_cpu(hdr->ver) & 0xff);
@@ -2202,8 +2205,9 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
(le32_to_cpu(blk->ver) >> 16) & 0xff,
(le32_to_cpu(blk->ver) >> 8) & 0xff,
le32_to_cpu(blk->ver) & 0xff);
cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
file, blocks, le32_to_cpu(blk->len), offset, type);
cs_dsp_dbg(dsp, "%s.%d: %d bytes off:%#x off32:%#x in %#x\n",
file, blocks, le32_to_cpu(blk->len), offset,
le32_to_cpu(blk->offset32), type);
reg = 0;
region_name = "Unknown";
@@ -2236,6 +2240,13 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
}
break;
case WMFW_ADSP2_XM_LONG:
case WMFW_ADSP2_YM_LONG:
case WMFW_HALO_XM_PACKED_LONG:
case WMFW_HALO_YM_PACKED_LONG:
offset = le32_to_cpu(blk->offset32);
type &= 0xff; /* strip extended block type flags */
fallthrough;
case WMFW_ADSP1_DM:
case WMFW_ADSP1_ZM:
case WMFW_ADSP2_XM:

View File

@@ -56,13 +56,14 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_get_firmware, "FW_CS_DSP_KUNIT_TEST_UTILS")
* @alg_id: Algorithm ID.
* @alg_ver: Algorithm version.
* @type: Type of the block.
* @offset: Offset.
* @offset: 16-bit offset.
* @offset32: 32-bit offset (sample rate on V1 and V2 file formats).
* @payload_data: Pointer to buffer containing the payload data.
* @payload_len_bytes: Length of payload data in bytes.
*/
void cs_dsp_mock_bin_add_raw_block(struct cs_dsp_mock_bin_builder *builder,
unsigned int alg_id, unsigned int alg_ver,
int type, unsigned int offset,
int type, u16 offset, u32 offset32,
const void *payload_data, size_t payload_len_bytes)
{
struct wmfw_coeff_item *item;
@@ -75,6 +76,7 @@ void cs_dsp_mock_bin_add_raw_block(struct cs_dsp_mock_bin_builder *builder,
item = builder->write_p;
item->offset = cpu_to_le16(offset);
item->offset32 = cpu_to_le32(offset32);
item->type = cpu_to_le16(type);
item->id = cpu_to_le32(alg_id);
item->ver = cpu_to_le32(alg_ver << 8);
@@ -104,7 +106,7 @@ static void cs_dsp_mock_bin_add_name_or_info(struct cs_dsp_mock_bin_builder *bui
info = tmp;
}
cs_dsp_mock_bin_add_raw_block(builder, 0, 0, WMFW_INFO_TEXT, 0, info, info_len);
cs_dsp_mock_bin_add_raw_block(builder, 0, 0, WMFW_INFO_TEXT, 0, 0, info, info_len);
kunit_kfree(builder->test_priv->test, tmp);
}
@@ -156,11 +158,39 @@ void cs_dsp_mock_bin_add_patch(struct cs_dsp_mock_bin_builder *builder,
KUNIT_ASSERT_EQ(builder->test_priv->test, payload_len_bytes % 4, 0);
cs_dsp_mock_bin_add_raw_block(builder, alg_id, alg_ver,
mem_region, reg_addr_offset,
mem_region, (u16)reg_addr_offset, 0,
payload_data, payload_len_bytes);
}
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_patch, "FW_CS_DSP_KUNIT_TEST_UTILS");
/**
* cs_dsp_mock_bin_add_patch_off32() - Add a patch data block with 32-bit offset.
*
* @builder: Pointer to struct cs_dsp_mock_bin_builder.
* @alg_id: Algorithm ID for the patch.
* @alg_ver: Algorithm version for the patch.
* @mem_region: Memory region for the patch.
* @reg_addr_offset: Offset to start of data in register addresses.
* @payload_data: Pointer to buffer containing the payload data.
* @payload_len_bytes: Length of payload data in bytes.
*/
void cs_dsp_mock_bin_add_patch_off32(struct cs_dsp_mock_bin_builder *builder,
unsigned int alg_id, unsigned int alg_ver,
int mem_region, unsigned int reg_addr_offset,
const void *payload_data, size_t payload_len_bytes)
{
/* Payload length must be a multiple of 4 */
KUNIT_ASSERT_EQ(builder->test_priv->test, payload_len_bytes % 4, 0);
/* Mark the block as using the 32-bit offset */
mem_region |= 0xf400;
cs_dsp_mock_bin_add_raw_block(builder, alg_id, alg_ver,
mem_region, 0, reg_addr_offset,
payload_data, payload_len_bytes);
}
EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_bin_add_patch_off32, "FW_CS_DSP_KUNIT_TEST_UTILS");
/**
* cs_dsp_mock_bin_init() - Initialize a struct cs_dsp_mock_bin_builder.
*

View File

@@ -23,10 +23,10 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_mock_halo_dsp1_regions, "FW_CS_DSP_KUNIT_TEST_UTILS"
/* List of sizes in bytes, for each entry above */
const unsigned int cs_dsp_mock_halo_dsp1_region_sizes[] = {
0x5000, /* PM_PACKED */
0x6000, /* XM_PACKED */
0x47F4, /* YM_PACKED */
0x8000, /* XM_UNPACKED_24 */
0x5FF8, /* YM_UNPACKED_24 */
0x8fff4, /* XM_PACKED */
0x8fff4, /* YM_PACKED */
0xbfff8, /* XM_UNPACKED_24 */
0xbfff8, /* YM_UNPACKED_24 */
0 /* terminator */
};

View File

@@ -157,22 +157,22 @@ static const struct reg_default halo_register_defaults[] = {
};
static const struct regmap_range halo_readable_registers[] = {
regmap_reg_range(0x2000000, 0x2005fff), /* XM_PACKED */
regmap_reg_range(0x2000000, 0x208fff0), /* XM_PACKED */
regmap_reg_range(0x25e0000, 0x25e004f), /* SYSINFO */
regmap_reg_range(0x25e2000, 0x25e2047), /* SYSINFO */
regmap_reg_range(0x2800000, 0x2807fff), /* XM */
regmap_reg_range(0x2800000, 0x28bfff4), /* XM */
regmap_reg_range(0x2b80000, 0x2bc700b), /* CORE CTRL */
regmap_reg_range(0x2c00000, 0x2c047f3), /* YM_PACKED */
regmap_reg_range(0x3400000, 0x3405ff7), /* YM */
regmap_reg_range(0x2c00000, 0x2c8fff0), /* YM_PACKED */
regmap_reg_range(0x3400000, 0x34bfff4), /* YM */
regmap_reg_range(0x3800000, 0x3804fff), /* PM_PACKED */
};
static const struct regmap_range halo_writeable_registers[] = {
regmap_reg_range(0x2000000, 0x2005fff), /* XM_PACKED */
regmap_reg_range(0x2800000, 0x2807fff), /* XM */
regmap_reg_range(0x2000000, 0x208fff0), /* XM_PACKED */
regmap_reg_range(0x2800000, 0x28bfff4), /* XM */
regmap_reg_range(0x2b80000, 0x2bc700b), /* CORE CTRL */
regmap_reg_range(0x2c00000, 0x2c047f3), /* YM_PACKED */
regmap_reg_range(0x3400000, 0x3405ff7), /* YM */
regmap_reg_range(0x2c00000, 0x2c8fff0), /* YM_PACKED */
regmap_reg_range(0x3400000, 0x34bfff4), /* YM */
regmap_reg_range(0x3800000, 0x3804fff), /* PM_PACKED */
};

File diff suppressed because it is too large Load Diff

View File

@@ -66,24 +66,24 @@ static void bin_load_with_unknown_blocks(struct kunit *test)
cs_dsp_mock_bin_add_raw_block(local->bin_builder,
cs_dsp_bin_err_test_mock_algs[0].id,
cs_dsp_bin_err_test_mock_algs[0].ver,
0xf5, 0,
0xf5, 0, 0,
random_data, sizeof(random_data));
cs_dsp_mock_bin_add_raw_block(local->bin_builder,
cs_dsp_bin_err_test_mock_algs[0].id,
cs_dsp_bin_err_test_mock_algs[0].ver,
0xf500, 0,
0xf500, 0, 0,
random_data, sizeof(random_data));
cs_dsp_mock_bin_add_raw_block(local->bin_builder,
cs_dsp_bin_err_test_mock_algs[0].id,
cs_dsp_bin_err_test_mock_algs[0].ver,
0xc300, 0,
0xc300, 0, 0,
random_data, sizeof(random_data));
/* Add a single payload to be written to DSP memory */
cs_dsp_mock_bin_add_raw_block(local->bin_builder,
cs_dsp_bin_err_test_mock_algs[0].id,
cs_dsp_bin_err_test_mock_algs[0].ver,
WMFW_ADSP2_YM, 0,
WMFW_ADSP2_YM, 0, 0,
payload_data, payload_size_bytes);
bin = cs_dsp_mock_bin_get_firmware(local->bin_builder);
@@ -277,7 +277,7 @@ static void bin_too_short_for_block_header(struct kunit *test)
cs_dsp_mock_bin_add_raw_block(local->bin_builder,
cs_dsp_bin_err_test_mock_algs[0].id,
cs_dsp_bin_err_test_mock_algs[0].ver,
param->block_type, 0,
param->block_type, 0, 0,
NULL, 0);
bin = cs_dsp_mock_bin_get_firmware(local->bin_builder);
@@ -309,7 +309,7 @@ static void bin_too_short_for_block_payload(struct kunit *test)
cs_dsp_mock_bin_add_raw_block(local->bin_builder,
cs_dsp_bin_err_test_mock_algs[0].id,
cs_dsp_bin_err_test_mock_algs[0].ver,
param->block_type, 0,
param->block_type, 0, 0,
payload, sizeof(payload));
bin = cs_dsp_mock_bin_get_firmware(local->bin_builder);
@@ -341,7 +341,7 @@ static void bin_block_payload_len_garbage(struct kunit *test)
cs_dsp_mock_bin_add_raw_block(local->bin_builder,
cs_dsp_bin_err_test_mock_algs[0].id,
cs_dsp_bin_err_test_mock_algs[0].ver,
param->block_type, 0,
param->block_type, 0, 0,
&payload, sizeof(payload));
bin = cs_dsp_mock_bin_get_firmware(local->bin_builder);

View File

@@ -126,7 +126,7 @@ struct cs_dsp_mock_bin_builder *cs_dsp_mock_bin_init(struct cs_dsp_test *priv,
unsigned int fw_version);
void cs_dsp_mock_bin_add_raw_block(struct cs_dsp_mock_bin_builder *builder,
unsigned int alg_id, unsigned int alg_ver,
int type, unsigned int offset,
int type, u16 offset, u32 offset32,
const void *payload_data, size_t payload_len_bytes);
void cs_dsp_mock_bin_add_info(struct cs_dsp_mock_bin_builder *builder,
const char *info);
@@ -136,6 +136,10 @@ void cs_dsp_mock_bin_add_patch(struct cs_dsp_mock_bin_builder *builder,
unsigned int alg_id, unsigned int alg_ver,
int mem_region, unsigned int reg_addr_offset,
const void *payload_data, size_t payload_len_bytes);
void cs_dsp_mock_bin_add_patch_off32(struct cs_dsp_mock_bin_builder *builder,
unsigned int alg_id, unsigned int alg_ver,
int mem_region, unsigned int reg_addr_offset,
const void *payload_data, size_t payload_len_bytes);
struct firmware *cs_dsp_mock_bin_get_firmware(struct cs_dsp_mock_bin_builder *builder);
struct cs_dsp_mock_wmfw_builder *cs_dsp_mock_wmfw_init(struct cs_dsp_test *priv,

View File

@@ -172,7 +172,7 @@ struct wmfw_coeff_item {
__le16 type;
__le32 id;
__le32 ver;
__le32 sr;
__le32 offset32;
__le32 len;
u8 data[];
} __packed;
@@ -200,4 +200,9 @@ struct wmfw_coeff_item {
#define WMFW_HALO_XM_PACKED 0x11
#define WMFW_HALO_YM_PACKED 0x12
#define WMFW_ADSP2_XM_LONG 0xf405
#define WMFW_ADSP2_YM_LONG 0xf406
#define WMFW_HALO_XM_PACKED_LONG 0xf411
#define WMFW_HALO_YM_PACKED_LONG 0xf412
#endif