diff options
-rw-r--r-- | include/sound/apr_audio-v2.h | 145 | ||||
-rw-r--r-- | include/sound/q6adm-v2.h | 8 | ||||
-rw-r--r-- | sound/soc/msm/qdsp6v2/q6adm.c | 134 |
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); |