ASoC: msm: Move ADM management out of QDSP6 CPU driver
Audio hardware path can be started not only for audio playback/capture
but also voice call. ADM COPP is created through Q6ADM driver
when AFE port is started. For voice call use case, creating
ADM COPP in DSP wastes unnecessary memory resource. To create
ADM COPP only for audio playback/capture case, management logic
is moved to pcm routing driver which has information about session
ID of MultiMedia streams and state of audio back-ends. With this
information, pcm routing driver decides to start/stop ADM COPP.
Signed-off-by: Patrick Lai <plai@codeaurora.org>
diff --git a/include/sound/q6adm.h b/include/sound/q6adm.h
index ef6eb9e..80374c5 100644
--- a/include/sound/q6adm.h
+++ b/include/sound/q6adm.h
@@ -24,11 +24,6 @@
unsigned int session_id;
};
-int adm_open_mixer(int port_id, int path, int rate, int channel_mode,
- int topology);
-
-int adm_route_session(int port_id, uint session_id, int set);
-
int adm_open(int port, int path, int rate, int mode, int topology);
int adm_memory_map_regions(uint32_t *buf_add, uint32_t mempool_id,
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index c69600f..5e02797 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -342,13 +342,6 @@
struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
int rc = 0;
- rc = adm_close(dai->id);
-
- if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to close ADM COPP\n");
-
- pr_debug("%s: dai->id = %d", __func__, dai->id);
-
if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
rc = afe_close(dai->id); /* can block */
if (IS_ERR_VALUE(rc))
@@ -369,27 +362,14 @@
(struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
- rc = adm_open_mixer(dai->id, 1, dai_data->rate,
- dai_data->channels, DEFAULT_COPP_TOPOLOGY);
-
+ rc = afe_q6_interface_prepare();
if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to open ADM\n");
- else {
- rc = afe_q6_interface_prepare();
- if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to open AFE APR\n");
- }
+ dev_err(dai->dev, "fail to open AFE APR\n");
- rc = adm_open_mixer(PCM_TX, 2, dai_data->rate,
- dai_data->channels, DEFAULT_COPP_TOPOLOGY);
-
+ rc = afe_q6_interface_prepare();
if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to open ADM\n");
- else {
- rc = afe_q6_interface_prepare();
- if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to open AFE APR\n");
- }
+ dev_err(dai->dev, "fail to open AFE APR\n");
+
pr_debug("%s:dai->id:%d dai_data->status_mask = %ld\n",
__func__, dai->id, *dai_data->status_mask);
@@ -434,21 +414,10 @@
int rc = 0;
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- rc = adm_open_mixer(dai->id, 1, dai_data->rate,
- dai_data->channels, DEFAULT_COPP_TOPOLOGY);
- else
- rc = adm_open_mixer(dai->id, 2, dai_data->rate,
- dai_data->channels, DEFAULT_COPP_TOPOLOGY);
+ /* PORT START should be set if prepare called in active state */
+ rc = afe_q6_interface_prepare();
if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to open ADM\n");
- else {
- rc = afe_q6_interface_prepare();
- if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to open AFE APR\n");
- }
- pr_debug("%s:dai->id:%d dai_data->status_mask = %ld\n",
- __func__, dai->id, *dai_data->status_mask);
+ dev_err(dai->dev, "fail to open AFE APR\n");
}
return rc;
}
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index f136646..3eb9a42 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -30,12 +30,6 @@
#include "msm-pcm-routing.h"
#include "qdsp6/q6voice.h"
-struct audio_mixer_data {
- u32 port_id; /* AFE port ID for Rx, FE DAI ID for TX */
- unsigned long dai_sessions; /* Rx: FE DAIs Tx: BE DAI */
- u32 mixer_type; /* playback or capture */
-};
-
struct msm_pcm_routing_bdai_data {
u16 port_id; /* AFE port ID */
u8 active; /* track if this backend is enabled */
@@ -45,27 +39,11 @@
};
#define INVALID_SESSION -1
+#define SESSION_TYPE_RX 0
+#define SESSION_TYPE_TX 1
static struct mutex routing_lock;
-enum {
- AUDIO_MIXER_PRI_I2S_RX = 0,
- AUDIO_MIXER_SLIMBUS_0_RX,
- AUDIO_MIXER_HDMI_RX,
- AUDIO_MIXER_MM_UL1,
- AUDIO_MIXER_MM_UL2,
- AUDIO_MIXER_INT_BT_SCO_RX,
- AUDIO_MIXER_INT_FM_RX,
- AUDIO_MIXER_AFE_PCM_RX,
- AUDIO_MIXER_AUX_PCM_RX,
- AUDIO_MIXER_MAX,
-};
-
-enum {
- AUDIO_PORT_MIXER_SLIM_0_RX = 0,
- AUDIO_PORT_MIXER_MAX,
-};
-
static int fm_switch_enable;
#define INT_FM_RX_VOL_MAX_STEPS 100
#define INT_FM_RX_VOL_GAIN 2000
@@ -81,27 +59,6 @@
static const DECLARE_TLV_DB_SCALE(lpa_rx_vol_gain, 0,
INT_LPA_RX_VOL_MAX_STEPS, 0);
-/* Tx mixer session is stored based on BE DAI ID
- * Need to map to actual AFE port ID since AFE port
- * ID can get really large.
- * The table convert DAI back to AFE port ID
- */
-static int bedai_port_map[MSM_BACKEND_DAI_MAX] = {
- PRIMARY_I2S_RX,
- PRIMARY_I2S_TX,
- SLIMBUS_0_RX,
- SLIMBUS_0_TX,
- HDMI_RX,
- INT_BT_SCO_RX,
- INT_BT_SCO_TX,
- INT_FM_RX,
- INT_FM_TX,
- RT_PROXY_PORT_001_RX,
- RT_PROXY_PORT_001_TX,
- PCM_RX,
- PCM_TX,
-};
-
/* This array is indexed by back-end DAI ID defined in msm-pcm-routing.h
* If new back-end is defined, add new back-end DAI ID at the end of enum
*/
@@ -132,121 +89,136 @@
{INVALID_SESSION, INVALID_SESSION},
};
-static struct audio_mixer_data audio_mixers[AUDIO_MIXER_MAX] = {
- /* AUDIO_MIXER_PRI_I2S_RX */
- {PRIMARY_I2S_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
- /* AUDIO_MIXER_SLIMBUS_0_RX */
- {SLIMBUS_0_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
- /* AUDIO_MIXER_HDMI_RX */
- {HDMI_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
- /* AUDIO_MIXER_MM_UL1 */
- {MSM_FRONTEND_DAI_MULTIMEDIA1, 0, SNDRV_PCM_STREAM_CAPTURE},
- /* AUDIO_MIXER_MM_UL2 */
- {MSM_FRONTEND_DAI_MULTIMEDIA2, 0, SNDRV_PCM_STREAM_CAPTURE},
- /* AUDIO_MIXER_INT_BT_SCO_RX */
- {INT_BT_SCO_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
- /* AUDIO_MIXER_INT_FM_RX */
- {INT_FM_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
- /* AUDIO_MIXER_AFE_PCM_RX */
- {RT_PROXY_PORT_001_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
- /* AUDIO_MIXER_AUX_PCM_RX */
- {PCM_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
-};
+static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
+ int path_type)
+{
+ int i, port_type;
+ struct route_payload payload;
-/* Reuse audio_mixer_data struct but ignore mixer type field
- * unless there is use case for RX -> TX
- */
-static struct audio_mixer_data audio_port_mixers[AUDIO_PORT_MIXER_MAX] = {
- /* AUDIO_PORT_MIXER_SLIM_0_RX */
- {SLIMBUS_0_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
-};
+ payload.num_copps = 0;
+ port_type = (path_type == ADM_PATH_PLAYBACK ?
+ MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
+
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if ((afe_get_port_type(msm_bedais[i].port_id) ==
+ port_type) &&
+ msm_bedais[i].active && (test_bit(fedai_id,
+ &msm_bedais[i].fe_sessions)))
+ payload.copp_ids[payload.num_copps++] =
+ msm_bedais[i].port_id;
+ }
+
+ if (payload.num_copps)
+ adm_matrix_map(dspst_id, path_type,
+ payload.num_copps, payload.copp_ids, 0);
+}
void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id, int stream_type)
{
- int i, be_id;
+ int i, session_type, path_type, port_type;
+ struct route_payload payload;
if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
- fe_dai_map[fedai_id][0] = dspst_id;
- for (i = 0; i < AUDIO_MIXER_MAX; i++) {
- if ((audio_mixers[i].mixer_type == stream_type) &&
- (test_bit(fedai_id, &audio_mixers[i].dai_sessions)))
- /* To do: multiple devices case */
- adm_route_session(audio_mixers[i].port_id,
- dspst_id, 1);
- }
+ session_type = SESSION_TYPE_RX;
+ path_type = ADM_PATH_PLAYBACK;
+ port_type = MSM_AFE_PORT_TYPE_RX;
} else {
- fe_dai_map[fedai_id][1] = dspst_id;
- for (i = 0; i < AUDIO_MIXER_MAX; i++) {
- if ((audio_mixers[i].mixer_type == stream_type) &&
- (fedai_id == audio_mixers[i].port_id)) {
- /* To-do: Handle mixing of inputs */
- be_id = find_next_bit(
- &audio_mixers[i].dai_sessions,
- MSM_BACKEND_DAI_MAX, 0);
- if (be_id < MSM_BACKEND_DAI_MAX)
- adm_route_session(bedai_port_map[be_id],
- dspst_id, 1);
- else
- pr_err("%s: no routing\n", __func__);
- }
+ session_type = SESSION_TYPE_TX;
+ path_type = ADM_PATH_LIVE_REC;
+ port_type = MSM_AFE_PORT_TYPE_TX;
+ }
+
+ mutex_lock(&routing_lock);
+
+ payload.num_copps = 0; /* only RX needs to use payload */
+ fe_dai_map[fedai_id][session_type] = dspst_id;
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if ((afe_get_port_type(msm_bedais[i].port_id) ==
+ port_type) && msm_bedais[i].active &&
+ (test_bit(fedai_id,
+ &msm_bedais[i].fe_sessions))) {
+ adm_open(msm_bedais[i].port_id,
+ path_type,
+ params_rate(msm_bedais[i].hw_params),
+ params_channels(msm_bedais[i].hw_params),
+ DEFAULT_COPP_TOPOLOGY);
+ payload.copp_ids[payload.num_copps++] =
+ msm_bedais[i].port_id;
}
}
+ if (payload.num_copps)
+ adm_matrix_map(dspst_id, path_type,
+ payload.num_copps, payload.copp_ids, 0);
+
+ mutex_unlock(&routing_lock);
}
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
{
- int i, be_id;
+ int i, port_type, session_type;
if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
- for (i = 0; i < AUDIO_MIXER_MAX; i++) {
- if ((audio_mixers[i].mixer_type == stream_type) &&
- (test_bit(fedai_id, &audio_mixers[i].dai_sessions))) {
- /* To do: multiple devices case */
- adm_route_session(audio_mixers[i].port_id,
- fe_dai_map[fedai_id][0], 0);
- }
- }
- fe_dai_map[fedai_id][0] = INVALID_SESSION;
+ port_type = MSM_AFE_PORT_TYPE_RX;
+ session_type = SESSION_TYPE_RX;
} else {
- for (i = 0; i < AUDIO_MIXER_MAX; i++) {
- if ((audio_mixers[i].mixer_type == stream_type) &&
- (fedai_id == audio_mixers[i].port_id)) {
- /* To-do: Handle mixing of inputs */
- be_id = find_next_bit(
- &audio_mixers[i].dai_sessions,
- MSM_BACKEND_DAI_MAX, 0);
- if (be_id < MSM_BACKEND_DAI_MAX)
- adm_route_session(bedai_port_map[be_id],
- fe_dai_map[fedai_id][1], 0);
- else
- pr_err("%s: no routing\n", __func__);
- }
- }
- fe_dai_map[fedai_id][1] = INVALID_SESSION;
+ port_type = MSM_AFE_PORT_TYPE_TX;
+ session_type = SESSION_TYPE_TX;
}
+
+ mutex_lock(&routing_lock);
+
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if ((afe_get_port_type(msm_bedais[i].port_id) ==
+ port_type) && msm_bedais[i].active &&
+ (test_bit(fedai_id,
+ &msm_bedais[i].fe_sessions)))
+ adm_close(msm_bedais[i].port_id);
+ }
+
+ fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
+
+ mutex_unlock(&routing_lock);
}
static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
{
+ int session_type, path_type;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
- if (set)
- set_bit(val, &audio_mixers[reg].dai_sessions);
- else
- clear_bit(val, &audio_mixers[reg].dai_sessions);
-
-
- if (audio_mixers[reg].mixer_type == SNDRV_PCM_STREAM_PLAYBACK) {
- if (fe_dai_map[val][0] != INVALID_SESSION)
- adm_route_session(audio_mixers[reg].port_id,
- fe_dai_map[val][0], set);
+ if (afe_get_port_type(msm_bedais[reg].port_id) ==
+ MSM_AFE_PORT_TYPE_RX) {
+ session_type = SESSION_TYPE_RX;
+ path_type = ADM_PATH_PLAYBACK;
} else {
- int fe_id = audio_mixers[reg].port_id;
- if (fe_dai_map[fe_id][1] != INVALID_SESSION)
- adm_route_session(bedai_port_map[val],
- fe_dai_map[fe_id][1], set);
+ session_type = SESSION_TYPE_TX;
+ path_type = ADM_PATH_LIVE_REC;
}
+
+ mutex_lock(&routing_lock);
+
+ if (set) {
+ set_bit(val, &msm_bedais[reg].fe_sessions);
+ if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ INVALID_SESSION) {
+ adm_open(msm_bedais[reg].port_id, path_type,
+ params_rate(msm_bedais[reg].hw_params),
+ params_channels(msm_bedais[reg].hw_params),
+ DEFAULT_COPP_TOPOLOGY);
+ msm_pcm_routing_build_matrix(val,
+ fe_dai_map[val][session_type], path_type);
+ }
+ } else {
+ clear_bit(val, &msm_bedais[reg].fe_sessions);
+ if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ INVALID_SESSION) {
+ adm_close(msm_bedais[reg].port_id);
+ msm_pcm_routing_build_matrix(val,
+ fe_dai_map[val][session_type], path_type);
+ }
+ }
+
+ mutex_unlock(&routing_lock);
}
static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
@@ -255,7 +227,7 @@
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- if (test_bit(mc->shift, &audio_mixers[mc->reg].dai_sessions))
+ if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
ucontrol->value.integer.value[0] = 1;
else
ucontrol->value.integer.value[0] = 0;
@@ -327,7 +299,6 @@
if (set) {
voc_set_rxtx_port(session_id,
msm_bedais[reg].port_id, DEV_TX);
-
if (voc_get_route_flag(session_id, RX_PATH) &&
voc_get_route_flag(session_id, TX_PATH))
voc_enable_cvp(session_id);
@@ -407,7 +378,7 @@
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- if (test_bit(mc->shift, &audio_port_mixers[mc->reg].dai_sessions))
+ if (test_bit(mc->shift, &msm_bedais[mc->reg].port_sessions))
ucontrol->value.integer.value[0] = 1;
else
ucontrol->value.integer.value[0] = 0;
@@ -428,15 +399,15 @@
mc->shift, ucontrol->value.integer.value[0]);
if (ucontrol->value.integer.value[0]) {
- afe_loopback(1, audio_port_mixers[mc->reg].port_id,
- bedai_port_map[mc->shift]);
+ afe_loopback(1, msm_bedais[mc->reg].port_id,
+ msm_bedais[mc->shift].port_id);
set_bit(mc->shift,
- &audio_port_mixers[mc->reg].dai_sessions);
+ &msm_bedais[mc->reg].port_sessions);
} else {
- afe_loopback(0, audio_port_mixers[mc->reg].port_id,
- bedai_port_map[mc->shift]);
+ afe_loopback(0, msm_bedais[mc->reg].port_id,
+ msm_bedais[mc->shift].port_id);
clear_bit(mc->shift,
- &audio_port_mixers[mc->reg].dai_sessions);
+ &msm_bedais[mc->reg].port_sessions);
}
return 1;
@@ -477,113 +448,113 @@
}
static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_PRI_I2S_RX ,
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_PRI_I2S_RX,
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_PRI_I2S_RX,
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_SLIMBUS_0_RX ,
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_SLIMBUS_0_RX,
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_SLIMBUS_0_RX,
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_HDMI_RX,
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_HDMI_RX,
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_HDMI_RX,
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_INT_BT_SCO_RX,
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_INT_BT_SCO_RX,
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_INT_BT_SCO_RX,
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_INT_FM_RX,
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_INT_FM_RX,
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_INT_FM_RX,
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_AFE_PCM_RX,
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_AFE_PCM_RX,
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_AFE_PCM_RX,
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_AUX_PCM_RX ,
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_AUX_PCM_RX,
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_AUX_PCM_RX,
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_TX", AUDIO_MIXER_MM_UL1,
- MSM_BACKEND_DAI_PRI_I2S_TX, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("SLIM_0_TX", AUDIO_MIXER_MM_UL1,
- MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("AUX_PCM_UL_TX", AUDIO_MIXER_MM_UL1,
- MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", AUDIO_MIXER_MM_UL1,
- MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("INTERNAL_FM_TX", AUDIO_MIXER_MM_UL1,
- MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("AFE_PCM_TX", AUDIO_MIXER_MM_UL1,
- MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul2_mixer_controls[] = {
- SOC_SINGLE_EXT("INTERNAL_FM_TX", AUDIO_MIXER_MM_UL2,
- MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_audio_mixer,
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
@@ -669,10 +640,10 @@
};
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
- SOC_SINGLE_EXT("INTERNAL_FM_TX", AUDIO_PORT_MIXER_SLIM_0_RX,
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
- SOC_SINGLE_EXT("SLIM_0_TX", AUDIO_PORT_MIXER_SLIM_0_RX,
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
};
@@ -881,7 +852,107 @@
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
};
-static struct snd_pcm_ops msm_routing_pcm_ops = {};
+static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int be_id = rtd->dai_link->be_id;
+
+ mutex_lock(&routing_lock);
+ msm_bedais[be_id].hw_params = params;
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+static int msm_pcm_routing_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int be_id = rtd->dai_link->be_id;
+ int i, session_type;
+ struct msm_pcm_routing_bdai_data *bedai;
+
+ if (be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+ return -EINVAL;
+ }
+
+ bedai = &msm_bedais[be_id];
+
+ session_type = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ 0 : 1);
+
+ mutex_lock(&routing_lock);
+
+ for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MAX) {
+ if (fe_dai_map[i][session_type] != INVALID_SESSION)
+ adm_close(bedai->port_id);
+ }
+
+ bedai->active = 0;
+ bedai->hw_params = NULL;
+
+ mutex_unlock(&routing_lock);
+
+ return 0;
+}
+
+static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int be_id = rtd->dai_link->be_id;
+ int i, path_type, session_type;
+ struct msm_pcm_routing_bdai_data *bedai;
+
+ if (be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+ return -EINVAL;
+ }
+
+
+ bedai = &msm_bedais[be_id];
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ path_type = ADM_PATH_PLAYBACK;
+ session_type = SESSION_TYPE_RX;
+ } else {
+ path_type = ADM_PATH_LIVE_REC;
+ session_type = SESSION_TYPE_TX;
+ }
+
+ mutex_lock(&routing_lock);
+
+ if (bedai->active == 1)
+ goto done; /* Ignore prepare if back-end already active */
+
+ /* AFE port is not active at this point. However, still
+ * go ahead setting active flag under the notion that
+ * QDSP6 is able to handle ADM starting before AFE port
+ * is started.
+ */
+ bedai->active = 1;
+
+ for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MAX) {
+ if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+ adm_open(bedai->port_id, path_type,
+ params_rate(bedai->hw_params),
+ params_channels(bedai->hw_params),
+ DEFAULT_COPP_TOPOLOGY);
+ msm_pcm_routing_build_matrix(i,
+ fe_dai_map[i][session_type], path_type);
+ }
+ }
+
+done:
+ mutex_unlock(&routing_lock);
+
+ return 0;
+}
+
+static struct snd_pcm_ops msm_routing_pcm_ops = {
+ .hw_params = msm_pcm_routing_hw_params,
+ .close = msm_pcm_routing_close,
+ .prepare = msm_pcm_routing_prepare,
+};
static unsigned int msm_routing_read(struct snd_soc_platform *platform,
unsigned int reg)
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index cac2fc6..db7552d 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -30,9 +30,9 @@
enum {
MSM_FRONTEND_DAI_MULTIMEDIA1 = 0,
MSM_FRONTEND_DAI_MULTIMEDIA2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3,
MSM_FRONTEND_DAI_CS_VOICE,
MSM_FRONTEND_DAI_VOIP,
- MSM_FRONTEND_DAI_MULTIMEDIA3,
MSM_FRONTEND_DAI_AFE_RX,
MSM_FRONTEND_DAI_AFE_TX,
MSM_FRONTEND_DAI_MAX,
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index baac498..51be337 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -16,7 +16,6 @@
#include <linux/jiffies.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>
-#include <linux/bitops.h>
#include <mach/qdsp6v2/audio_dev_ctl.h>
#include <mach/qdsp6v2/audio_acdb.h>
@@ -28,6 +27,7 @@
#define TIMEOUT_MS 1000
#define AUDIO_RX 0x0
#define AUDIO_TX 0x1
+
#define ASM_MAX_SESSION 0x8 /* To do: define in a header */
#define RESET_COPP_ID 99
#define INVALID_COPP_ID 0xFF
@@ -37,7 +37,6 @@
atomic_t copp_id[AFE_MAX_PORTS];
atomic_t copp_cnt[AFE_MAX_PORTS];
atomic_t copp_stat[AFE_MAX_PORTS];
- unsigned long sessions[AFE_MAX_PORTS];
wait_queue_head_t wait;
};
@@ -206,205 +205,6 @@
return;
}
-/* This function issues routing command of ASM stream
- * to ADM mixer associated with a particular AFE port
- */
-int adm_cmd_map(int port_id, int session_id)
-{
- struct adm_routings_command route;
- int ret = 0;
- int index = afe_get_port_index(port_id);
-
- pr_debug("%s: port %x session %x\n", __func__, port_id, session_id);
-
- if (!atomic_read(&this_adm.copp_cnt[index]))
- return 0;
-
- route.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- route.hdr.pkt_size = sizeof(route);
- route.hdr.src_svc = 0;
- route.hdr.src_domain = APR_DOMAIN_APPS;
- route.hdr.src_port = port_id;
- route.hdr.dest_svc = APR_SVC_ADM;
- route.hdr.dest_domain = APR_DOMAIN_ADSP;
- route.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
- route.hdr.token = port_id;
- route.hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS;
- route.num_sessions = 1;
- route.session[0].id = session_id;
- route.session[0].num_copps = 1;
- route.session[0].copp_id[0] =
- atomic_read(&this_adm.copp_id[index]);
-
- /* This rule can change */
- if ((port_id & 0x1))
- route.path = AUDIO_TX;
- else
- route.path = AUDIO_RX;
-
- atomic_set(&this_adm.copp_stat[index], 0);
-
- ret = apr_send_pkt(this_adm.apr, (uint32_t *)&route);
- if (ret < 0) {
- pr_err("%s: ADM routing for port %d failed\n",
- __func__, port_id);
- ret = -EINVAL;
- goto fail_cmd;
- }
- ret = wait_event_timeout(this_adm.wait,
- atomic_read(&this_adm.copp_stat[index]),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: ADM cmd Route failed for port %d\n",
- __func__, port_id);
- ret = -EINVAL;
- }
-
- /* have to convert path to dev ctrl standard */
- send_adm_cal(port_id, (route.path + 1));
- rtac_add_adm_device(port_id, atomic_read(&this_adm.copp_id[index]),
- (route.path + 1), session_id);
-fail_cmd:
- return ret;
-}
-
-/* This function establish routing of ASM stream to a particular
- * ADM mixer that is routed to a particular hardware port
- * session id must be in range of 0 ~ 31.
- */
-int adm_route_session(int port_id, uint session_id, int set)
-{
- int rc = 0;
- int index;
-
- pr_debug("%s: port %x session %x set %x\n", __func__,
- port_id, session_id, set);
-
- port_id = afe_convert_virtual_to_portid(port_id);
-
- index = afe_get_port_index(port_id);
-
- if (index >= AFE_MAX_PORTS) {
- pr_err("%s port idi[%d] out of limit[%d]\n", __func__,
- port_id, AFE_MAX_PORTS);
- return -ENODEV;
- }
-
- if (set) {
- set_bit(session_id, &this_adm.sessions[index]);
- rc = adm_cmd_map(port_id, session_id); /* not thread safe */
- } else /* Not sure how to deroute yet */
- clear_bit(session_id, &this_adm.sessions[index]);
-
- return rc;
-}
-
-/* This function instantiates a mixer in QDSP6 audio path for
- * given audio hardware port. Topology should be made part
- * of audio calibration
- */
-int adm_open_mixer(int port_id, int path, int rate,
- int channel_mode, int topology) {
- struct adm_copp_open_command open;
- int ret = 0;
- u32 i;
- int index;
-
- pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
- port_id, path, rate, channel_mode);
-
- port_id = afe_convert_virtual_to_portid(port_id);
-
- if (afe_validate_port(port_id) < 0) {
- pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
- return -ENODEV;
- }
- index = afe_get_port_index(port_id);
- if (this_adm.apr == NULL) {
- this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
- 0xFFFFFFFF, &this_adm);
- if (this_adm.apr == NULL) {
- pr_err("%s: Unable to register ADM\n", __func__);
- ret = -ENODEV;
- return ret;
- }
- rtac_set_adm_handle(this_adm.apr);
- }
-
- if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
-
- open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- open.hdr.pkt_size = sizeof(open);
- open.hdr.src_svc = APR_SVC_ADM;
- open.hdr.src_domain = APR_DOMAIN_APPS;
- open.hdr.src_port = port_id;
- open.hdr.dest_svc = APR_SVC_ADM;
- open.hdr.dest_domain = APR_DOMAIN_ADSP;
- open.hdr.dest_port = port_id;
- open.hdr.token = port_id;
- open.hdr.opcode = ADM_CMD_COPP_OPEN;
-
- open.mode = path;
- open.endpoint_id1 = port_id;
- open.endpoint_id2 = 0xFFFF;
-
- /* convert path to acdb path */
- if (path == ADM_PATH_PLAYBACK)
- open.topology_id = get_adm_rx_topology();
- else {
- open.topology_id = get_adm_tx_topology();
- if ((open.topology_id ==
- VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
- (open.topology_id ==
- VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
- rate = 16000;
- }
-
- if (open.topology_id == 0)
- open.topology_id = topology;
-
- open.channel_config = channel_mode & 0x00FF;
- open.rate = rate;
-
- pr_debug("%s: channel_config=%d port_id=%d rate=%d\
- topology_id=0x%X\n", __func__, open.channel_config,\
- open.endpoint_id1, open.rate,\
- open.topology_id);
-
- atomic_set(&this_adm.copp_stat[index], 0);
-
- ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
- if (ret < 0) {
- pr_err("%s:ADM enable for port %d failed\n",
- __func__, port_id);
- ret = -EINVAL;
- goto fail_cmd;
- }
- /* Wait for the callback with copp id */
- ret = wait_event_timeout(this_adm.wait,
- atomic_read(&this_adm.copp_stat[index]),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s ADM open failed for port %d\n", __func__,
- port_id);
- ret = -EINVAL;
- goto fail_cmd;
- }
- }
- atomic_inc(&this_adm.copp_cnt[index]);
-
- /* Set up routing for cached session */
- for (i = find_first_bit(&this_adm.sessions[index], ASM_MAX_SESSION);
- i < ASM_MAX_SESSION; i = find_next_bit(&this_adm.sessions[index],
- ASM_MAX_SESSION, i + 1))
- adm_cmd_map(port_id, i); /* Not thread safe */
-
-fail_cmd:
- return ret;
-}
-
int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
{
struct adm_copp_open_command open;