Unverified Commit d4b2aee1 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: qcom: audioreach: add compress offload

Merge series from Srinivas Kandagatla <srinivas.kandagatla@linaro.org>:

This patchset adds compressed offload support to Qualcomm audioreach drivers.
Currently it supports AAC, MP3 and FALC along with gapless.

Tested this on SM8450 and sc7280.
parents 29735f6f c317d148
Loading
Loading
Loading
Loading
+156 −94
Original line number Diff line number Diff line
@@ -732,33 +732,32 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
	return rc;
}

static int audioreach_sal_limiter_enable(struct q6apm_graph *graph,
					 struct audioreach_module *module, bool enable)
int audioreach_send_u32_param(struct q6apm_graph *graph, struct audioreach_module *module,
			      uint32_t param_id, uint32_t param_val)
{
	struct apm_module_param_data *param_data;
	struct param_id_sal_limiter_enable *limiter_enable;
	int payload_size;
	struct gpr_pkt *pkt;
	int rc;
	uint32_t *param;
	int rc, payload_size;
	void *p;

	payload_size = sizeof(*limiter_enable) + APM_MODULE_PARAM_DATA_SIZE;
	payload_size = sizeof(uint32_t) + APM_MODULE_PARAM_DATA_SIZE;
	p = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
	if (IS_ERR(p))
		return -ENOMEM;

	pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
	if (IS_ERR(pkt))
		return PTR_ERR(pkt);

	p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
	pkt = p;
	p = p + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;

	param_data = p;
	param_data->module_instance_id = module->instance_id;
	param_data->error_code = 0;
	param_data->param_id = PARAM_ID_SAL_LIMITER_ENABLE;
	param_data->param_size = sizeof(*limiter_enable);
	p = p + APM_MODULE_PARAM_DATA_SIZE;
	limiter_enable = p;
	param_data->param_id = param_id;
	param_data->param_size = sizeof(uint32_t);

	limiter_enable->enable_lim = enable;
	p = p + APM_MODULE_PARAM_DATA_SIZE;
	param = p;
	*param = param_val;

	rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);

@@ -766,77 +765,34 @@ static int audioreach_sal_limiter_enable(struct q6apm_graph *graph,

	return rc;
}
EXPORT_SYMBOL_GPL(audioreach_send_u32_param);

static int audioreach_sal_limiter_enable(struct q6apm_graph *graph,
					 struct audioreach_module *module, bool enable)
{
	return audioreach_send_u32_param(graph, module, PARAM_ID_SAL_LIMITER_ENABLE, enable);
}

static int audioreach_sal_set_media_format(struct q6apm_graph *graph,
					   struct audioreach_module *module,
					   struct audioreach_module_config *cfg)
{
	struct apm_module_param_data *param_data;
	struct param_id_sal_output_config *media_format;
	int payload_size;
	struct gpr_pkt *pkt;
	int rc;
	void *p;

	payload_size = sizeof(*media_format) + APM_MODULE_PARAM_DATA_SIZE;

	pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
	if (IS_ERR(pkt))
		return PTR_ERR(pkt);

	p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;

	param_data = p;
	param_data->module_instance_id = module->instance_id;
	param_data->error_code = 0;
	param_data->param_id = PARAM_ID_SAL_OUTPUT_CFG;
	param_data->param_size = sizeof(*media_format);
	p = p + APM_MODULE_PARAM_DATA_SIZE;
	media_format = p;

	media_format->bits_per_sample = cfg->bit_width;

	rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);

	kfree(pkt);

	return rc;
	return audioreach_send_u32_param(graph, module, PARAM_ID_SAL_OUTPUT_CFG,  cfg->bit_width);
}

static int audioreach_module_enable(struct q6apm_graph *graph,
				    struct audioreach_module *module,
				    bool enable)
{
	struct apm_module_param_data *param_data;
	struct param_id_module_enable *param;
	int payload_size;
	struct gpr_pkt *pkt;
	int rc;
	void *p;

	payload_size = sizeof(*param) + APM_MODULE_PARAM_DATA_SIZE;

	pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
	if (IS_ERR(pkt))
		return PTR_ERR(pkt);

	p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;

	param_data = p;
	param_data->module_instance_id = module->instance_id;
	param_data->error_code = 0;
	param_data->param_id = PARAM_ID_MODULE_ENABLE;
	param_data->param_size = sizeof(*param);
	p = p + APM_MODULE_PARAM_DATA_SIZE;
	param = p;

	param->enable = enable;

	rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);

	kfree(pkt);
	return audioreach_send_u32_param(graph, module, PARAM_ID_MODULE_ENABLE, enable);
}

	return rc;
