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

Commit 88fad2e0 authored by Ben Romberger's avatar Ben Romberger
Browse files

ASoC: msm: qdsp6v2: Add matrix limiter support



Add matrix limiter to ADM. Limiter is used to
prevent saturation when mixing multiple audio
streams. It should be applied after ADM open
but before ADM matrix map.

Change-Id: I6787fe869e8ceee13694245b744ecd74c3a49682
CRs-Fixed: 2064258
Signed-off-by: default avatarBen Romberger <bromberg@codeaurora.org>
parent 93b52204
Loading
Loading
Loading
Loading
+82 −1
Original line number Diff line number Diff line
@@ -446,6 +446,88 @@ struct adm_param_data_v5 {
	 */
} __packed;


struct param_data_v6 {
	/* Unique ID of the module. */
	u32		module_id;
	/* Unique ID of the instance. */
	u16		instance_id;
	/* Reserved for future enhancements.
	 * This field must be set to zero.
	 */
	u16		reserved;
	/* Unique ID of the parameter. */
	u32		param_id;
	/* Data size of the param_id/module_id combination.
	 * This value is a
	 * multiple of 4 bytes.
	 */
	u32		param_size;
} __packed;

/* ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1 command is used to set
 * calibration data to the ADSP Matrix Mixer the payload is
 * of struct adm_cmd_set_mtmx_params_v1.
 *
 * ADM_CMD_GET_MTMX_STRTR_DEV_PARAMS_V1 can be used to get
 * the calibration data from the ADSP Matrix Mixer and
 * ADM_CMDRSP_GET_MTMX_STRTR_DEV_PARAMS_V1 is the response
 * ioctl to ADM_CMD_GET_MTMX_STRTR_DEV_PARAMS_V1.
 */
#define ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1	0x00010367
#define ADM_CMD_GET_MTMX_STRTR_DEV_PARAMS_V1	0x00010368
#define ADM_CMDRSP_GET_MTMX_STRTR_DEV_PARAMS_V1	0x00010369

/* Payload of the #define ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1 command.
 * If the data_payload_addr_lsw and data_payload_addr_msw element
 * are NULL, a series of struct param_data_v6 structures immediately
 * follows, whose total size is payload_size bytes.
 */
struct adm_cmd_set_mtmx_params_v1 {
	struct apr_hdr	hdr;
	/* LSW of parameter data payload address.*/
	u32		payload_addr_lsw;

	/* MSW of parameter data payload address.*/
	u32		payload_addr_msw;

	/* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS
	 * command.
	 * If mem_map_handle is zero it implies the message is in
	 * the payload
	 */
	u32		mem_map_handle;

	/* Size in bytes of the variable payload accompanying this
	 * message or in shared memory. This is used for parsing
	 * the parameter payload.
	 */
	u32		payload_size;

	/* COPP ID/Device ID */
	u16		copp_id;

	/* For alignment, must be set to 0 */
	u16		reserved;
} __packed;

struct enable_param_v6 {
	/*
	 * Specifies whether the Audio processing module is enabled.
	 * This parameter is generic/common parameter to configure or
	 * determine the state of any audio processing module.
	 */
	struct param_data_v6		param;

	/* @values 0 : Disable 1: Enable */
	uint32_t			enable;
} __packed;

/* Defined in ADSP as VOICE_MODULE_TX_STREAM_LIMITER but
 * used for RX stream limiter on matrix input to ADM.
 */
#define ADM_MTMX_MODULE_STREAM_LIMITER  0x00010F15

#define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213
#define ASM_STREAM_PP_EVENT 0x00013214
#define ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE 0x13333
@@ -9151,7 +9233,6 @@ struct srs_trumedia_params {
} __packed;
/* SRS TruMedia end */

#define AUDPROC_PARAM_ID_ENABLE		0x00010904
#define ASM_STREAM_POSTPROC_TOPO_ID_SA_PLUS 0x1000FFFF
/* DTS Eagle */
#define AUDPROC_MODULE_ID_DTS_HPX_PREMIX 0x0001077C
+8 −0
Original line number Diff line number Diff line
@@ -51,6 +51,13 @@ enum {
	ADM_CLIENT_ID_MAX,
};

