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

Commit ef48ca58 authored by Walter Yang's avatar Walter Yang
Browse files

ASoC: wcd_cpe: Add CPE FTM feature



Add debugfs nodes for CPE FTM.
The callback will load the instruction and execute it.
CPE status will be retrieved and be read by userspace.
New CPE service command validation is added to guarantee
the concurrency of CPE FTM and normal CPE SVA detection.

Change-Id: I0748e357a21d873af5a85bbb80e982db0323beb7
Signed-off-by: default avatarWalter Yang <yandongy@codeaurora.org>
parent 8ca03863
Loading
Loading
Loading
Loading
+86 −6
Original line number Diff line number Diff line
@@ -108,7 +108,15 @@ static struct wcd_cmi_afe_port_data afe_ports[WCD_CPE_AFE_MAX_PORTS + 1];
static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param);
static int wcd_cpe_setup_irqs(struct wcd_cpe_core *core);
static void wcd_cpe_cleanup_irqs(struct wcd_cpe_core *core);
static ssize_t cpe_ftm_test_trigger(struct file *file,
				     const char __user *user_buf,
				     size_t count, loff_t *ppos);
static u32 ramdump_enable;
static u32 cpe_ftm_test_status;
static const struct file_operations cpe_ftm_test_trigger_fops = {
	.open = simple_open,
	.write = cpe_ftm_test_trigger,
};

static int wcd_cpe_afe_svc_cmd_mode(void *core_handle,
				    u8 mode);
@@ -372,6 +380,14 @@ static int wcd_cpe_enable_cpe_clks(struct wcd_cpe_core *core, bool enable)
		return ret;
	}

	if (!enable && core->cpe_clk_ref > 0)
		core->cpe_clk_ref--;

	/*
	 * CPE clk will be enabled at the first time
	 * and be disabled at the last time.
	 */
	if (core->cpe_clk_ref == 0) {
		ret = core->cpe_cdc_cb->cpe_clk_en(core->codec, enable);
		if (ret) {
			dev_err(core->dev,
@@ -379,6 +395,10 @@ static int wcd_cpe_enable_cpe_clks(struct wcd_cpe_core *core, bool enable)
				__func__, ret);
			goto cpe_clk_fail;
		}
	}

	if (enable)
		core->cpe_clk_ref++;

	return 0;

@@ -1650,6 +1670,22 @@ static int wcd_cpe_debugfs_init(struct wcd_cpe_core *core)
		goto err_create_entry;
	}

	if (!debugfs_create_file("cpe_ftm_test_trigger", S_IWUSR,
				dir, core, &cpe_ftm_test_trigger_fops)) {
		dev_err(core->dev, "%s: Failed to create debugfs node %s\n",
			__func__, "cpe_ftm_test_trigger");
		rc = -ENODEV;
		goto err_create_entry;
	}

	if (!debugfs_create_u32("cpe_ftm_test_status", S_IRUGO,
				dir, &cpe_ftm_test_status)) {
		dev_err(core->dev, "%s: Failed to create debugfs node %s\n",
			__func__, "cpe_ftm_test_status");
		rc = -ENODEV;
		goto err_create_entry;
	}

err_create_entry:
	debugfs_remove(dir);

@@ -1757,6 +1793,49 @@ done:
	return rc;
}

static ssize_t cpe_ftm_test_trigger(struct file *file,
				     const char __user *user_buf,
				     size_t count, loff_t *ppos)
{
	struct wcd_cpe_core *core = file->private_data;
	int ret = 0;

	/* Enable the clks for cpe */
	ret = wcd_cpe_enable_cpe_clks(core, true);
	if (IS_ERR_VALUE(ret)) {
		dev_err(core->dev,
			"%s: CPE clk enable failed, err = %d\n",
			__func__, ret);
		goto done;
	}

	/* Get the CPE_STATUS */
	ret = cpe_svc_ftm_test(core->cpe_handle, &cpe_ftm_test_status);
	if (IS_ERR_VALUE(ret)) {
		dev_err(core->dev,
			"%s: CPE FTM test failed, err = %d\n",
			__func__, ret);
		if (ret == CPE_SVC_BUSY) {
			cpe_ftm_test_status = 1;
			ret = 0;
		}
	}

	/* Disable the clks for cpe */
	ret = wcd_cpe_enable_cpe_clks(core, false);
	if (IS_ERR_VALUE(ret)) {
		dev_err(core->dev,
			"%s: CPE clk disable failed, err = %d\n",
			__func__, ret);
	}

done:
	if (ret < 0)
		return ret;
	else
		return count;
}

