summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sound/apr_audio-v2.h145
-rw-r--r--include/sound/q6adm-v2.h8
-rw-r--r--sound/soc/msm/qdsp6v2/q6adm.c134
3 files changed, 279 insertions, 8 deletions
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index e098e2329ac6..7b8ad4e0c475 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -97,6 +97,16 @@ struct adm_cmd_matrix_map_routings_v5 {
*/
#define ADM_CMD_DEVICE_OPEN_V5 0x00010326
+/* This command allows a client to open a COPP/Voice Proc the
+* way as ADM_CMD_DEVICE_OPEN_V5 but supports multiple endpoint2
+* channels.
+*
+* @return
+* #ADM_CMDRSP_DEVICE_OPEN_V6 with the resulting status and
+* COPP ID.
+*/
+#define ADM_CMD_DEVICE_OPEN_V6 0x00010356
+
/* Definition for a low latency stream session. */
#define ADM_LOW_LATENCY_DEVICE_SESSION 0x2000
@@ -246,12 +256,135 @@ struct adm_cmd_device_open_v5 {
/* Array of channel mapping of buffers that the audio COPP
* sends to the endpoint. Channel[i] mapping describes channel
* I inside the buffer, where 0 < i < dev_num_channel.
- * This value is relevent only for an audio Rx COPP.
+ * This value is relevant only for an audio Rx COPP.
* For the voice processor block and Tx audio block, this field
* is set to zero and is ignored.
*/
} __packed;
+/* ADM device open command payload of the
+ * #ADM_CMD_DEVICE_OPEN_V6 command.
+ */
+struct adm_cmd_device_open_v6 {
+ struct apr_hdr hdr;
+ u16 flags;
+/* Reserved for future use. Clients must set this field
+ * to zero.
+ */
+
+ u16 mode_of_operation;
+/* Specifies whether the COPP must be opened on the Tx or Rx
+ * path. Use the ADM_CMD_COPP_OPEN_MODE_OF_OPERATION_* macros for
+ * supported values and interpretation.
+ * Supported values:
+ * - 0x1 -- Rx path COPP
+ * - 0x2 -- Tx path live COPP
+ * - 0x3 -- Tx path nonlive COPP
+ * Live connections cause sample discarding in the Tx device
+ * matrix if the destination output ports do not pull them
+ * fast enough. Nonlive connections queue the samples
+ * indefinitely.
+ */
+
+ u16 endpoint_id_1;
+/* Logical and physical endpoint ID of the audio path.
+ * If the ID is a voice processor Tx block, it receives near
+ * samples. Supported values: Any pseudoport, AFE Rx port,
+ * or AFE Tx port For a list of valid IDs, refer to
+ * @xhyperref{Q4,[Q4]}.
+ * Q4 = Hexagon Multimedia: AFE Interface Specification
+ */
+
+ u16 endpoint_id_2;
+/* Logical and physical endpoint ID 2 for a voice processor
+ * Tx block.
+ * This is not applicable to audio COPP.
+ * Supported values:
+ * - AFE Rx port
+ * - 0xFFFF -- Endpoint 2 is unavailable and the voice
+ * processor Tx
+ * block ignores this endpoint
+ * When the voice processor Tx block is created on the audio
+ * record path,
+ * it can receive far-end samples from an AFE Rx port if the
+ * voice call
+ * is active. The ID of the AFE port is provided in this
+ * field.
+ * For a list of valid IDs, refer @xhyperref{Q4,[Q4]}.
+ */
+
+ u32 topology_id;
+/* Audio COPP topology ID; 32-bit GUID. */
+
+ u16 dev_num_channel;
+/* Number of channels the audio COPP sends to/receives from
+ * the endpoint.
+ * Supported values: 1 to 8.
+ * The value is ignored for the voice processor Tx block,
+ * where channel
+ * configuration is derived from the topology ID.
+ */
+
+ u16 bit_width;
+/* Bit width (in bits) that the audio COPP sends to/receives
+ * from the
+ * endpoint. The value is ignored for the voice processing
+ * Tx block,
+ * where the PCM width is 16 bits.
+ */
+
+ u32 sample_rate;
+/* Sampling rate at which the audio COPP/voice processor
+ * Tx block
+ * interfaces with the endpoint.
+ * Supported values for voice processor Tx: 8000, 16000,
+ * 48000 Hz
+ * Supported values for audio COPP: >0 and <=192 kHz
+ */
+
+ u8 dev_channel_mapping[8];
+/* Array of channel mapping of buffers that the audio COPP
+ * sends to the endpoint. Channel[i] mapping describes channel
+ * I inside the buffer, where 0 < i < dev_num_channel.
+ * This value is relevant only for an audio Rx COPP.
+ * For the voice processor block and Tx audio block, this field
+ * is set to zero and is ignored.
+ */
+
+ u16 dev_num_channel_eid2;
+/* Number of channels the voice processor block sends
+ * to/receives from the endpoint2.
+ * Supported values: 1 to 8.
+ * The value is ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+
+ u16 bit_width_eid2;
+/* Bit width (in bits) that the voice processor sends
+ * to/receives from the endpoint2.
+ * Supported values: 16 and 24.
+ * The value is ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+
+ u32 sample_rate_eid2;
+/* Sampling rate at which the voice processor Tx block
+ * interfaces with the endpoint2.
+ * Supported values for Tx voice processor: >0 and <=384 kHz
+ * The value is ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+
+ u8 dev_channel_mapping_eid2[8];
+/* Array of channel mapping of buffers that the voice processor
+ * sends to the endpoint. Channel[i] mapping describes channel
+ * I inside the buffer, where 0 < i < dev_num_channel.
+ * This value is relevant only for the Tx voice processor.
+ * The values are ignored for audio COPP or if endpoint_id_2 is
+ * set to 0xFFFF.
+ */
+} __packed;
+
/*
* This command allows the client to close a COPP and disconnect
* the device session.
@@ -368,6 +501,16 @@ struct adm_cmd_rsp_device_open_v5 {
/* Reserved. This field must be set to zero.*/
} __packed;
+/* Returns the status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V6 command.
+ */
+#define ADM_CMDRSP_DEVICE_OPEN_V6 0x00010357
+
+/* Payload of the #ADM_CMDRSP_DEVICE_OPEN_V6 message,
+ * which returns the
+ * status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V6 command
+ * is the exact same as ADM_CMDRSP_DEVICE_OPEN_V5.
+ */
+
/* This command allows a query of one COPP parameter.
*/
#define ADM_CMD_GET_PP_PARAMS_V5 0x0001032A
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index c9a429d8607d..292575f2bfaf 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, 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
@@ -102,6 +102,12 @@ int adm_connect_afe_port(int mode, int session_id, int port_id);
void adm_ec_ref_rx_id(int port_id);
+void adm_num_ec_ref_rx_chans(int num_chans);
+
+void adm_ec_ref_rx_bit_width(int bit_width);
+
+void adm_ec_ref_rx_sampling_rate(int sampling_rate);
+
int adm_get_lowlatency_copp_id(int port_id);
int adm_set_multi_ch_map(char *channel_map, int path);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 30876b52ec9e..0dcce8810343 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -102,6 +102,9 @@ struct adm_ctl {
int set_custom_topology;
int ec_ref_rx;
+ int num_ec_ref_rx_chans;
+ int ec_ref_rx_bit_width;
+ int ec_ref_rx_sampling_rate;
};
static struct adm_ctl this_adm;
@@ -1355,6 +1358,7 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
*/
case ADM_CMD_DEVICE_OPEN_V5:
case ADM_CMD_DEVICE_CLOSE_V5:
+ case ADM_CMD_DEVICE_OPEN_V6:
pr_debug("%s: Basic callback received, wake up.\n",
__func__);
atomic_set(&this_adm.copp.stat[port_idx]
@@ -1450,7 +1454,8 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv)
}
switch (data->opcode) {
- case ADM_CMDRSP_DEVICE_OPEN_V5: {
+ case ADM_CMDRSP_DEVICE_OPEN_V5:
+ case ADM_CMDRSP_DEVICE_OPEN_V6: {
struct adm_cmd_rsp_device_open_v5 *open =
(struct adm_cmd_rsp_device_open_v5 *)data->payload;
@@ -2257,10 +2262,64 @@ inval_ch_mod:
return rc;
}
+int adm_arrange_mch_ep2_map(struct adm_cmd_device_open_v6 *open_v6,
+ int channel_mode)
+{
+ int rc = 0;
+
+ memset(open_v6->dev_channel_mapping_eid2, 0,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (channel_mode == 1) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FC;
+ } else if (channel_mode == 2) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ } else if (channel_mode == 3) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
+ } else if (channel_mode == 4) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LS;
+ open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_RS;
+ } else if (channel_mode == 5) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_FC;
+ open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_LS;
+ open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_RS;
+ } else if (channel_mode == 6) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
+ open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
+ open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
+ open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
+ } else if (channel_mode == 8) {
+ open_v6->dev_channel_mapping_eid2[0] = PCM_CHANNEL_FL;
+ open_v6->dev_channel_mapping_eid2[1] = PCM_CHANNEL_FR;
+ open_v6->dev_channel_mapping_eid2[2] = PCM_CHANNEL_LFE;
+ open_v6->dev_channel_mapping_eid2[3] = PCM_CHANNEL_FC;
+ open_v6->dev_channel_mapping_eid2[4] = PCM_CHANNEL_LS;
+ open_v6->dev_channel_mapping_eid2[5] = PCM_CHANNEL_RS;
+ open_v6->dev_channel_mapping_eid2[6] = PCM_CHANNEL_LB;
+ open_v6->dev_channel_mapping_eid2[7] = PCM_CHANNEL_RB;
+ } else {
+ pr_err("%s: invalid num_chan %d\n", __func__,
+ channel_mode);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
int perf_mode, uint16_t bit_width, int app_type, int acdb_id)
{
struct adm_cmd_device_open_v5 open;
+ struct adm_cmd_device_open_v6 open_v6;
int ret = 0;
int port_idx, copp_idx, flags;
int tmp_port = q6audio_get_port_id(port_id);
@@ -2409,10 +2468,9 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
open.flags = flags;
open.mode_of_operation = path;
open.endpoint_id_1 = tmp_port;
+ open.endpoint_id_2 = 0xFFFF;
- if (this_adm.ec_ref_rx == -1) {
- open.endpoint_id_2 = 0xFFFF;
- } else if (this_adm.ec_ref_rx && (path != 1)) {
+ if (this_adm.ec_ref_rx && (path != 1)) {
open.endpoint_id_2 = this_adm.ec_ref_rx;
this_adm.ec_ref_rx = -1;
}
@@ -2436,7 +2494,47 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
- ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+ if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) &&
+ (open.endpoint_id_2 != 0xFFFF)) {
+ memcpy(&open_v6, &open,
+ sizeof(struct adm_cmd_device_open_v5));
+ open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
+ open_v6.hdr.pkt_size = sizeof(open_v6);
+ open_v6.dev_num_channel_eid2 =
+ this_adm.num_ec_ref_rx_chans;
+ this_adm.num_ec_ref_rx_chans = 0;
+
+ if (this_adm.ec_ref_rx_bit_width != 0) {
+ open_v6.bit_width_eid2 =
+ this_adm.ec_ref_rx_bit_width;
+ this_adm.ec_ref_rx_bit_width = 0;
+ } else {
+ open_v6.bit_width_eid2 = bit_width;
+ }
+
+ if (this_adm.ec_ref_rx_sampling_rate != 0) {
+ open_v6.sample_rate_eid2 =
+ this_adm.ec_ref_rx_sampling_rate;
+ this_adm.ec_ref_rx_sampling_rate = 0;
+ } else {
+ open_v6.sample_rate_eid2 = rate;
+ }
+
+ pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
+ __func__, open_v6.dev_num_channel_eid2,
+ open_v6.bit_width_eid2,
+ open_v6.sample_rate_eid2);
+
+ ret = adm_arrange_mch_ep2_map(&open_v6,
+ open_v6.dev_num_channel_eid2);
+
+ if (ret)
+ return ret;
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open_v6);
+ } else {
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+ }
if (ret < 0) {
pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n",
__func__, tmp_port, port_id, ret);
@@ -2729,7 +2827,28 @@ fail_cmd:
void adm_ec_ref_rx_id(int port_id)
{
this_adm.ec_ref_rx = port_id;
- pr_debug("%s: ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
+ pr_debug("%s: ec_ref_rx:%d\n", __func__, this_adm.ec_ref_rx);
+}
+
+void adm_num_ec_ref_rx_chans(int num_chans)
+{
+ this_adm.num_ec_ref_rx_chans = num_chans;
+ pr_debug("%s: num_ec_ref_rx_chans:%d\n",
+ __func__, this_adm.num_ec_ref_rx_chans);
+}
+
+void adm_ec_ref_rx_bit_width(int bit_width)
+{
+ this_adm.ec_ref_rx_bit_width = bit_width;
+ pr_debug("%s: ec_ref_rx_bit_width:%d\n",
+ __func__, this_adm.ec_ref_rx_bit_width);
+}
+
+void adm_ec_ref_rx_sampling_rate(int sampling_rate)
+{
+ this_adm.ec_ref_rx_sampling_rate = sampling_rate;
+ pr_debug("%s: ec_ref_rx_sampling_rate:%d\n",
+ __func__, this_adm.ec_ref_rx_sampling_rate);
}
int adm_close(int port_id, int perf_mode, int copp_idx)
@@ -4345,6 +4464,9 @@ static int __init adm_init(void)
int i = 0, j;
this_adm.apr = NULL;
this_adm.ec_ref_rx = -1;
+ this_adm.num_ec_ref_rx_chans = 0;
+ this_adm.ec_ref_rx_bit_width = 0;
+ this_adm.ec_ref_rx_sampling_rate = 0;
atomic_set(&this_adm.matrix_map_stat, 0);
init_waitqueue_head(&this_adm.matrix_map_wait);
atomic_set(&this_adm.adm_stat, 0);