ASoC: Add support "adm cmd register" and "adm pp" events

Added support for "ADM_CMD_REGISTER_EVENT" and "ADM_PP_EVENT"
events.

Signed-off-by: Srinivasa Reddy M N <quic_c_mullan@quicinc.com>
Change-Id: I80d8dc6d9fccdac67ea616d19415aa2133a3f370
This commit is contained in:
Srinivasa Reddy M N
2022-10-20 17:59:48 +05:30
committed by Gerrit - the friendly Code Review server
parent 5fb54fcd05
commit 7581982cee
10 changed files with 875 additions and 1 deletions

View File

@@ -565,6 +565,8 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
uint16_t format = 0;
uint16_t req_format = 0;
uint16_t input_file_format = 0;
int port_id = 0, copp_idx = -1;
bool found = false;
if (!component) {
pr_err("%s: component is NULL\n", __func__);
@@ -691,6 +693,15 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
return ret;
}
found = msm_pcm_routing_get_portid_copp_idx(soc_prtd->dai_link->id,
SESSION_TYPE_RX, &port_id, &copp_idx);
if (found) {
q6adm_update_rtd_info(soc_prtd, port_id, copp_idx,
soc_prtd->dai_link->id, 1);
} else {
pr_err("%s: copp_idx not found\n", __func__);
}
/*Format block is configure with input file bits_per_sample*/
switch (input_file_format) {
case SNDRV_PCM_FORMAT_S32_LE:
@@ -1070,8 +1081,10 @@ static int msm_pcm_open(struct snd_pcm_substream *substream)
prtd->reset_event = false;
runtime->private_data = prtd;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
msm_adsp_init_mixer_ctl_adm_pp_event_queue(soc_prtd);
}
/* Vote to update the Rx thread priority to RT Thread for playback */
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
@@ -1189,6 +1202,8 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
uint32_t timeout;
int dir = 0;
int ret = 0;
int port_id = 0, copp_idx = -1;
bool found = false;
pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
@@ -1239,9 +1254,21 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
prtd->audio_client);
q6asm_audio_client_free(prtd->audio_client);
}
found = msm_pcm_routing_get_portid_copp_idx(soc_prtd->dai_link->id,
SESSION_TYPE_RX, &port_id, &copp_idx);
if (found) {
q6adm_update_rtd_info(soc_prtd, port_id, copp_idx,
soc_prtd->dai_link->id, 0);
q6adm_clear_callback();
} else {
pr_err("%s: copp_idx not found\n", __func__);
}
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
SNDRV_PCM_STREAM_PLAYBACK);
msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
msm_adsp_clean_mixer_ctl_adm_pp_event_queue(soc_prtd);
kfree(prtd);
runtime->private_data = NULL;
mutex_unlock(&pdata->lock);

339
asoc/msm-pcm-routing-auto.c Executable file → Normal file
View File

