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;
}