Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 05873c64 authored by Ben Romberger's avatar Ben Romberger Committed by Banajit Goswami
Browse files

ASoC: msm: qdsp6v2: Add IEC61937 compressed HDMI pass-though



Add support for IEC61937 which is an audio packaging
standard used for compressed HDMI pass-through. Any
audio format can be sent through HDMI pass-through
formatted as IEC61937.

Change-Id: I09821add306e2aeae6530cecbac189471a55e589
Signed-off-by: default avatarBen Romberger <bromberg@codeaurora.org>
parent 34426195
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -4011,6 +4011,32 @@ struct asm_generic_compressed_fmt_blk_t {

} __packed;


/* Command to send sample rate & channels for IEC61937 (compressed) or IEC60958
 * (pcm) streams. Both audio standards use the same format and are used for
 * HDMI or SPDIF.
 */
#define ASM_DATA_CMD_IEC_60958_MEDIA_FMT        0x0001321E

struct asm_iec_compressed_fmt_blk_t {
	struct apr_hdr hdr;

	/*
	 * Nominal sampling rate of the incoming bitstream.
	 * Supported values: 8000, 11025, 16000, 22050, 24000, 32000,
	 *                   44100, 48000, 88200, 96000, 176400, 192000,
	 *                   352800, 384000
	 */
	uint32_t sampling_rate;

	/*
	 * Number of channels of the incoming bitstream.
	 * Supported values: 1,2,3,4,5,6,7,8
	 */
	uint32_t num_channels;

} __packed;

struct asm_multi_channel_pcm_fmt_blk_v2 {
	struct apr_hdr hdr;
	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
@@ -5073,6 +5099,11 @@ struct asm_amrwbplus_fmt_blk_v2 {
#define ASM_MEDIA_FMT_APE                    0x00012F32
#define ASM_MEDIA_FMT_DSD                    0x00012F3E
#define ASM_MEDIA_FMT_TRUEHD                 0x00013215
/* 0x0 is used for fomat ID since ADSP dynamically determines the
 * format encapsulated in the IEC61937 (compressed) or IEC60958
 * (pcm) packets.
 */
#define ASM_MEDIA_FMT_IEC                    0x00000000

/* Media format ID for adaptive transform acoustic coding. This
 * ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED command
@@ -10555,6 +10586,7 @@ enum {
	COMPRESSED_PASSTHROUGH_DSD,
	LISTEN,
	COMPRESSED_PASSTHROUGH_GEN,
	COMPRESSED_PASSTHROUGH_IEC61937
};

#define AUDPROC_MODULE_ID_COMPRESSED_MUTE                0x00010770
+5 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@
#define FORMAT_APTX         0x001e
#define FORMAT_GEN_COMPR    0x001f
#define FORMAT_TRUEHD       0x0020
#define FORMAT_IEC61937     0x0021

#define ENCDEC_SBCBITRATE   0x0001
#define ENCDEC_IMMEDIATE_DECODE 0x0002
@@ -509,6 +510,10 @@ int q6asm_media_format_block_gen_compr(
			bool use_default_chmap, char *channel_map,
			uint16_t bits_per_sample);

int q6asm_media_format_block_iec(
			struct audio_client *ac,
			uint32_t rate, uint32_t channels);

int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
					     uint32_t rate, uint32_t channels,
					     bool use_default_chmap,
+26 −4
Original line number Diff line number Diff line
@@ -178,7 +178,7 @@ struct msm_compr_audio {

const u32 compr_codecs[] = {
	SND_AUDIOCODEC_AC3, SND_AUDIOCODEC_EAC3, SND_AUDIOCODEC_DTS,
	SND_AUDIOCODEC_DSD, SND_AUDIOCODEC_TRUEHD};
	SND_AUDIOCODEC_DSD, SND_AUDIOCODEC_TRUEHD, SND_AUDIOCODEC_IEC61937};

struct query_audio_effect {
	uint32_t mod_id;
@@ -928,7 +928,7 @@ static void populate_codec_list(struct msm_compr_audio *prtd)
			COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
	prtd->compr_cap.max_fragments =
			COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
	prtd->compr_cap.num_codecs = 16;
	prtd->compr_cap.num_codecs = 17;
	prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
	prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
	prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
@@ -945,6 +945,7 @@ static void populate_codec_list(struct msm_compr_audio *prtd)
	prtd->compr_cap.codecs[13] = SND_AUDIOCODEC_DSD;
	prtd->compr_cap.codecs[14] = SND_AUDIOCODEC_APTX;
	prtd->compr_cap.codecs[15] = SND_AUDIOCODEC_TRUEHD;
	prtd->compr_cap.codecs[16] = SND_AUDIOCODEC_IEC61937;
}

static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -1203,6 +1204,15 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
		pr_debug("SND_AUDIOCODEC_TRUEHD\n");
		/* no media format block needed */
		break;
	case FORMAT_IEC61937:
		pr_debug("SND_AUDIOCODEC_IEC61937\n");
		ret = q6asm_media_format_block_iec(prtd->audio_client,
						   prtd->sample_rate,
						   prtd->num_channels);
		if (ret < 0)
			pr_err("%s: CMD IEC61937 Format block failed ret %d\n",
				__func__, ret);
		break;
	case FORMAT_APTX:
		pr_debug("SND_AUDIOCODEC_APTX\n");
		memset(&aptx_cfg, 0x0, sizeof(struct aptx_dec_bt_addr_cfg));
@@ -1863,8 +1873,11 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream,
	prtd->sample_rate = prtd->codec_param.codec.sample_rate;
	pr_debug("%s: sample_rate %d\n", __func__, prtd->sample_rate);

	if (prtd->codec_param.codec.compr_passthr >= LEGACY_PCM &&
	    prtd->codec_param.codec.compr_passthr <= COMPRESSED_PASSTHROUGH_DSD)
	if ((prtd->codec_param.codec.compr_passthr >= LEGACY_PCM &&
	    prtd->codec_param.
	    codec.compr_passthr <= COMPRESSED_PASSTHROUGH_DSD) ||
	    (prtd->codec_param.
	    codec.compr_passthr == COMPRESSED_PASSTHROUGH_IEC61937))
		prtd->compr_passthr = prtd->codec_param.codec.compr_passthr;
	else
		prtd->compr_passthr = LEGACY_PCM;
@@ -1987,6 +2000,12 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream,
		break;
	}

