diff options
author | Richard Fitzgerald <rf@opensource.cirrus.com> | 2020-12-16 11:25:12 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-12-28 12:24:43 +0000 |
commit | 7726e49837af634accaec317c8d246d1d90d8fc5 (patch) | |
tree | 45af6845d85f32b8af261141a83e6b8ba491a0fc /sound/soc/codecs/wm_adsp.c | |
parent | a9830fc388817c90282925694474fae005fec990 (diff) |
ASoC: wm_adsp: Improve handling of raw byte streams
As the register map is 16-bit or 32-bit big-endian, the 24-bit
DSP words appear padded and with the bytes swapped. When reading a
raw stream of bytes, the pad bytes must be removed and the data bytes
swapped back to their original order.
The previous implementation of this assumed that the be32_to_cpu() in
wm_adsp_read_data_block() would swap back to little-endian. But this is
obviously only true on a little-endian CPU. It also made two walks
through the data, once to endian-swap and again to strip the pad bytes.
This patch re-works the code so that the endian-swap and unpad are done
together in a single walk, and it is not dependent on the endianness of
the CPU. The data_word_size argument to wm_adsp_remove_padding() has been
dropped because currently this is always 3.
Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20201216112512.26503-1-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 55 |
1 files changed, 30 insertions, 25 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index dec8716aa8ef..5b7d81a91df3 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3664,12 +3664,12 @@ int wm_adsp_compr_get_caps(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps); -static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type, - unsigned int mem_addr, - unsigned int num_words, u32 *data) +static int wm_adsp_read_raw_data_block(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, + unsigned int num_words, __be32 *data) { struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); - unsigned int i, reg; + unsigned int reg; int ret; if (!mem) @@ -3682,16 +3682,22 @@ static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type, if (ret < 0) return ret; - for (i = 0; i < num_words; ++i) - data[i] = be32_to_cpu(data[i]) & 0x00ffffffu; - return 0; } static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type, unsigned int mem_addr, u32 *data) { - return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data); + __be32 raw; + int ret; + + ret = wm_adsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw); + if (ret) + return ret; + + *data = be32_to_cpu(raw) & 0x00ffffffu; + + return 0; } static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type, @@ -3724,18 +3730,22 @@ static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf, buf->host_buf_ptr + field_offset, data); } -static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size) +static void wm_adsp_remove_padding(u32 *buf, int nwords) { - u8 *pack_in = (u8 *)buf; + const __be32 *pack_in = (__be32 *)buf; u8 *pack_out = (u8 *)buf; - int i, j; + int i; - /* Remove the padding bytes from the data read from the DSP */ + /* + * DSP words from the register map have pad bytes and the data bytes + * are in swapped order. This swaps back to the original little-endian + * order and strips the pad bytes. + */ for (i = 0; i < nwords; i++) { - for (j = 0; j < data_word_size; j++) - *pack_out++ = *pack_in++; - - pack_in += sizeof(*buf) - data_word_size; + u32 word = be32_to_cpu(*pack_in++); + *pack_out++ = (u8)word; + *pack_out++ = (u8)(word >> 8); + *pack_out++ = (u8)(word >> 16); } } @@ -3919,12 +3929,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) return -EINVAL; } - for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++) - coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]); - - wm_adsp_remove_padding((u32 *)&coeff_v1.name, - ARRAY_SIZE(coeff_v1.name), - WM_ADSP_DATA_WORD_SIZE); + wm_adsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name)); buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part, (char *)&coeff_v1.name); @@ -4263,12 +4268,12 @@ static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) return 0; /* Read data from DSP */ - ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr, - nwords, compr->raw_buf); + ret = wm_adsp_read_raw_data_block(buf->dsp, mem_type, adsp_addr, + nwords, compr->raw_buf); if (ret < 0) return ret; - wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE); + wm_adsp_remove_padding(compr->raw_buf, nwords); /* update read index to account for words read */ buf->read_index += nwords; |