static int q6v5_wcss_qcs404_power_on()

in qcom_q6v5_wcss.c [294:438]


static int q6v5_wcss_qcs404_power_on(struct q6v5_wcss *wcss)
{
	unsigned long val;
	int ret, idx;

	/* Toggle the restart */
	reset_control_assert(wcss->wcss_reset);
	usleep_range(200, 300);
	reset_control_deassert(wcss->wcss_reset);
	usleep_range(200, 300);

	/* Enable GCC_WDSP_Q6SS_AHBS_CBCR clock */
	ret = clk_prepare_enable(wcss->gcc_abhs_cbcr);
	if (ret)
		return ret;

	/* Remove reset to the WCNSS QDSP6SS */
	reset_control_deassert(wcss->wcss_q6_bcr_reset);

	/* Enable Q6SSTOP_AHBFABRIC_CBCR clock */
	ret = clk_prepare_enable(wcss->ahbfabric_cbcr_clk);
	if (ret)
		goto disable_gcc_abhs_cbcr_clk;

	/* Enable the LCCCSR CBC clock, Q6SSTOP_Q6SSTOP_LCC_CSR_CBCR clock */
	ret = clk_prepare_enable(wcss->lcc_csr_cbcr);
	if (ret)
		goto disable_ahbfabric_cbcr_clk;

	/* Enable the Q6AHBS CBC, Q6SSTOP_Q6SS_AHBS_CBCR clock */
	ret = clk_prepare_enable(wcss->ahbs_cbcr);
	if (ret)
		goto disable_csr_cbcr_clk;

	/* Enable the TCM slave CBC, Q6SSTOP_Q6SS_TCM_SLAVE_CBCR clock */
	ret = clk_prepare_enable(wcss->tcm_slave_cbcr);
	if (ret)
		goto disable_ahbs_cbcr_clk;

	/* Enable the Q6SS AHB master CBC, Q6SSTOP_Q6SS_AHBM_CBCR clock */
	ret = clk_prepare_enable(wcss->qdsp6ss_abhm_cbcr);
	if (ret)
		goto disable_tcm_slave_cbcr_clk;

	/* Enable the Q6SS AXI master CBC, Q6SSTOP_Q6SS_AXIM_CBCR clock */
	ret = clk_prepare_enable(wcss->qdsp6ss_axim_cbcr);
	if (ret)
		goto disable_abhm_cbcr_clk;

	/* Enable the Q6SS XO CBC */
	val = readl(wcss->reg_base + Q6SS_XO_CBCR);
	val |= BIT(0);
	writel(val, wcss->reg_base + Q6SS_XO_CBCR);
	/* Read CLKOFF bit to go low indicating CLK is enabled */
	ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
				 val, !(val & BIT(31)), 1,
				 HALT_CHECK_MAX_LOOPS);
	if (ret) {
		dev_err(wcss->dev,
			"xo cbcr enabling timed out (rc:%d)\n", ret);
		return ret;
	}

	writel(0, wcss->reg_base + Q6SS_CGC_OVERRIDE);

	/* Enable QDSP6 sleep clock clock */
	val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
	val |= BIT(0);
	writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);

	/* Enable the Enable the Q6 AXI clock, GCC_WDSP_Q6SS_AXIM_CBCR*/
	ret = clk_prepare_enable(wcss->gcc_axim_cbcr);
	if (ret)
		goto disable_sleep_cbcr_clk;

	/* Assert resets, stop core */
	val = readl(wcss->reg_base + Q6SS_RESET_REG);
	val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
	writel(val, wcss->reg_base + Q6SS_RESET_REG);

	/* Program the QDSP6SS PWR_CTL register */
	writel(0x01700000, wcss->reg_base + Q6SS_PWR_CTL_REG);

	writel(0x03700000, wcss->reg_base + Q6SS_PWR_CTL_REG);

	writel(0x03300000, wcss->reg_base + Q6SS_PWR_CTL_REG);

	writel(0x033C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/*
	 * Enable memories by turning on the QDSP6 memory foot/head switch, one
	 * bank at a time to avoid in-rush current
	 */
	for (idx = 28; idx >= 0; idx--) {
		writel((readl(wcss->reg_base + Q6SS_MEM_PWR_CTL) |
			(1 << idx)), wcss->reg_base + Q6SS_MEM_PWR_CTL);
	}

	writel(0x031C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);
	writel(0x030C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);

	val = readl(wcss->reg_base + Q6SS_RESET_REG);
	val &= ~Q6SS_CORE_ARES;
	writel(val, wcss->reg_base + Q6SS_RESET_REG);

	/* Enable the Q6 core clock at the GFM, Q6SSTOP_QDSP6SS_GFMUX_CTL */
	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
	val |= Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC;
	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);

	/* Enable sleep clock branch needed for BCR circuit */
	ret = clk_prepare_enable(wcss->lcc_bcr_sleep);
	if (ret)
		goto disable_core_gfmux_clk;

	return 0;

disable_core_gfmux_clk:
	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
	val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC);
	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
	clk_disable_unprepare(wcss->gcc_axim_cbcr);
disable_sleep_cbcr_clk:
	val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
	val &= ~Q6SS_CLK_ENABLE;
	writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);
	val = readl(wcss->reg_base + Q6SS_XO_CBCR);
	val &= ~Q6SS_CLK_ENABLE;
	writel(val, wcss->reg_base + Q6SS_XO_CBCR);
	clk_disable_unprepare(wcss->qdsp6ss_axim_cbcr);
disable_abhm_cbcr_clk:
	clk_disable_unprepare(wcss->qdsp6ss_abhm_cbcr);
disable_tcm_slave_cbcr_clk:
	clk_disable_unprepare(wcss->tcm_slave_cbcr);
disable_ahbs_cbcr_clk:
	clk_disable_unprepare(wcss->ahbs_cbcr);
disable_csr_cbcr_clk:
	clk_disable_unprepare(wcss->lcc_csr_cbcr);
disable_ahbfabric_cbcr_clk:
	clk_disable_unprepare(wcss->ahbfabric_cbcr_clk);
disable_gcc_abhs_cbcr_clk:
	clk_disable_unprepare(wcss->gcc_abhs_cbcr);

	return ret;
}