/* ENUM for adm_status & route_status */
enum adm_status_flags {
	ADM_STATUS_CALIBRATION_REQUIRED = 0,
	ADM_STATUS_LIMITER,
	ADM_STATUS_MAX,
};

#define MAX_COPPS_PER_PORT 0x8
#define ADM_MAX_CHANNELS 8

@@ -61,6 +68,7 @@ struct route_payload {
	int app_type[MAX_COPPS_PER_PORT];
	int acdb_dev_id[MAX_COPPS_PER_PORT];
	int sample_rate[MAX_COPPS_PER_PORT];
	unsigned long route_status[MAX_COPPS_PER_PORT];
	unsigned short num_copps;
	unsigned int session_id;
};
+59 −39
Original line number Diff line number Diff line
@@ -118,17 +118,13 @@ static const char * const lsm_port_text[] = {
};
struct msm_pcm_route_bdai_pp_params {
	u16 port_id; /* AFE port ID */
	unsigned long pp_params_config;
	bool mute_on;
	int latency;
};
static struct msm_pcm_route_bdai_pp_params
	msm_bedais_pp_params[MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX] = {
	{HDMI_RX, 0, 0, 0},
	{DISPLAY_PORT_RX, 0, 0, 0},
};
	msm_bedais_pp_params[MSM_BACKEND_DAI_MAX];