@@ -103,6 +103,10 @@ static int afe_loopback_tx_port_id = -1;
static struct msm_pcm_channel_mixer ec_ref_chmix_cfg[MSM_FRONTEND_DAI_MAX];
static struct msm_ec_ref_port_cfg ec_ref_port_cfg;
static uint32_t adm_pp_reg_event_opcode[] = {
ADM_CMD_REGISTER_EVENT
};
#define WEIGHT_0_DB 0x4000
/* all the FEs which can support channel mixer */
static struct msm_pcm_channel_mixer channel_mixer[MSM_FRONTEND_DAI_MM_SIZE];
@@ -2418,6 +2422,56 @@ int msm_pcm_routing_set_channel_mixer_runtime(int be_id, int session_id,
}
EXPORT_SYMBOL(msm_pcm_routing_set_channel_mixer_runtime);
/*
* msm_pcm_routing_get_portid_copp_idx:
* update the port_id and copp_idx for a given
* fe_id
*
* @fe_id: front end id
* @session_type: indicates session is of type TX or RX
* port: port_id to be updated as output
* copp_idx: copp_idx is updated as output
* @stream_type: indicates either Audio or Listen stream type
*/
bool msm_pcm_routing_get_portid_copp_idx(int fe_id,
int session_type, int *port, int *copp_idx)
{
int idx = 0;
bool found = false;
int be_index = 0, port_id = 0;
pr_debug("%s:fe_id[%d] sess_type [%d]\n",
__func__, fe_id, session_type);
if (!is_mm_lsm_fe_id(fe_id)) {
/* bad ID assigned in machine driver */
pr_err("%s: bad MM ID %d\n", __func__, fe_id);
return -EINVAL;
}
for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) {
port_id = msm_bedais[be_index].port_id;
if (!msm_bedais[be_index].active ||
!test_bit(fe_id, &msm_bedais[be_index].fe_sessions[0]))
continue;
for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
unsigned long copp_id =
session_copp_map[fe_id][session_type][be_index];
if (test_bit(idx, &copp_id)) {
pr_debug("%s: port_id: %d, copp_idx:%d\n",
__func__, port_id, idx);
*port = port_id;
*copp_idx = idx;
found = true;
break;
}
}
}
return found;
}
EXPORT_SYMBOL(msm_pcm_routing_get_portid_copp_idx);
int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
int dspst_id, int stream_type)
{
@@ -32481,6 +32535,273 @@ static void msm_routing_unload_topology(uint32_t topology_id)
}
static int msm_audio_get_copp_idx_from_port_id(int port_id, int session_type,
int *copp_idx)
{
int i = 0, idx = 0, be_idx = 0;
int ret = 0;
unsigned long copp = 0;
pr_debug("%s: Enter, port_id=%d\n", __func__, port_id);
ret = q6audio_validate_port(port_id);
if (ret < 0) {
pr_err("%s: port validation failed id 0x%x ret %d\n",
__func__, port_id, ret);
ret = -EINVAL;
goto done;
}
for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) {
if (msm_bedais[be_idx].port_id == port_id)
break;
}
if (be_idx >= MSM_BACKEND_DAI_MAX) {
pr_err("%s: Invalid be id %d\n", __func__, be_idx);
ret = -EINVAL;
goto done;
}
for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions[0],
MSM_FRONTEND_DAI_MAX) {
if (!(is_mm_lsm_fe_id(i) &&
route_check_fe_id_adm_support(i)))
continue;
for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
copp = session_copp_map[i]
[session_type][be_idx];
if (test_bit(idx, &copp))
break;
}
if (idx >= MAX_COPPS_PER_PORT)
continue;
else
break;
}
if (i >= MSM_FRONTEND_DAI_MAX) {
pr_err("%s: Invalid FE, exiting\n", __func__);
ret = -EINVAL;
goto done;
}
*copp_idx = idx;
pr_debug("%s: copp_idx=%d\n", __func__, *copp_idx);
done:
return ret;
}
static int msm_routing_put_copp_dtmf_module_enable
(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
uint8_t *be_id = NULL, be_id_val = 0;
int copp_idx = -1, port_id = 0;
struct param_hdr_v3 param_hdr = {0};
int rc = 0;
u32 flag = (bool)ucontrol->value.integer.value[0];
be_id = (uint8_t *)ucontrol->value.bytes.data;
be_id_val = *be_id;
if((be_id_val < 0) || (be_id_val >= MSM_BACKEND_DAI_MAX)) {
pr_err("%s: received invalid be_id %lu\n", __func__, be_id_val);
return -EINVAL;
}
port_id = msm_bedais[be_id_val].port_id;
rc = msm_audio_get_copp_idx_from_port_id(port_id, SESSION_TYPE_RX,
&copp_idx);
if (rc) {
pr_err(" %s:failure in getting copp_idx\n", __func__);
return rc;
}
memset(&param_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = AUDPROC_MODULE_ID_DTMF_DETECTION;
param_hdr.instance_id = INSTANCE_ID_0;
param_hdr.param_id = AUDPROC_PARAM_ID_ENABLE;
param_hdr.param_size = 4;
rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr,
(u8 *)&flag);
if (rc)
pr_err("%s: Failed to set adm_pack_and_set_one_pp_param, err %d\n",
__func__, rc);
return rc;
}
static const struct snd_kcontrol_new copp_dtmf_detect_enable_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1 COPP DTMF Detect Enable", SND_SOC_NOPM,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, NULL,
msm_routing_put_copp_dtmf_module_enable),
SOC_SINGLE_EXT("MultiMedia6 COPP DTMF Detect Enable", SND_SOC_NOPM,
MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, NULL,
msm_routing_put_copp_dtmf_module_enable),
SOC_SINGLE_EXT("MultiMedia21 COPP DTMF Detect Enable", SND_SOC_NOPM,
MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, NULL,
msm_routing_put_copp_dtmf_module_enable),
};
static int adsp_copp_event_handler(uint32_t opcode,
uint32_t token_adm, uint32_t *payload, void *priv)
{
struct snd_soc_pcm_runtime *rtd = priv;
int ret = 0;
if (!rtd) {
pr_err("%s: rtd is NULL\n", __func__);
return -EINVAL;
}
ret = msm_adsp_copp_inform_mixer_ctl(rtd, payload);
if (ret) {
pr_err("%s: failed to inform mixer ctrl. err = %d\n",
__func__, ret);
return -EINVAL;
}
return ret;
}
static int msm_routing_get_copp_callback_event(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
uint32_t payload_size = 0;
struct dsp_adm_callback_list *oldest_event = NULL;
unsigned long spin_flags = 0;
struct dsp_adm_callback_prtd *kctl_prtd = NULL;
int ret = 0;
kctl_prtd = (struct dsp_adm_callback_prtd *)
kcontrol->private_data;
if (kctl_prtd == NULL) {
pr_err("%s: ADM PP event queue is not initialized.\n",
__func__);
ret = -EINVAL;
goto done;
}
spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags);
pr_debug("%s: %d events in queue.\n", __func__, kctl_prtd->event_count);
if (list_empty(&kctl_prtd->event_queue)) {
pr_err("%s: ADM PP event queue is empty.\n", __func__);
ret = -EINVAL;
spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags);
goto done;
}
oldest_event = list_first_entry(&kctl_prtd->event_queue,
struct dsp_adm_callback_list, list);
list_del(&oldest_event->list);
kctl_prtd->event_count--;
spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags);
payload_size = oldest_event->event.payload_len;
pr_debug("%s: event fetched: type %d length %d\n",
__func__, oldest_event->event.event_type,
oldest_event->event.payload_len);
memcpy(ucontrol->value.bytes.data, &oldest_event->event,
sizeof(struct msm_adsp_event_data) + payload_size);
kfree(oldest_event);
done:
return ret;
}
static int msm_routing_put_copp_callback_event(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s\n", __func__);
return 0;
}
static int msm_copp_callback_event_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
uinfo->count =
sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data);
return 0;
}
static const struct snd_kcontrol_new copp_callback_event_controls[] = {
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "ADSP COPP Callback Event",
.info = msm_copp_callback_event_info,
.get = msm_routing_get_copp_callback_event,
.put = msm_routing_put_copp_callback_event,
},
};
int msm_copp_event_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
uinfo->count =
sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data);
return 0;
}
static int msm_routing_get_copp_event_cmd(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s\n", __func__);
return 0;
}
static int msm_routing_put_copp_event_cmd(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct msm_adm_event_data *ev = NULL;
int be_id = 0, ret = 0, param_size = 0, opcode = 0;
int copp_idx = -1, port_id = 0;
ev = (struct msm_adm_event_data *)ucontrol->value.bytes.data;
param_size = ev->payload_length - sizeof(struct module_info_data);
opcode = adm_pp_reg_event_opcode[(ev->event_type)
- ADSP_ADM_SERVICE_ID];
be_id = ev->mod_info.be_id;
port_id = msm_bedais[be_id].port_id;
pr_debug("%s: port_id= 0x%x, be_id=%d\n", __func__,port_id, be_id);
ret = msm_audio_get_copp_idx_from_port_id(port_id, SESSION_TYPE_RX,
&copp_idx);
if (ret) {
pr_debug("%s:failure in getting copp_idx\n", __func__);
return ret;
}
q6adm_register_callback(&adsp_copp_event_handler);
q6adm_send_event_register_cmd(port_id, copp_idx, (u8 *) (ev->payload),
param_size, opcode);
return ret;
}
static const struct snd_kcontrol_new copp_event_controls[] = {
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "COPP Event Cmd",
.info = msm_copp_event_info,
.get = msm_routing_get_copp_event_cmd,
.put = msm_routing_put_copp_event_cmd,
},
};
static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -33661,6 +33982,7 @@ static void snd_soc_dapm_add_routes_aux_pcm(struct snd_soc_component *component)
/* Not used but frame seems to require it */
static int msm_routing_probe(struct snd_soc_component *component)
{
struct snd_kcontrol *kctl = NULL;
snd_soc_dapm_new_controls(&component->dapm, msm_qdsp6_widgets,
ARRAY_SIZE(msm_qdsp6_widgets));
@@ -33718,10 +34040,27 @@ static int msm_routing_probe(struct snd_soc_component *component)
ARRAY_SIZE(asrc_config_controls));
snd_soc_add_component_controls(component, asrc_start_controls,
ARRAY_SIZE(asrc_start_controls));
snd_soc_add_component_controls(component,
copp_dtmf_detect_enable_mixer_controls,
ARRAY_SIZE(copp_dtmf_detect_enable_mixer_controls));
#ifdef CONFIG_MSM_INTERNAL_MCLK
snd_soc_add_component_controls(component, internal_mclk_control,
ARRAY_SIZE(internal_mclk_control));
#endif
snd_soc_add_component_controls(component, copp_callback_event_controls,
ARRAY_SIZE(copp_callback_event_controls));
snd_soc_add_component_controls(component, copp_event_controls,
ARRAY_SIZE(copp_event_controls));
kctl = snd_soc_card_get_kcontrol(component->dapm.card,
"ADSP COPP Callback Event");
if (!kctl) {
pr_err("%s: failed to get kctl %s.\n", __func__,
"ADSP COPP Callback Event");
return -EINVAL;
}
kctl->private_data = NULL;
return 0;
}

