diff --git a/src/audio/module_adapter/module/dolby/dax.c b/src/audio/module_adapter/module/dolby/dax.c index 0261d3767b3c..3fb4d15a8107 100644 --- a/src/audio/module_adapter/module/dolby/dax.c +++ b/src/audio/module_adapter/module/dolby/dax.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -38,9 +39,34 @@ SOF_DEFINE_REG_UUID(dolby_dax_audio_processing); #define DAX_ENUM_PROFILE_CONTROL_ID 0 #define DAX_ENUM_DEVICE_CONTROL_ID 1 +#define DAX_USER_ID_INVALID 0 +#define DAX_MAX_INSTANCE 2 + +enum dax_user_priority { + DAX_USER_PRIORITY_DEFAULT = 0, + DAX_USER_PRIORITY_P0 = 0, + DAX_USER_PRIORITY_P1 = 1, /* Highest priority */ +}; + +struct dax_user { + uint32_t id; + enum dax_user_priority priority; + bool allocated; /* Whether the instance memory has been allocated */ +}; + +struct dax_user_manager { + struct dax_user users[DAX_MAX_INSTANCE]; + bool on_user_changed; + struct k_spinlock lock; + bool initialized; +}; + +static struct dax_user_manager user_mgr; + struct dax_adapter_data { struct sof_dax dax_ctx; atomic_t proc_flags; + uint32_t comp_id; }; enum dax_flag_opt_mode { @@ -50,6 +76,103 @@ enum dax_flag_opt_mode { DAX_FLAG_READ_AND_CLEAR, }; +static void update_alloc_state_l(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + struct dax_user *user = NULL; + + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (user_mgr.users[i].id == adapter_data->comp_id) { + user = &user_mgr.users[i]; + break; + } + } + + if (!user) + return; + + if (dax_ctx->p_dax && dax_ctx->persist_buffer.addr && dax_ctx->scratch_buffer.addr) { + user_mgr.on_user_changed = user->allocated ? false : true; + user->allocated = true; + } else { + user_mgr.on_user_changed = user->allocated ? true : false; + user->allocated = false; + } +} + +static int add_user_l(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + struct dax_user *user = NULL; + + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (user_mgr.users[i].id == DAX_USER_ID_INVALID) { + user = &user_mgr.users[i]; + break; + } + } + + if (!user) + return -ENOSPC; + + user->id = adapter_data->comp_id; + if (dax_ctx->out_device == DAX_DEVICE_SPEAKER) + user->priority = DAX_USER_PRIORITY_P1; + else if (dax_ctx->out_device == DAX_DEVICE_HEADPHONE) + user->priority = DAX_USER_PRIORITY_P0; + update_alloc_state_l(mod); + user_mgr.on_user_changed = true; + return 0; +} + +static void remove_user_l(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (user_mgr.users[i].id == adapter_data->comp_id) { + user_mgr.users[i].id = DAX_USER_ID_INVALID; + user_mgr.users[i].priority = DAX_USER_PRIORITY_DEFAULT; + user_mgr.users[i].allocated = false; + user_mgr.on_user_changed = true; + break; + } + } +} + +static bool check_priority_l(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct dax_user *user = NULL; + + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (user_mgr.users[i].id == adapter_data->comp_id) { + user = &user_mgr.users[i]; + break; + } + } + + if (!user) + return false; + + for (int i = 0; i < DAX_MAX_INSTANCE; i++) { + if (user_mgr.users[i].priority > user->priority && !user_mgr.users[i].allocated) + return false; + } + + return true; +} + +static bool is_enabled(struct processing_module *mod) +{ + struct dax_adapter_data *adapter_data = module_get_private_data(mod); + struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + + return dax_ctx->enable && dax_ctx->p_dax; +} + static int32_t flag_process(struct dax_adapter_data *adapter_data, uint32_t flag, enum dax_flag_opt_mode opt_mode) @@ -253,13 +376,19 @@ static void destroy_instance(struct processing_module *mod) static int establish_instance(struct processing_module *mod) { - int ret = 0; + int ret; struct comp_dev *dev = mod->dev; struct dax_adapter_data *adapter_data = module_get_private_data(mod); struct sof_dax *dax_ctx = &adapter_data->dax_ctx; uint32_t persist_sz; uint32_t scratch_sz; + if (dax_ctx->p_dax && dax_ctx->persist_buffer.addr && dax_ctx->scratch_buffer.addr) + return 0; + + if (dax_ctx->persist_buffer.addr || dax_ctx->scratch_buffer.addr) + destroy_instance(mod); + persist_sz = dax_query_persist_memory(dax_ctx); if (dax_buffer_alloc(mod, &dax_ctx->persist_buffer, persist_sz) != 0) { comp_err(dev, "allocate %u bytes failed for persist", persist_sz); @@ -313,18 +442,11 @@ static int set_tuning_file(struct processing_module *mod, void *value, uint32_t static int set_enable(struct processing_module *mod, int32_t enable) { - int ret = 0; + int ret; struct dax_adapter_data *adapter_data = module_get_private_data(mod); struct sof_dax *dax_ctx = &adapter_data->dax_ctx; - if (enable) { - ret = dax_set_enable(1, dax_ctx); - dax_ctx->enable = (ret == 0 ? 1 : 0); - } else { - dax_ctx->enable = 0; - dax_set_enable(0, dax_ctx); - } - + ret = dax_set_enable(enable, dax_ctx); comp_info(mod->dev, "set dax enable %d, ret %d", enable, ret); return ret; } @@ -335,10 +457,6 @@ static int set_volume(struct processing_module *mod, int32_t abs_volume) struct dax_adapter_data *adapter_data = module_get_private_data(mod); struct sof_dax *dax_ctx = &adapter_data->dax_ctx; - dax_ctx->volume = abs_volume; - if (!dax_ctx->enable) - return 0; - ret = dax_set_volume(abs_volume, dax_ctx); comp_info(mod->dev, "set volume %d, ret %d", abs_volume, ret); return ret; @@ -350,9 +468,7 @@ static int set_device(struct processing_module *mod, int32_t out_device) struct dax_adapter_data *adapter_data = module_get_private_data(mod); struct sof_dax *dax_ctx = &adapter_data->dax_ctx; - dax_ctx->out_device = out_device; ret = dax_set_device(out_device, dax_ctx); - comp_info(mod->dev, "set device %d, ret %d", out_device, ret); return ret; } @@ -363,9 +479,7 @@ static int set_crosstalk_cancellation_enable(struct processing_module *mod, int3 struct dax_adapter_data *adapter_data = module_get_private_data(mod); struct sof_dax *dax_ctx = &adapter_data->dax_ctx; - dax_ctx->ctc_enable = enable; ret = dax_set_ctc_enable(enable, dax_ctx); - comp_info(mod->dev, "set ctc enable %d, ret %d", enable, ret); return ret; } @@ -381,14 +495,9 @@ static int set_profile(struct processing_module *mod, int32_t profile_id) uint32_t params_sz = 0; void *params; - dax_ctx->profile = profile_id; - if (!dax_ctx->enable) - return 0; - params = dax_find_params(DAX_PARAM_ID_PROFILE, profile_id, ¶ms_sz, dax_ctx); if (params) ret = update_params_from_buffer(mod, params, params_sz); - comp_info(dev, "switched to profile %d, ret %d", profile_id, ret); return ret; } @@ -402,14 +511,9 @@ static int set_tuning_device(struct processing_module *mod, int32_t tuning_devic uint32_t params_sz = 0; void *params; - dax_ctx->tuning_device = tuning_device; - if (!dax_ctx->enable) - return 0; - params = dax_find_params(DAX_PARAM_ID_TUNING_DEVICE, tuning_device, ¶ms_sz, dax_ctx); if (params) ret = update_params_from_buffer(mod, params, params_sz); - comp_info(dev, "switched to tuning device %d, ret %d", tuning_device, ret); return ret; } @@ -423,14 +527,9 @@ static int set_content_processing_enable(struct processing_module *mod, int32_t uint32_t params_sz = 0; void *params; - dax_ctx->content_processing_enable = enable; - if (!dax_ctx->enable) - return 0; - params = dax_find_params(DAX_PARAM_ID_CP_ENABLE, enable, ¶ms_sz, dax_ctx); if (params) ret = update_params_from_buffer(mod, params, params_sz); - comp_info(dev, "set content processing enable %d, ret %d", enable, ret); return ret; } @@ -537,6 +636,29 @@ static int update_params_from_buffer(struct processing_module *mod, void *data, return 0; } +static void check_and_update_instance(struct processing_module *mod) +{ + k_spinlock_key_t key; + bool has_priority; + + key = k_spin_lock(&user_mgr.lock); + if (!user_mgr.on_user_changed) { + k_spin_unlock(&user_mgr.lock, key); + return; + } + has_priority = check_priority_l(mod); + k_spin_unlock(&user_mgr.lock, key); + + if (has_priority) + establish_instance(mod); + else + destroy_instance(mod); + + key = k_spin_lock(&user_mgr.lock); + update_alloc_state_l(mod); + k_spin_unlock(&user_mgr.lock, key); +} + static void check_and_update_settings(struct processing_module *mod) { struct dax_adapter_data *adapter_data = module_get_private_data(mod); @@ -544,12 +666,16 @@ static void check_and_update_settings(struct processing_module *mod) if (flag_process(adapter_data, DAX_ENABLE_MASK, DAX_FLAG_READ_AND_CLEAR)) { set_enable(mod, dax_ctx->enable); - if (dax_ctx->enable) { + if (is_enabled(mod)) { flag_process(adapter_data, DAX_DEVICE_MASK, DAX_FLAG_SET); flag_process(adapter_data, DAX_VOLUME_MASK, DAX_FLAG_SET); } return; } + + if (!is_enabled(mod)) + return; + if (flag_process(adapter_data, DAX_DEVICE_MASK, DAX_FLAG_READ_AND_CLEAR)) { set_device(mod, dax_ctx->out_device); set_tuning_device(mod, dax_ctx->tuning_device); @@ -579,6 +705,7 @@ static int sof_dax_reset(struct processing_module *mod) { struct dax_adapter_data *adapter_data = module_get_private_data(mod); struct sof_dax *dax_ctx; + k_spinlock_key_t key; /* dax instance will be established on prepare(), and destroyed on reset() */ if (adapter_data) { @@ -586,7 +713,11 @@ static int sof_dax_reset(struct processing_module *mod) if (flag_process(adapter_data, DAX_PROCESSING_MASK, DAX_FLAG_READ)) { flag_process(adapter_data, DAX_RESET_MASK, DAX_FLAG_SET); } else { - destroy_instance(mod); + key = k_spin_lock(&user_mgr.lock); + remove_user_l(mod); + k_spin_unlock(&user_mgr.lock, key); + check_and_update_instance(mod); + dax_buffer_release(mod, &dax_ctx->input_buffer); dax_buffer_release(mod, &dax_ctx->output_buffer); } @@ -644,6 +775,7 @@ static int sof_dax_init(struct processing_module *mod) } adapter_data = module_get_private_data(mod); + adapter_data->comp_id = dev->ipc_config.id; dax_ctx = &adapter_data->dax_ctx; dax_ctx->enable = 0; dax_ctx->profile = 0; @@ -661,6 +793,11 @@ static int sof_dax_init(struct processing_module *mod) return -ENOMEM; } + if (!user_mgr.initialized) { + k_spinlock_init(&user_mgr.lock); + user_mgr.initialized = true; + } + return 0; } @@ -746,6 +883,7 @@ static int sof_dax_prepare(struct processing_module *mod, struct sof_source **so struct dax_adapter_data *adapter_data = module_get_private_data(mod); struct sof_dax *dax_ctx = &adapter_data->dax_ctx; uint32_t ibs, obs; + k_spinlock_key_t key; if (num_of_sources != 1 || num_of_sinks != 1) { comp_err(dev, "unsupported number of buffers, in %d, out %d", @@ -757,11 +895,6 @@ static int sof_dax_prepare(struct processing_module *mod, struct sof_source **so if (ret != 0) return ret; - /* dax instance will be established on prepare(), and destroyed on reset() */ - ret = establish_instance(mod); - if (ret != 0) - return ret; - dax_ctx->sof_period_bytes = dev->frames * dax_ctx->output_media_format.num_channels * dax_ctx->output_media_format.bytes_per_sample; @@ -791,6 +924,11 @@ static int sof_dax_prepare(struct processing_module *mod, struct sof_source **so dax_buffer_produce(&dax_ctx->output_buffer, dax_ctx->output_buffer.size); comp_info(dev, "allocated: ibs %u, obs %u", ibs, obs); + key = k_spin_lock(&user_mgr.lock); + add_user_l(mod); + k_spin_unlock(&user_mgr.lock, key); + check_and_update_instance(mod); + return 0; err: @@ -832,6 +970,7 @@ static int sof_dax_process(struct processing_module *mod, struct sof_source **so dax_buffer_produce(dax_input_buffer, consumed_bytes); source_release_data(source, consumed_bytes); + check_and_update_instance(mod); check_and_update_settings(mod); /* internal input buffer -> internal output buffer */ @@ -1013,7 +1152,7 @@ static const struct sof_man_module_manifest main_manifest __section(".module") _ .name = "DAX", .uuid = SOF_REG_UUID(dolby_dax_audio_processing), .entry_point = (uint32_t)(&dolby_dax_audio_processing_interface), - .instance_max_count = 1, + .instance_max_count = 2, .type = { .load_type = SOF_MAN_MOD_TYPE_LLEXT, .domain_dp = 1, diff --git a/src/audio/module_adapter/module/dolby/dax.toml b/src/audio/module_adapter/module/dolby/dax.toml index c53911a3b33e..e57f29c8c792 100644 --- a/src/audio/module_adapter/module/dolby/dax.toml +++ b/src/audio/module_adapter/module/dolby/dax.toml @@ -7,7 +7,7 @@ name = "DAX" uuid = "40F66C8B-5AA5-4345-8919-53EC431AAA98" affinity_mask = "0x7" - instance_count = "1" + instance_count = "2" domain_types = "1" load_type = LOAD_TYPE module_type = "9" diff --git a/third_party/include/dax_inf.h b/third_party/include/dax_inf.h index a257cfd9e24f..8e25f52fc4a7 100644 --- a/third_party/include/dax_inf.h +++ b/third_party/include/dax_inf.h @@ -14,6 +14,12 @@ #include #include +enum dax_device { + DAX_DEVICE_UNSUPPORTED = -1, + DAX_DEVICE_SPEAKER = 0, + DAX_DEVICE_HEADPHONE = 1, +}; + enum dax_frame_fmt { DAX_FMT_UNSUPPORTED = -1, DAX_FMT_SHORT_16 = 4, @@ -144,6 +150,10 @@ int dax_init(struct sof_dax *dax_ctx); /** * @brief Process audio data through the DAX module * + * If DAX is disabled or the DAX instance is invalid (dax_ctx->p_dax is NULL), + * the dax_process will by default perform only copy operations, without any + * audio processing. + * * @param[in] dax_ctx Pointer to the DAX context structure * * @return Bytes of processed. negative error code on failure