diff --git a/app/compr/README.txt b/app/compr/README.txt new file mode 100644 index 000000000000..a9c28957edbb --- /dev/null +++ b/app/compr/README.txt @@ -0,0 +1,37 @@ +Cadence Codec Configuration Overlays +===================================== + +This directory contains Kconfig overlay files for enabling Cadence codec support +in SOF firmware builds. + +Prerequisites +------------- +The Cadence codec libraries must be placed in the cadence_libs directory, one level +up from the SOF project directory: + sof/../cadence_libs/ + +Available Overlay Files +----------------------- +cadence.conf - Base Cadence codec module only (no individual codecs) +mp3.conf - MP3 decoder and encoder +aac.conf - AAC decoder +vorbis.conf - Vorbis decoder +all_codecs.conf - All supported codecs (MP3, AAC, Vorbis) + +Usage Examples +-------------- +Use with scripts/xtensa-build-zephyr.py via -o parameter: + +# Base module only (e.g., for Tiger Lake) +scripts/xtensa-build-zephyr.py tgl -o app/compr/cadence.conf + +# Single codec +scripts/xtensa-build-zephyr.py mtl -o app/compr/mp3.conf + +# Multiple codecs (use separate -o for each) +scripts/xtensa-build-zephyr.py mtl -o app/compr/mp3.conf -o app/compr/aac.conf + +# All codecs +scripts/xtensa-build-zephyr.py mtl -o app/compr/all_codecs.conf + +For more information about Cadence codecs, see the SOF documentation. diff --git a/app/compr/aac.conf b/app/compr/aac.conf new file mode 100644 index 000000000000..2adf1db86007 --- /dev/null +++ b/app/compr/aac.conf @@ -0,0 +1,4 @@ +# Cadence AAC decoder +CONFIG_CADENCE_CODEC=y +CONFIG_CADENCE_CODEC_AAC_DEC=y +CONFIG_CADENCE_CODEC_AAC_DEC_LIB="../cadence_libs/xa_aac_dec.a" diff --git a/app/compr/all_codecs.conf b/app/compr/all_codecs.conf new file mode 100644 index 000000000000..26b507f7f452 --- /dev/null +++ b/app/compr/all_codecs.conf @@ -0,0 +1,11 @@ +# All Cadence codecs (MP3, AAC, Vorbis) +CONFIG_CADENCE_CODEC=y +CONFIG_CADENCE_CODEC_MP3_DEC=y +CONFIG_CADENCE_CODEC_MP3_DEC_LIB="../cadence_libs/xa_mp3_dec.a" +CONFIG_CADENCE_CODEC_MP3_ENC=y +CONFIG_CADENCE_CODEC_MP3_ENC_LIB="../cadence_libs/xa_mp3_enc.a" +CONFIG_CADENCE_CODEC_AAC_DEC=y +CONFIG_CADENCE_CODEC_AAC_DEC_LIB="../cadence_libs/xa_aac_dec.a" +CONFIG_CADENCE_CODEC_VORBIS_DEC=y +CONFIG_CADENCE_CODEC_VORBIS_DEC_LIB="../cadence_libs/xa_vorbis_dec.a" + diff --git a/app/compr/cadence.conf b/app/compr/cadence.conf new file mode 100644 index 000000000000..9223140cab73 --- /dev/null +++ b/app/compr/cadence.conf @@ -0,0 +1,2 @@ +# Cadence codec module base support +CONFIG_CADENCE_CODEC=y diff --git a/app/compr/mp3.conf b/app/compr/mp3.conf new file mode 100644 index 000000000000..968f97295f57 --- /dev/null +++ b/app/compr/mp3.conf @@ -0,0 +1,6 @@ +# Cadence MP3 decoder and encoder +CONFIG_CADENCE_CODEC=y +CONFIG_CADENCE_CODEC_MP3_DEC=y +CONFIG_CADENCE_CODEC_MP3_DEC_LIB="../cadence_libs/xa_mp3_dec.a" +CONFIG_CADENCE_CODEC_MP3_ENC=y +CONFIG_CADENCE_CODEC_MP3_ENC_LIB="../cadence_libs/xa_mp3_enc.a" diff --git a/app/compr/vorbis.conf b/app/compr/vorbis.conf new file mode 100644 index 000000000000..064ac71b6616 --- /dev/null +++ b/app/compr/vorbis.conf @@ -0,0 +1,4 @@ +# Cadence Vorbis decoder +CONFIG_CADENCE_CODEC=y +CONFIG_CADENCE_CODEC_VORBIS_DEC=y +CONFIG_CADENCE_CODEC_VORBIS_DEC_LIB="../cadence_libs/xa_vorbis_dec.a" diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 1b10dca4362e..17c86fdb1df3 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,69 @@ __cold static uint32_t get_host_buffer_size(void) return periods; } +struct sof_ipc4_codec_info_data { + uint32_t count; + uint32_t items[32]; +} __packed __aligned(4); + +/** + * Encodes codec and direction information into a single 32-bit value. + * @param codec Codec type (bits 0-7) + * @param dir Stream direction (bits 8-11) + * @return Encoded 32-bit value + */ +#define SET_CODEC_INFO_ITEM(codec, dir) (((codec) & 0xff) | (((dir) & 0xf) << 8)) + +static void get_codec_info(struct sof_tlv **tuple) +{ + struct sof_ipc4_codec_info_data codec_info = { 0 }; + +#ifdef CONFIG_CADENCE_CODEC_AAC_DEC + codec_info.items[codec_info.count++] = + SET_CODEC_INFO_ITEM(SND_AUDIOCODEC_AAC, SOF_IPC_STREAM_PLAYBACK); +#endif +#ifdef CONFIG_CADENCE_CODEC_MP3_DEC + codec_info.items[codec_info.count++] = + SET_CODEC_INFO_ITEM(SND_AUDIOCODEC_MP3, SOF_IPC_STREAM_PLAYBACK); +#endif +#ifdef CONFIG_CADENCE_CODEC_MP3_ENC + codec_info.items[codec_info.count++] = + SET_CODEC_INFO_ITEM(SND_AUDIOCODEC_MP3, SOF_IPC_STREAM_CAPTURE); +#endif +#ifdef CONFIG_CADENCE_CODEC_VORBIS_DEC + codec_info.items[codec_info.count++] = + SET_CODEC_INFO_ITEM(SND_AUDIOCODEC_VORBIS, SOF_IPC_STREAM_PLAYBACK); +#endif + + if (!codec_info.count) + return; + + tlv_value_set(*tuple, IPC4_SOF_CODEC_INFO, sizeof(codec_info.count) + + sizeof(codec_info.items[0]) * codec_info.count, &codec_info); + + *tuple = tlv_next(*tuple); +} + +#define SOF_CONFIG_MEMBER_SIZE(struct_name) (sizeof(struct sof_tlv) + \ + sizeof(struct struct_name)) +#define SOF_CONFIG_SIZE_MAX (SOF_CONFIG_MEMBER_SIZE(sof_ipc4_codec_info_data)) + +static void base_fw_sof_config(struct sof_tlv **tuple) +{ + char sof_config_data[SOF_CONFIG_SIZE_MAX] = { 0 }; + struct sof_tlv *sof_config_tuple = (struct sof_tlv *)sof_config_data; + uint32_t sof_config_size; + + get_codec_info(&sof_config_tuple); + sof_config_size = (uint32_t)((char *)sof_config_tuple - sof_config_data); + if (sof_config_size == 0) + return; + + tlv_value_set(*tuple, IPC4_FW_SOF_INFO, sof_config_size, sof_config_data); + + *tuple = tlv_next(*tuple); +} + __cold static int basefw_config(uint32_t *data_offset, char *data) { uint16_t version[4] = {SOF_MAJOR, SOF_MINOR, SOF_MICRO, SOF_BUILD}; @@ -150,6 +214,8 @@ __cold static int basefw_config(uint32_t *data_offset, char *data) tuple = tlv_next(tuple); + base_fw_sof_config(&tuple); + /* add platform specific tuples */ basefw_vendor_fw_config(&plat_data_offset, (char *)tuple); diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 1fc69002a51d..a8f16e98c7b8 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -478,27 +478,30 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev * in order to avoid high load spike * if FAST_MODE is enabled, then one period limitation is omitted */ - if (!(hd->ipc_host.feature_mask & BIT(IPC4_COPIER_FAST_MODE))) - dma_copy_bytes = MIN(hd->period_bytes, dma_copy_bytes); - - const uint64_t now = k_uptime_get(); - const uint64_t delta = now - hd->nobytes_last_logged; - const bool reset_skipped = delta > SOF_MIN_NO_BYTES_INTERVAL_MS; + if (!(hd->ipc_host.feature_mask & BIT(IPC4_COPIER_FAST_MODE))) { + const uint64_t now = k_uptime_get(); + const uint64_t delta = now - hd->nobytes_last_logged; + const bool reset_skipped = delta > SOF_MIN_NO_BYTES_INTERVAL_MS; - if (hd->n_skipped > 1 && (dma_copy_bytes || reset_skipped)) { - comp_warn(dev, "Skipped %u no-bytes events in last %llu ms, bytes %u", - hd->n_skipped - 1, delta, dma_copy_bytes); - hd->n_skipped = 0; - } + dma_copy_bytes = MIN(hd->period_bytes, dma_copy_bytes); - if (!dma_copy_bytes) { - if (!hd->n_skipped || reset_skipped) { - hd->nobytes_last_logged = now; + if (hd->n_skipped > 1 && (dma_copy_bytes || reset_skipped)) { + comp_warn(dev, + "Skipped %u no-bytes events in last %llu ms, bytes %u", + hd->n_skipped - 1, delta, dma_copy_bytes); hd->n_skipped = 0; - comp_warn(dev, "no bytes to copy, available samples: %u, free_samples: %u", - avail_samples, free_samples); } - hd->n_skipped++; + + if (!dma_copy_bytes) { + if (!hd->n_skipped || reset_skipped) { + hd->nobytes_last_logged = now; + hd->n_skipped = 0; + comp_warn(dev, + "no bytes to copy, available samples: %u, free_samples: %u", + avail_samples, free_samples); + } + hd->n_skipped++; + } } /* dma_copy_bytes should be aligned to minimum possible chunk of diff --git a/src/audio/module_adapter/CMakeLists.txt b/src/audio/module_adapter/CMakeLists.txt index f51361c10d45..c728ef6d54b8 100644 --- a/src/audio/module_adapter/CMakeLists.txt +++ b/src/audio/module_adapter/CMakeLists.txt @@ -21,6 +21,10 @@ endif() zephyr_library_import(xa_aac_dec ${CONFIG_CADENCE_CODEC_AAC_DEC_LIB}) endif() + if (CONFIG_CADENCE_CODEC_VORBIS_DEC) + zephyr_library_import(xa_vorbis_dec ${CONFIG_CADENCE_CODEC_VORBIS_DEC_LIB}) + endif() + if (CONFIG_CADENCE_CODEC_MP3_DEC) zephyr_library_import(xa_mp3_dec ${CONFIG_CADENCE_CODEC_MP3_DEC_LIB}) endif() diff --git a/src/audio/module_adapter/module/cadence.c b/src/audio/module_adapter/module/cadence.c index b7df8d41a910..f8157d8f1d67 100644 --- a/src/audio/module_adapter/module/cadence.c +++ b/src/audio/module_adapter/module/cadence.c @@ -250,6 +250,9 @@ int cadence_codec_init_process(struct processing_module *mod) struct cadence_codec_data *cd = codec->private; struct comp_dev *dev = mod->dev; + codec->mpd.eos_reached = false; + codec->mpd.eos_notification_sent = false; + API_CALL(cd, XA_API_CMD_SET_INPUT_BYTES, 0, &codec->mpd.avail, ret); if (ret != LIB_NO_ERROR) { comp_err(dev, "error %x: failed to set size of input data", @@ -475,6 +478,13 @@ int cadence_codec_process_data(struct processing_module *mod) struct comp_dev *dev = mod->dev; int ret; + if (codec->mpd.eos_reached) { + codec->mpd.produced = 0; + codec->mpd.consumed = 0; + + return 0; + } + API_CALL(cd, XA_API_CMD_SET_INPUT_BYTES, 0, &codec->mpd.avail, ret); if (ret != LIB_NO_ERROR) { comp_err(dev, "failed to set size of input data with error: %x:", ret); @@ -503,5 +513,8 @@ int cadence_codec_process_data(struct processing_module *mod) return ret; } + if (!codec->mpd.produced && dev->pipeline->expect_eos) + codec->mpd.eos_reached = true; + return 0; } diff --git a/src/audio/module_adapter/module/cadence_ipc4.c b/src/audio/module_adapter/module/cadence_ipc4.c index 1dfbe2a07545..845283a208c3 100644 --- a/src/audio/module_adapter/module/cadence_ipc4.c +++ b/src/audio/module_adapter/module/cadence_ipc4.c @@ -8,8 +8,10 @@ #include #include #include +#include #include #include +#include #include SOF_DEFINE_REG_UUID(cadence_codec); @@ -204,6 +206,9 @@ static int cadence_configure_codec_params(struct processing_module *mod) return cadence_configure_mp3_enc_params(mod); case CADENCE_CODEC_AAC_DEC_ID: return cadence_configure_aac_dec_params(mod); + case CADENCE_CODEC_VORBIS_DEC_ID: + /* No configuration needed for Vorbis */ + return 0; default: break; } @@ -217,8 +222,8 @@ static int cadence_codec_init(struct processing_module *mod) struct module_data *codec = &mod->priv; struct module_config *cfg = &codec->cfg; struct module_ext_init_data *ext_data = cfg->ext_data; + struct module_config *setup_cfg = NULL; struct cadence_codec_data *cd; - struct module_config *setup_cfg; struct comp_dev *dev = mod->dev; int mem_tabs_size; int ret; @@ -308,7 +313,8 @@ static int cadence_codec_init(struct processing_module *mod) free: mod_free(mod, cd->mem_tabs); free_cfg: - mod_free(mod, setup_cfg->data); + if (setup_cfg) + mod_free(mod, setup_cfg->data); free_cd: mod_free(mod, cd); @@ -465,6 +471,36 @@ static int cadence_codec_process(struct processing_module *mod, struct sof_sourc return ret; } + if (codec->mpd.eos_reached && !codec->mpd.eos_notification_sent) { + struct ipc_msg msg_proto; + struct comp_ipc_config *ipc_config = &dev->ipc_config; + union ipc4_notification_header *primary = + (union ipc4_notification_header *)&msg_proto.header; + struct sof_ipc4_notify_module_data *msg_module_data; + struct ipc_msg *msg; + + memset_s(&msg_proto, sizeof(msg_proto), 0, sizeof(msg_proto)); + primary->r.notif_type = SOF_IPC4_MODULE_NOTIFICATION; + primary->r.type = SOF_IPC4_GLB_NOTIFICATION; + primary->r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; + primary->r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG; + msg = ipc_msg_w_ext_init(msg_proto.header, msg_proto.extension, + sizeof(*msg_module_data)); + if (msg) { + msg_module_data = (struct sof_ipc4_notify_module_data *)msg->tx_data; + msg_module_data->instance_id = IPC4_INST_ID(ipc_config->id); + msg_module_data->module_id = IPC4_MOD_ID(ipc_config->id); + msg_module_data->event_id = SOF_IPC4_NOTIFY_MODULE_EVENTID_COMPR_MAGIC_VAL; + msg_module_data->event_data_size = 0; + + ipc_msg_send(msg, NULL, false); + codec->mpd.eos_notification_sent = true; + } + + /* Set EOS for the sink as we are not going to produce more data */ + audio_buffer_set_eos(sof_audio_buffer_from_sink(sinks[0])); + } + /* do not proceed if not enough free space left */ if (out_space < codec->mpd.produced) { source_release_data(sources[0], 0); diff --git a/src/include/ipc4/base_fw.h b/src/include/ipc4/base_fw.h index 77b825ceffef..289ab76830e3 100644 --- a/src/include/ipc4/base_fw.h +++ b/src/include/ipc4/base_fw.h @@ -376,12 +376,28 @@ enum ipc4_fw_config_params { IPC4_FW_CONTEXT_SAVE = 29, /* Minimum size of host buffer in ms */ IPC4_FW_MIN_HOST_BUFFER_PERIODS = 33, + /* decoder/encoder codec information */ + IPC4_FW_SOF_INFO = 35, /* Total number of FW config parameters */ IPC4_FW_CFG_PARAMS_COUNT, /* Max config parameter id */ IPC4_MAX_FW_CFG_PARAM = IPC4_FW_CFG_PARAMS_COUNT - 1, }; +/* + * tuple based array for SOF specific information under IPC4_FW_SOF_INFO + * tuple of fw_config + */ +enum ipc4_fw_sof_info_params { + /* decoder/encoder codec information */ + IPC4_SOF_CODEC_INFO = 0, + + /* Total number of SOF config parameters */ + IPC4_SOF_CFG_PARAMS_COUNT, + /* Max config parameter id */ + IPC4_MAX_SOF_CFG_PARAM = IPC4_SOF_CFG_PARAMS_COUNT - 1, +}; + enum ipc4_hw_config_params { /* Version of cAVS implemented by FW (from ROMInfo) */ IPC4_CAVS_VER_HW_CFG = 0, diff --git a/src/include/ipc4/header.h b/src/include/ipc4/header.h index 643ded46050a..6a6eb59d02e5 100644 --- a/src/include/ipc4/header.h +++ b/src/include/ipc4/header.h @@ -177,6 +177,7 @@ struct ipc4_message_reply { #define SOF_IPC4_ENUM_CONTROL_PARAM_ID 201 #define SOF_IPC4_BYTES_CONTROL_PARAM_ID 202 #define SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL ((uint32_t)(0xA15A << 16)) +#define SOF_IPC4_NOTIFY_MODULE_EVENTID_COMPR_MAGIC_VAL ((uint32_t)(0xC0C0 << 16)) /** * struct sof_ipc4_ctrl_value_chan: generic channel mapped value data diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index f23bb602a28e..c60c22becf5c 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -172,6 +172,8 @@ struct module_processing_data { uint32_t produced; /**< Specifies how much data the module produced in its last task.*/ uint32_t consumed; /**< Specified how much data the module consumed in its last task */ uint32_t init_done; /**< Specifies if the module initialization is finished */ + bool eos_reached; /**< End of stream processing is reached */ + bool eos_notification_sent; /**< EOS notification is sent to host */ void *in_buff; /**< A pointer to module input buffer. */ void *out_buff; /**< A pointer to module output buffer. */ }; diff --git a/tools/rimage/config/lnl.toml.h b/tools/rimage/config/lnl.toml.h index 38ea9d9fabff..7a574d4ae906 100644 --- a/tools/rimage/config/lnl.toml.h +++ b/tools/rimage/config/lnl.toml.h @@ -62,6 +62,10 @@ #include