Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/audio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,12 @@ config PCM_CONVERTER_FORMAT_S24LE
help
Support 24 bit processing data format with sign and in little endian format

config PCM_CONVERTER_FORMAT_S24_3LE
bool "Support S24_3LE"
default n
help
Support packed 24 bit processing data format with sign and in little endian format

config PCM_CONVERTER_FORMAT_S32LE
bool "Support S32LE"
default y
Expand Down Expand Up @@ -500,6 +506,20 @@ config PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32
Support conversion between 16 bit valid sample size in 32 bit container
and 24 bit valid sample size in 32 bit container

config PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32
bool "Support S24C24 <-> S24C32"
default n
help
Support conversion between 24 bit valid sample size in 24 bit container
and 24 bit valid sample size in 32 bit container

config PCM_CONVERTER_FORMAT_S24_C32_AND_S24_C24
bool "Support S24C32 <-> S24C24"
default n
help
Support conversion between 24 bit valid sample size in 32 bit container
and 24 bit valid sample size in 24 bit container

config PCM_CONVERTER_FORMAT_CONVERT_HIFI3
bool "HIFI3 optimized conversion"
default y
Expand Down
42 changes: 27 additions & 15 deletions src/audio/copier.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ struct copier_data {
};

static pcm_converter_func get_converter_func(struct ipc4_audio_format *in_fmt,
struct ipc4_audio_format *out_fmt);
struct ipc4_audio_format *out_fmt,
enum ipc4_gateway_type type);

static void create_endpoint_buffer(struct comp_dev *parent_dev,
struct copier_data *cd,
Expand Down Expand Up @@ -145,8 +146,6 @@ static void create_endpoint_buffer(struct comp_dev *parent_dev,

for (i = 0; i < SOF_IPC_MAX_CHANNELS; i++)
cd->endpoint_buffer->chmap[i] = (copier_cfg->base.audio_fmt.ch_map >> i * 4) & 0xf;

cd->converter[0] = get_converter_func(&copier_cfg->base.audio_fmt, &copier_cfg->out_fmt);
}

/* if copier is linked to host gateway, it will manage host dma.
Expand Down Expand Up @@ -192,6 +191,9 @@ static struct comp_dev *create_host(struct comp_dev *parent_dev, struct copier_d
cd->bsource_buffer = true;
}

cd->converter[0] = get_converter_func(&copier_cfg->base.audio_fmt, &copier_cfg->out_fmt,
ipc4_gtw_host);

return dev;
}

Expand All @@ -207,6 +209,7 @@ static struct comp_dev *create_dai(struct comp_dev *parent_dev, struct copier_da
{
struct sof_uuid id = {0xc2b00d27, 0xffbc, 0x4150, {0xa5, 0x1a, 0x24,
0x5c, 0x79, 0xc5, 0xe5, 0x4b}};
enum ipc4_gateway_type type;
const struct comp_driver *drv;
struct ipc_config_dai dai;
struct comp_dev *dev;
Expand All @@ -229,22 +232,26 @@ static struct comp_dev *create_dai(struct comp_dev *parent_dev, struct copier_da
case ipc4_hda_link_input_class:
dai.type = SOF_DAI_INTEL_HDA;
dai.is_config_blob = true;
type = ipc4_gtw_link;
break;
case ipc4_i2s_link_output_class:
case ipc4_i2s_link_input_class:
dai.dai_index = (dai.dai_index >> 4) & 0xF;
dai.type = SOF_DAI_INTEL_SSP;
dai.is_config_blob = true;
type = ipc4_gtw_ssp;
break;
case ipc4_alh_link_output_class:
case ipc4_alh_link_input_class:
dai.type = SOF_DAI_INTEL_ALH;
dai.is_config_blob = true;
type = ipc4_gtw_alh;
dai.dai_index -= IPC4_ALH_DAI_INDEX_OFFSET;
break;
case ipc4_dmic_link_input_class:
dai.type = SOF_DAI_INTEL_DMIC;
dai.is_config_blob = true;
type = ipc4_gtw_dmic;
break;
default:
return NULL;
Expand Down Expand Up @@ -278,6 +285,8 @@ static struct comp_dev *create_dai(struct comp_dev *parent_dev, struct copier_da
cd->bsource_buffer = false;
}

cd->converter[0] = get_converter_func(&copier->base.audio_fmt, &copier->out_fmt, type);

return dev;
}

Expand Down Expand Up @@ -441,7 +450,8 @@ static bool use_no_container_convert_function(enum sof_ipc_frame in,
}

static pcm_converter_func get_converter_func(struct ipc4_audio_format *in_fmt,
struct ipc4_audio_format *out_fmt)
struct ipc4_audio_format *out_fmt,
enum ipc4_gateway_type type)
{
enum sof_ipc_frame in, in_valid, out, out_valid;

Expand All @@ -454,7 +464,7 @@ static pcm_converter_func get_converter_func(struct ipc4_audio_format *in_fmt,
if (use_no_container_convert_function(in, in_valid, out, out_valid))
return pcm_get_conversion_function(in, out);
else
return pcm_get_conversion_vc_function(in, in_valid, out, out_valid);
return pcm_get_conversion_vc_function(in, in_valid, out, out_valid, type);
}

static int copier_prepare(struct comp_dev *dev)
Expand Down Expand Up @@ -482,7 +492,7 @@ static int copier_prepare(struct comp_dev *dev)
} else {
/* set up format conversion function */
cd->converter[0] = get_converter_func(&cd->config.base.audio_fmt,
&cd->config.out_fmt);
&cd->config.out_fmt, ipc4_gtw_none);
if (!cd->converter[0]) {
comp_err(dev, "can't support for in format %d, out format %d",
cd->config.base.audio_fmt.depth, cd->config.out_fmt.depth);
Expand Down Expand Up @@ -584,27 +594,24 @@ static int do_conversion_copy(struct comp_dev *dev,
uint32_t *src_copy_bytes)
{
struct comp_copy_limits c;
uint32_t sink_bytes;
uint32_t src_bytes;
int i;
int ret;

comp_get_copy_limits_with_lock(src, sink, &c);
src_bytes = c.frames * c.source_frame_bytes;
*src_copy_bytes = src_bytes;
sink_bytes = c.frames * c.sink_frame_bytes;
*src_copy_bytes = c.source_bytes;

i = IPC4_SINK_QUEUE_ID(sink->id);
buffer_stream_invalidate(src, src_bytes);
buffer_stream_invalidate(src, c.source_bytes);

cd->converter[i](&src->stream, 0, &sink->stream, 0, c.frames * sink->stream.channels);
if (cd->attenuation) {
ret = apply_attenuation(dev, cd, sink, c.frames);
if (ret < 0)
return ret;
}

buffer_stream_writeback(sink, sink_bytes);
comp_update_buffer_produce(sink, sink_bytes);
buffer_stream_writeback(sink, c.sink_bytes);
comp_update_buffer_produce(sink, c.sink_bytes);

return 0;
}
Expand Down Expand Up @@ -802,9 +809,14 @@ static int copier_set_sink_fmt(struct comp_dev *dev, void *data,
return -EINVAL;
}

if (cd->endpoint) {
comp_err(dev, "can't change gateway format");
return -EINVAL;
}

cd->out_fmt[sink_fmt->sink_id] = sink_fmt->sink_fmt;
cd->converter[sink_fmt->sink_id] = get_converter_func(&sink_fmt->source_fmt,
&sink_fmt->sink_fmt);
&sink_fmt->sink_fmt, ipc4_gtw_none);