/*
 * The be_dai_name_table is passed to HAL so that it can specify the
@@ -142,6 +138,7 @@ struct msm_pcm_route_bdai_name {
};
static struct msm_pcm_route_bdai_name be_dai_name_table[MSM_BACKEND_DAI_MAX];
static bool msm_pcm_routing_test_pp_param(int be_idx, long param_bit);
static int msm_routing_send_device_pp_params(int port_id,  int copp_idx,
					     int fe_id);
@@ -953,7 +950,7 @@ static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type,
					 uint32_t passthr_mode)
{
	int i, port_type, j, num_copps = 0;
	struct route_payload payload;
	struct route_payload payload = { {0} };
	port_type = ((path_type == ADM_PATH_PLAYBACK ||
		      path_type == ADM_PATH_COMPRESSED_RX) ?
@@ -983,6 +980,11 @@ static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type,
						fe_dai_app_type_cfg
							[fedai_id][sess_type][i]
								.sample_rate;
					if (msm_pcm_routing_test_pp_param(i,
					    ADM_PP_PARAM_LIMITER_BIT))
						set_bit(ADM_STATUS_LIMITER,
							&payload.route_status
							[num_copps]);
					num_copps++;
				}
			}
@@ -1204,6 +1206,11 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
						fe_dai_app_type_cfg
							[fe_id][session_type][i]
								.sample_rate;
					if (msm_pcm_routing_test_pp_param(i,
					    ADM_PP_PARAM_LIMITER_BIT))
						set_bit(ADM_STATUS_LIMITER,
							&payload.route_status
							[num_copps]);
					num_copps++;
				}
			}
@@ -1434,6 +1441,11 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
						fe_dai_app_type_cfg
							[fedai_id][session_type]
							[i].sample_rate;
					if (msm_pcm_routing_test_pp_param(i,
					    ADM_PP_PARAM_LIMITER_BIT))
						set_bit(ADM_STATUS_LIMITER,
							&payload.route_status
							[num_copps]);
					num_copps++;
				}
			}
@@ -15168,7 +15180,7 @@ done:
static int msm_routing_send_device_pp_params(int port_id, int copp_idx,
					     int fe_id)
{
	int index, topo_id, be_idx;
	int topo_id, be_idx;
	unsigned long pp_config = 0;
	bool mute_on;
	int latency;
@@ -15192,16 +15204,6 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx,
		return  -EINVAL;
	}
	for (index = 0; index < MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX; index++) {
		if (msm_bedais_pp_params[index].port_id == port_id)
			break;
	}
	if (index >= MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX) {
		pr_err("%s: Invalid backend pp params index %d\n",
			__func__, index);
		return -EINVAL;
	}
	topo_id = adm_get_topology_for_port_copp_idx(port_id, copp_idx);
	if (topo_id != COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY) {
		pr_err("%s: Invalid passthrough topology 0x%x\n",
@@ -15213,11 +15215,11 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx,
		(msm_bedais[be_idx].passthr_mode[fe_id] == LISTEN))
		compr_passthr_mode = false;
	pp_config = msm_bedais_pp_params[index].pp_params_config;
	pp_config = msm_bedais_pp_params[be_idx].pp_params_config;
	if (test_bit(ADM_PP_PARAM_MUTE_BIT, &pp_config)) {
		pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__);
		clear_bit(ADM_PP_PARAM_MUTE_BIT, &pp_config);
		mute_on = msm_bedais_pp_params[index].mute_on;
		mute_on = msm_bedais_pp_params[be_idx].mute_on;
		if ((msm_bedais[be_idx].active) && compr_passthr_mode)
			adm_send_compressed_device_mute(port_id,
								copp_idx,
@@ -15227,7 +15229,7 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx,
		pr_debug("%s: ADM_PP_PARAM_LATENCY\n", __func__);
		clear_bit(ADM_PP_PARAM_LATENCY_BIT,
			  &pp_config);
		latency = msm_bedais_pp_params[index].latency;
		latency = msm_bedais_pp_params[be_idx].latency;
		if ((msm_bedais[be_idx].active) && compr_passthr_mode)
			adm_send_compressed_device_latency(port_id,
							   copp_idx,
@@ -15236,18 +15238,47 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx,
	return 0;
}
static bool msm_pcm_routing_test_pp_param(int be_idx, long param_bit)
{
	return test_bit(param_bit,
		&msm_bedais_pp_params[be_idx].pp_params_config);
}
static void msm_routing_set_pp_param(long param_bit, int value)
{
	int be_idx;
	if (value) {
		for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++)
			set_bit(param_bit,
				&msm_bedais_pp_params[be_idx].
				pp_params_config);
	} else {
		for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++)
			clear_bit(param_bit,
				&msm_bedais_pp_params[be_idx].
				pp_params_config);
	}
}
static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol,
					struct snd_ctl_elem_value *ucontrol)
{
	int pp_id = ucontrol->value.integer.value[0];
	int value = ucontrol->value.integer.value[1];
	int port_id = 0;
	int index, be_idx, i, topo_id, idx;
	int be_idx, i, topo_id, idx;
	bool mute;
	int latency;
	bool compr_passthr_mode = true;
	pr_debug("%s: pp_id: 0x%x\n", __func__, pp_id);
	if (pp_id == ADM_PP_PARAM_LIMITER_ID) {
		msm_routing_set_pp_param(ADM_PP_PARAM_LIMITER_BIT, value);
		goto done;
	}
	for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) {
		port_id = msm_bedais[be_idx].port_id;
		if (port_id == HDMI_RX || port_id == DISPLAY_PORT_RX)
@@ -15259,16 +15290,6 @@ static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol,
		return  -EINVAL;
	}
	for (index = 0; index < MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX; index++) {
		if (msm_bedais_pp_params[index].port_id == port_id)
			break;
	}
	if (index >= MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX) {
		pr_err("%s: Invalid pp params backend index %d\n",
			__func__, index);
		return -EINVAL;
	}
	for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions[0],
				MSM_FRONTEND_DAI_MM_SIZE) {
		if ((msm_bedais[be_idx].passthr_mode[i] == LEGACY_PCM) ||
@@ -15291,22 +15312,20 @@ static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol,
		switch (pp_id) {
		case ADM_PP_PARAM_MUTE_ID:
			pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__);
			mute = ucontrol->value.integer.value[1] ? true : false;
			msm_bedais_pp_params[index].mute_on = mute;
			mute = value ? true : false;
			msm_bedais_pp_params[be_idx].mute_on = mute;
			set_bit(ADM_PP_PARAM_MUTE_BIT,
				&msm_bedais_pp_params[index].pp_params_config);
				&msm_bedais_pp_params[be_idx].pp_params_config);
			if ((msm_bedais[be_idx].active) && compr_passthr_mode)
				adm_send_compressed_device_mute(port_id,
					idx, mute);
			break;
		case ADM_PP_PARAM_LATENCY_ID:
			pr_debug("%s: ADM_PP_PARAM_LATENCY\n", __func__);
			msm_bedais_pp_params[index].latency =
				ucontrol->value.integer.value[1];
			msm_bedais_pp_params[be_idx].latency = value;
			set_bit(ADM_PP_PARAM_LATENCY_BIT,
				&msm_bedais_pp_params[index].pp_params_config);
			latency = msm_bedais_pp_params[index].latency =
				ucontrol->value.integer.value[1];
				&msm_bedais_pp_params[be_idx].pp_params_config);
			latency = msm_bedais_pp_params[be_idx].latency = value;
			if ((msm_bedais[be_idx].active) && compr_passthr_mode)
				adm_send_compressed_device_latency(port_id,
					idx, latency);
@@ -15318,6 +15337,7 @@ static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol,
		}
		}
	}
done:
	return 0;
}
+13 −5
Original line number Diff line number Diff line
@@ -392,12 +392,20 @@ enum {
#define RELEASE_LOCK	0
#define ACQUIRE_LOCK	1

#define MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX	2
#define HDMI_RX_ID				0x8001
#define ADM_PP_PARAM_MUTE_ID			0
#define ADM_PP_PARAM_MUTE_BIT			1
#define ADM_PP_PARAM_LATENCY_ID			1
#define ADM_PP_PARAM_LATENCY_BIT		2

enum {
	ADM_PP_PARAM_MUTE_ID,
	ADM_PP_PARAM_LATENCY_ID,
	ADM_PP_PARAM_LIMITER_ID
};

enum {
	ADM_PP_PARAM_MUTE_BIT		= 0x1,
	ADM_PP_PARAM_LATENCY_BIT	= 0x2,
	ADM_PP_PARAM_LIMITER_BIT	= 0x4
};

#define BE_DAI_PORT_SESSIONS_IDX_MAX		4
#define BE_DAI_FE_SESSIONS_IDX_MAX		2

+100 −8
Original line number Diff line number Diff line
@@ -48,12 +48,6 @@
#define DS2_ADM_COPP_TOPOLOGY_ID 0xFFFFFFFF
#endif

/* ENUM for adm_status */
enum adm_cal_status {
	ADM_STATUS_CALIBRATION_REQUIRED = 0,
	ADM_STATUS_MAX,
};

