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

Commit db58c58a authored by Pradnya Chaphekar's avatar Pradnya Chaphekar
Browse files

ASoC: msm: qdsp6v2: Propagate device HW delay to AFE



HW delay for each supported device is maintained in ACDB. This needs
to be propagated to AFE for timestamp calculation in voice path. AFE
provides device HW and SW delays to CVD, based on which timestamps
are calculated for voice packets.

Change-Id: I959676c1ee4e0568e661e7666a61c98152344047
Signed-off-by: default avatarPradnya Chaphekar <pradnyac@codeaurora.org>
parent 795c7f2e
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -1998,6 +1998,14 @@ struct afe_param_id_pseudo_port_cfg {
	 */
} __packed;

#define AFE_PARAM_ID_DEVICE_HW_DELAY     0x00010243
#define AFE_API_VERSION_DEVICE_HW_DELAY  0x1

struct afe_param_id_device_hw_delay_cfg {
	uint32_t    device_hw_delay_minor_version;
	uint32_t    delay_in_us;
} __packed;

union afe_port_config {
	struct afe_param_id_pcm_cfg               pcm;
	struct afe_param_id_i2s_cfg               i2s;
@@ -2006,6 +2014,7 @@ union afe_port_config {
	struct afe_param_id_rt_proxy_port_cfg     rtproxy;
	struct afe_param_id_internal_bt_fm_cfg    int_bt_fm;
	struct afe_param_id_pseudo_port_cfg       pseudo_port;
	struct afe_param_id_device_hw_delay_cfg   hw_delay;
} __packed;

struct afe_audioif_config_command_no_payload {
+9 −0
Original line number Diff line number Diff line
@@ -63,6 +63,10 @@
			(AUDIO_MAX_COMMON_IOCTL_NUM+28), unsigned)
#define AUDIO_DEREGISTER_VOCPROC_VOL_TABLE	_IOW(AUDIO_IOCTL_MAGIC, \
			(AUDIO_MAX_COMMON_IOCTL_NUM+29), unsigned)
#define AUDIO_SET_HW_DELAY_RX	_IOW(AUDIO_IOCTL_MAGIC, \
			(AUDIO_MAX_COMMON_IOCTL_NUM+30), struct hw_delay)
#define AUDIO_SET_HW_DELAY_TX	_IOW(AUDIO_IOCTL_MAGIC, \
			(AUDIO_MAX_COMMON_IOCTL_NUM+31), struct hw_delay)
#define	AUDIO_MAX_ACDB_IOCTL	(AUDIO_MAX_COMMON_IOCTL_NUM+40)

/* ACDB structures */
@@ -96,6 +100,11 @@ struct msm_spk_prot_status {
	int status;
};

struct hw_delay {
	uint32_t num_entries;
	void *delay_info;
};

/* For Real-Time Audio Calibration */
#define AUDIO_GET_RTAC_ADM_INFO		_IOR(AUDIO_IOCTL_MAGIC, \
			(AUDIO_MAX_ACDB_IOCTL+1), unsigned)
+153 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#define NUM_VOCPROC_BLOCKS		(6 * MAX_NETWORKS)
#define ACDB_TOTAL_VOICE_ALLOCATION	(ACDB_BLOCK_SIZE * NUM_VOCPROC_BLOCKS)

#define MAX_HW_DELAY_ENTRIES	25

struct sidetone_atomic_cal {
	atomic_t	enable;
@@ -98,6 +99,10 @@ struct acdb_data {

	/* Speaker protection */
	struct msm_spk_prot_cfg spk_prot_cfg;

	/* Av sync delay info */
	struct hw_delay hw_delay_rx;
	struct hw_delay hw_delay_tx;
};

static struct acdb_data		acdb_data;
@@ -371,6 +376,122 @@ done:
	return result;
}