50
asoc/msm-pcm-routing-v2.c Executable file → Normal file
View File

@@ -2458,6 +2458,56 @@ int msm_pcm_routing_set_channel_mixer_runtime(int be_id, int session_id,
}
EXPORT_SYMBOL(msm_pcm_routing_set_channel_mixer_runtime);
/*
* msm_pcm_routing_get_portid_copp_idx:
* update the port_id and copp_idx for a given
* fe_id
*
* @fe_id: front end id
* @session_type: indicates session is of type TX or RX
* port: port_id to be updated as output
* copp_idx: copp_idx is updated as output
* @stream_type: indicates either Audio or Listen stream type
*/
bool msm_pcm_routing_get_portid_copp_idx(int fe_id,
int session_type, int *port, int *copp_idx)
{
int idx = 0;
bool found = false;
int be_index = 0, port_id = 0;
pr_debug("%s:fe_id[%d] sess_type [%d]\n",
__func__, fe_id, session_type);
if (!is_mm_lsm_fe_id(fe_id)) {
/* bad ID assigned in machine driver */
pr_err("%s: bad MM ID %d\n", __func__, fe_id);
return -EINVAL;
}
for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) {
port_id = msm_bedais[be_index].port_id;
if (!msm_bedais[be_index].active ||
!test_bit(fe_id, &msm_bedais[be_index].fe_sessions[0]))
continue;
for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
unsigned long copp_id =
session_copp_map[fe_id][session_type][be_index];
if (test_bit(idx, &copp_id)) {
pr_debug("%s: port_id: %d, copp_idx:%d\n",
__func__, port_id, idx);
*port = port_id;
*copp_idx = idx;
found = true;
break;
}
}
}
return found;
}
EXPORT_SYMBOL(msm_pcm_routing_get_portid_copp_idx);
int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
int dspst_id, int stream_type)
{

View File

@@ -897,4 +897,7 @@ int snd_pcm_add_usr_ctls(struct snd_pcm *pcm, int stream,
unsigned long private_value,
struct snd_pcm_usr **info_ret);
#endif
bool msm_pcm_routing_get_portid_copp_idx(int fe_id,
int session_type, int *port_id, int *copp_idx);
#endif /*_MSM_PCM_H*/

View File

@@ -1207,6 +1207,217 @@ done:
return ret;
}
int msm_adsp_init_mixer_ctl_adm_pp_event_queue(struct snd_soc_pcm_runtime *rtd)
{
struct snd_kcontrol *kctl = NULL;
char *mixer_str = NULL;
int ctl_len = 0, ret = 0;
const char *mixer_ctl_name = DSP_ADM_CALLBACK;
struct dsp_adm_callback_prtd *kctl_prtd = NULL;
if (!rtd) {
pr_err("%s: rtd is NULL\n", __func__);
ret = -EINVAL;
goto done;
}
ctl_len = strlen(mixer_ctl_name) + 1;
mixer_str = kzalloc(ctl_len, GFP_KERNEL);
if (!mixer_str) {
ret = -EINVAL;
goto done;
}
snprintf(mixer_str, ctl_len, "%s", mixer_ctl_name);
kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
kfree(mixer_str);
if (!kctl) {
pr_err("%s: failed to get kctl.\n", __func__);
ret = -EINVAL;
goto done;
}
if (kctl->private_data != NULL) {
pr_err("%s: kctl_prtd is not NULL at initialization.\n",
__func__);
return -EINVAL;
}
kctl_prtd = kzalloc(sizeof(struct dsp_adm_callback_prtd),
GFP_KERNEL);
if (!kctl_prtd) {
ret = -ENOMEM;
goto done;
}
spin_lock_init(&kctl_prtd->prtd_spin_lock);
INIT_LIST_HEAD(&kctl_prtd->event_queue);
kctl_prtd->event_count = 0;
kctl->private_data = kctl_prtd;
done:
return ret;
}
int msm_adsp_clean_mixer_ctl_adm_pp_event_queue(struct snd_soc_pcm_runtime *rtd)
{
struct snd_kcontrol *kctl = NULL;
char *mixer_str = NULL;
int ctl_len = 0, ret = 0;
struct dsp_adm_callback_list *node = NULL, *n = NULL;
unsigned long spin_flags = 0;
const char *mixer_ctl_name = DSP_ADM_CALLBACK;
struct dsp_adm_callback_prtd *kctl_prtd = NULL;
if (!rtd) {
pr_err("%s: rtd is NULL\n", __func__);
ret = -EINVAL;
goto done;
}
ctl_len = strlen(mixer_ctl_name) + 1;
mixer_str = kzalloc(ctl_len, GFP_KERNEL);
if (!mixer_str) {
ret = -EINVAL;
goto done;
}
snprintf(mixer_str, ctl_len, "%s", mixer_ctl_name);
kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
kfree(mixer_str);
if (!kctl) {
pr_err("%s: failed to get kctl.\n", __func__);
ret = -EINVAL;
goto done;
}
kctl_prtd = (struct dsp_adm_callback_prtd *)
kctl->private_data;
if (kctl_prtd != NULL) {
spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags);
/* clean the queue */
list_for_each_entry_safe(node, n,
&kctl_prtd->event_queue, list) {
list_del(&node->list);
kctl_prtd->event_count--;
pr_debug("%s: %d remaining events after del.\n",
__func__, kctl_prtd->event_count);
kfree(node);
}
spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags);
}
kfree(kctl_prtd);
kctl->private_data = NULL;
done:
return ret;
}
int msm_adsp_copp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
uint32_t *payload)
{
/* adsp adm pp event notifier */
struct snd_kcontrol *kctl = NULL;
struct snd_ctl_elem_value control = {0};
char *mixer_str = NULL;
int ctl_len = 0, ret = 0;
struct dsp_adm_callback_list *new_event = NULL;
struct dsp_adm_callback_list *oldest_event = NULL;
unsigned long spin_flags = 0;
struct dsp_adm_callback_prtd *kctl_prtd = NULL;
struct msm_adsp_event_data *event_data = NULL;
const char *mixer_ctl_name = DSP_ADM_CALLBACK;
struct snd_ctl_elem_info kctl_info = {0};
if (!rtd || !payload) {
pr_err("%s: %s is NULL\n", __func__,
(!rtd) ? "rtd" : "payload");
ret = -EINVAL;
goto done;
}
if (rtd->card->snd_card == NULL) {
pr_err("%s: snd_card is null.\n", __func__);
ret = -EINVAL;
goto done;
}
ctl_len = strlen(mixer_ctl_name) + 1;
mixer_str = kzalloc(ctl_len, GFP_ATOMIC);
if (!mixer_str) {
ret = -EINVAL;
goto done;
}
snprintf(mixer_str, ctl_len, "%s", mixer_ctl_name);
kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
kfree(mixer_str);
if (!kctl) {
pr_err("%s: failed to get kctl.\n", __func__);
ret = -EINVAL;
goto done;
}
event_data = (struct msm_adsp_event_data *)payload;
kctl->info(kctl, &kctl_info);
if (sizeof(struct msm_adsp_event_data)
+ event_data->payload_len > kctl_info.count) {
pr_err("%s: payload length exceeds limit of %u bytes.\n",
__func__, kctl_info.count);
ret = -EINVAL;
goto done;
}
kctl_prtd = (struct dsp_adm_callback_prtd *)
kctl->private_data;
if (kctl_prtd == NULL) {
/* queue is not initialized */
ret = -EINVAL;
pr_err("%s: event queue is not initialized.\n", __func__);
goto done;
}
new_event = kzalloc(sizeof(struct dsp_adm_callback_list)
+ event_data->payload_len + sizeof(uint32_t),
GFP_ATOMIC);
if (new_event == NULL) {
ret = -ENOMEM;
goto done;
}
memcpy((void *)&new_event->event, (void *)payload,
event_data->payload_len
+ sizeof(struct msm_adsp_event_data));
spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags);
while (kctl_prtd->event_count >= DSP_ADM_CALLBACK_QUEUE_SIZE) {
pr_info("%s: queue of size %d is full. delete oldest one.\n",
__func__, DSP_ADM_CALLBACK_QUEUE_SIZE);
oldest_event = list_first_entry(&kctl_prtd->event_queue,
struct dsp_adm_callback_list, list);
pr_info("%s: event deleted: type %d length %d\n",
__func__, oldest_event->event.event_type,
oldest_event->event.payload_len);
list_del(&oldest_event->list);
kctl_prtd->event_count--;
kfree(oldest_event);
}
list_add_tail(&new_event->list, &kctl_prtd->event_queue);
kctl_prtd->event_count++;
spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags);
control.id = kctl->id;
snd_ctl_notify(rtd->card->snd_card,
SNDRV_CTL_EVENT_MASK_INFO,
&control.id);
done:
return ret;
}
int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
uint32_t *payload)
{

View File

@@ -9,6 +9,14 @@
#include <sound/soc.h>
#define DSP_BIT_WIDTH_MIXER_CTL "ASM Bit Width"
#ifdef CONFIG_QTI_PP
int msm_adsp_adm_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
uint32_t *payload);
int msm_adsp_init_mixer_ctl_adm_pp_event_queue(struct snd_soc_pcm_runtime *rtd);
int msm_adsp_clean_mixer_ctl_adm_pp_event_queue(
struct snd_soc_pcm_runtime *rtd);
int msm_adsp_copp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
uint32_t *payload);
int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
uint32_t *payload);
int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd);