static int audioreach_gapless_set_media_format(struct q6apm_graph *graph,
					       struct audioreach_module *module,
					       struct audioreach_module_config *cfg)
{
	return audioreach_send_u32_param(graph, module, PARAM_ID_EARLY_EOS_DELAY,
					 EARLY_EOS_DELAY_MS);
}

static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
@@ -886,6 +842,99 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
	return rc;
}

static int audioreach_set_compr_media_format(struct media_format *media_fmt_hdr,
					     void *p, struct audioreach_module_config *mcfg)
{
	struct payload_media_fmt_aac_t *aac_cfg;
	struct payload_media_fmt_pcm *mp3_cfg;
	struct payload_media_fmt_flac_t *flac_cfg;

	switch (mcfg->fmt) {
	case SND_AUDIOCODEC_MP3:
		media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED;
		media_fmt_hdr->fmt_id = MEDIA_FMT_ID_MP3;
		media_fmt_hdr->payload_size = 0;
		p = p + sizeof(*media_fmt_hdr);
		mp3_cfg = p;
		mp3_cfg->sample_rate = mcfg->sample_rate;
		mp3_cfg->bit_width = mcfg->bit_width;
		mp3_cfg->alignment = PCM_LSB_ALIGNED;
		mp3_cfg->bits_per_sample = mcfg->bit_width;
		mp3_cfg->q_factor = mcfg->bit_width - 1;
		mp3_cfg->endianness = PCM_LITTLE_ENDIAN;
		mp3_cfg->num_channels = mcfg->num_channels;

		if (mcfg->num_channels == 1) {
			mp3_cfg->channel_mapping[0] =  PCM_CHANNEL_L;
		} else if (mcfg->num_channels == 2) {
			mp3_cfg->channel_mapping[0] =  PCM_CHANNEL_L;
			mp3_cfg->channel_mapping[1] =  PCM_CHANNEL_R;
		}
		break;
	case SND_AUDIOCODEC_AAC:
		media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED;
		media_fmt_hdr->fmt_id = MEDIA_FMT_ID_AAC;
		media_fmt_hdr->payload_size = sizeof(struct payload_media_fmt_aac_t);
		p = p + sizeof(*media_fmt_hdr);
		aac_cfg = p;
		aac_cfg->aac_fmt_flag = 0;
		aac_cfg->audio_obj_type = 5;
		aac_cfg->num_channels = mcfg->num_channels;
		aac_cfg->total_size_of_PCE_bits = 0;
		aac_cfg->sample_rate = mcfg->sample_rate;
		break;
	case SND_AUDIOCODEC_FLAC:
		media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED;
		media_fmt_hdr->fmt_id = MEDIA_FMT_ID_FLAC;
		media_fmt_hdr->payload_size = sizeof(struct payload_media_fmt_flac_t);
		p = p + sizeof(*media_fmt_hdr);
		flac_cfg = p;
		flac_cfg->sample_size = mcfg->codec.options.flac_d.sample_size;
		flac_cfg->num_channels = mcfg->num_channels;
		flac_cfg->min_blk_size = mcfg->codec.options.flac_d.min_blk_size;
		flac_cfg->max_blk_size = mcfg->codec.options.flac_d.max_blk_size;
		flac_cfg->sample_rate = mcfg->sample_rate;
		flac_cfg->min_frame_size = mcfg->codec.options.flac_d.min_frame_size;
		flac_cfg->max_frame_size = mcfg->codec.options.flac_d.max_frame_size;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

int audioreach_compr_set_param(struct q6apm_graph *graph, struct audioreach_module_config *mcfg)
{
	struct media_format *header;
	struct gpr_pkt *pkt;
	int iid, payload_size, rc;
	void *p;

	payload_size = sizeof(struct apm_sh_module_media_fmt_cmd);

	iid = q6apm_graph_get_rx_shmem_module_iid(graph);
	pkt = audioreach_alloc_cmd_pkt(payload_size, DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT,
			0, graph->port->id, iid);

	if (IS_ERR(pkt))
		return -ENOMEM;

	p = (void *)pkt + GPR_HDR_SIZE;
	header = p;
	rc = audioreach_set_compr_media_format(header, p, mcfg);
	if (rc) {
		kfree(pkt);
		return rc;
	}

	rc = gpr_send_port_pkt(graph->port, pkt);
	kfree(pkt);

	return rc;
}
EXPORT_SYMBOL_GPL(audioreach_compr_set_param);

static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
					   struct audioreach_module *module,
					   struct audioreach_module_config *cfg)
@@ -1089,6 +1138,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
	p = p + APM_MODULE_PARAM_DATA_SIZE;

	header = p;
	if (mcfg->fmt == SND_AUDIOCODEC_PCM) {
		header->data_format = DATA_FORMAT_FIXED_POINT;
		header->fmt_id =  MEDIA_FMT_ID_PCM;
		header->payload_size = payload_size - sizeof(*header);
@@ -1103,12 +1153,19 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
		cfg->endianness = PCM_LITTLE_ENDIAN;
		cfg->num_channels = mcfg->num_channels;

	if (mcfg->num_channels == 1) {
		if (mcfg->num_channels == 1)
			cfg->channel_mapping[0] =  PCM_CHANNEL_L;
	} else if (num_channels == 2) {
		else if (num_channels == 2) {
			cfg->channel_mapping[0] =  PCM_CHANNEL_L;
			cfg->channel_mapping[1] =  PCM_CHANNEL_R;
		}
	} else {
		rc = audioreach_set_compr_media_format(header, p, mcfg);
		if (rc) {
			kfree(pkt);
			return rc;
		}
	}

	rc = audioreach_graph_send_cmd_sync(graph, pkt, 0);

@@ -1192,6 +1249,8 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
	case MODULE_ID_PCM_DEC:
	case MODULE_ID_PCM_ENC:
	case MODULE_ID_PCM_CNV:
	case MODULE_ID_PLACEHOLDER_DECODER:
	case MODULE_ID_PLACEHOLDER_ENCODER:
		rc = audioreach_pcm_set_media_format(graph, module, cfg);
		break;
	case MODULE_ID_DISPLAY_PORT_SINK:
@@ -1219,6 +1278,9 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
	case MODULE_ID_MFC:
		rc = audioreach_mfc_set_media_format(graph, module, cfg);
		break;
	case MODULE_ID_GAPLESS:
		rc = audioreach_gapless_set_media_format(graph, module, cfg);
		break;
	default:
		rc = 0;
	}
+51 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@ struct q6apm_graph;
#define MODULE_ID_PCM_CNV		0x07001003
#define MODULE_ID_PCM_ENC		0x07001004
#define MODULE_ID_PCM_DEC		0x07001005
#define MODULE_ID_PLACEHOLDER_ENCODER	0x07001008
#define MODULE_ID_PLACEHOLDER_DECODER	0x07001009
#define MODULE_ID_SAL			0x07001010
#define MODULE_ID_MFC			0x07001015
#define MODULE_ID_CODEC_DMA_SINK	0x07001023
@@ -22,6 +24,10 @@ struct q6apm_graph;
#define MODULE_ID_I2S_SINK		0x0700100A
#define MODULE_ID_I2S_SOURCE		0x0700100B
#define MODULE_ID_DATA_LOGGING		0x0700101A
#define MODULE_ID_AAC_DEC		0x0700101F
#define MODULE_ID_FLAC_DEC		0x0700102F
#define MODULE_ID_MP3_DECODE		0x0700103B
#define MODULE_ID_GAPLESS		0x0700104D
#define MODULE_ID_DISPLAY_PORT_SINK	0x07001069

#define APM_CMD_GET_SPF_STATE		0x01001021
@@ -143,12 +149,15 @@ struct param_id_enc_bitrate_param {
} __packed;

#define DATA_FORMAT_FIXED_POINT		1
#define DATA_FORMAT_GENERIC_COMPRESSED	5
#define DATA_FORMAT_RAW_COMPRESSED	6
#define PCM_LSB_ALIGNED			1
#define PCM_MSB_ALIGNED			2
#define PCM_LITTLE_ENDIAN		1
#define PCM_BIT_ENDIAN			2

#define MEDIA_FMT_ID_PCM	0x09001000
#define MEDIA_FMT_ID_MP3	0x09001009
#define PCM_CHANNEL_L		1
#define PCM_CHANNEL_R		2
#define SAMPLE_RATE_48K		48000
@@ -226,6 +235,28 @@ struct apm_media_format {
	uint32_t payload_size;
} __packed;

#define MEDIA_FMT_ID_FLAC	0x09001004

struct payload_media_fmt_flac_t {
	uint16_t num_channels;
	uint16_t sample_size;
	uint16_t min_blk_size;
	uint16_t max_blk_size;
	uint32_t sample_rate;
	uint32_t min_frame_size;
	uint32_t max_frame_size;
} __packed;

#define MEDIA_FMT_ID_AAC	0x09001001

struct payload_media_fmt_aac_t {
	uint16_t aac_fmt_flag;
	uint16_t audio_obj_type;
	uint16_t num_channels;
	uint16_t total_size_of_PCE_bits;
	uint32_t sample_rate;
} __packed;

#define DATA_CMD_WR_SH_MEM_EP_EOS			0x04001002
#define WR_SH_MEM_EP_EOS_POLICY_LAST	1
#define WR_SH_MEM_EP_EOS_POLICY_EACH	2
@@ -522,6 +553,8 @@ struct param_id_sal_limiter_enable {
} __packed;

#define PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT	0x08001024
#define PARAM_ID_EARLY_EOS_DELAY		0x0800114C
#define EARLY_EOS_DELAY_MS			150

struct param_id_mfc_media_format {
	uint32_t sample_rate;
@@ -530,6 +563,10 @@ struct param_id_mfc_media_format {
	uint16_t channel_mapping[];
} __packed;

struct param_id_gapless_early_eos_delay_t {
	uint32_t early_eos_delay_ms;
} __packed;

struct media_format {
	uint32_t data_format;
	uint32_t fmt_id;
@@ -608,6 +645,15 @@ struct param_id_vol_ctrl_master_gain {
} __packed;


#define PARAM_ID_REMOVE_INITIAL_SILENCE		0x0800114B
#define PARAM_ID_REMOVE_TRAILING_SILENCE	0x0800115D

#define PARAM_ID_REAL_MODULE_ID	0x0800100B

struct param_id_placeholder_real_module_id {
	uint32_t real_module_id;
} __packed;

/* Graph */
struct audioreach_connection {
	/* Connections */
@@ -716,6 +762,7 @@ struct audioreach_module_config {
	u32	channel_allocation;
	u32	sd_line_mask;
	int	fmt;
	struct snd_codec codec;
	u8 channel_map[AR_PCM_MAX_NUM_CHANNEL];
};

@@ -752,4 +799,8 @@ int audioreach_set_media_format(struct q6apm_graph *graph,
int audioreach_shared_memory_send_eos(struct q6apm_graph *graph);
int audioreach_gain_set_vol_ctrl(struct q6apm *apm,
				 struct audioreach_module *module, int vol);
int audioreach_send_u32_param(struct q6apm_graph *graph, struct audioreach_module *module,
			      uint32_t param_id, uint32_t param_val);
int audioreach_compr_set_param(struct q6apm_graph *graph, struct audioreach_module_config *mcfg);

#endif /* __AUDIOREACH_H__ */
+445 −0

File changed.

Preview size limit exceeded, changes collapsed.

+68 −0
Original line number Diff line number Diff line
@@ -298,6 +298,71 @@ int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir)
}
EXPORT_SYMBOL_GPL(q6apm_unmap_memory_regions);

int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
{
	struct audioreach_module *module;

	module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
	if (!module)
		return -ENODEV;

	return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_INITIAL_SILENCE, samples);
}
EXPORT_SYMBOL_GPL(q6apm_remove_initial_silence);

int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
{
	struct audioreach_module *module;

	module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
	if (!module)
		return -ENODEV;

	return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_TRAILING_SILENCE, samples);
}
EXPORT_SYMBOL_GPL(q6apm_remove_trailing_silence);

int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph, bool en)
{
	struct audioreach_module *module;

	module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
	if (!module)
		return -ENODEV;

	return audioreach_send_u32_param(graph, module, PARAM_ID_MODULE_ENABLE, en);
}
EXPORT_SYMBOL_GPL(q6apm_enable_compress_module);

