diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 1a58a146c3b0..06b72b262395 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -3678,6 +3678,8 @@ struct asm_softvolume_params { #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 0x00010DDC +#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 0x0001320C + #define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF #define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0 @@ -3780,6 +3782,56 @@ struct asm_multi_channel_pcm_fmt_blk_v3 { */ } __packed; +struct asm_multi_channel_pcm_fmt_blk_v4 { + uint16_t num_channels; +/* + * Number of channels + * Supported values: 1 to 8 + */ + + uint16_t bits_per_sample; +/* + * Number of bits per sample per channel + * Supported values: 16, 24, 32 + */ + + uint32_t sample_rate; +/* + * Number of samples per second + * Supported values: 2000 to 48000, 96000,192000 Hz + */ + + uint16_t is_signed; +/* Flag that indicates that PCM samples are signed (1) */ + + uint16_t sample_word_size; +/* + * Size in bits of the word that holds a sample of a channel. + * Supported values: 12,24,32 + */ + + uint8_t channel_mapping[8]; +/* + * Each element, i, in the array describes channel i inside the buffer where + * 0 <= i < num_channels. Unused channels are set to 0. + */ + uint16_t endianness; +/* + * Flag to indicate the endianness of the pcm sample + * Supported values: 0 - Little endian (all other formats) + * 1 - Big endian (AIFF) + */ + uint16_t mode; +/* + * Mode to provide additional info about the pcm input data. + * Supported values: 0 - Default QFs (Q15 for 16b, Q23 for packed 24b, + * Q31 for unpacked 24b or 32b) + * 15 - for 16 bit + * 23 - for 24b packed or 8.24 format + * 31 - for 24b unpacked or 32bit + */ +} __packed; + /* * Payload of the multichannel PCM configuration parameters in * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 media format. @@ -3790,6 +3842,16 @@ struct asm_multi_channel_pcm_fmt_blk_param_v3 { struct asm_multi_channel_pcm_fmt_blk_v3 param; } __packed; +/* + * Payload of the multichannel PCM configuration parameters in + * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 media format. + */ +struct asm_multi_channel_pcm_fmt_blk_param_v4 { + struct apr_hdr hdr; + struct asm_data_cmd_media_fmt_update_v2 fmt_blk; + struct asm_multi_channel_pcm_fmt_blk_v4 param; +} __packed; + struct asm_stream_cmd_set_encdec_param { u32 param_id; /* ID of the parameter. */ @@ -3825,6 +3887,79 @@ struct asm_dec_ddp_endp_param_v2 { int endp_param_value; } __packed; +/* + * Payload of the multichannel PCM encoder configuration parameters in + * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 media format. + */ + +struct asm_multi_channel_pcm_enc_cfg_v4 { + struct apr_hdr hdr; + struct asm_stream_cmd_set_encdec_param encdec; + struct asm_enc_cfg_blk_param_v2 encblk; + uint16_t num_channels; + /* + * Number of PCM channels. + * @values + * - 0 -- Native mode + * - 1 -- 8 channels + * Native mode indicates that encoding must be performed with the number + * of channels at the input. + */ + uint16_t bits_per_sample; + /* + * Number of bits per sample per channel. + * @values 16, 24 + */ + uint32_t sample_rate; + /* + * Number of samples per second. + * @values 0, 8000 to 48000 Hz + * A value of 0 indicates the native sampling rate. Encoding is + * performed at the input sampling rate. + */ + uint16_t is_signed; + /* + * Flag that indicates the PCM samples are signed (1). Currently, only + * signed PCM samples are supported. + */ + uint16_t sample_word_size; + /* + * The size in bits of the word that holds a sample of a channel. + * @values 16, 24, 32 + * 16-bit samples are always placed in 16-bit words: + * sample_word_size = 1. + * 24-bit samples can be placed in 32-bit words or in consecutive + * 24-bit words. + * - If sample_word_size = 32, 24-bit samples are placed in the + * most significant 24 bits of a 32-bit word. + * - If sample_word_size = 24, 24-bit samples are placed in + * 24-bit words. @tablebulletend + */ + uint8_t channel_mapping[8]; + /* + * Channel mapping array expected at the encoder output. + * Channel[i] mapping describes channel i inside the buffer, where + * 0 @le i < num_channels. All valid used channels must be present at + * the beginning of the array. + * If Native mode is set for the channels, this field is ignored. + * @values See Section @xref{dox:PcmChannelDefs} + */ + uint16_t endianness; + /* + * Flag to indicate the endianness of the pcm sample + * Supported values: 0 - Little endian (all other formats) + * 1 - Big endian (AIFF) + */ + uint16_t mode; + /* + * Mode to provide additional info about the pcm input data. + * Supported values: 0 - Default QFs (Q15 for 16b, Q23 for packed 24b, + * Q31 for unpacked 24b or 32b) + * 15 - for 16 bit + * 23 - for 24b packed or 8.24 format + * 31 - for 24b unpacked or 32bit + */ +} __packed; /* * Payload of the multichannel PCM encoder configuration parameters in diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 00129eb08888..f08bd73edb59 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -97,6 +97,24 @@ #define ASM_SHIFT_GAPLESS_MODE_FLAG 31 #define ASM_SHIFT_LAST_BUFFER_FLAG 30 +#define ASM_LITTLE_ENDIAN 0 +#define ASM_BIG_ENDIAN 1 + +/* PCM_MEDIA_FORMAT_Version */ +enum { + PCM_MEDIA_FORMAT_V2 = 0, + PCM_MEDIA_FORMAT_V3, + PCM_MEDIA_FORMAT_V4, +}; + +/* PCM format modes in DSP */ +enum { + DEFAULT_QF = 0, + Q15 = 15, + Q23 = 23, + Q31 = 31, +}; + /* payload structure bytes */ #define READDONE_IDX_STATUS 0 #define READDONE_IDX_BUFADD_LSW 1 @@ -245,6 +263,9 @@ int q6asm_open_read_v2(struct audio_client *ac, uint32_t format, int q6asm_open_read_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample); +int q6asm_open_read_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample); + int q6asm_open_write(struct audio_client *ac, uint32_t format /*, uint16_t bits_per_sample*/); @@ -257,6 +278,9 @@ int q6asm_open_shared_io(struct audio_client *ac, int q6asm_open_write_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample); +int q6asm_open_write_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample); + int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, int32_t stream_id, bool is_gapless_mode); @@ -265,6 +289,10 @@ int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, int32_t stream_id, bool is_gapless_mode); +int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample, int32_t stream_id, + bool is_gapless_mode); + int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, uint32_t passthrough_flag); @@ -369,6 +397,13 @@ int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac, bool use_back_flavor, u8 *channel_map, uint16_t sample_word_size); +int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, bool use_default_chmap, + bool use_back_flavor, u8 *channel_map, + uint16_t sample_word_size, uint16_t endianness, + uint16_t mode); + int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, uint32_t rate, uint32_t channels, uint16_t bits_per_sample); @@ -378,6 +413,13 @@ int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac, uint16_t bits_per_sample, uint16_t sample_word_size); +int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode); + int q6asm_set_encdec_chan_map(struct audio_client *ac, uint32_t num_channels); @@ -427,6 +469,17 @@ int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac, char *channel_map, uint16_t sample_word_size); +int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac, + uint32_t rate, + uint32_t channels, + uint16_t bits_per_sample, + int stream_id, + bool use_default_chmap, + char *channel_map, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode); + int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, bool use_default_chmap, char *channel_map); @@ -444,6 +497,15 @@ int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac, uint16_t bits_per_sample, uint16_t sample_word_size); +int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + bool use_default_chmap, + char *channel_map, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode); + int q6asm_media_format_block_aac(struct audio_client *ac, struct asm_aac_cfg *cfg); diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index b4257f990aa5..88c27339b299 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -183,6 +183,25 @@ static inline void q6asm_update_token(u32 *token, u8 session_id, u8 stream_id, *token = asm_token.token; } +static inline uint32_t q6asm_get_pcm_format_id(uint32_t media_format_block_ver) +{ + uint32_t pcm_format_id; + + switch (media_format_block_ver) { + case PCM_MEDIA_FORMAT_V4: + pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4; + break; + case PCM_MEDIA_FORMAT_V3: + pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3; + break; + case PCM_MEDIA_FORMAT_V2: + default: + pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + break; + } + return pcm_format_id; +} + /* * q6asm_get_buf_index_from_token: * Retrieve buffer index from token. @@ -2263,7 +2282,7 @@ static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr, static int __q6asm_open_read(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, - bool use_v3_format) + uint32_t pcm_format_block_ver) { int rc = 0x00; struct asm_stream_cmd_open_read_v3 open; @@ -2306,10 +2325,7 @@ static int __q6asm_open_read(struct audio_client *ac, switch (format) { case FORMAT_LINEAR_PCM: open.mode_flags |= 0x00; - if (use_v3_format) - open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3; - else - open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver); break; case FORMAT_MPEG4_AAC: open.mode_flags |= BUFFER_META_ENABLE; @@ -2372,14 +2388,14 @@ int q6asm_open_read(struct audio_client *ac, uint32_t format) { return __q6asm_open_read(ac, format, 16, - false /*use_v3_format*/); + PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/); } int q6asm_open_read_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - false /*use_v3_format*/); + PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/); } /* @@ -2393,10 +2409,25 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - true /*use_v3_format*/); + PCM_MEDIA_FORMAT_V3/*media fmt block ver*/); } EXPORT_SYMBOL(q6asm_open_read_v3); +/* + * asm_open_read_v4 - Opens audio capture session + * + * @ac: Client session handle + * @format: encoder format + * @bits_per_sample: bit width of capture session + */ +int q6asm_open_read_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample) +{ + return __q6asm_open_read(ac, format, bits_per_sample, + PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/); +} +EXPORT_SYMBOL(q6asm_open_read_v4); + int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, uint32_t passthrough_flag) { @@ -2488,7 +2519,8 @@ fail_cmd: static int __q6asm_open_write(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, uint32_t stream_id, - bool is_gapless_mode, bool use_v3_format) + bool is_gapless_mode, + uint32_t pcm_format_block_ver) { int rc = 0x00; struct asm_stream_cmd_open_write_v3 open; @@ -2564,11 +2596,7 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format, } switch (format) { case FORMAT_LINEAR_PCM: - if (use_v3_format) - open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3; - else - open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; - + open.dec_fmt_id = q6asm_get_pcm_format_id(pcm_format_block_ver); break; case FORMAT_MPEG4_AAC: open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2; @@ -2647,7 +2675,7 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format) { return __q6asm_open_write(ac, format, 16, ac->stream_id, false /*gapless*/, - false /*use_v3_format*/); + PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/); } int q6asm_open_write_v2(struct audio_client *ac, uint32_t format, @@ -2655,7 +2683,7 @@ int q6asm_open_write_v2(struct audio_client *ac, uint32_t format, { return __q6asm_open_write(ac, format, bits_per_sample, ac->stream_id, false /*gapless*/, - false /*use_v3_format*/); + PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/); } /* @@ -2670,17 +2698,33 @@ int q6asm_open_write_v3(struct audio_client *ac, uint32_t format, { return __q6asm_open_write(ac, format, bits_per_sample, ac->stream_id, false /*gapless*/, - true /*use_v3_format*/); + PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/); } EXPORT_SYMBOL(q6asm_open_write_v3); +/* + * q6asm_open_write_v4 - Opens audio playback session + * + * @ac: Client session handle + * @format: decoder format + * @bits_per_sample: bit width of playback session + */ +int q6asm_open_write_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample) +{ + return __q6asm_open_write(ac, format, bits_per_sample, + ac->stream_id, false /*gapless*/, + PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/); +} +EXPORT_SYMBOL(q6asm_open_write_v4); + int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, int32_t stream_id, bool is_gapless_mode) { return __q6asm_open_write(ac, format, bits_per_sample, stream_id, is_gapless_mode, - false /*use_v3_format*/); + PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/); } /* @@ -2698,10 +2742,29 @@ int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format, { return __q6asm_open_write(ac, format, bits_per_sample, stream_id, is_gapless_mode, - true /*use_v3_format*/); + PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/); } EXPORT_SYMBOL(q6asm_stream_open_write_v3); +/* + * q6asm_stream_open_write_v4 - Creates audio stream for playback + * + * @ac: Client session handle + * @format: asm playback format + * @bits_per_sample: bit width of requested stream + * @stream_id: stream id of stream to be associated with this session + * @is_gapless_mode: true if gapless mode needs to be enabled + */ +int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample, int32_t stream_id, + bool is_gapless_mode) +{ + return __q6asm_open_write(ac, format, bits_per_sample, + stream_id, is_gapless_mode, + PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/); +} +EXPORT_SYMBOL(q6asm_stream_open_write_v4); + static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format, uint32_t wr_format, bool is_meta_data_mode, uint32_t bits_per_sample, @@ -3524,6 +3587,108 @@ fail_cmd: return rc; } +/* + * q6asm_enc_cfg_blk_pcm_v4 - sends encoder configuration parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @use_default_chmap: true if default channel map to be used + * @use_back_flavor: to configure back left and right channel + * @channel_map: input channel map + * @sample_word_size: Size in bits of the word that holds a sample of a channel + * @endianness: endianness of the pcm data + * @mode: Mode to provide additional info about the pcm input data + */ +int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, bool use_default_chmap, + bool use_back_flavor, u8 *channel_map, + uint16_t sample_word_size, uint16_t endianness, + uint16_t mode) +{ + struct asm_multi_channel_pcm_enc_cfg_v4 enc_cfg; + struct asm_enc_cfg_blk_param_v2 enc_fg_blk; + u8 *channel_mapping; + u32 frames_per_buf = 0; + int rc; + + if (!use_default_chmap && (channel_map == NULL)) { + pr_err("%s: No valid chan map and can't use default\n", + __func__); + rc = -EINVAL; + goto fail_cmd; + } + + pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__, + ac->session, rate, channels, + bits_per_sample, sample_word_size); + + memset(&enc_cfg, 0, sizeof(enc_cfg)); + q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE); + atomic_set(&ac->cmd_state, -1); + enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; + enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; + enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) - + sizeof(enc_cfg.encdec); + enc_cfg.encblk.frames_per_buf = frames_per_buf; + enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size - + sizeof(enc_fg_blk); + enc_cfg.num_channels = channels; + enc_cfg.bits_per_sample = bits_per_sample; + enc_cfg.sample_rate = rate; + enc_cfg.is_signed = 1; + enc_cfg.sample_word_size = sample_word_size; + enc_cfg.endianness = endianness; + enc_cfg.mode = mode; + channel_mapping = enc_cfg.channel_mapping; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + + if (use_default_chmap) { + pr_debug("%s: setting default channel map for %d channels", + __func__, channels); + if (q6asm_map_channels(channel_mapping, channels, + use_back_flavor)) { + pr_err("%s: map channels failed %d\n", + __func__, channels); + rc = -EINVAL; + goto fail_cmd; + } + } else { + pr_debug("%s: Using pre-defined channel map", __func__); + memcpy(channel_mapping, channel_map, + PCM_FORMAT_MAX_NUM_CHANNEL); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg); + if (rc < 0) { + pr_err("%s: Command open failed %d\n", __func__, rc); + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout opcode[0x%x]\n", + __func__, enc_cfg.hdr.opcode); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} +EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v4); + /* * q6asm_enc_cfg_blk_pcm_v3 - sends encoder configuration parameters * @@ -3700,6 +3865,18 @@ fail_cmd: return rc; } +static int __q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + return q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels, + bits_per_sample, true, false, NULL, + sample_word_size, endianness, mode); +} + static int __q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac, uint32_t rate, uint32_t channels, uint16_t bits_per_sample, @@ -3749,6 +3926,31 @@ int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac, } EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v3); +/* + * q6asm_enc_cfg_blk_pcm_format_support_v4 - sends encoder configuration + * parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @sample_word_size: Size in bits of the word that holds a sample of a channel + * @endianness: endianness of the pcm data + * @mode: Mode to provide additional info about the pcm input data + */ +int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + return __q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels, + bits_per_sample, sample_word_size, + endianness, mode); +} +EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v4); + int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac, uint32_t rate, uint32_t channels) { @@ -4381,6 +4583,91 @@ fail_cmd: return rc; } +static int __q6asm_media_format_block_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + int stream_id, + bool use_default_chmap, + char *channel_map, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt; + u8 *channel_mapping; + int rc; + + pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__, + ac->session, rate, channels, + bits_per_sample, sample_word_size); + + memset(&fmt, 0, sizeof(fmt)); + q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id); + atomic_set(&ac->cmd_state, -1); + /* + * Updated the token field with stream/session for compressed playback + * Platform driver must know the the stream with which the command is + * associated + */ + if (ac->io_mode & COMPRESSED_STREAM_IO) + fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) | + (stream_id & 0xFF); + + pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n", + __func__, fmt.hdr.token, stream_id, ac->session); + + fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) - + sizeof(fmt.fmt_blk); + fmt.param.num_channels = channels; + fmt.param.bits_per_sample = bits_per_sample; + fmt.param.sample_rate = rate; + fmt.param.is_signed = 1; + fmt.param.sample_word_size = sample_word_size; + fmt.param.endianness = endianness; + fmt.param.mode = mode; + channel_mapping = fmt.param.channel_mapping; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + + if (use_default_chmap) { + if (q6asm_map_channels(channel_mapping, channels, false)) { + pr_err("%s: map channels failed %d\n", + __func__, channels); + rc = -EINVAL; + goto fail_cmd; + } + } else { + memcpy(channel_mapping, channel_map, + PCM_FORMAT_MAX_NUM_CHANNEL); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt); + if (rc < 0) { + pr_err("%s: Comamnd open failed %d\n", __func__, rc); + rc = -EINVAL; + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout. waited for format update\n", __func__); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} + int q6asm_media_format_block_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels) { @@ -4448,6 +4735,47 @@ int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac, } EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v3); +/* + * q6asm_media_format_block_pcm_format_support_v4- sends pcm decoder + * configuration parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @stream_id: stream id of stream to be associated with this session + * @use_default_chmap: true if default channel map to be used + * @channel_map: input channel map + * @sample_word_size: Size in bits of the word that holds a sample of a channel + * @endianness: endianness of the pcm data + * @mode: Mode to provide additional info about the pcm input data + */ +int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac, + uint32_t rate, + uint32_t channels, + uint16_t bits_per_sample, + int stream_id, + bool use_default_chmap, + char *channel_map, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + if (!use_default_chmap && (channel_map == NULL)) { + pr_err("%s: No valid chan map and can't use default\n", + __func__); + return -EINVAL; + } + return __q6asm_media_format_block_pcm_v4(ac, rate, + channels, bits_per_sample, stream_id, + use_default_chmap, channel_map, + sample_word_size, endianness, + mode); + +} +EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v4); + + static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, bool use_default_chmap, char *channel_map, @@ -4581,6 +4909,78 @@ fail_cmd: return rc; } +static int __q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac, + uint32_t rate, + uint32_t channels, + bool use_default_chmap, + char *channel_map, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt; + u8 *channel_mapping; + int rc; + + pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__, + ac->session, rate, channels, + bits_per_sample, sample_word_size); + + memset(&fmt, 0, sizeof(fmt)); + q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE); + atomic_set(&ac->cmd_state, -1); + + fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) - + sizeof(fmt.fmt_blk); + fmt.param.num_channels = channels; + fmt.param.bits_per_sample = bits_per_sample; + fmt.param.sample_rate = rate; + fmt.param.is_signed = 1; + fmt.param.sample_word_size = sample_word_size; + fmt.param.endianness = endianness; + fmt.param.mode = mode; + channel_mapping = fmt.param.channel_mapping; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + + if (use_default_chmap) { + if (q6asm_map_channels(channel_mapping, channels, false)) { + pr_err("%s: map channels failed %d\n", + __func__, channels); + rc = -EINVAL; + goto fail_cmd; + } + } else { + memcpy(channel_mapping, channel_map, + PCM_FORMAT_MAX_NUM_CHANNEL); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt); + if (rc < 0) { + pr_err("%s: Comamnd open failed %d\n", __func__, rc); + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout. waited for format update\n", __func__); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, @@ -4628,6 +5028,39 @@ int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac, } EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v3); +/* + * q6asm_media_format_block_multi_ch_pcm_v4 - sends pcm decoder configuration + * parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @use_default_chmap: true if default channel map to be used + * @channel_map: input channel map + * @sample_word_size: Size in bits of the word that holds a sample of a channel + * @endianness: endianness of the pcm data + * @mode: Mode to provide additional info about the pcm input data + */ +int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + bool use_default_chmap, + char *channel_map, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + return __q6asm_media_format_block_multi_ch_pcm_v4(ac, rate, channels, + use_default_chmap, + channel_map, + bits_per_sample, + sample_word_size, + endianness, + mode); +} +EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4); + static int __q6asm_media_format_block_multi_aac(struct audio_client *ac, struct asm_aac_cfg *cfg, int stream_id) {