static int wcd_cpe_validate_params(
	struct snd_soc_codec *codec,
	struct wcd_cpe_params *params)
@@ -1844,6 +1923,7 @@ struct wcd_cpe_core *wcd_cpe_init(const char *img_fname,
	init_waitqueue_head(&core->ssr_entry.offline_poll_wait);
	mutex_init(&core->ssr_lock);
	core->cpe_users = 0;
	core->cpe_clk_ref = 0;

	/*
	 * By default, during probe, it is assumed that
+3 −0
Original line number Diff line number Diff line
@@ -182,6 +182,9 @@ struct wcd_cpe_core {

	/* Kobject for sysfs entry */
	struct kobject cpe_kobj;

	/* Reference count for cpe clk*/
	int cpe_clk_ref;
};

struct wcd_cpe_params {
+143 −0
Original line number Diff line number Diff line
@@ -141,6 +141,7 @@ enum cpe_command {
	CPE_LAB_CFG_SB,
	CPE_CMD_CANCEL_MEMACCESS,
	CPE_CMD_PROC_INCOMING_MSG,
	CPE_CMD_FTM_TEST,
};

enum cpe_process_result {
@@ -181,6 +182,11 @@ struct cpe_info {
	struct completion core_svc_cmd_compl;
};

struct cpe_tgt_waiti_info {
	u8 tgt_waiti_size;
	u8 *tgt_waiti_data;
};

struct cpe_svc_tgt_abstraction {
	enum cpe_svc_result (*tgt_boot) (int debug_mode);

@@ -218,6 +224,7 @@ struct cpe_svc_tgt_abstraction {
				(bool);
	u8 *inbox;
	u8 *outbox;
	struct cpe_tgt_waiti_info *tgt_waiti_info;
};

static enum cpe_svc_result cpe_tgt_tomtom_init(
@@ -1374,6 +1381,7 @@ static enum cpe_svc_result cpe_mt_validate_cmd(
		case CPE_CMD_PROCESS_IRQ:
		case CPE_CMD_KILL_THREAD:
		case CPE_CMD_DEINITIALIZE:
		case CPE_CMD_FTM_TEST:
			rc = CPE_SVC_SUCCESS;
			break;
		default:
@@ -1387,6 +1395,7 @@ static enum cpe_svc_result cpe_mt_validate_cmd(
		case CPE_CMD_RESET:
		case CPE_CMD_DL_SEGMENT:
		case CPE_CMD_BOOT:
		case CPE_CMD_FTM_TEST:
			rc = CPE_SVC_SUCCESS;
			break;
		default:
@@ -1403,6 +1412,9 @@ static enum cpe_svc_result cpe_mt_validate_cmd(
		case CPE_CMD_SHUTDOWN:
			rc = CPE_SVC_SUCCESS;
			break;
		case CPE_CMD_FTM_TEST:
			rc = CPE_SVC_BUSY;
			break;
		default:
			rc = CPE_SVC_NOT_READY;
			break;
@@ -1421,6 +1433,9 @@ static enum cpe_svc_result cpe_mt_validate_cmd(
		case CPE_CMD_PROC_INCOMING_MSG:
			rc = CPE_SVC_SUCCESS;
			break;
		case CPE_CMD_FTM_TEST:
			rc = CPE_SVC_BUSY;
			break;
		default:
			rc = CPE_SVC_FAILED;
			break;
@@ -1438,6 +1453,9 @@ static enum cpe_svc_result cpe_mt_validate_cmd(
		case CPE_CMD_PROC_INCOMING_MSG:
			rc = CPE_SVC_SUCCESS;
			break;
		case CPE_CMD_FTM_TEST:
			rc = CPE_SVC_BUSY;
			break;
		default:
			rc = CPE_SVC_FAILED;
			break;
@@ -1971,6 +1989,115 @@ enum cmi_api_result cmi_send_msg(void *message)
	return rc;
}

enum cpe_svc_result cpe_svc_ftm_test(void *cpe_handle, u32 *status)
{
	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
	struct cpe_svc_mem_segment backup_seg;
	struct cpe_svc_mem_segment waiti_seg;
	u8 *backup_data = NULL;

	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
	if (!t_info)
		t_info = cpe_d.cpe_default_handle;

	rc = cpe_is_command_valid(t_info, CPE_CMD_FTM_TEST);
	if (rc != CPE_SVC_SUCCESS) {
		pr_err("%s: cmd validation fail, cmd = %d\n",
			__func__, CPE_CMD_FTM_TEST);
		goto fail_cmd;
	}

	if (t_info && t_info->tgt) {
		backup_data = kzalloc(
				t_info->tgt->tgt_waiti_info->tgt_waiti_size,
				GFP_KERNEL);

		/* CPE reset */
		rc = t_info->tgt->tgt_reset();
		if (rc != CPE_SVC_SUCCESS) {
			pr_err("%s: CPE reset fail! err = %d\n",
				__func__, rc);
			goto err_return;
		}

		/* Back up the 4 byte IRAM data first */
		backup_seg.type = CPE_SVC_INSTRUCTION_MEM;
		backup_seg.cpe_addr =
			t_info->tgt->tgt_get_cpe_info()->IRAM_offset;
		backup_seg.size = t_info->tgt->tgt_waiti_info->tgt_waiti_size;
		backup_seg.data = backup_data;

		pr_debug("%s: Backing up IRAM data from CPE\n",
			__func__);

		rc = t_info->tgt->tgt_read_ram(t_info, &backup_seg);
		if (rc != CPE_SVC_SUCCESS) {
			pr_err("%s: Fail to backup CPE IRAM data, err = %d\n",
				__func__, rc);
			goto err_return;
		}

		pr_debug("%s: Complete backing up IRAM data from CPE\n",
			__func__);

		/* Write the WAITI instruction data */
		waiti_seg.type = CPE_SVC_INSTRUCTION_MEM;
		waiti_seg.cpe_addr =
			t_info->tgt->tgt_get_cpe_info()->IRAM_offset;
		waiti_seg.size = t_info->tgt->tgt_waiti_info->tgt_waiti_size;
		waiti_seg.data = t_info->tgt->tgt_waiti_info->tgt_waiti_data;

		rc = t_info->tgt->tgt_write_ram(t_info, &waiti_seg);
		if (rc != CPE_SVC_SUCCESS) {
			pr_err("%s: Fail to write the WAITI data, err = %d\n",
				__func__, rc);
			goto restore_iram;
		}

		/* Boot up cpe to execute the WAITI instructions */
		rc = t_info->tgt->tgt_boot(1);
		if (rc != CPE_SVC_SUCCESS) {
			pr_err("%s: Fail to boot CPE, err = %d\n",
				__func__, rc);
			goto reset;
		}

		/*
		 * 1ms delay is suggested by the hw team to
		 * wait for cpe to boot up.
		 */
		usleep_range(1000, 1100);

		/* Check if the cpe init is done after executing the WAITI */
		*status = t_info->tgt->tgt_cpar_init_done();

reset:
		/* Set the cpe back to reset state */
		rc = t_info->tgt->tgt_reset();
		if (rc != CPE_SVC_SUCCESS) {
			pr_err("%s: CPE reset fail! err = %d\n",
				__func__, rc);
			goto restore_iram;
		}

restore_iram:
		/* Restore the IRAM 4 bytes data */
		rc = t_info->tgt->tgt_write_ram(t_info, &backup_seg);
		if (rc != CPE_SVC_SUCCESS) {
			pr_err("%s: Fail to restore the IRAM data, err = %d\n",
				__func__, rc);
			goto err_return;
		}
	}

err_return:
	kfree(backup_data);
fail_cmd:
	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
	return rc;
}

static enum cpe_svc_result cpe_tgt_tomtom_boot(int debug_mode)
{
	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
@@ -2319,6 +2446,13 @@ static enum cpe_svc_result cpe_tgt_tomtom_deinit(
	return CPE_SVC_SUCCESS;
}

static u8 cpe_tgt_tomtom_waiti_data[] = {0x00, 0x70, 0x00, 0x00};

static struct cpe_tgt_waiti_info cpe_tgt_tomtom_waiti_info = {
	.tgt_waiti_size = ARRAY_SIZE(cpe_tgt_tomtom_waiti_data),
	.tgt_waiti_data = cpe_tgt_tomtom_waiti_data,
};

static enum cpe_svc_result cpe_tgt_tomtom_init(
		struct cpe_svc_codec_info_v1 *codec_info,
		struct cpe_svc_tgt_abstraction *param)
@@ -2343,6 +2477,7 @@ static enum cpe_svc_result cpe_tgt_tomtom_init(
		param->tgt_get_cpe_info = cpe_tgt_tomtom_get_cpe_info;
		param->tgt_deinit = cpe_tgt_tomtom_deinit;
		param->tgt_voice_tx_lab = cpe_tgt_tomtom_voicetx;
		param->tgt_waiti_info = &cpe_tgt_tomtom_waiti_info;

		param->inbox = kzalloc(TOMTOM_A_SVASS_SPE_INBOX_SIZE,
				       GFP_KERNEL);
@@ -2753,6 +2888,13 @@ static enum cpe_svc_result
	return rc;
}

static u8 cpe_tgt_wcd9335_waiti_data[] = {0x00, 0x70, 0x00, 0x00};

static struct cpe_tgt_waiti_info cpe_tgt_wcd9335_waiti_info = {
	.tgt_waiti_size = ARRAY_SIZE(cpe_tgt_wcd9335_waiti_data),
	.tgt_waiti_data = cpe_tgt_wcd9335_waiti_data,
};

static enum cpe_svc_result cpe_tgt_wcd9335_init(
		struct cpe_svc_codec_info_v1 *codec_info,
		struct cpe_svc_tgt_abstraction *param)
@@ -2777,6 +2919,7 @@ static enum cpe_svc_result cpe_tgt_wcd9335_init(
		param->tgt_get_cpe_info = cpe_tgt_wcd9335_get_cpe_info;
		param->tgt_deinit = cpe_tgt_wcd9335_deinit;
		param->tgt_voice_tx_lab = cpe_tgt_wcd9335_voicetx;
		param->tgt_waiti_info = &cpe_tgt_wcd9335_waiti_info;

		param->inbox = kzalloc(WCD9335_CPE_SS_SPE_INBOX_SIZE,
				       GFP_KERNEL);
+2 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ enum cpe_svc_result {
	CPE_SVC_INVALID_HANDLE		= -EINVAL,
	CPE_SVC_NOT_READY		= -ENOTREADY,
	CPE_SVC_SHUTTING_DOWN		= -ESHUTDOWN,
	CPE_SVC_BUSY			= -EBUSY,
};

enum cpe_svc_event {
@@ -174,4 +175,5 @@ enum cpe_svc_result cpe_svc_set_debug_mode(void *cpe_handle, u32 mode);

const struct cpe_svc_hw_cfg *cpe_svc_get_hw_cfg(void *cpe_handle);
enum cpe_svc_result cpe_svc_toggle_lab(void *cpe_handle, bool enable);
enum cpe_svc_result cpe_svc_ftm_test(void *cpe_handle, u32 *status);
#endif /*__CPE_SERVICES__*/