return 0;
}
Expand Down
153 changes: 145 additions & 8 deletions src/audio/pcm_converter/pcm_converter_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,9 @@ const struct pcm_func_map pcm_func_map[] = {
#if CONFIG_PCM_CONVERTER_FORMAT_S24LE
{ SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, audio_stream_copy },
#endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE */
#if CONFIG_PCM_CONVERTER_FORMAT_S24_3LE
{ SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, audio_stream_copy },
#endif /* CONFIG_PCM_CONVERTER_FORMAT_S24_3LE */
#if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE
{ SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s16_to_s24 },
{ SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s24_to_s16 },
Expand Down Expand Up @@ -494,8 +497,6 @@ const struct pcm_func_map pcm_func_map[] = {

const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map);

#endif

#if CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32
static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
Expand Down Expand Up @@ -673,25 +674,161 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source,
return samples;
}
#endif

#if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32
static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples)
{
uint8_t *src = source->r_ptr;
int32_t *dst = sink->w_ptr;
int processed;
int nmax, i, n;

src += ioffset * 3;
dst += ooffset;
for (processed = 0; processed < samples; processed += n) {
src = audio_stream_wrap(source, src);
dst = audio_stream_wrap(sink, dst);
n = samples - processed;
nmax = audio_stream_bytes_without_wrap(source, src) / 3;
n = MIN(n, nmax);
nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES;
n = MIN(n, nmax);
for (i = 0; i < n; i += 1) {
*dst = (*(src + 2) << 24) | (*(src + 1) << 16) | (*(src + 0) << 8);
*dst >>= 8;
dst++;
src += 3;
}
}

return samples;
}

