remoteproc: q6v5: Add support for mss remoteproc on SDM845
authorSibi Sankar <sibis@codeaurora.org>
Mon, 21 May 2018 17:27:13 +0000 (22:57 +0530)
committerBjorn Andersson <bjorn.andersson@linaro.org>
Wed, 30 May 2018 03:10:34 +0000 (20:10 -0700)
From SDM845, the Q6SS reset sequence on software side has been
simplified with the introduction of boot FSM which assists in
bringing the Q6 out of reset.

SDM845 brings a new reset signal ALT_RESET which is a part of
the MSS subsystem hence requires reset clks to be enabled before
assert/deassert. Use the SoC specific reset helper function to
add support for ALT_RESET in SDM845.

Signed-off-by: Sibi Sankar <sibis@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
drivers/remoteproc/qcom_q6v5_pil.c

index 7e2691c..b48e5f3 100644 (file)
@@ -57,6 +57,8 @@
 #define RMB_PMI_META_DATA_REG          0x10
 #define RMB_PMI_CODE_START_REG         0x14
 #define RMB_PMI_CODE_LENGTH_REG                0x18
+#define RMB_MBA_MSS_STATUS             0x40
+#define RMB_MBA_ALT_RESET              0x44
 
 #define RMB_CMD_META_DATA_READY                0x1
 #define RMB_CMD_LOAD_READY             0x2
 #define QDSP6SS_XO_CBCR                0x0038
 #define QDSP6SS_ACC_OVERRIDE_VAL               0x20
 
