Skip to content

Commit

Permalink
ipc4: copier: Add IPC4 channel map handler
Browse files Browse the repository at this point in the history
Adds IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP handler that applies
channel map to DAI gateway audio conversion function.

Signed-off-by: Serhiy Katsyuba <[email protected]>
  • Loading branch information
serhiy-katsyuba-intel committed Jul 8, 2024
1 parent cf43dce commit de671d3
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 9 deletions.
87 changes: 86 additions & 1 deletion src/audio/copier/copier.c
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data,
struct copier_data *cd = module_get_private_data(mod);
struct list_item *sink_list;
struct comp_buffer *sink;
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 @@ -693,9 +694,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, DUMMY_CHMAP);
ipc4_bidirection, chmap);

/* update corresponding sink format */
list_for_item(sink_list, &dev->bsink_list) {
Expand Down Expand Up @@ -748,6 +755,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);

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 @@ -765,6 +848,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
14 changes: 13 additions & 1 deletion src/audio/copier/copier.h
Original file line number Diff line number Diff 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 Down
13 changes: 9 additions & 4 deletions src/audio/copier/copier_dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ static int copier_dai_init(struct comp_dev *dev,
{
struct processing_module *mod = comp_mod(dev);
struct copier_data *cd = module_get_private_data(mod);
uint32_t chmap;
struct dai_data *dd;
int ret;

Expand All @@ -178,6 +179,7 @@ static int copier_dai_init(struct comp_dev *dev,
config->frame_fmt = out_frame_fmt;
pipeline->sink_comp = dev;
cd->bsource_buffer = true;
chmap = copier->base.audio_fmt.ch_map;
} else {
enum sof_ipc_frame in_frame_fmt, in_valid_fmt;

Expand All @@ -187,6 +189,7 @@ static int copier_dai_init(struct comp_dev *dev,
copier->base.audio_fmt.s_type);
config->frame_fmt = in_frame_fmt;
pipeline->source_comp = dev;
chmap = copier->out_fmt.ch_map;
}

/* save the channel map and count for ALH multi-gateway */
Expand All @@ -205,6 +208,8 @@ static int copier_dai_init(struct comp_dev *dev,
if (ret < 0)
goto free_dd;

dd->chmap = chmap;

pipeline->sched_id = config->id;

cd->dd[index] = dd;
Expand Down Expand Up @@ -449,9 +454,9 @@ static int copy_single_channel_c32(const struct audio_stream *src,
return 0;
}

static void copier_dai_adjust_params(const struct copier_data *cd,
struct ipc4_audio_format *in_fmt,
struct ipc4_audio_format *out_fmt)
void copier_dai_adjust_params(const struct copier_data *cd,
struct ipc4_audio_format *in_fmt,
struct ipc4_audio_format *out_fmt)
{
struct comp_buffer *dma_buf;
int dma_buf_channels;
Expand Down Expand Up @@ -519,7 +524,7 @@ int copier_dai_params(struct copier_data *cd, struct comp_dev *dev,
ipc4_playback : ipc4_capture;

cd->dd[0]->process =
get_converter_func(&in_fmt, &out_fmt, cd->gtw_type, dir, DUMMY_CHMAP);
get_converter_func(&in_fmt, &out_fmt, cd->gtw_type, dir, cd->dd[0]->chmap);

return ret;
}
Expand Down
4 changes: 4 additions & 0 deletions src/audio/copier/dai_copier.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ void copier_dai_free(struct copier_data *cd);

int copier_dai_prepare(struct comp_dev *dev, struct copier_data *cd);

void copier_dai_adjust_params(const struct copier_data *cd,
struct ipc4_audio_format *in_fmt,
struct ipc4_audio_format *out_fmt);

int copier_dai_params(struct copier_data *cd, struct comp_dev *dev,
struct sof_ipc_stream_params *params, int dai_index);

Expand Down
8 changes: 5 additions & 3 deletions src/audio/dai-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,15 +271,15 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,

if (dev->direction == SOF_IPC_STREAM_PLAYBACK) {
ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer,
dd->process, bytes, DUMMY_CHMAP);
dd->process, bytes, dd->chmap);
} else {
audio_stream_invalidate(&dd->dma_buffer->stream, bytes);
/*
* The PCM converter functions used during DMA buffer copy can never fail,
* so no need to check the return value of dma_buffer_copy_from_no_consume().
*/
ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, dd->local_buffer,
dd->process, bytes, DUMMY_CHMAP);
dd->process, bytes, dd->chmap);
#if CONFIG_IPC_MAJOR_4
struct list_item *sink_list;
/* Skip in case of endpoint DAI devices created by the copier */
Expand Down Expand Up @@ -320,7 +320,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
sink->hw_params_configured)
ret = dma_buffer_copy_from_no_consume(dd->dma_buffer,
sink, converter[j],
bytes, DUMMY_CHMAP);
bytes, dd->chmap);
}
}
#endif
Expand Down Expand Up @@ -470,6 +470,8 @@ static struct comp_dev *dai_new(const struct comp_driver *drv,
if (ret < 0)
goto error;

dd->chmap = DUMMY_CHMAP;

dev->state = COMP_STATE_READY;

return dev;
Expand Down
1 change: 1 addition & 0 deletions src/include/sof/lib/dai-zephyr.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ struct dai_data {
int xrun; /* true if we are doing xrun recovery */

pcm_converter_func process; /* processing function */
uint32_t chmap;

channel_copy_func channel_copy; /* channel copy func used by multi-endpoint
* gateway to mux/demux stream from/to multiple
Expand Down

0 comments on commit de671d3

Please sign in to comment.