static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples)
{
int32_t *src = source->r_ptr;
uint8_t *dst = sink->w_ptr;
int processed;
int nmax, i, n;

src += ioffset;
dst += ooffset * 3;
for (processed = 0; processed < samples; processed += n) {
src = audio_stream_wrap(source, src);
dst = audio_stream_wrap(sink, dst);
n = samples - processed;
nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES;
n = MIN(n, nmax);
nmax = audio_stream_bytes_without_wrap(sink, dst) / 3;
n = MIN(n, nmax);
for (i = 0; i < n; i += 1) {
*dst = *src & 0xFF;
dst++;
*dst = (*src >> 8) & 0xFF;
dst++;
*dst = (*src >> 16) & 0xFF;
dst++;
src++;
}
}

return samples;
}

/* 2x24bit samples are packed into 3x16bit samples for hda link dma */
static int pcm_convert_s24_c32_to_s24_c24_link_gtw(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples)
{
int32_t *src = source->r_ptr;
uint16_t *dst = sink->w_ptr;
int processed;
int nmax, i, n;

src += ioffset;
assert(ooffset == 0);
for (processed = 0; processed < samples; processed += n) {
src = audio_stream_wrap(source, src);
dst = audio_stream_wrap(sink, dst);
n = samples - processed;
nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES;
n = MIN(n, nmax);
nmax = audio_stream_bytes_without_wrap(sink, dst) / 3;
n = MIN(n, nmax);
for (i = 0; i < n; i += 2) {
*dst = (*src >> 8) & 0xFFFF;
dst++;
*dst = (*src & 0xFF << 8) | ((*(src + 1) >> 16) & 0xFF);
dst++;
*dst = *(src + 1) & 0xFFFF;
dst++;
src += 2;
}
}

/* odd n */
if (i > n) {
*dst = (*src >> 8) & 0xFFFF;
dst++;
*dst = (*src & 0xFF << 8);
}

return samples;
}

#endif

const struct pcm_func_vc_map pcm_func_vc_map[] = {
#if CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32
{ SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE,
pcm_convert_s16_c16_to_s16_c32 },
ipc4_gtw_all, pcm_convert_s16_c16_to_s16_c32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE,
pcm_convert_s16_c32_to_s16_c16 },
ipc4_gtw_all, pcm_convert_s16_c32_to_s16_c16 },
#endif
#if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE,
pcm_convert_s16_c32_to_s32_c32 },
ipc4_gtw_all, pcm_convert_s16_c32_to_s32_c32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE,
pcm_convert_s32_c32_to_s16_c32 },
ipc4_gtw_all, pcm_convert_s32_c32_to_s16_c32 },
#endif
#if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE,
pcm_convert_s16_c32_to_s24_c32 },
ipc4_gtw_all, pcm_convert_s16_c32_to_s24_c32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE,
pcm_convert_s24_c32_to_s16_c32 },
ipc4_gtw_all, pcm_convert_s24_c32_to_s16_c32 },
#endif
#if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE,
ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), audio_stream_copy },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE,
ipc4_gtw_link | ipc4_gtw_alh, pcm_convert_s24_to_s32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE,
ipc4_gtw_host, pcm_convert_s32_to_s24 },
#endif
#if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE
{ SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE,
SOF_IPC_FRAME_S24_4LE, ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh),
pcm_convert_s16_to_s24 },
{ SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE,
SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, pcm_convert_s16_to_s32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE,
SOF_IPC_FRAME_S16_LE, ipc4_gtw_all, pcm_convert_s24_to_s16 },
#endif
#if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32
{ SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S32_LE,
SOF_IPC_FRAME_S24_4LE, ipc4_gtw_all, pcm_convert_s24_c24_to_s24_c32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_3LE,
SOF_IPC_FRAME_S24_3LE, ipc4_gtw_all & ~ipc4_gtw_link,
pcm_convert_s24_c32_to_s24_c24 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_3LE,
SOF_IPC_FRAME_S24_3LE, ipc4_gtw_link, pcm_convert_s24_c32_to_s24_c24_link_gtw },
#endif
};

const size_t pcm_func_vc_count = ARRAY_SIZE(pcm_func_vc_map);

#endif
9 changes: 6 additions & 3 deletions src/drivers/intel/hda/hda-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -842,11 +842,14 @@ static int hda_dma_set_config(struct dma_chan_data *channel,
/* firmware control buffer */
dgcs = DGCS_FWCB;

/* set DGCS.SCS bit to 1 for 16bit(2B) container */
/* set DGCS.SCS bit to 1 for 16bit(2B) container
* S24_3LE stream is treated as 16bit or 8bit
* stream in host side
*/
if ((config->direction & (DMA_DIR_HMEM_TO_LMEM | DMA_DIR_DEV_TO_MEM) &&
config->dest_width <= 2) ||
config->dest_width <= 3) ||
(config->direction & (DMA_DIR_LMEM_TO_HMEM | DMA_DIR_MEM_TO_DEV) &&
config->src_width <= 2))
config->src_width <= 3))
dgcs |= DGCS_SCS;

/* set DGCS.FIFORDY for input/output host DMA only. It is not relevant for link DMA's */
Expand Down
Loading