View File

@@ -52,6 +52,9 @@ enum adm_cal_status {
ADM_STATUS_MAX,
};
typedef int (*adm_cb)(uint32_t opcode, uint32_t token,
uint32_t *pp_event_package, void *pvt);
struct adm_copp {
atomic_t id[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
@@ -71,6 +74,8 @@ struct adm_copp {
uint32_t adm_delay[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
unsigned long adm_status[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
atomic_t token[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
adm_cb cb;
void *priv[AFE_MAX_PORTS][MAX_COPPS_PER_PORT][MAX_FE_ID];
};
struct source_tracking_data {
@@ -163,6 +168,93 @@ static int adm_arrange_mch_map_v8(
int channel_mode,
int port_idx);
static uint32_t adm_pp_raise_event_opcode[] = {
ADM_PP_EVENT };
int q6adm_send_event_register_cmd(int port_id, int copp_idx, u8 *data,
int param_size, int opcode)
{
struct adm_register_event *adm_reg_params = NULL;
int ret = 0, port_idx = 0, sz = 0;
port_id = afe_convert_virtual_to_portid(port_id);
port_idx = adm_validate_and_get_port_index(port_id);
if (port_idx < 0) {
pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
return -EINVAL;
}
sz = sizeof(struct apr_hdr) + param_size;
adm_reg_params = kzalloc(sz, GFP_KERNEL);
if (!adm_reg_params)
return -ENOMEM;
memcpy(adm_reg_params->payload, data, param_size);
adm_reg_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
adm_reg_params->hdr.src_svc = APR_SVC_ADM;
adm_reg_params->hdr.src_domain = APR_DOMAIN_APPS;
adm_reg_params->hdr.src_port = port_id;
adm_reg_params->hdr.dest_svc = APR_SVC_ADM;
adm_reg_params->hdr.dest_domain = APR_DOMAIN_ADSP;
adm_reg_params->hdr.dest_port =
atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
adm_reg_params->hdr.token = port_idx << 16 | copp_idx;
adm_reg_params->hdr.opcode = opcode;
adm_reg_params->hdr.pkt_size = sz;
atomic_set(&this_adm.copp.stat[port_idx][copp_idx], 0);
ret = apr_send_pkt(this_adm.apr, (uint32_t *)adm_reg_params);
if (ret < 0) {
pr_err("%s: Set adm register params failed port %d rc %d\n",
__func__, port_id, ret);
ret = -EINVAL;
goto fail_cmd;
}
ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
atomic_read(
&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: set params timed out port = %d\n",
__func__, port_id);
ret = -ETIMEDOUT;
goto fail_cmd;
}
ret = 0;
fail_cmd:
kfree(adm_reg_params);
return ret;
}
EXPORT_SYMBOL(q6adm_send_event_register_cmd);
static int is_adsp_adm_raise_event(uint32_t cmd)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(adm_pp_raise_event_opcode); i++) {
if (cmd == adm_pp_raise_event_opcode[i])
return i;
}
return -EINVAL;
}
void q6adm_register_callback(void *cb)
{
this_adm.copp.cb = cb;
}
EXPORT_SYMBOL(q6adm_register_callback);
void q6adm_clear_callback(void)
{
this_adm.copp.cb = NULL;
}
EXPORT_SYMBOL(q6adm_clear_callback);
/**
* adm_validate_and_get_port_index -
* validate given port id
@@ -1578,6 +1670,9 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
int port_idx, copp_idx, idx, client_id;
int num_modules;
int ret;
int payload_size = 0, i = 0;
struct msm_adsp_event_data *pp_event_package = NULL;
struct adm_usr_info usr_data = {0};
if (data == NULL) {
pr_err("%s: data parameter is null\n", __func__);
@@ -1749,6 +1844,13 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
pr_err("%s: ADM get topo list error = %d\n",
__func__, payload[1]);
break;
case ADM_CMD_REGISTER_EVENT:
pr_debug("%s:ADM_CMD_REGISTER_EVENT\n",
__func__);
if (payload[1] != 0)
pr_err("%s: ADM_CMD_REGISTER_EVENT error = %d\n",
__func__, payload[1]);
break;
default:
pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
payload[0]);
@@ -1859,6 +1961,63 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
atomic_set(&this_adm.adm_stat, 0);
wake_up(&this_adm.adm_wait);
break;
case ADM_PP_EVENT:
if (data->payload_size < (2 * sizeof(uint32_t))) {
pr_err("%s: payload has invalid size %d\n",
__func__, data->payload_size);
return -EINVAL;
}
pr_debug("%s: ADM_PP_EVENT payload[0][0x%x] payload[1][0x%x]\n",
__func__, payload[0], payload[1]);
ret = is_adsp_adm_raise_event(data->opcode);
if (ret < 0)
return 0;
/*
* repack payload for adm_copp_pp_event
* package is composed of event type + size + payload
*/
payload_size = data->payload_size;
pp_event_package = kzalloc(payload_size
+ sizeof(struct msm_adsp_event_data)
, GFP_ATOMIC);
if (!pp_event_package)
return -ENOMEM;
pp_event_package->event_type = ret
+ ADSP_ADM_SERVICE_ID;
usr_data.service_id = ADSP_ADM_SERVICE_ID;
usr_data.token_coppidx = data->token;
pp_event_package->payload_len = data->payload_size +
sizeof(struct adm_usr_info);
memcpy((void *)pp_event_package->payload, &(usr_data),
sizeof(struct adm_usr_info));
memcpy((void *)pp_event_package->payload +
sizeof(struct adm_usr_info),
data->payload, data->payload_size);
if (this_adm.copp.cb) {
for (i = 0; i < MAX_FE_ID; i++) {
if (this_adm.copp.priv[port_idx]
[copp_idx][i]) {
pr_debug("%s: calling adm callback for feid %d port_idx %d copp_idx %d\n",
__func__, i, port_idx, copp_idx);
this_adm.copp.cb(data->opcode,
data->token,
(void *)pp_event_package,
this_adm.copp.priv[port_idx]
[copp_idx][i]);
}
}
}
kfree(pp_event_package);
break;
default:
pr_err("%s: Unknown cmd:0x%x\n", __func__,
data->opcode);
@@ -3006,6 +3165,33 @@ static int adm_arrange_mch_ep2_map_v8(
return rc;
}
int q6adm_update_rtd_info(void *rtd, int port_id,
int copp_idx, int fe_id, int enable)
{
int port_idx = 0;
port_id = q6audio_convert_virtual_to_portid(port_id);
port_idx = adm_validate_and_get_port_index(port_id);
if (port_idx < 0) {
pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
return -EINVAL;
}
pr_debug("%s: port_id %#x copp_idx %d fe_id %d enable %d\n",
__func__, port_id, copp_idx, fe_id, enable);
if (enable) {
this_adm.copp.priv[port_idx][copp_idx][fe_id] = rtd;
}
else {
this_adm.copp.priv[port_idx][copp_idx][fe_id] = NULL;
}
return 0;
}
EXPORT_SYMBOL(q6adm_update_rtd_info);
static int adm_copp_set_ec_ref_mfc_cfg_v2(int port_id, int copp_idx,
int sample_rate, int bps,
struct msm_pcm_channel_mixer *cfg)

29
include/dsp/apr_audio-v2.h Executable file → Normal file
View File

@@ -30,6 +30,11 @@ struct param_outband {
/* Instance ID definitions */
#define INSTANCE_ID_0 0x0000
struct adm_register_event {
struct apr_hdr hdr;
__u8 payload[0];
} __packed;
struct mem_mapping_hdr {
/*
* LSW of parameter data payload address. Supported values: any.
@@ -135,6 +140,10 @@ struct module_instance_info {
#define ADM_CMD_MATRIX_MAP_ROUTINGS_V5 0x00010325
#define ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5 0x0001033D
#define ADM_CMD_REGISTER_EVENT 0x00010365
#define ADM_PP_EVENT 0x00010366
/* Enumeration for an audio Rx matrix ID.*/
#define ADM_MATRIX_ID_AUDIO_RX 0
@@ -671,6 +680,26 @@ struct dsp_stream_callback_prtd {
spinlock_t prtd_spin_lock;
};
#define DSP_ADM_CALLBACK "ADSP COPP Callback Event"
#define DSP_ADM_CALLBACK_QUEUE_SIZE 1024
struct dsp_adm_callback_list {
struct list_head list;
struct msm_adsp_event_data event;
};
struct adm_usr_info {
u32 service_id;
u32 reserved;
u32 token_coppidx;
};
struct dsp_adm_callback_prtd {
uint16_t event_count;
struct list_head event_queue;
spinlock_t prtd_spin_lock;
};
/* set customized mixing on matrix mixer */
#define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344
struct adm_cmd_set_pspd_mtmx_strtr_params_v5 {

View File

@@ -16,6 +16,7 @@
#include <dsp/q6audio-v2.h>
#define MAX_MODULES_IN_TOPO 16
#define MAX_FE_ID 33
#define ADM_GET_TOPO_MODULE_LIST_LENGTH\
((MAX_MODULES_IN_TOPO + 1) * sizeof(uint32_t))
#define ADM_GET_TOPO_MODULE_INSTANCE_LIST_LENGTH \
@@ -246,4 +247,10 @@ void adm_set_native_mode(int mode);
int adm_set_ffecns_freeze_event(bool ffecns_freeze_event);
int adm_apr_send_pkt(void *data, wait_queue_head_t *wait,
int port_idx, int copp_idx, int opcode);
void q6adm_register_callback(void *cb);
void q6adm_clear_callback(void);
int q6adm_send_event_register_cmd(int port_id, int copp_idx, u8 *data,
int param_size, int opcode);
int q6adm_update_rtd_info(void *rtd, int port_id,
int copp_idx, int fe_id, int enable);
#endif /* __Q6_ADM_V2_H__ */

View File

@@ -456,6 +456,7 @@ struct msm_hwacc_effects_config {
#define ADSP_STREAM_ENCDEC_EVENT 1
#define ADSP_STREAM_IEC_61937_FMT_UPDATE_EVENT 2
#define ADSP_STREAM_EVENT_MAX 3
#define ADSP_ADM_SERVICE_ID 3
struct msm_adsp_event_data {
__u32 event_type;
@@ -463,4 +464,17 @@ struct msm_adsp_event_data {
__u8 payload[0];
};
struct module_info_data {
__u32 module_id;
__u32 instance_id;
__u32 be_id;
__u32 fe_id;
};
struct msm_adm_event_data {
__u32 event_type;
__u32 payload_length;
struct module_info_data mod_info;
__u8 payload[0];
};
#endif