int get_hw_delay(int32_t path, struct hw_delay_entry *entry)
{
	int i, result = 0;
	struct hw_delay *delay = NULL;
	struct hw_delay_entry *info = NULL;
	pr_debug("%s,\n", __func__);

	if (entry == NULL) {
		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
		result = -EINVAL;
		goto ret;
	}
	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
		       __func__, path);
		result = -EINVAL;
		goto ret;
	}
	mutex_lock(&acdb_data.acdb_mutex);
	if (path == RX_CAL)
		delay = &acdb_data.hw_delay_rx;
	else if (path == TX_CAL)
		delay = &acdb_data.hw_delay_tx;

	if ((delay == NULL) || ((delay != NULL) && delay->num_entries == 0)) {
		pr_err("ACDB=> %s Invalid delay/ delay entries\n", __func__);
		result = -EINVAL;
		goto done;
	}

	info = (struct hw_delay_entry *)(delay->delay_info);
	if (info == NULL) {
		pr_err("ACDB=> %s Delay entries info is NULL\n", __func__);
		result = -EFAULT;
		goto done;
	}
	for (i = 0; i < delay->num_entries; i++) {
		if (info[i].sample_rate == entry->sample_rate) {
			entry->delay_usec = info[i].delay_usec;
			break;
		}
	}
	if (i == delay->num_entries) {
		pr_err("ACDB=> %s: Unable to find delay for sample rate %d\n",
		       __func__, entry->sample_rate);
		result = -EFAULT;
	}

done:
	mutex_unlock(&acdb_data.acdb_mutex);
ret:
	pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
		 __func__, path, entry->sample_rate, entry->delay_usec, result);
	return result;
}

int store_hw_delay(int32_t path, void *arg)
{
	int result = 0;
	struct hw_delay delay;
	struct hw_delay *delay_dest = NULL;
	pr_debug("%s,\n", __func__);

	if ((path >= MAX_AUDPROC_TYPES) || (path < 0) || (arg == NULL)) {
		pr_err("ACDB=> Bad path/ pointer sent to %s, path: %d\n",
		      __func__, path);
		result = -EINVAL;
		goto done;
	}
	result = copy_from_user((void *)&delay, (void *)arg,
				sizeof(struct hw_delay));
	if (result) {
		pr_err("ACDB=> %s failed to copy hw delay: result=%d path=%d\n",
		       __func__, result, path);
		result = -EFAULT;
		goto done;
	}
	if ((delay.num_entries <= 0) ||
		(delay.num_entries > MAX_HW_DELAY_ENTRIES)) {
		pr_err("ACDB=> %s incorrect no of hw delay entries: %d\n",
		       __func__, delay.num_entries);
		result = -EINVAL;
		goto done;
	}
	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
		__func__, path);
		result = -EINVAL;
		goto done;
	}

	pr_debug("ACDB=> %s : Path = %d num_entries = %d\n",
		 __func__, path, delay.num_entries);

	mutex_lock(&acdb_data.acdb_mutex);
	if (path == RX_CAL)
		delay_dest = &acdb_data.hw_delay_rx;
	else if (path == TX_CAL)
		delay_dest = &acdb_data.hw_delay_tx;

	delay_dest->num_entries = delay.num_entries;

	result = copy_from_user(delay_dest->delay_info,
				delay.delay_info,
				(sizeof(struct hw_delay_entry)*
				delay.num_entries));
	if (result) {
		pr_err("ACDB=> %s failed to copy hw delay info res=%d path=%d",
		       __func__, result, path);
		result = -EFAULT;
	}
	mutex_unlock(&acdb_data.acdb_mutex);
done:
	return result;
}

int get_anc_cal(struct acdb_cal_block *cal_block)
{
	int result = 0;
@@ -998,6 +1119,29 @@ static int acdb_open(struct inode *inode, struct file *f)
	atomic_set(&acdb_data.valid_adm_custom_top, 1);
	atomic_set(&acdb_data.valid_asm_custom_top, 1);
	atomic_inc(&usage_count);

	/* Allocate memory for hw delay entries */
	mutex_lock(&acdb_data.acdb_mutex);
	acdb_data.hw_delay_rx.num_entries = 0;
	acdb_data.hw_delay_tx.num_entries = 0;
	acdb_data.hw_delay_rx.delay_info =
				kmalloc(sizeof(struct hw_delay_entry)*
					MAX_HW_DELAY_ENTRIES,
					GFP_KERNEL);
	if (acdb_data.hw_delay_rx.delay_info == NULL) {
		pr_err("%s : Failed to allocate av sync delay entries rx\n",
			__func__);
	}
	acdb_data.hw_delay_tx.delay_info =
				kmalloc(sizeof(struct hw_delay_entry)*
					MAX_HW_DELAY_ENTRIES,
					GFP_KERNEL);
	if (acdb_data.hw_delay_tx.delay_info == NULL) {
		pr_err("%s : Failed to allocate av sync delay entries tx\n",
			__func__);
	}
	mutex_unlock(&acdb_data.acdb_mutex);

	return result;
}

