Skip to content
Merged
13 changes: 5 additions & 8 deletions posix/include/sof/lib/dma.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -254,7 +254,7 @@ struct dma_info {
struct audio_stream;
typedef int (*dma_process_func)(const struct audio_stream __sparse_cache *source,
uint32_t ioffset, struct audio_stream __sparse_cache *sink,
uint32_t ooffset, uint32_t frames);
uint32_t ooffset, uint32_t source_samples, uint32_t chmap);

/**
* \brief API to initialize a platform DMA controllers.
Expand DownExpand Up@@ -523,19 +523,15 @@ static inline uint32_t dma_sg_get_size(struct dma_sg_elem_array *ea)
return size;
}

struct audio_stream;
typedef void (*dma_process)(const struct audio_stream *,
struct audio_stream *, uint32_t);

/* copies data from DMA buffer using provided processing function */
int dma_buffer_copy_from(struct comp_buffer __sparse_cache *source,
struct comp_buffer __sparse_cache *sink,
dma_process_func process, uint32_t source_bytes);
dma_process_func process, uint32_t source_bytes, uint32_t chmap);

/* copies data to DMA buffer using provided processing function */
int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source,
struct comp_buffer __sparse_cache *sink,
dma_process_func process, uint32_t sink_bytes);
dma_process_func process, uint32_t sink_bytes, uint32_t chmap);

/*
* Used when copying DMA buffer bytes into multiple sink buffers, one at a time using the provided
Expand All@@ -544,7 +540,8 @@ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source,
*/
int dma_buffer_copy_from_no_consume(struct comp_buffer __sparse_cache *source,
struct comp_buffer __sparse_cache *sink,
dma_process_func process, uint32_t source_bytes);
dma_process_func process,
uint32_t source_bytes, uint32_t chmap);

/* generic DMA DSP <-> Host copier */

Expand Down
15 changes: 15 additions & 0 deletions src/audio/Kconfig
Original file line numberDiff line numberDiff line change
Expand Up@@ -251,6 +251,13 @@ config PCM_CONVERTER_FORMAT_S32LE
help
Support 32 bit processing data format with sign and in little endian format

config PCM_CONVERTER_FORMAT_S16_4LE
bool "Support S16_4LE"
default y
help
Support the format of signed 16-bit little-endian in the 2 lower bytes
of a 32-bit container. This format is used, for example, by the SSP gateway.

config PCM_CONVERTER_FORMAT_FLOAT
bool "Support float"
default y
Expand DownExpand Up@@ -305,6 +312,14 @@ config PCM_CONVERTER_FORMAT_CONVERT_HIFI3
help
Use HIFI3 extensions for optimized format conversion (experimental).

config PCM_REMAPPING_CONVERTERS
bool "Channel remapping conversions"
default y
depends on IPC_MAJOR_4
help
Enable conversion functions that perform both format conversion
and channel remapping simultaneously.

config TRACE_CHANNEL
int "TRACE DMA Channel configuration"
default 0
Expand Down
103 changes: 96 additions & 7 deletions src/audio/copier/copier.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -164,6 +164,8 @@ static int copier_init(struct processing_module *mod)

dev->direction_set = true;
} else {
cd->gtw_type = ipc4_gtw_none;

/* set max sink count for module copier */
mod->max_sinks = IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT;
}
Expand DownExpand Up@@ -244,7 +246,7 @@ static int copier_prepare(struct processing_module *mod,
*/
cd->converter[0] = get_converter_func(&cd->config.base.audio_fmt,
&cd->config.out_fmt, ipc4_gtw_none,
ipc4_bidirection);
ipc4_bidirection, DUMMY_CHMAP);
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 DownExpand Up@@ -440,7 +442,8 @@ static int do_conversion_copy(struct comp_dev *dev,
buffer_stream_invalidate(src, processed_data->source_bytes);

cd->converter[i](&src->stream, 0, &sink->stream, 0,
processed_data->frames * audio_stream_get_channels(&sink->stream));
processed_data->frames * audio_stream_get_channels(&src->stream),
DUMMY_CHMAP);