struct adm_copp {

	atomic_t id[AFE_MAX_PORTS][MAX_COPPS_PER_PORT];
@@ -1413,6 +1407,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:
			case ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1:
				pr_debug("%s: Basic callback received, wake up.\n",
					__func__);
				atomic_set(&this_adm.copp.stat[port_idx]
@@ -2701,6 +2696,97 @@ fail_cmd:
	return;
}


static int adm_set_mtmx_params_v1(int port_idx, int copp_idx,
				  int params_length, void *params)
{
	struct adm_cmd_set_mtmx_params_v1 *adm_params = NULL;
	int rc = 0;
	int sz;

	sz = sizeof(*adm_params) + params_length;
	adm_params = kzalloc(sz, GFP_KERNEL);
	if (!adm_params)
		return -ENOMEM;

	memcpy(((u8 *)adm_params + sizeof(*adm_params)),
			params, params_length);
	adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
	adm_params->hdr.pkt_size = sz;
	adm_params->hdr.src_svc = APR_SVC_ADM;
	adm_params->hdr.src_domain = APR_DOMAIN_APPS;
	adm_params->hdr.src_port = 0;
	adm_params->hdr.dest_svc = APR_SVC_ADM;
	adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
	adm_params->hdr.dest_port =
			atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
	adm_params->hdr.token = port_idx << 16 | copp_idx;
	adm_params->hdr.opcode = ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1;
	adm_params->payload_addr_lsw = 0;
	adm_params->payload_addr_msw = 0;
	adm_params->mem_map_handle = 0;
	adm_params->payload_size = params_length;
	adm_params->copp_id = atomic_read(&this_adm.copp.
					  id[port_idx][copp_idx]);

	atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
	rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
	if (rc < 0) {
		pr_err("%s: Set params failed port_idx = 0x%x rc %d\n",
			__func__, port_idx, rc);
		rc = -EINVAL;
		goto send_param_return;
	}
	/* Wait for the callback */
	rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
		atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
		msecs_to_jiffies(TIMEOUT_MS));
	if (!rc) {
		pr_err("%s: Set params timed out port_idx = 0x%x\n",
			 __func__, port_idx);
		rc = -EINVAL;
		goto send_param_return;
	} else if (atomic_read(&this_adm.copp.stat
				[port_idx][copp_idx]) > 0) {
		pr_err("%s: DSP returned error[%s]\n",
				__func__, adsp_err_get_err_str(
				atomic_read(&this_adm.copp.stat
				[port_idx][copp_idx])));
		rc = adsp_err_get_lnx_err_code(
				atomic_read(&this_adm.copp.stat
					[port_idx][copp_idx]));
		goto send_param_return;
	}
	rc = 0;
send_param_return:
	kfree(adm_params);
	return rc;
}