@@ -1238,6 +1382,12 @@ static long acdb_ioctl(struct file *f,
	case AUDIO_DEREGISTER_VOCPROC_VOL_TABLE:
		result = deregister_vocvol_table();
		goto done;
	case AUDIO_SET_HW_DELAY_RX:
		result = store_hw_delay(RX_CAL, (void *)arg);
		goto done;
	case AUDIO_SET_HW_DELAY_TX:
		result = store_hw_delay(TX_CAL, (void *)arg);
		goto done;
	}

	if (copy_from_user(&size, (void *) arg, sizeof(size))) {
@@ -1393,6 +1543,9 @@ static int acdb_release(struct inode *inode, struct file *f)
	else
		result = deregister_memory();

	kfree(acdb_data.hw_delay_rx.delay_info);
	kfree(acdb_data.hw_delay_tx.delay_info);

	return result;
}

+6 −0
Original line number Diff line number Diff line
@@ -41,6 +41,11 @@ struct acdb_atomic_cal_block {
	atomic_t		cal_paddr;
};

struct hw_delay_entry {
	uint32_t sample_rate;
	uint32_t delay_usec;
};

uint32_t get_voice_rx_topology(void);
uint32_t get_voice_tx_topology(void);
uint32_t get_adm_rx_topology(void);
@@ -65,5 +70,6 @@ int get_vocvol_cal(struct acdb_cal_block *cal_block);
int get_sidetone_cal(struct sidetone_cal *cal_data);
int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
int get_aanc_cal(struct acdb_cal_block *cal_block);
int get_hw_delay(int32_t path, struct hw_delay_entry *delay_info);

#endif
+67 −0
Original line number Diff line number Diff line
@@ -632,6 +632,72 @@ static void afe_send_cal_spkr_prot_rx(int port_id)
	}
}

static int afe_send_hw_delay(u16 port_id, u32 rate)
{
	struct hw_delay_entry delay_entry;
	struct afe_audioif_config_command config;
	int index = 0;
	int ret = -EINVAL;

	pr_debug("%s\n", __func__);

	delay_entry.sample_rate = rate;
	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
		ret = get_hw_delay(TX_CAL, &delay_entry);
	else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
		ret = get_hw_delay(RX_CAL, &delay_entry);

	if (ret != 0) {
		pr_warn("%s: Failed to get hw delay info\n", __func__);
		goto fail_cmd;
	}

	index = q6audio_get_port_index(port_id);
	if (index < 0) {
		pr_debug("%s: AFE port index invalid!\n", __func__);
		goto fail_cmd;
	}

	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
	config.hdr.pkt_size = sizeof(config);
	config.hdr.src_port = 0;
	config.hdr.dest_port = 0;
	config.hdr.token = index;

	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
	config.param.port_id = q6audio_get_port_id(port_id);
	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
				    sizeof(config.param);
	config.param.payload_address_lsw = 0x00;
	config.param.payload_address_msw = 0x00;
	config.param.mem_map_handle = 0x00;
	config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
	config.pdata.param_id = AFE_PARAM_ID_DEVICE_HW_DELAY;
	config.pdata.param_size = sizeof(config.port);

	config.port.hw_delay.delay_in_us = delay_entry.delay_usec;
	config.port.hw_delay.device_hw_delay_minor_version =
				AFE_API_VERSION_DEVICE_HW_DELAY;

	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
	if (ret) {
		pr_err("%s: AFE hw delay for port %#x failed\n",
		       __func__, port_id);
		goto fail_cmd;
	} else if (atomic_read(&this_afe.status) != 0) {
		pr_err("%s: config cmd failed\n", __func__);
		ret = -EINVAL;
		goto fail_cmd;
	}

fail_cmd:
	pr_debug("%s port_id %u rate %u delay_usec %d status %d\n",
	__func__, port_id, rate, delay_entry.delay_usec, ret);
	return ret;

}

void afe_send_cal(u16 port_id)
{
	pr_debug("%s\n", __func__);
@@ -1248,6 +1314,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config,
		return ret;

	afe_send_cal(port_id);
	afe_send_hw_delay(port_id, rate);

	/* Start SW MAD module */
	mad_type = afe_port_get_mad_type(port_id);