summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/remoteproc/qcom_q6v5_pil.c151
1 files changed, 109 insertions, 42 deletions
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
index 1bebe88fdb62..991193596d9e 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pil.c
@@ -95,6 +95,8 @@
struct rproc_hexagon_res {
const char *hexagon_mba_image;
+ char **proxy_clk_names;
+ char **active_clk_names;
};
struct q6v5 {
@@ -114,11 +116,13 @@ struct q6v5 {
struct qcom_smem_state *state;
unsigned stop_bit;
+ struct clk *active_clks[8];
+ struct clk *proxy_clks[4];
+ int active_clk_count;
+ int proxy_clk_count;
+
struct regulator_bulk_data supply[4];
- struct clk *ahb_clk;
- struct clk *axi_clk;
- struct clk *rom_clk;
struct completion start_done;
struct completion stop_done;
@@ -193,6 +197,37 @@ static void q6v5_regulator_disable(struct q6v5 *qproc)
regulator_set_voltage(mss, 0, 1150000);
}
+static int q6v5_clk_enable(struct device *dev,
+ struct clk **clks, int count)
+{
+ int rc;
+ int i;
+
+ for (i = 0; i < 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_clk_disable(struct device *dev,
+ struct clk **clks, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ clk_disable_unprepare(clks[i]);
+}
+
static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
{
struct q6v5 *qproc = rproc->priv;
@@ -488,23 +523,24 @@ 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_vdd;
+ }
ret = reset_control_deassert(qproc->mss_restart);
if (ret) {
dev_err(qproc->dev, "failed to deassert mss restart\n");
- goto disable_vdd;
+ goto disable_proxy_clk;
}
- 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);
@@ -539,7 +575,8 @@ static int q6v5_start(struct rproc *rproc)
qproc->running = true;
- /* TODO: All done, release the handover resources */
+ q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
+ qproc->proxy_clk_count);
return 0;
@@ -547,14 +584,13 @@ 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_clk_disable(qproc->dev, qproc->active_clks,
+ qproc->active_clk_count);
assert_reset:
reset_control_assert(qproc->mss_restart);
+disable_proxy_clk:
+ q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
+ qproc->proxy_clk_count);
disable_vdd:
q6v5_regulator_disable(qproc);
@@ -583,9 +619,8 @@ 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->dev, qproc->active_clks,
+ qproc->active_clk_count);
q6v5_regulator_disable(qproc);
return 0;
@@ -706,27 +741,27 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
return 0;
}
-static int q6v5_init_clocks(struct q6v5 *qproc)
+static int q6v5_init_clocks(struct device *dev, struct clk **clks,
+ char **clk_names)
{
- qproc->ahb_clk = devm_clk_get(qproc->dev, "iface");
- if (IS_ERR(qproc->ahb_clk)) {
- dev_err(qproc->dev, "failed to get iface clock\n");
- return PTR_ERR(qproc->ahb_clk);
- }
+ int i;
- qproc->axi_clk = devm_clk_get(qproc->dev, "bus");
- if (IS_ERR(qproc->axi_clk)) {
- dev_err(qproc->dev, "failed to get bus clock\n");
- return PTR_ERR(qproc->axi_clk);
- }
+ if (!clk_names)
+ return 0;
+
+ for (i = 0; clk_names[i]; i++) {
+ clks[i] = devm_clk_get(dev, clk_names[i]);
+ if (IS_ERR(clks[i])) {
+ int rc = PTR_ERR(clks[i]);
- qproc->rom_clk = devm_clk_get(qproc->dev, "mem");
- if (IS_ERR(qproc->rom_clk)) {
- dev_err(qproc->dev, "failed to get mem clock\n");
- return PTR_ERR(qproc->rom_clk);
+ if (rc != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get %s clock\n",
+ clk_names[i]);
+ return rc;
+ }
}
- return 0;
+ return i;
}
static int q6v5_init_reset(struct q6v5 *qproc)
@@ -843,9 +878,21 @@ static int q6v5_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;
- ret = q6v5_init_clocks(qproc);
- if (ret)
+ ret = q6v5_init_clocks(&pdev->dev, qproc->proxy_clks,
+ desc->proxy_clk_names);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to get proxy clocks.\n");
goto free_rproc;
+ }
+ qproc->proxy_clk_count = ret;
+
+ ret = q6v5_init_clocks(&pdev->dev, qproc->active_clks,
+ desc->active_clk_names);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to get active clocks.\n");
+ goto free_rproc;
+ }
+ qproc->active_clk_count = ret;
ret = q6v5_regulator_init(qproc);
if (ret)
@@ -901,10 +948,30 @@ static int q6v5_remove(struct platform_device *pdev)
static const struct rproc_hexagon_res msm8916_mss = {
.hexagon_mba_image = "mba.mbn",
+ .proxy_clk_names = (char*[]){
+ "xo",
+ NULL
+ },
+ .active_clk_names = (char*[]){
+ "iface",
+ "bus",
+ "mem",
+ NULL
+ },
};
static const struct rproc_hexagon_res msm8974_mss = {
.hexagon_mba_image = "mba.b00",
+ .proxy_clk_names = (char*[]){
+ "xo",
+ NULL
+ },
+ .active_clk_names = (char*[]){
+ "iface",
+ "bus",
+ "mem",
+ NULL
+ },
};
static const struct of_device_id q6v5_of_match[] = {