@@ -127,10 +127,6 @@ struct q6v5 {
struct qcom_smem_state *state;
unsigned stop_bit;
-
- struct clk *ahb_clk;
- struct clk *axi_clk;
- struct clk *rom_clk;
struct clk **active_clks;
struct clk **proxy_clks;
struct reg_info *active_regs;
@@ -293,6 +289,52 @@ static void q6v5_regulator_disable(struct q6v5 *qproc)
q6v5_active_regulator_disable(qproc);
}
+static int q6v5_clk_enable(struct device *dev, struct clk **clks,
+ int clk_count)
+{
+ int rc = 0;
+ int i;
+
+ for (i = 0; i < clk_count; i++) {
+ rc = clk_prepare_enable(clks[i]);
+ if (rc) {
+ dev_err(dev, "Clock enable failed\n");
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ for (i--; i >= 0; i--)
+ clk_disable_unprepare(clks[i]);
+
+ return rc;
+}
+
+static void q6v5_proxy_clk_disable(struct q6v5 *qproc)
+{
+ int i;
+ struct clk **clks = qproc->proxy_clks;
+
+ for (i = 0; i < qproc->proxy_clk_count; i++)
+ clk_disable_unprepare(clks[i]);
+}
+
+static void q6v5_active_clk_disable(struct q6v5 *qproc)
+{
+ int i;
+ struct clk **clks = qproc->proxy_clks;
+
+ for (i = 0; i < qproc->proxy_clk_count; i++)
+ clk_disable_unprepare(clks[i]);
+}
+
+static void q6v5_clk_disable(struct q6v5 *qproc)
+{
+ q6v5_proxy_clk_disable(qproc);
+ q6v5_active_clk_disable(qproc);
+}
+
static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
{
struct q6v5 *qproc = rproc->priv;
@@ -589,6 +631,13 @@ static int q6v5_start(struct rproc *rproc)
return ret;
}
+ 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) {
@@ -601,17 +650,12 @@ static int q6v5_start(struct rproc *rproc)
goto disable_vdd;
}
- ret = clk_prepare_enable(qproc->ahb_clk);
- if (ret)
+ 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 = clk_prepare_enable(qproc->axi_clk);
- if (ret)
- goto disable_ahb_clk;
-
- ret = clk_prepare_enable(qproc->rom_clk);
- if (ret)
- goto disable_axi_clk;
+ }
writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
@@ -646,25 +690,23 @@ static int q6v5_start(struct rproc *rproc)
qproc->running = true;
- /* TODO: All done, release the handover resources */
-
+ q6v5_proxy_clk_disable(qproc);
+ q6v5_proxy_regulator_disable(qproc);
return 0;
halt_axi_ports:
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
-
- clk_disable_unprepare(qproc->rom_clk);
-disable_axi_clk:
- clk_disable_unprepare(qproc->axi_clk);
-disable_ahb_clk:
- clk_disable_unprepare(qproc->ahb_clk);
+ q6v5_active_clk_disable(qproc);
assert_reset:
reset_control_assert(qproc->mss_restart);
disable_vdd:
q6v5_active_regulator_disable(qproc);
disable_proxy_clk:
+ q6v5_proxy_clk_disable(qproc);
+disable_proxy_reg:
+ q6v5_proxy_regulator_disable(qproc);
return ret;
}
@@ -690,9 +732,7 @@ static int q6v5_stop(struct rproc *rproc)
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
reset_control_assert(qproc->mss_restart);
- clk_disable_unprepare(qproc->rom_clk);
- clk_disable_unprepare(qproc->axi_clk);
- clk_disable_unprepare(qproc->ahb_clk);
+ q6v5_clk_disable(qproc);
q6v5_regulator_disable(qproc);
return 0;
Clock handling is made generic than need to add new clock every time when required to support new hexagon version. also where ever required invoking clock enable disable routine is replaced by this new prototype. Also clock disable interface is separated out into two separate routine to handle proxy clock alone unvoting when handover interrupt is arrived. Signed-off-by: Avaneesh Kumar Dwivedi <akdwived@codeaurora.org> --- drivers/remoteproc/qcom_q6v5_pil.c | 90 +++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 25 deletions(-)