	case SND_AUDIOCODEC_IEC61937: {
		pr_debug("%s: SND_AUDIOCODEC_IEC61937\n", __func__);
		prtd->codec = FORMAT_IEC61937;
		break;
	}

	case SND_AUDIOCODEC_APTX: {
		pr_debug("%s: SND_AUDIOCODEC_APTX\n", __func__);
		prtd->codec = FORMAT_APTX;
@@ -2862,6 +2881,7 @@ static int msm_compr_get_codec_caps(struct snd_compr_stream *cstream,
	case SND_AUDIOCODEC_DTS:
	case SND_AUDIOCODEC_DSD:
	case SND_AUDIOCODEC_TRUEHD:
	case SND_AUDIOCODEC_IEC61937:
	case SND_AUDIOCODEC_APTX:
		break;
	default:
@@ -3301,6 +3321,7 @@ static int msm_compr_send_dec_params(struct snd_compr_stream *cstream,
	case FORMAT_MP3:
	case FORMAT_MPEG4_AAC:
	case FORMAT_TRUEHD:
	case FORMAT_IEC61937:
	case FORMAT_APTX:
		pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
			 prtd->codec);
@@ -3369,6 +3390,7 @@ static int msm_compr_dec_params_put(struct snd_kcontrol *kcontrol,
	case FORMAT_DTS:
	case FORMAT_DSD:
	case FORMAT_TRUEHD:
	case FORMAT_IEC61937:
	case FORMAT_APTX:
		pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
			 prtd->codec);
+64 −0
Original line number Diff line number Diff line
@@ -1783,6 +1783,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
		case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
		case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
		case ASM_DATA_CMD_IEC_60958_MEDIA_FMT:
		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
		case ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2:
		case ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS:
@@ -2628,6 +2629,9 @@ int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
	case FORMAT_TRUEHD:
		open.fmt_id = ASM_MEDIA_FMT_TRUEHD;
		break;
	case FORMAT_IEC61937:
		open.fmt_id = ASM_MEDIA_FMT_IEC;
		break;
	default:
		pr_err("%s: Invalid format[%d]\n", __func__, format);
		rc = -EINVAL;
@@ -2645,6 +2649,10 @@ int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
		open.flags = 0x8;
		pr_debug("%s: Flag 8 - COMPRESSED_PASSTHROUGH_CONVERT\n",
			 __func__);
	} else if (passthrough_flag == COMPRESSED_PASSTHROUGH_IEC61937) {
		open.flags = 0x1;
		pr_debug("%s: Flag 1 - COMPRESSED_PASSTHROUGH_IEC61937\n",
			 __func__);
	} else {
		pr_err("%s: Invalid passthrough type[%d]\n",
			__func__, passthrough_flag);
@@ -5415,6 +5423,62 @@ int q6asm_media_format_block_gen_compr(struct audio_client *ac,
}
EXPORT_SYMBOL(q6asm_media_format_block_gen_compr);


/*
 * q6asm_media_format_block_iec - set up IEC61937 (compressed) or IEC60958
 *                                (pcm) format params. Both audio standards
 *                                use the same format and are used for
 *                                HDMI or SPDIF.
 *
 * @ac: Client session handle
 * @rate: sample rate
 * @channels: number of channels
 */
int q6asm_media_format_block_iec(struct audio_client *ac,
				uint32_t rate, uint32_t channels)
{
	struct asm_iec_compressed_fmt_blk_t fmt;
	int rc = 0;

	pr_debug("%s: session[%d]rate[%d]ch[%d]\n",
		 __func__, ac->session, rate,
		 channels);

	memset(&fmt, 0, sizeof(fmt));
	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);

	fmt.hdr.opcode = ASM_DATA_CMD_IEC_60958_MEDIA_FMT;
	fmt.num_channels = channels;
	fmt.sampling_rate = rate;

	atomic_set(&ac->cmd_state, -1);
	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));
	}
	return 0;
fail_cmd:
	return rc;
}
EXPORT_SYMBOL(q6asm_media_format_block_iec);

static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
				struct asm_aac_cfg *cfg, int stream_id)
{