static int q6v5_mba_load()

in qcom_q6v5_mss.c [1003:1164]


static int q6v5_mba_load(struct q6v5 *qproc)
{
	int ret;
	int xfermemop_ret;
	bool mba_load_err = false;

	ret = qcom_q6v5_prepare(&qproc->q6v5);
	if (ret)
		return ret;

	ret = q6v5_pds_enable(qproc, qproc->proxy_pds, qproc->proxy_pd_count);
	if (ret < 0) {
		dev_err(qproc->dev, "failed to enable proxy power domains\n");
		goto disable_irqs;
	}

	ret = q6v5_regulator_enable(qproc, qproc->fallback_proxy_regs,
				    qproc->fallback_proxy_reg_count);
	if (ret) {
		dev_err(qproc->dev, "failed to enable fallback proxy supplies\n");
		goto disable_proxy_pds;
	}

	ret = q6v5_regulator_enable(qproc, qproc->proxy_regs,
				    qproc->proxy_reg_count);
	if (ret) {
		dev_err(qproc->dev, "failed to enable proxy supplies\n");
		goto disable_fallback_proxy_reg;
	}

	ret = q6v5_clk_enable(qproc->dev, qproc->proxy_clks,
			      qproc->proxy_clk_count);
	if (ret) {
		dev_err(qproc->dev, "failed to enable proxy clocks\n");
		goto disable_proxy_reg;
	}

	ret = q6v5_regulator_enable(qproc, qproc->active_regs,
				    qproc->active_reg_count);
	if (ret) {
		dev_err(qproc->dev, "failed to enable supplies\n");
		goto disable_proxy_clk;
	}

	ret = q6v5_clk_enable(qproc->dev, qproc->reset_clks,
			      qproc->reset_clk_count);
	if (ret) {
		dev_err(qproc->dev, "failed to enable reset clocks\n");
		goto disable_vdd;
	}

	ret = q6v5_reset_deassert(qproc);
	if (ret) {
		dev_err(qproc->dev, "failed to deassert mss restart\n");
		goto disable_reset_clks;
	}

	ret = q6v5_clk_enable(qproc->dev, qproc->active_clks,
			      qproc->active_clk_count);
	if (ret) {
		dev_err(qproc->dev, "failed to enable clocks\n");
		goto assert_reset;
	}

	ret = q6v5proc_enable_qchannel(qproc, qproc->halt_map, qproc->qaccept_axi);
	if (ret) {
		dev_err(qproc->dev, "failed to enable axi bridge\n");
		goto disable_active_clks;
	}

	/*
	 * Some versions of the MBA firmware will upon boot wipe the MPSS region as well, so provide
	 * the Q6 access to this region.
	 */
	ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, false, true,
				      qproc->mpss_phys, qproc->mpss_size);
	if (ret) {
		dev_err(qproc->dev, "assigning Q6 access to mpss memory failed: %d\n", ret);
		goto disable_active_clks;
	}

	/* Assign MBA image access in DDR to q6 */
	ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, false, true,
				      qproc->mba_phys, qproc->mba_size);
	if (ret) {
		dev_err(qproc->dev,
			"assigning Q6 access to mba memory failed: %d\n", ret);
		goto disable_active_clks;
	}

	writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
	if (qproc->dp_size) {
		writel(qproc->mba_phys + SZ_1M, qproc->rmb_base + RMB_PMI_CODE_START_REG);
		writel(qproc->dp_size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
	}

	ret = q6v5proc_reset(qproc);
	if (ret)
		goto reclaim_mba;

	ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
	if (ret == -ETIMEDOUT) {
		dev_err(qproc->dev, "MBA boot timed out\n");
		goto halt_axi_ports;
	} else if (ret != RMB_MBA_XPU_UNLOCKED &&
		   ret != RMB_MBA_XPU_UNLOCKED_SCRIBBLED) {
		dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret);
		ret = -EINVAL;
		goto halt_axi_ports;
	}

	qproc->dump_mba_loaded = true;
	return 0;

halt_axi_ports:
	q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
	if (qproc->has_vq6)
		q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_vq6);
	q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
	q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
	q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_mdm);
	q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_cx);
	q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_axi);
	mba_load_err = true;
reclaim_mba:
	xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true,
						false, qproc->mba_phys,
						qproc->mba_size);
	if (xfermemop_ret) {
		dev_err(qproc->dev,
			"Failed to reclaim mba buffer, system may become unstable\n");
	} else if (mba_load_err) {
		q6v5_dump_mba_logs(qproc);
	}

disable_active_clks:
	q6v5_clk_disable(qproc->dev, qproc->active_clks,
			 qproc->active_clk_count);
assert_reset:
	q6v5_reset_assert(qproc);
disable_reset_clks:
	q6v5_clk_disable(qproc->dev, qproc->reset_clks,
			 qproc->reset_clk_count);
disable_vdd:
	q6v5_regulator_disable(qproc, qproc->active_regs,
			       qproc->active_reg_count);
disable_proxy_clk:
	q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
			 qproc->proxy_clk_count);
disable_proxy_reg:
	q6v5_regulator_disable(qproc, qproc->proxy_regs,
			       qproc->proxy_reg_count);
disable_fallback_proxy_reg:
	q6v5_regulator_disable(qproc, qproc->fallback_proxy_regs,
			       qproc->fallback_proxy_reg_count);
disable_proxy_pds:
	q6v5_pds_disable(qproc, qproc->proxy_pds, qproc->proxy_pd_count);
disable_irqs:
	qcom_q6v5_unprepare(&qproc->q6v5);

	return ret;
}