buffer_stream_writeback(sink, processed_data->sink_bytes);
comp_update_buffer_produce(sink, processed_data->sink_bytes);
Expand DownExpand Up@@ -509,7 +512,7 @@ static int copier_module_copy(struct processing_module *mod,
sink_dev = sink_c->sink;
processed_data.sink_bytes = 0;
if (sink_dev->state == COMP_STATE_ACTIVE) {
uint32_t samples;
uint32_t source_samples;
int sink_queue_id;

sink_queue_id = IPC4_SINK_QUEUE_ID(buf_get_id(sink_c));
Expand All@@ -518,10 +521,11 @@ static int copier_module_copy(struct processing_module *mod,

comp_get_copy_limits(src_c, sink_c, &processed_data);

samples = processed_data.frames *
audio_stream_get_channels(output_buffers[i].data);
source_samples = processed_data.frames *
audio_stream_get_channels(input_buffers[0].data);
cd->converter[sink_queue_id](input_buffers[0].data, 0,
output_buffers[i].data, 0, samples);
output_buffers[i].data, 0,
source_samples, DUMMY_CHMAP);

output_buffers[i].size = processed_data.sink_bytes;
cd->output_total_data_processed += processed_data.sink_bytes;
Expand DownExpand Up@@ -657,6 +661,7 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data,
const struct ipc4_copier_config_set_sink_format *sink_fmt = data;
struct processing_module *mod = comp_mod(dev);
struct copier_data *cd = module_get_private_data(mod);
uint32_t chmap;

if (max_data_size < sizeof(*sink_fmt)) {
comp_err(dev, "error: max_data_size %d should be bigger than %d", max_data_size,
Expand All@@ -682,9 +687,15 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data,
}

cd->out_fmt[sink_fmt->sink_id] = sink_fmt->sink_fmt;

if (cd->endpoint_num > 0 && dev->ipc_config.type == SOF_COMP_DAI)
chmap = cd->dd[0]->chmap;
else
chmap = DUMMY_CHMAP;

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

return 0;
}
Expand DownExpand Up@@ -724,6 +735,82 @@ static int set_attenuation(struct comp_dev *dev, uint32_t data_offset, const cha
return 0;
}

static int set_chmap(struct comp_dev *dev, const void *data, size_t data_size)
{
const struct ipc4_copier_config_channel_map *chmap_cfg = data;
struct processing_module *mod = comp_mod(dev);
struct copier_data *cd = module_get_private_data(mod);
enum ipc4_direction_type dir;
struct ipc4_audio_format in_fmt = cd->config.base.audio_fmt;
struct ipc4_audio_format out_fmt = cd->config.out_fmt;
pcm_converter_func process;
pcm_converter_func converters[IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT];
int i;
uint32_t irq_flags;

if (data_size < sizeof(*chmap_cfg)) {
comp_err(dev, "Wrong payload size: %d", data_size);
return -EINVAL;
}

if (cd->endpoint_num == 0 || dev->ipc_config.type != SOF_COMP_DAI) {
comp_err(dev, "Only DAI gateway supports changing chmap");
return -EINVAL;
}

comp_info(dev, "New chmap requested: %x", chmap_cfg->channel_map);

if (!cd->dd[0]->dma_buffer) {
/* DMA buffer not yet created. Remember the chmap, it will be used
* later in .params() handler.
*
* The assignment should be atomic as LL thread can preempt this IPC thread.
*/
cd->dd[0]->chmap = chmap_cfg->channel_map;
return 0;
}

copier_dai_adjust_params(cd, &in_fmt, &out_fmt);

dir = (cd->direction == SOF_IPC_STREAM_PLAYBACK) ?
ipc4_playback : ipc4_capture;

process = get_converter_func(&in_fmt, &out_fmt, cd->gtw_type, dir, chmap_cfg->channel_map);

if (!process) {
comp_err(dev, "No gtw converter func found!");
return -EINVAL;
}

/* Channel map is same for all sinks. However, as sinks allowed to have different
* sample formats, get new convert/remap function for each sink.
*/
for (i = 0; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; i++) {
if (cd->converter[i]) {
converters[i] = get_converter_func(&in_fmt, &cd->out_fmt[i],
ipc4_gtw_none, ipc4_bidirection,
chmap_cfg->channel_map);
/* Do not report an error if converter not found as sinks could be
* bound/unbound on a fly and out_fmt[i] may contain obsolete data.
*/
} else {
converters[i] = NULL;
}
}

/* Atomically update chmap, process and converters */
irq_local_disable(irq_flags);
Comment thread
serhiy-katsyuba-intel marked this conversation as resolved.

cd->dd[0]->chmap = chmap_cfg->channel_map;
cd->dd[0]->process = process;
for (i = 0; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; i++)
cd->converter[i] = converters[i];

irq_local_enable(irq_flags);

return 0;
}

static int copier_set_configuration(struct processing_module *mod,
uint32_t config_id,
enum module_cfg_fragment_position pos,
Expand All@@ -741,6 +828,8 @@ static int copier_set_configuration(struct processing_module *mod,
return copier_set_sink_fmt(dev, fragment, fragment_size);
case IPC4_COPIER_MODULE_CFG_ATTENUATION:
return set_attenuation(dev, fragment_size, (const char *)fragment);
case IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP:
return set_chmap(dev, fragment, fragment_size);
default:
return -EINVAL;
}
Expand Down
18 changes: 16 additions & 2 deletions src/audio/copier/copier.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -180,7 +180,12 @@ enum ipc4_copier_module_config_params {
* uint32_t. Config is only allowed when output pin is set up for 32bit and
* source is connected to Gateway
*/
IPC4_COPIER_MODULE_CFG_ATTENUATION = 6
IPC4_COPIER_MODULE_CFG_ATTENUATION = 6,
/* Use LARGE_CONFIG_SET to setup new channel map, which allows to map channels
* from gateway buffer to copier with any order.
* Same mapping will be applied for all copier sinks.
*/
IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP = 7
};

struct ipc4_copier_config_timestamp_init_data {
Expand All@@ -201,6 +206,13 @@ struct ipc4_copier_config_set_sink_format {
struct ipc4_audio_format sink_fmt;
} __attribute__((packed, aligned(4)));

struct ipc4_copier_config_channel_map {
/* Each half-byte of the channel map is an index of the DMA stream channel that
* should be copied to the position determined by this half-byte index.
*/
uint32_t channel_map;
} __attribute__((packed, aligned(4)));

#define IPC4_COPIER_DATA_SEGMENT_DISABLE (0 << 0)
#define IPC4_COPIER_DATA_SEGMENT_ENABLE (1 << 0)
#define IPC4_COPIER_DATA_SEGMENT_RESTART (1 << 1)
Expand DownExpand Up@@ -232,6 +244,7 @@ struct copier_data {
*/
struct ipc4_copier_module_cfg config;
void *gtw_cfg;
enum ipc4_gateway_type gtw_type;
struct comp_dev *endpoint[IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT];
struct comp_buffer *endpoint_buffer[IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT];
uint32_t endpoint_num;
Expand DownExpand Up@@ -267,7 +280,8 @@ int apply_attenuation(struct comp_dev *dev, struct copier_data *cd,
pcm_converter_func get_converter_func(const struct ipc4_audio_format *in_fmt,
const struct ipc4_audio_format *out_fmt,
enum ipc4_gateway_type type,
enum ipc4_direction_type dir);
enum ipc4_direction_type dir,
uint32_t chmap);

struct comp_ipc_config;
int create_endpoint_buffer(struct comp_dev *dev,
Expand Down
Loading