/* BHS require xo cbcr to be enabled */
val = readl(wcss->reg_base + Q6SS_XO_CBCR);
val |= 0x1;
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;
} /* Enable power block headswitch and wait for it to stabilize */
val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
val |= Q6SS_BHS_ON;
writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
udelay(1);
/* Put LDO in bypass mode */
val |= Q6SS_LDO_BYP;
writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
/* Deassert Q6 compiler memory clamp */
val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
val &= ~Q6SS_CLAMP_QMC_MEM;
writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
/* Deassert memory peripheral sleep and L2 memory standby */
val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
/* Turn on L1, L2, ETB and JU memories 1 at a time */
val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL); for (i = MEM_BANKS; i >= 0; i--) {
val |= BIT(i);
writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL); /* * Read back value to ensure the write is done then * wait for 1us for both memory peripheral and data * array to turn on.
*/
val |= readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
udelay(1);
} /* Remove word line clamp */
val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
val &= ~Q6SS_CLAMP_WL;
writel(val, 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);
}
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);
disable_xo_cbcr_clk:
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);
/* Check if we're already idle */
ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val); if (!ret && val) return;
/* Assert halt request */
regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
/* Wait for halt */
timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS); for (;;) {
ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val); if (ret || val || time_after(jiffies, timeout)) break;
msleep(1);
}
ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val); if (ret || !val)
dev_err(wcss->dev, "port failed halt\n");
/* Clear halt request (port will remain halted until reset) */
regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
}
staticint q6v5_qcs404_wcss_shutdown(struct q6v5_wcss *wcss)
{ unsignedlong val; int ret;
/* 7 - turn off Q6 memory foot/head switch one bank at a time */ for (i = 0; i < 20; i++) {
val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
val &= ~BIT(i);
writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
mdelay(1);
}
/* 8 - Assert QMC memory RTN */
val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
val |= Q6SS_CLAMP_QMC_MEM;
writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
/* 9 - Turn off BHS */
val &= ~Q6SS_BHS_ON;
writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
udelay(1);
/* 10 - Wait till BHS Reset is done */
ret = readl_poll_timeout(wcss->reg_base + Q6SS_BHS_STATUS,
val, !(val & BHS_EN_REST_ACK), 1000,
HALT_CHECK_MAX_LOOPS); if (ret) {
dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret); return ret;
}
/* WCSS powerdown */ if (wcss->requires_force_stop) {
ret = qcom_q6v5_request_stop(&wcss->q6v5, NULL); if (ret == -ETIMEDOUT) {
dev_err(wcss->dev, "timed out on wait\n"); return ret;
}
}
if (wcss->version == WCSS_QCS404) {
ret = q6v5_qcs404_wcss_shutdown(wcss); if (ret) return ret;
} else {
ret = q6v5_wcss_powerdown(wcss); if (ret) return ret;
/* Q6 Power down */
ret = q6v5_q6_powerdown(wcss); if (ret) return ret;
}
qcom_q6v5_unprepare(&wcss->q6v5);
return 0;
}
staticvoid *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
{ struct q6v5_wcss *wcss = rproc->priv; int offset;
offset = da - wcss->mem_reloc; if (offset < 0 || offset + len > wcss->mem_size) return NULL;
staticint q6v5_wcss_init_clock(struct q6v5_wcss *wcss)
{
wcss->xo = devm_clk_get(wcss->dev, "xo"); if (IS_ERR(wcss->xo)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->xo), "failed to get xo clock");
wcss->gcc_abhs_cbcr = devm_clk_get(wcss->dev, "gcc_abhs_cbcr"); if (IS_ERR(wcss->gcc_abhs_cbcr)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->gcc_abhs_cbcr), "failed to get gcc abhs clock");
wcss->gcc_axim_cbcr = devm_clk_get(wcss->dev, "gcc_axim_cbcr"); if (IS_ERR(wcss->gcc_axim_cbcr)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->gcc_axim_cbcr), "failed to get gcc axim clock\n");
wcss->ahbfabric_cbcr_clk = devm_clk_get(wcss->dev, "lcc_ahbfabric_cbc"); if (IS_ERR(wcss->ahbfabric_cbcr_clk)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->ahbfabric_cbcr_clk), "failed to get ahbfabric clock\n");
wcss->lcc_csr_cbcr = devm_clk_get(wcss->dev, "tcsr_lcc_cbc"); if (IS_ERR(wcss->lcc_csr_cbcr)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->lcc_csr_cbcr), "failed to get csr cbcr clk\n");
wcss->ahbs_cbcr = devm_clk_get(wcss->dev, "lcc_abhs_cbc"); if (IS_ERR(wcss->ahbs_cbcr)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->ahbs_cbcr), "failed to get ahbs_cbcr clk\n");
wcss->tcm_slave_cbcr = devm_clk_get(wcss->dev, "lcc_tcm_slave_cbc"); if (IS_ERR(wcss->tcm_slave_cbcr)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->tcm_slave_cbcr), "failed to get tcm cbcr clk\n");
wcss->qdsp6ss_abhm_cbcr = devm_clk_get(wcss->dev, "lcc_abhm_cbc"); if (IS_ERR(wcss->qdsp6ss_abhm_cbcr)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->qdsp6ss_abhm_cbcr), "failed to get abhm cbcr clk\n");
wcss->qdsp6ss_axim_cbcr = devm_clk_get(wcss->dev, "lcc_axim_cbc"); if (IS_ERR(wcss->qdsp6ss_axim_cbcr)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->qdsp6ss_axim_cbcr), "failed to get axim cbcr clk\n");
wcss->lcc_bcr_sleep = devm_clk_get(wcss->dev, "lcc_bcr_sleep"); if (IS_ERR(wcss->lcc_bcr_sleep)) return dev_err_probe(wcss->dev, PTR_ERR(wcss->lcc_bcr_sleep), "failed to get bcr cbcr clk\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.