diff --git a/dsp/Kbuild b/dsp/Kbuild index 74a2a7471e17..02a25e10fa19 100644 --- a/dsp/Kbuild +++ b/dsp/Kbuild @@ -92,11 +92,16 @@ ifdef CONFIG_SND_SOC_MSM_QDSP6V2_INTF Q6_OBJS += msm_audio_ion.o Q6_OBJS += avtimer.o Q6_OBJS += q6_init.o + endif ifdef CONFIG_DTS_SRS_TM Q6_OBJS += msm-dts-srs-tm-config.o endif +ifdef CONFIG_AFE_HWDEP + Q6_OBJS += q6afecal-hwdep.o +endif + ifdef CONFIG_MSM_ADSP_LOADER ADSP_LOADER_OBJS += adsp-loader.o endif diff --git a/dsp/q6afe.c b/dsp/q6afe.c index 6d2a5733f55c..c17721046256 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -28,6 +28,7 @@ #include #include #include "adsp_err.h" +#include "q6afecal-hwdep.h" #define WAKELOCK_TIMEOUT 5000 enum { @@ -126,6 +127,10 @@ struct afe_ctl { int dev_acdb_id[AFE_MAX_PORTS]; routing_cb rt_cb; struct audio_uevent_data *uevent_data; + /* cal info for AFE */ + struct afe_fw_info *fw_data; + u32 island_mode[AFE_MAX_PORTS]; + struct vad_config vad_cfg[AFE_MAX_PORTS]; }; static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX]; @@ -1810,6 +1815,148 @@ done: } + +static int afe_get_island_mode(u16 port_id, u32 *island_mode) +{ + int ret = 0; + int index = 0; + *island_mode = 0; + + index = q6audio_get_port_index(port_id); + if (index < 0 || index >= AFE_MAX_PORTS) { + pr_err("%s: AFE port index[%d] invalid!\n", + __func__, index); + return -EINVAL; + } + + *island_mode = this_afe.island_mode[index]; + return ret; +} + +/* + * afe_send_port_island_mode - + * for sending island mode to AFE + * + * @port_id: AFE port id number + * + * Returns 0 on success or error on failure. + */ +int afe_send_port_island_mode(u16 port_id) +{ + struct afe_param_id_island_cfg_t island_cfg; + struct param_hdr_v3 param_info; + u32 island_mode = 0; + int ret = 0; + + memset(&island_cfg, 0, sizeof(island_cfg)); + memset(¶m_info, 0, sizeof(param_info)); + + ret = afe_get_island_mode(port_id, &island_mode); + if (ret) { + pr_err("%s: AFE port[%d] get island mode is invalid!\n", + __func__, port_id); + return ret; + } + param_info.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; + param_info.instance_id = INSTANCE_ID_0; + param_info.param_id = AFE_PARAM_ID_ISLAND_CONFIG; + param_info.param_size = sizeof(island_cfg); + + island_cfg.island_cfg_minor_version = AFE_API_VERSION_ISLAND_CONFIG; + island_cfg.island_enable = island_mode; + + ret = q6afe_pack_and_set_param_in_band(port_id, + q6audio_get_port_index(port_id), + param_info, (u8 *) &island_cfg); + if (ret) { + pr_err("%s: AFE set island mode enable for port 0x%x failed %d\n", + __func__, port_id, ret); + return ret; + } + pr_debug("%s: AFE set island mode 0x%x enable for port 0x%x ret %d\n", + __func__, island_mode, port_id, ret); + return ret; +} +EXPORT_SYMBOL(afe_send_port_island_mode); + +static int afe_get_vad_preroll_cfg(u16 port_id, u32 *preroll_cfg) +{ + int ret = 0; + int index = 0; + *preroll_cfg = 0; + + index = q6audio_get_port_index(port_id); + if (index < 0 || index >= AFE_MAX_PORTS) { + pr_err("%s: AFE port index[%d] invalid!\n", + __func__, index); + return -EINVAL; + } + + *preroll_cfg = this_afe.vad_cfg[index].pre_roll; + return ret; +} + +static int afe_send_port_vad_cfg_params(u16 port_id) +{ + struct afe_param_id_vad_cfg_t vad_cfg; + struct param_hdr_v3 param_info; + u32 pre_roll_cfg = 0; + struct firmware_cal *hwdep_cal = NULL; + int ret = 0; + + memset(&vad_cfg, 0, sizeof(vad_cfg)); + memset(¶m_info, 0, sizeof(param_info)); + + ret = afe_get_vad_preroll_cfg(port_id, &pre_roll_cfg); + if (ret) { + pr_err("%s: AFE port[%d] get preroll cfg is invalid!\n", + __func__, port_id); + return ret; + } + param_info.module_id = AFE_MODULE_VAD; + param_info.instance_id = INSTANCE_ID_0; + param_info.param_id = AFE_PARAM_ID_VAD_CFG; + param_info.param_size = sizeof(vad_cfg); + + vad_cfg.vad_cfg_minor_version = AFE_API_VERSION_VAD_CFG; + vad_cfg.pre_roll_in_ms = pre_roll_cfg; + + ret = q6afe_pack_and_set_param_in_band(port_id, + q6audio_get_port_index(port_id), + param_info, (u8 *) &vad_cfg); + if (ret) { + pr_err("%s: AFE set vad cfg for port 0x%x failed %d\n", + __func__, port_id, ret); + return ret; + } + + memset(¶m_info, 0, sizeof(param_info)); + + hwdep_cal = q6afecal_get_fw_cal(this_afe.fw_data, Q6AFE_VAD_CORE_CAL); + if (!hwdep_cal) { + pr_err("%s: error in retrieving vad core calibration", + __func__); + return -EINVAL; + } + + param_info.module_id = AFE_MODULE_VAD; + param_info.instance_id = INSTANCE_ID_0; + param_info.param_id = AFE_PARAM_ID_VAD_CORE_CFG; + param_info.param_size = hwdep_cal->size; + + ret = q6afe_pack_and_set_param_in_band(port_id, + q6audio_get_port_index(port_id), + param_info, (u8 *) hwdep_cal->data); + if (ret) { + pr_err("%s: AFE set vad cfg for port 0x%x failed %d\n", + __func__, port_id, ret); + return ret; + } + pr_debug("%s: AFE set preroll cfg %d vad core cfg port 0x%x ret %d\n", + __func__, pre_roll_cfg, port_id, ret); + return ret; +} + static int remap_cal_data(struct cal_block_data *cal_block, int cal_index) { int ret = 0; @@ -2804,6 +2951,44 @@ void afe_set_cal_mode(u16 port_id, enum afe_cal_mode afe_cal_mode) } EXPORT_SYMBOL(afe_set_cal_mode); +/** + * afe_set_vad_cfg - + * set configuration for VAD + * + * @port_id: AFE port id number + * @vad_enable: enable/disable vad + * @preroll_config: Preroll configuration + * + */ +void afe_set_vad_cfg(u32 vad_enable, u32 preroll_config, + u32 port_id) +{ + uint16_t port_index; + + port_index = afe_get_port_index(port_id); + this_afe.vad_cfg[port_index].is_enable = vad_enable; + this_afe.vad_cfg[port_index].pre_roll = preroll_config; +} +EXPORT_SYMBOL(afe_set_vad_cfg); + +/** + * afe_set_island_mode_cfg - + * set island mode configuration + * + * @port_id: AFE port id number + * @enable_flag: Enable or Disable + * + */ +void afe_set_island_mode_cfg(u16 port_id, u32 enable_flag) +{ + uint16_t port_index; + + port_index = afe_get_port_index(port_id); + this_afe.island_mode[port_index] = enable_flag; + +} +EXPORT_SYMBOL(afe_set_island_mode_cfg); + /** * afe_set_routing_callback - * Update callback function for routing @@ -3245,8 +3430,21 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, } mutex_lock(&this_afe.afe_cmd_lock); - /* Also send the topology id here: */ port_index = afe_get_port_index(port_id); + + if (q6core_get_avcs_api_version_per_service( + APRV2_IDS_SERVICE_ID_ADSP_AFE_V) >= AFE_API_VERSION_V4) { + /* send VAD configuration if is enabled */ + if (this_afe.vad_cfg[port_index].is_enable) { + ret = afe_send_port_vad_cfg_params(port_id); + if (ret) + pr_err("%s: afe send VAD config failed %d\n", + __func__, ret); + goto fail_cmd; + } + } + + /* Also send the topology id here: */ if (!(this_afe.afe_cal_mode[port_index] == AFE_CAL_MODE_NONE)) { /* One time call: only for first time */ afe_send_custom_topology(); @@ -7354,6 +7552,9 @@ int __init afe_init(void) this_afe.afe_cal_mode[i] = AFE_CAL_MODE_DEFAULT; this_afe.afe_sample_rates[i] = 0; this_afe.dev_acdb_id[i] = 0; + this_afe.island_mode[i] = 0; + this_afe.vad_cfg[i].is_enable = 0; + this_afe.vad_cfg[i].pre_roll = 0; init_waitqueue_head(&this_afe.wait[i]); } wakeup_source_init(&wl.ws, "spkr-prot"); @@ -7394,3 +7595,29 @@ void afe_exit(void) mutex_destroy(&this_afe.afe_cmd_lock); wakeup_source_trash(&wl.ws); } + +/* + * afe_cal_init_hwdep - + * Initiliaze AFE HW dependent Node + * + * @card: pointer to sound card + * + */ +int afe_cal_init_hwdep(void *card) +{ + int ret = 0; + + this_afe.fw_data = kzalloc(sizeof(*(this_afe.fw_data)), + GFP_KERNEL); + if (!this_afe.fw_data) + return -ENOMEM; + + set_bit(Q6AFE_VAD_CORE_CAL, this_afe.fw_data->cal_bit); + ret = q6afe_cal_create_hwdep(this_afe.fw_data, Q6AFE_HWDEP_NODE, card); + if (ret < 0) { + pr_err("%s: couldn't create hwdep for AFE %d\n", __func__, ret); + return ret; + } + return ret; +} +EXPORT_SYMBOL(afe_cal_init_hwdep); diff --git a/dsp/q6afecal-hwdep.c b/dsp/q6afecal-hwdep.c new file mode 100644 index 000000000000..5fea2d27a40f --- /dev/null +++ b/dsp/q6afecal-hwdep.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2015, 2017 - 2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include "q6afecal-hwdep.h" + +const int cal_size_info[Q6AFE_MAX_CAL] = { + [Q6AFE_VAD_CORE_CAL] = 132, +}; + +const char *cal_name_info[Q6AFE_MAX_CAL] = { + [Q6AFE_VAD_CORE_CAL] = "vad_core", +}; + +#define AFE_HW_NAME_LENGTH 40 + +/* + * q6afecal_get_fw_cal - + * To get calibration from AFE HW dependent node + * + * @fw_data: pointer to firmware data + * type: AFE calibration type + * + */ +struct firmware_cal *q6afecal_get_fw_cal(struct afe_fw_info *fw_data, + enum q6afe_cal_type type) +{ + if (!fw_data) { + pr_err("%s: fw_data is NULL\n", __func__); + return NULL; + } + if (type >= Q6AFE_MAX_CAL || + type < Q6AFE_MIN_CAL) { + pr_err("%s: wrong cal type sent %d\n", __func__, type); + return NULL; + } + mutex_lock(&fw_data->lock); + if (!test_bit(Q6AFECAL_RECEIVED, + &fw_data->q6afecal_state[type])) { + pr_err("%s: cal not sent by userspace %d\n", + __func__, type); + mutex_unlock(&fw_data->lock); + return NULL; + } + set_bit(Q6AFECAL_INITIALISED, &fw_data->q6afecal_state[type]); + mutex_unlock(&fw_data->lock); + return fw_data->fw[type]; +} +EXPORT_SYMBOL(q6afecal_get_fw_cal); + +static int q6afecal_hwdep_ioctl_shared(struct snd_hwdep *hw, + struct q6afecal_ioctl_buffer fw_user) +{ + struct afe_fw_info *fw_data = hw->private_data; + struct firmware_cal **fw = fw_data->fw; + void *data; + + if (!test_bit(fw_user.cal_type, fw_data->cal_bit)) { + pr_err("%s: q6afe didn't set this %d!!\n", + __func__, fw_user.cal_type); + return -EFAULT; + } + if (fw_user.cal_type >= Q6AFE_MAX_CAL || + fw_user.cal_type < Q6AFE_MIN_CAL) { + pr_err("%s: wrong cal type sent %d\n", + __func__, fw_user.cal_type); + return -EFAULT; + } + if (fw_user.size > cal_size_info[fw_user.cal_type] || + fw_user.size <= 0) { + pr_err("%s: incorrect firmware size %d for %s\n", + __func__, fw_user.size, + cal_name_info[fw_user.cal_type]); + return -EFAULT; + } + data = fw[fw_user.cal_type]->data; + if (copy_from_user(data, fw_user.buffer, fw_user.size)) + return -EFAULT; + fw[fw_user.cal_type]->size = fw_user.size; + mutex_lock(&fw_data->lock); + set_bit(Q6AFECAL_RECEIVED, &fw_data->q6afecal_state[fw_user.cal_type]); + mutex_unlock(&fw_data->lock); + return 0; +} + +#ifdef CONFIG_COMPAT +struct q6afecal_ioctl_buffer32 { + u32 size; + compat_uptr_t buffer; + enum q6afe_cal_type cal_type; +}; + +enum { + SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32 = + _IOW('U', 0x1, struct q6afecal_ioctl_buffer32), +}; + +static int q6afecal_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6afecal_ioctl_buffer __user *argp = (void __user *)arg; + struct q6afecal_ioctl_buffer32 fw_user32; + struct q6afecal_ioctl_buffer fw_user_compat; + + if (cmd != SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32) { + pr_err("%s: wrong ioctl command sent %u!\n", __func__, cmd); + return -ENOIOCTLCMD; + } + if (copy_from_user(&fw_user32, argp, sizeof(fw_user32))) { + pr_err("%s: failed to copy\n", __func__); + return -EFAULT; + } + fw_user_compat.size = fw_user32.size; + fw_user_compat.buffer = compat_ptr(fw_user32.buffer); + fw_user_compat.cal_type = fw_user32.cal_type; + return q6afecal_hwdep_ioctl_shared(hw, fw_user_compat); +} +#else +#define q6afecal_hwdep_ioctl_compat NULL +#endif + +static int q6afecal_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct q6afecal_ioctl_buffer __user *argp = (void __user *)arg; + struct q6afecal_ioctl_buffer fw_user; + + if (cmd != SNDRV_IOCTL_HWDEP_VAD_CAL_TYPE) { + pr_err("%s: wrong ioctl command sent %d!\n", __func__, cmd); + return -ENOIOCTLCMD; + } + if (copy_from_user(&fw_user, argp, sizeof(fw_user))) { + pr_err("%s: failed to copy\n", __func__); + return -EFAULT; + } + return q6afecal_hwdep_ioctl_shared(hw, fw_user); +} + +static int q6afecal_hwdep_release(struct snd_hwdep *hw, struct file *file) +{ + struct afe_fw_info *fw_data = hw->private_data; + + mutex_lock(&fw_data->lock); + /* clear all the calibrations */ + memset(fw_data->q6afecal_state, 0, + sizeof(fw_data->q6afecal_state)); + mutex_unlock(&fw_data->lock); + return 0; +} + +/** + * q6afe_cal_create_hwdep - + * for creating HW dependent node for AFE + * + * @data: Pointer to hold fw data + * @node: node type + * @card: Pointer to sound card + * + */ +int q6afe_cal_create_hwdep(void *data, int node, void *card) +{ + char hwname[AFE_HW_NAME_LENGTH]; + struct snd_hwdep *hwdep; + struct firmware_cal **fw; + struct afe_fw_info *fw_data = data; + int err, cal_bit; + + if (!fw_data || !card) { + pr_err("%s: Invalid parameters\n", __func__); + return -EINVAL; + } + + fw = fw_data->fw; + snprintf(hwname, strlen("Q6AFE"), "Q6AFE"); + err = snd_hwdep_new(((struct snd_soc_card *)card)->snd_card, + hwname, node, &hwdep); + if (err < 0) { + pr_err("%s: new hwdep for q6afe failed %d\n", __func__, err); + return err; + } + snprintf(hwdep->name, strlen("Q6AFECAL"), "Q6AFECAL"); + hwdep->iface = SNDRV_HWDEP_IFACE_AUDIO_BE; + hwdep->private_data = fw_data; + hwdep->ops.ioctl_compat = q6afecal_hwdep_ioctl_compat; + hwdep->ops.ioctl = q6afecal_hwdep_ioctl; + hwdep->ops.release = q6afecal_hwdep_release; + mutex_init(&fw_data->lock); + + for_each_set_bit(cal_bit, fw_data->cal_bit, Q6AFE_MAX_CAL) { + set_bit(Q6AFECAL_UNINITIALISED, + &fw_data->q6afecal_state[cal_bit]); + fw[cal_bit] = kzalloc(sizeof *(fw[cal_bit]), GFP_KERNEL); + if (!fw[cal_bit]) { + pr_err("%s: no memory for %s cal\n", + __func__, cal_name_info[cal_bit]); + goto end; + } + } + for_each_set_bit(cal_bit, fw_data->cal_bit, Q6AFE_MAX_CAL) { + fw[cal_bit]->data = kzalloc(cal_size_info[cal_bit], + GFP_KERNEL); + if (!fw[cal_bit]->data) + goto exit; + set_bit(Q6AFECAL_INITIALISED, + &fw_data->q6afecal_state[cal_bit]); + } + return 0; +exit: + for_each_set_bit(cal_bit, fw_data->cal_bit, Q6AFE_MAX_CAL) { + kfree(fw[cal_bit]->data); + fw[cal_bit]->data = NULL; + } +end: + for_each_set_bit(cal_bit, fw_data->cal_bit, Q6AFE_MAX_CAL) { + kfree(fw[cal_bit]); + fw[cal_bit] = NULL; + } + return -ENOMEM; +} +EXPORT_SYMBOL(q6afe_cal_create_hwdep); diff --git a/dsp/q6afecal-hwdep.h b/dsp/q6afecal-hwdep.h new file mode 100644 index 000000000000..7e6efdac57f4 --- /dev/null +++ b/dsp/q6afecal-hwdep.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014,2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __Q6AFECAL_HWDEP_H__ +#define __Q6AFECAL_HWDEP_H__ +#include + +enum q6afe_cal_states { + Q6AFECAL_UNINITIALISED, + Q6AFECAL_INITIALISED, + Q6AFECAL_RECEIVED +}; + +struct afe_fw_info { + struct firmware_cal *fw[Q6AFE_MAX_CAL]; + DECLARE_BITMAP(cal_bit, Q6AFE_MAX_CAL); + /* for calibration tracking */ + unsigned long q6afecal_state[Q6AFE_MAX_CAL]; + struct mutex lock; +}; + +struct firmware_cal { + u8 *data; + size_t size; +}; + +#if IS_ENABLED(CONFIG_AFE_HWDEP) +int q6afe_cal_create_hwdep(void *fw, int node, void *card); +struct firmware_cal *q6afecal_get_fw_cal(struct afe_fw_info *fw_data, + enum q6afe_cal_type type); +#else /* CONFIG_AFE_HWDEP */ +static inline int q6afe_cal_create_hwdep(void *fw, int node, void *card) +{ + return 0; +} + +static inline struct firmware_cal *q6afecal_get_fw_cal( + struct afe_fw_info *fw_data, + enum q6afe_cal_type type) +{ + return NULL; +} +#endif /* CONFIG_AFE_HWDEP */ +#endif /* __Q6AFECAL_HWDEP_H__ */ diff --git a/dsp/q6core.c b/dsp/q6core.c index 9b0b588fdda1..d8fdb4c2a450 100644 --- a/dsp/q6core.c +++ b/dsp/q6core.c @@ -513,10 +513,9 @@ int q6core_get_service_version(uint32_t service_id, } EXPORT_SYMBOL(q6core_get_service_version); -size_t q6core_get_fwk_version_size(uint32_t service_id) +static int q6core_get_avcs_fwk_version(void) { int ret = 0; - uint32_t num_services; mutex_lock(&(q6core_lcl.ver_lock)); pr_debug("%s: q6core_avcs_ver_info.status(%d)\n", __func__, @@ -547,7 +546,15 @@ size_t q6core_get_fwk_version_size(uint32_t service_id) break; } mutex_unlock(&(q6core_lcl.ver_lock)); + return ret; +} +size_t q6core_get_fwk_version_size(uint32_t service_id) +{ + int ret = 0; + uint32_t num_services; + + ret = q6core_get_avcs_fwk_version(); if (ret) goto done; @@ -570,6 +577,42 @@ done: } EXPORT_SYMBOL(q6core_get_fwk_version_size); +/** + * q6core_get_avcs_version_per_service - + * to get api version of a particular service + * + * @service_id: id of the service + * + * Returns valid version on success or error (negative value) on failure + */ +int q6core_get_avcs_api_version_per_service(uint32_t service_id) +{ + struct avcs_fwk_ver_info *cached_ver_info = NULL; + int i; + uint32_t num_services; + int ret = 0; + + if (service_id == AVCS_SERVICE_ID_ALL) + return -EINVAL; + + ret = q6core_get_avcs_fwk_version(); + if (ret < 0) { + pr_err("%s: failure in getting AVCS version\n", __func__); + return ret; + } + + cached_ver_info = q6core_lcl.q6core_avcs_ver_info.ver_info; + num_services = cached_ver_info->avcs_fwk_version.num_services; + + for (i = 0; i < num_services; i++) { + if (cached_ver_info->services[i].service_id == service_id) + return cached_ver_info->services[i].api_version; + } + pr_err("%s: No service matching service ID %d\n", __func__, service_id); + return -EINVAL; +} +EXPORT_SYMBOL(q6core_get_avcs_api_version_per_service); + /** * core_set_license - * command to set license for module diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index 5a5fb6f57bd9..4f03c17d1d94 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -3941,6 +3941,32 @@ struct avs_dec_depacketizer_id_param_t { uint32_t dec_depacketizer_id; }; +/* ID of the parameter used by #AFE_MODULE_AUDIO_DEV_INTERFACE to configure + * the island mode for a given AFE port. + */ +#define AFE_PARAM_ID_ISLAND_CONFIG 0x000102B4 + +/* Version information used to handle future additions to codec DMA + * configuration (for backward compatibility). + */ +#define AFE_API_VERSION_ISLAND_CONFIG 0x1 + +/* Payload of the AFE_PARAM_ID_ISLAND_CONFIG parameter used by + * AFE_MODULE_AUDIO_DEV_INTERFACE. + */ +struct afe_param_id_island_cfg_t { + uint32_t island_cfg_minor_version; + /* Tracks the configuration of this parameter. + * Supported values: #AFE_API_VERSION_ISLAND_CONFIG + */ + + uint32_t island_enable; + /* Specifies whether island mode should be enabled or disabled for the + * use-case being setup. + * Supported values: 0 - Disable, 1 - Enable + */ +} __packed; + /* ID of the parameter used by #AFE_MODULE_AUDIO_DEV_INTERFACE to configure * the Codec DMA interface. */ @@ -9814,6 +9840,7 @@ struct asm_aptx_dec_fmt_blk_v2 { #define AVCS_SERVICE_ID_ALL (0xFFFFFFFF) #define APRV2_IDS_SERVICE_ID_ADSP_CVP_V (0xB) +#define APRV2_IDS_SERVICE_ID_ADSP_AFE_V (0x4) struct avcs_get_fwk_version { /* @@ -11265,4 +11292,32 @@ struct admx_sec_primary_mic_ch { uint16_t reserved1; } __packed; +/** ID of the Voice Activity Detection (VAD) module, which is used to + * configure AFE VAD. + */ +#define AFE_MODULE_VAD 0x000102B9 + +/** ID of the parameter used by #AFE_MODULE_VAD to configure the VAD. + */ +#define AFE_PARAM_ID_VAD_CFG 0x000102BA + +#define AFE_API_VERSION_VAD_CFG 0x1 + +/* Payload of the AFE_PARAM_ID_VAD_CONFIG parameter used by + * AFE_MODULE_VAD. + */ +struct afe_param_id_vad_cfg_t { + uint32_t vad_cfg_minor_version; + /** Tracks the configuration of this parameter. + * Supported Values: #AFE_API_VERSION_VAD_CFG + */ + + uint32_t pre_roll_in_ms; + /** Pre-roll period in ms. + * Supported Values: 0x0 to 0x3E8 + */ +} __packed; + +#define AFE_PARAM_ID_VAD_CORE_CFG 0x000102BB + #endif /*_APR_AUDIO_V2_H_ */ diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h index b420ef333b56..e3ec1bc971fa 100644 --- a/include/dsp/q6afe-v2.h +++ b/include/dsp/q6afe-v2.h @@ -41,7 +41,12 @@ #define AFE_CLK_VERSION_V1 1 #define AFE_CLK_VERSION_V2 2 + #define AFE_API_VERSION_SUPPORT_SPV3 2 +#define AFE_API_VERSION_V3 3 +/* for VAD and Island mode */ +#define AFE_API_VERSION_V4 4 + typedef int (*routing_cb)(int port); enum { @@ -248,6 +253,16 @@ enum afe_cal_mode { AFE_CAL_MODE_NONE, }; +enum afe_vad_cfg_type { + AFE_VAD_ENABLE = 0x00, + AFE_VAD_PREROLL, +}; + +struct vad_config { + u32 is_enable; + u32 pre_roll; +}; + struct afe_audio_buffer { dma_addr_t phys; void *data; @@ -323,6 +338,9 @@ int afe_rt_proxy_port_write(phys_addr_t buf_addr_p, int afe_rt_proxy_port_read(phys_addr_t buf_addr_p, u32 mem_map_handle, int bytes); void afe_set_cal_mode(u16 port_id, enum afe_cal_mode afe_cal_mode); +void afe_set_vad_cfg(u32 vad_enable, u32 preroll_config, + u32 port_id); +void afe_set_island_mode_cfg(u16 port_id, u32 enable_flag); int afe_port_start(u16 port_id, union afe_port_config *afe_config, u32 rate); int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config, @@ -396,4 +414,6 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port, void afe_set_routing_callback(routing_cb cb); int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats, u16 port); +int afe_cal_init_hwdep(void *card); +int afe_send_port_island_mode(u16 port_id); #endif /* __Q6AFE_V2_H__ */ diff --git a/include/dsp/q6core.h b/include/dsp/q6core.h index 03a7b31af52d..a4706a6d956d 100644 --- a/include/dsp/q6core.h +++ b/include/dsp/q6core.h @@ -35,6 +35,7 @@ struct audio_uevent_data { int q6core_init_uevent_data(struct audio_uevent_data *uevent_data, char *name); void q6core_destroy_uevent_data(struct audio_uevent_data *uevent_data); int q6core_send_uevent(struct audio_uevent_data *uevent_data, char *name); +int q6core_get_avcs_api_version_per_service(uint32_t service_id); #define ADSP_CMD_SET_DTS_EAGLE_DATA_ID 0x00012919 #define DTS_EAGLE_LICENSE_ID 0x00028346 diff --git a/include/uapi/sound/msmcal-hwdep.h b/include/uapi/sound/msmcal-hwdep.h index 2f6d37ad0a10..f2891863fa47 100644 --- a/include/uapi/sound/msmcal-hwdep.h +++ b/include/uapi/sound/msmcal-hwdep.h @@ -3,6 +3,7 @@ #define WCD9XXX_CODEC_HWDEP_NODE 1000 #define AQT1000_CODEC_HWDEP_NODE 1001 +#define Q6AFE_HWDEP_NODE 1002 enum wcd_cal_type { WCD9XXX_MIN_CAL, WCD9XXX_ANC_CAL = WCD9XXX_MIN_CAL, @@ -21,4 +22,19 @@ struct wcdcal_ioctl_buffer { #define SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE \ _IOW('U', 0x1, struct wcdcal_ioctl_buffer) +enum q6afe_cal_type { + Q6AFE_MIN_CAL, + Q6AFE_VAD_CORE_CAL = Q6AFE_MIN_CAL, + Q6AFE_MAX_CAL, +}; + +struct q6afecal_ioctl_buffer { + __u32 size; + __u8 __user *buffer; + enum q6afe_cal_type cal_type; +}; + +#define SNDRV_IOCTL_HWDEP_VAD_CAL_TYPE \ + _IOW('U', 0x1, struct q6afecal_ioctl_buffer) + #endif /*_CALIB_HWDEP_H*/