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

Commit c7034ffa authored by Prasad Sodagudi's avatar Prasad Sodagudi Committed by Gerrit - the friendly Code Review server
Browse files

soc: qcom: spcom: Provide retry mechanism for spss



On some SoCs, spss may be brought out of reset during
bootloader stage. Sometimes spss might be cashed during
the device boot due to some faults in spss firmware. When
spcom tried to boot the spss first time in the kernel stage,
it might be already crashed. So provide the retry
mechanism to load the firmwares and to bring out of reset.

Also, remove sending interrupt on link up to SPSS, since it
was workaround.

Change-Id: I81c1932527c02bfecdfd1cf0c126d18df0e57e57
Signed-off-by: default avatarPrasad Sodagudi <psodagud@codeaurora.org>
Signed-off-by: default avatarPrakruthi Deepak Heragu <pheragu@codeaurora.org>
Signed-off-by: default avatarKonstantin Dorfman <kdorfman@codeaurora.org>
parent 6dfa423a
Loading
Loading
Loading
Loading
+14 −182
Original line number Diff line number Diff line
@@ -271,26 +271,13 @@ struct spcom_device {

	int32_t nvm_ion_fd;
	struct mutex ioctl_lock;
	atomic_t subsys_req;
};

/* Device Driver State */
static struct spcom_device *spcom_dev;
static void *spcom_ipc_log_context;

/* Physical address of SP2SOC RMB shared register */
/* SP_SCSR_RMB_SP2SOC_IRQ_SET_ADDR */
static u32 spcom_sp2soc_rmb_reg_addr;
/* SP_SCSR_SP2SOC_IRQ_SET_SW_INIT_DONE_BMSK */
static u32 spcom_sp2soc_initdone_mask;
/* SP_SCSR_SP2SOC_IRQ_SET_PBL_DONE_BMSK */
static u32 spcom_sp2soc_pbldone_mask;

/* Physical address of SOC2SP RMB shared register */
/* SP_SCSR_RMB_SOC2SP_IRQ_SET_ADDR */
static u32 spcom_soc2sp_rmb_reg_addr;
/* Bit used by spcom kernel for indicating SSR to SP */
static u32 spcom_soc2sp_rmb_sp_ssr_mask;

/* static functions declaration */
static int spcom_create_channel_chardev(const char *name, bool is_sharable);
static int spcom_destroy_channel_chardev(const char *name);
@@ -298,9 +285,6 @@ static struct spcom_channel *spcom_find_channel_by_name(const char *name);
static int spcom_register_rpmsg_drv(struct spcom_channel *ch);
static int spcom_unregister_rpmsg_drv(struct spcom_channel *ch);

/* PIL's original SSR function*/
int (*desc_powerup)(const struct subsys_desc *) = NULL;

/**
 * spcom_is_channel_open() - channel is open on this side.
 *
@@ -641,47 +625,6 @@ static int spcom_handle_create_channel_command(void *cmd_buf, int cmd_size)
	return ret;
}

/**
 * spcom_local_powerup() - Helper function that causes PIL boot to skip
 * powerup. This function sets the INIT DONE register.
 *
 * @subsys: subsystem descriptor.
 *
 * Return: 0 on successful operation, negative value otherwise.
 */
static int spcom_local_powerup(const struct subsys_desc *subsys)
{
	void __iomem *regs;

	regs = ioremap_nocache(spcom_sp2soc_rmb_reg_addr, sizeof(u32));
	if (!regs)
		return -ENOMEM;

	writel_relaxed(spcom_sp2soc_pbldone_mask|spcom_sp2soc_initdone_mask,
		regs);
	iounmap(regs);
	spcom_pr_dbg("spcom local powerup - SPSS cold boot\n");
	return 0;
}

/**
 * spcom_local_powerup_after_fota() - SSR is not allowed after FOTA -
 * might cause cryptographic erase. Reset the device
 *
 * @subsys: subsystem descriptor.
 *
 * Return: 0 on successful operation, negative value otherwise.
 */