static void adm_enable_mtmx_limiter(int port_idx, int copp_idx)
{
	int rc;
	struct enable_param_v6 adm_param = { {0} };

	adm_param.param.module_id = ADM_MTMX_MODULE_STREAM_LIMITER;
	adm_param.param.param_id = AUDPROC_PARAM_ID_ENABLE;
	adm_param.param.param_size = sizeof(adm_param.enable);
	adm_param.enable = 1;

	rc = adm_set_mtmx_params_v1(port_idx, copp_idx,
				    sizeof(adm_param), &adm_param);
	if (rc < 0) {
		pr_err("%s: adm_set_mtmx_params_v1 failed port_idx = 0x%x rc %d\n",
			__func__, port_idx, rc);
		goto done;
	}
	set_bit(ADM_STATUS_LIMITER,
		(void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
done:
	return;
}

static void route_set_opcode_matrix_id(
			struct adm_cmd_matrix_map_routings_v5 **route_addr,
			int path, uint32_t passthr_mode)
@@ -2797,6 +2883,11 @@ int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode,
		copp_idx = payload_map.copp_idx[i];
		copps_list[i] = atomic_read(&this_adm.copp.id[port_idx]
							     [copp_idx]);
		if (test_bit(ADM_STATUS_LIMITER,
		    (void *)&payload_map.route_status) &&
		    ((path == ADM_PATH_PLAYBACK) ||
		     (path == ADM_PATH_COMPRESSED_RX)))
			adm_enable_mtmx_limiter(port_idx, copp_idx);
	}
	atomic_set(&this_adm.matrix_map_stat, -1);

@@ -2997,6 +3088,8 @@ int adm_close(int port_id, int perf_mode, int copp_idx)

		clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
			(void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
		clear_bit(ADM_STATUS_LIMITER,
			(void *)&this_adm.copp.adm_status[port_idx][copp_idx]);

		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
		if (ret < 0) {
@@ -4813,8 +4906,7 @@ static int __init adm_init(void)
				&this_adm.copp.adm_delay_wait[i][j]);
			atomic_set(&this_adm.copp.topology[i][j], 0);
			this_adm.copp.adm_delay[i][j] = 0;
			this_adm.copp.adm_status[i][j] =
				ADM_STATUS_CALIBRATION_REQUIRED;
			this_adm.copp.adm_status[i][j] = 0;
		}
	}