+/* QDSP6v65 parameters */
+#define QDSP6SS_SLEEP                   0x3C
+#define QDSP6SS_BOOT_CORE_START         0x400
+#define QDSP6SS_BOOT_CMD                0x404
+#define SLEEP_CHECK_MAX_LOOPS           200
+#define BOOT_FSM_TIMEOUT                10000
+
 struct reg_info {
        struct regulator *reg;
        int uV;
@@ -121,9 +130,11 @@ struct rproc_hexagon_res {
        struct qcom_mss_reg_res *proxy_supply;
        struct qcom_mss_reg_res *active_supply;
        char **proxy_clk_names;
+       char **reset_clk_names;
        char **active_clk_names;
        int version;
        bool need_mem_protection;
+       bool has_alt_reset;
 };
 
 struct q6v5 {
@@ -148,8 +159,10 @@ struct q6v5 {
        bool proxy_unvoted;
 
        struct clk *active_clks[8];
+       struct clk *reset_clks[4];
        struct clk *proxy_clks[4];
        int active_clk_count;
+       int reset_clk_count;
        int proxy_clk_count;
 
        struct reg_info active_regs[1];
@@ -174,6 +187,7 @@ struct q6v5 {
        struct qcom_rproc_ssr ssr_subdev;
        struct qcom_sysmon *sysmon;
        bool need_mem_protection;
+       bool has_alt_reset;
        int mpss_perm;
        int mba_perm;
        int version;
@@ -183,6 +197,7 @@ enum {
        MSS_MSM8916,
        MSS_MSM8974,
        MSS_MSM8996,
+       MSS_SDM845,
 };
 
 static int q6v5_regulator_init(struct device *dev, struct reg_info *regs,
@@ -339,12 +354,25 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
 
 static int q6v5_reset_assert(struct q6v5 *qproc)
 {
-       return reset_control_assert(qproc->mss_restart);
+       if (qproc->has_alt_reset)
+               return reset_control_reset(qproc->mss_restart);
+       else
+               return reset_control_assert(qproc->mss_restart);
 }
 
 static int q6v5_reset_deassert(struct q6v5 *qproc)
 {
-       return reset_control_deassert(qproc->mss_restart);
+       int ret;
+
+       if (qproc->has_alt_reset) {
+               writel(1, qproc->rmb_base + RMB_MBA_ALT_RESET);
+               ret = reset_control_reset(qproc->mss_restart);
+               writel(0, qproc->rmb_base + RMB_MBA_ALT_RESET);
+       } else {
+               ret = reset_control_deassert(qproc->mss_restart);
+       }
+
+       return ret;
 }
 
 static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms)
@@ -399,8 +427,35 @@ static int q6v5proc_reset(struct q6v5 *qproc)
        int ret;
        int i;
 
+       if (qproc->version == MSS_SDM845) {
+               val = readl(qproc->reg_base + QDSP6SS_SLEEP);
+               val |= 0x1;
+               writel(val, qproc->reg_base + QDSP6SS_SLEEP);
 
-       if (qproc->version == MSS_MSM8996) {
+               ret = readl_poll_timeout(qproc->reg_base + QDSP6SS_SLEEP,
+                                        val, !(val & BIT(31)), 1,
+                                        SLEEP_CHECK_MAX_LOOPS);
+               if (ret) {
+                       dev_err(qproc->dev, "QDSP6SS Sleep clock timed out\n");
+                       return -ETIMEDOUT;
+               }
+
+               /* De-assert QDSP6 stop core */
+               writel(1, qproc->reg_base + QDSP6SS_BOOT_CORE_START);
+               /* Trigger boot FSM */
+               writel(1, qproc->reg_base + QDSP6SS_BOOT_CMD);
+
+               ret = readl_poll_timeout(qproc->rmb_base + RMB_MBA_MSS_STATUS,
+                               val, (val & BIT(0)) != 0, 10, BOOT_FSM_TIMEOUT);
+               if (ret) {
+                       dev_err(qproc->dev, "Boot FSM failed to complete.\n");
+                       /* Reset the modem so that boot FSM is in reset state */
+                       q6v5_reset_deassert(qproc);
+                       return ret;
+               }
+
+               goto pbl_wait;
+       } else if (qproc->version == MSS_MSM8996) {
                /* Override the ACC value if required */
                writel(QDSP6SS_ACC_OVERRIDE_VAL,
                       qproc->reg_base + QDSP6SS_STRAP_ACC);
@@ -508,6 +563,7 @@ static int q6v5proc_reset(struct q6v5 *qproc)
        val &= ~Q6SS_STOP_CORE;
        writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
 
+pbl_wait:
        /* Wait for PBL status */
        ret = q6v5_rmb_pbl_wait(qproc, 1000);
        if (ret == -ETIMEDOUT) {
@@ -765,10 +821,18 @@ static int q6v5_start(struct rproc *rproc)
                dev_err(qproc->dev, "failed to enable supplies\n");
                goto disable_proxy_clk;
        }
+
+       ret = q6v5_clk_enable(qproc->dev, qproc->reset_clks,
+                             qproc->reset_clk_count);
+       if (ret) {
+               dev_err(qproc->dev, "failed to enable reset clocks\n");
+               goto disable_vdd;
+       }
+
        ret = q6v5_reset_deassert(qproc);
        if (ret) {
                dev_err(qproc->dev, "failed to deassert mss restart\n");
-               goto disable_vdd;
+               goto disable_reset_clks;
        }
 
        ret = q6v5_clk_enable(qproc->dev, qproc->active_clks,
@@ -854,6 +918,9 @@ disable_active_clks:
 
 assert_reset:
        q6v5_reset_assert(qproc);
+disable_reset_clks:
+       q6v5_clk_disable(qproc->dev, qproc->reset_clks,
+                        qproc->reset_clk_count);
 disable_vdd:
        q6v5_regulator_disable(qproc, qproc->active_regs,
                               qproc->active_reg_count);
@@ -917,6 +984,8 @@ static int q6v5_stop(struct rproc *rproc)
                                       qproc->proxy_reg_count);
        }
 
+       q6v5_clk_disable(qproc->dev, qproc->reset_clks,
+                        qproc->reset_clk_count);
        q6v5_clk_disable(qproc->dev, qproc->active_clks,
                         qproc->active_clk_count);
        q6v5_regulator_disable(qproc, qproc->active_regs,
@@ -1196,6 +1265,14 @@ static int q6v5_probe(struct platform_device *pdev)
        }
        qproc->proxy_clk_count = ret;
 
+       ret = q6v5_init_clocks(&pdev->dev, qproc->reset_clks,
+                              desc->reset_clk_names);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to get reset clocks.\n");
+               goto free_rproc;
+       }
+       qproc->reset_clk_count = ret;
+
        ret = q6v5_init_clocks(&pdev->dev, qproc->active_clks,
                               desc->active_clk_names);
        if (ret < 0) {
@@ -1225,6 +1302,7 @@ static int q6v5_probe(struct platform_device *pdev)
                goto free_rproc;
 
        qproc->version = desc->version;
+       qproc->has_alt_reset = desc->has_alt_reset;
        qproc->need_mem_protection = desc->need_mem_protection;
        ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
        if (ret < 0)
@@ -1285,6 +1363,31 @@ static int q6v5_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct rproc_hexagon_res sdm845_mss = {
+       .hexagon_mba_image = "mba.mbn",
+       .proxy_clk_names = (char*[]){
+                       "xo",
+                       "axis2",
+                       "prng",
+                       NULL
+       },
+       .reset_clk_names = (char*[]){
+                       "iface",
+                       "snoc_axi",
+                       NULL
+       },
+       .active_clk_names = (char*[]){
+                       "bus",
+                       "mem",
+                       "gpll0_mss",
+                       "mnoc_axi",
+                       NULL
+       },
+       .need_mem_protection = true,
+       .has_alt_reset = true,
+       .version = MSS_SDM845,
+};
+
 static const struct rproc_hexagon_res msm8996_mss = {
        .hexagon_mba_image = "mba.mbn",
        .proxy_clk_names = (char*[]){
@@ -1300,6 +1403,7 @@ static const struct rproc_hexagon_res msm8996_mss = {
                        NULL
        },
        .need_mem_protection = true,
+       .has_alt_reset = false,
        .version = MSS_MSM8996,
 };
 
@@ -1331,6 +1435,7 @@ static const struct rproc_hexagon_res msm8916_mss = {
                NULL
        },
        .need_mem_protection = false,
+       .has_alt_reset = false,
        .version = MSS_MSM8916,
 };
 
@@ -1370,6 +1475,7 @@ static const struct rproc_hexagon_res msm8974_mss = {
                NULL
        },
        .need_mem_protection = false,
+       .has_alt_reset = false,
        .version = MSS_MSM8974,
 };
 
@@ -1378,6 +1484,7 @@ static const struct of_device_id q6v5_of_match[] = {
        { .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss},
        { .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss},
        { .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss},
+       { .compatible = "qcom,sdm845-mss-pil", .data = &sdm845_mss},
        { },
 };
 MODULE_DEVICE_TABLE(of, q6v5_of_match);