static int spcom_local_powerup_after_fota(const struct subsys_desc *subsys)
{
	(void)subsys;

	spcom_pr_err("SSR after firmware update before calling IAR update - panic\n");
	panic("SSR after SPU firmware update\n");

	return 0;
}

/**
 * spcom_handle_restart_sp_command() - Handle Restart SP command from
 * user space.
@@ -695,8 +638,6 @@ static int spcom_handle_restart_sp_command(void *cmd_buf, int cmd_size)
{
	void *subsystem_get_retval = NULL;
	struct spcom_user_restart_sp_command *cmd = cmd_buf;
	struct subsys_desc *desc_p = NULL;
	int (*desc_powerup)(const struct subsys_desc *) = NULL;

	if (!cmd) {
		spcom_pr_err("NULL cmd_buf\n");
@@ -712,51 +653,16 @@ static int spcom_handle_restart_sp_command(void *cmd_buf, int cmd_size)
	spcom_pr_dbg("restart - PIL FW loading initiated: preloaded=%d\n",
		cmd->arg);

	if (cmd->arg) {
		subsystem_get_retval = find_subsys_device("spss");
		if (!subsystem_get_retval) {
			spcom_pr_err("restart - no device\n");
			return -ENODEV;
		}

		desc_p = *(struct subsys_desc **)subsystem_get_retval;
		if (!desc_p) {
			spcom_pr_err("restart - no device\n");
			return -ENODEV;
		}

		spcom_pr_dbg("restart - Name: %s FW name: %s Depends on: %s\n",
			desc_p->name, desc_p->fw_name, desc_p->pon_depends_on);
		desc_powerup = desc_p->powerup;
		/**
		 * Overwrite the subsys PIL powerup function with an spcom
		 * internal function which causes PIL to skip calling the
		 * PIL boot function. This is done because SP is already
		 * loaded in UEFI state and we do not want PIL to start
		 * loading the SP again. We still want to let PIL perform
		 * everything else wrt SP - hence calling the subsystem_get
		 * API with a spcom internal function that only writes the
		 * INIT DONE register on behalf of SP. Once done with this,
		 * we shall reset the PIL subsys power up function so that
		 * we let the PIL subsys to load/boot SP upon SSR
		 */
		desc_p->powerup = spcom_local_powerup;
	}

	subsystem_get_retval = subsystem_get("spss");
	if (!subsystem_get_retval) {
		spcom_pr_err("restart - unable to trigger PIL process for FW loading\n");
		return -EINVAL;
	if (IS_ERR_OR_NULL(subsystem_get_retval)) {
		spcom_pr_err("restart - spss crashed during device bootup\n");
		if (atomic_cmpxchg(&spcom_dev->subsys_req, 1, 0)) {
			subsystem_get_retval = subsystem_get("spss");
			if (IS_ERR_OR_NULL(subsystem_get_retval)) {
				spcom_pr_err("spss - restart - Failed start\n");
				return -ENODEV;
			}

	if (cmd->arg) {

		/* SPU got firmware update. Don't allow SSR*/
		if (cmd->is_updated) {
			desc_p->powerup = spcom_local_powerup_after_fota;
		} else {
			/* Reset the PIL subsystem power up function */
			desc_p->powerup = desc_powerup;
			spcom_pr_info("restart - spss started.\n");
		}
	}
	spcom_pr_dbg("restart - PIL FW loading process is complete\n");
@@ -1237,28 +1143,7 @@ static int spcom_handle_unlock_ion_buf_command(struct spcom_channel *ch,
 */
static int spcom_handle_enable_ssr_command(void)
{
	struct subsys_desc *desc_p = NULL;
	void *subsystem_get_retval = find_subsys_device("spss");

	if (!subsystem_get_retval) {
		spcom_pr_err("restart - no device\n");
		return -ENODEV;
	}

	desc_p = *(struct subsys_desc **)subsystem_get_retval;
	if (!desc_p) {
		spcom_pr_err("restart - no device\n");
		return -ENODEV;
	}

	if (!desc_powerup) {
		spcom_pr_err("no original SSR function\n");
		return -ENODEV;
	}

	desc_p->powerup = desc_powerup;
	spcom_pr_info("SSR is enabled after FOTA\n");

	spcom_pr_info("TBD: SSR is enabled after FOTA\n");
	return 0;
}

@@ -1893,8 +1778,6 @@ static inline int handle_poll(struct file *file,
	const char *name = file_to_filename(file);
	int ready = 0;
	int ret = 0;
	void __iomem *regs;


	switch (op->cmd_id) {
	case SPCOM_LINK_STATE_REQ:
@@ -1904,15 +1787,6 @@ static inline int handle_poll(struct file *file,
					  &spcom_dev->rpmsg_state_change);
			spcom_pr_dbg("ch [%s] link state change signaled\n",
				     name);
			regs = ioremap_nocache(spcom_soc2sp_rmb_reg_addr,
					sizeof(u32));
			if (regs) {
				writel_relaxed(spcom_soc2sp_rmb_sp_ssr_mask,
					regs);
				iounmap(regs);
			} else {
				spcom_pr_err("failed to set register indicating SSR\n");
			}
		}
		op->retval = atomic_read(&spcom_dev->rpmsg_dev_count) > 0;
		break;
@@ -2210,51 +2084,6 @@ static int spcom_parse_dt(struct device_node *np)
	int num_ch;
	int i;
	const char *name;
	u32 sp2soc_rmb_pbldone_bit = 0;
	u32 sp2soc_rmb_initdone_bit = 0;
	u32 soc2sp_rmb_sp_ssr_bit = 0;

	/* Read SP HLOS SCSR RMB IRQ register address */
	ret = of_property_read_u32(np, "qcom,spcom-sp2soc-rmb-reg-addr",
		&spcom_sp2soc_rmb_reg_addr);
	if (ret < 0) {
		spcom_pr_err("can't get sp2soc rmb reg addr\n");
		return ret;
	}

	ret = of_property_read_u32(np, "qcom,spcom-sp2soc-rmb-pbldone-bit",
		&sp2soc_rmb_pbldone_bit);
	if (ret < 0) {
		spcom_pr_err("can't get sp2soc rmb pbl done bit\n");
		return ret;
	}

	ret = of_property_read_u32(np, "qcom,spcom-sp2soc-rmb-initdone-bit",
		&sp2soc_rmb_initdone_bit);
	if (ret < 0) {
		spcom_pr_err("can't get sp2soc rmb sw init done bit\n");
		return ret;
	}

	spcom_sp2soc_pbldone_mask = BIT(sp2soc_rmb_pbldone_bit);
	spcom_sp2soc_initdone_mask = BIT(sp2soc_rmb_initdone_bit);

	/* Read SOC 2 SP SCSR RMB IRQ register address */
	ret = of_property_read_u32(np, "qcom,spcom-soc2sp-rmb-reg-addr",
		&spcom_soc2sp_rmb_reg_addr);
	if (ret < 0) {
		spcom_pr_err("can't get soc2sp rmb reg addr\n");
		return ret;
	}

	ret = of_property_read_u32(np, "qcom,spcom-soc2sp-rmb-sp-ssr-bit",
		&soc2sp_rmb_sp_ssr_bit);
	if (ret < 0) {
		spcom_pr_err("can't get soc2sp rmb SP SSR bit\n");
		return ret;
	}

	spcom_soc2sp_rmb_sp_ssr_mask = BIT(soc2sp_rmb_sp_ssr_bit);

	/* Get predefined channels info */
	num_ch = of_property_count_strings(np, propname);
@@ -2609,6 +2438,9 @@ static int spcom_probe(struct platform_device *pdev)
	if (ret < 0)
		goto fail_reg_chardev;

	if (of_property_read_bool(np, "qcom,boot-enabled"))
		atomic_set(&dev->subsys_req, 1);

	ret = spcom_create_predefined_channels_chardev();
	if (ret < 0) {
		pr_err("create character device failed\n");