|
@@ -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
|
|
@@ -104,6 +106,13 @@
|
|
|
#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);
|