int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph,
			     uint32_t codec_id)
{
	struct audioreach_module *module;
	uint32_t module_id;

	module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
	if (!module)
		return -ENODEV;

	switch (codec_id) {
	case SND_AUDIOCODEC_MP3:
		module_id = MODULE_ID_MP3_DECODE;
		break;
	case SND_AUDIOCODEC_AAC:
		module_id = MODULE_ID_AAC_DEC;
		break;
	case SND_AUDIOCODEC_FLAC:
		module_id = MODULE_ID_FLAC_DEC;
		break;
	default:
		return -EINVAL;
	}

	return audioreach_send_u32_param(graph, module, PARAM_ID_REAL_MODULE_ID,
					 module_id);
}
EXPORT_SYMBOL_GPL(q6apm_set_real_module_id);

int q6apm_graph_media_format_pcm(struct q6apm_graph *graph, struct audioreach_module_config *cfg)
{
	struct audioreach_graph_info *info = graph->info;
@@ -497,6 +562,9 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
		}
		break;
	case DATA_CMD_WR_SH_MEM_EP_EOS_RENDERED:
		client_event = APM_CLIENT_EVENT_CMD_EOS_DONE;
		if (graph->cb)
			graph->cb(client_event, hdr->token, data->payload, graph->priv);
		break;
	case GPR_BASIC_RSP_RESULT:
		switch (result->opcode) {
+6 −0
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@
#define APM_WRITE_TOKEN_LEN_SHIFT              16

#define APM_MAX_SESSIONS			8
#define APM_LAST_BUFFER_FLAG			BIT(30)
#define NO_TIMESTAMP				0xFF00

struct q6apm {
	struct device *dev;
@@ -147,4 +149,8 @@ int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph);

bool q6apm_is_adsp_ready(void);

int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph, bool en);
int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);
int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);
int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph, uint32_t codec_id);
#endif /* __APM_GRAPH_ */
Loading