From: Luca Weiss <luca@xxxxxxxxx> Add support for the external power block headswitch register needed by MSM8226 and some other qcom platforms. Signed-off-by: Luca Weiss <luca@xxxxxxxxx> Co-developed-by: Matti Lehtimäki <matti.lehtimaki@xxxxxxxxx> Signed-off-by: Matti Lehtimäki <matti.lehtimaki@xxxxxxxxx> --- drivers/remoteproc/qcom_q6v5_mss.c | 123 +++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 745627a36bcf..0dff7e811736 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -131,6 +131,11 @@ #define QDSP6SS_BOOT_CMD 0x404 #define BOOT_FSM_TIMEOUT 10000 +/* External power block headswitch */ +#define EXTERNAL_BHS_ON BIT(0) +#define EXTERNAL_BHS_STATUS BIT(4) +#define EXTERNAL_BHS_TIMEOUT_US 50 + struct reg_info { struct regulator *reg; int uV; @@ -158,6 +163,7 @@ struct rproc_hexagon_res { bool has_mba_logs; bool has_spare_reg; bool has_qaccept_regs; + bool has_ext_bhs_reg; bool has_ext_cntl_regs; bool has_vq6; }; @@ -177,6 +183,7 @@ struct q6v5 { u32 halt_nc; u32 halt_vq6; u32 conn_box; + u32 ext_bhs; u32 qaccept_mdm; u32 qaccept_cx; @@ -230,6 +237,7 @@ struct q6v5 { bool has_mba_logs; bool has_spare_reg; bool has_qaccept_regs; + bool has_ext_bhs_reg; bool has_ext_cntl_regs; bool has_vq6; int mpss_perm; @@ -239,6 +247,7 @@ struct q6v5 { }; enum { + MSS_MSM8226, MSS_MSM8909, MSS_MSM8916, MSS_MSM8953, @@ -1738,6 +1747,23 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev) qproc->qaccept_axi = args.args[2]; } + if (qproc->has_ext_bhs_reg) { + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "qcom,ext-bhs-reg", + 1, 0, &args); + if (ret < 0) { + dev_err(&pdev->dev, "failed to parse ext-bhs-reg index 0\n"); + return -EINVAL; + } + + qproc->conn_map = syscon_node_to_regmap(args.np); + of_node_put(args.np); + if (IS_ERR(qproc->conn_map)) + return PTR_ERR(qproc->conn_map); + + qproc->ext_bhs = args.args[0]; + } + if (qproc->has_ext_cntl_regs) { ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, "qcom,ext-regs", @@ -1863,6 +1889,36 @@ static void q6v5_pds_detach(struct q6v5 *qproc, struct device **pds, dev_pm_domain_detach(pds[i], false); } +static int q6v5_external_bhs_enable(struct q6v5 *qproc) +{ + u32 val; + int ret = 0; + + /* + * Enable external power block headswitch and wait for it to + * stabilize + */ + regmap_update_bits(qproc->conn_map, qproc->ext_bhs, + EXTERNAL_BHS_ON, 1); + + ret = regmap_read_poll_timeout(qproc->conn_map, qproc->ext_bhs, + val, val & EXTERNAL_BHS_STATUS, + 1, EXTERNAL_BHS_TIMEOUT_US); + + if (ret) { + dev_err(qproc->dev, "External BHS timed out\n"); + ret = -ETIMEDOUT; + } + + return ret; +} + +static void q6v5_external_bhs_disable(struct q6v5 *qproc) +{ + regmap_update_bits(qproc->conn_map, qproc->ext_bhs, + EXTERNAL_BHS_ON, 0); +} + static int q6v5_init_reset(struct q6v5 *qproc) { qproc->mss_restart = devm_reset_control_get_exclusive(qproc->dev, @@ -1984,6 +2040,7 @@ static int q6v5_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qproc); qproc->has_qaccept_regs = desc->has_qaccept_regs; + qproc->has_ext_bhs_reg = desc->has_ext_bhs_reg; qproc->has_ext_cntl_regs = desc->has_ext_cntl_regs; qproc->has_vq6 = desc->has_vq6; qproc->has_spare_reg = desc->has_spare_reg; @@ -2054,6 +2111,14 @@ static int q6v5_probe(struct platform_device *pdev) qproc->proxy_pd_count = ret; } + if (qproc->has_ext_bhs_reg) { + ret = q6v5_external_bhs_enable(qproc); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable external BHS.\n"); + goto detach_proxy_pds; + } + } + qproc->has_alt_reset = desc->has_alt_reset; ret = q6v5_init_reset(qproc); if (ret) @@ -2118,6 +2183,9 @@ static int q6v5_remove(struct platform_device *pdev) qcom_remove_smd_subdev(rproc, &qproc->smd_subdev); qcom_remove_glink_subdev(rproc, &qproc->glink_subdev); + if (qproc->has_ext_bhs_reg) + q6v5_external_bhs_disable(qproc); + q6v5_pds_detach(qproc, qproc->proxy_pds, qproc->proxy_pd_count); rproc_free(rproc); @@ -2153,6 +2221,7 @@ static const struct rproc_hexagon_res sc7180_mss = { .has_mba_logs = true, .has_spare_reg = true, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_SC7180, @@ -2181,6 +2250,7 @@ static const struct rproc_hexagon_res sc7280_mss = { .has_mba_logs = true, .has_spare_reg = false, .has_qaccept_regs = true, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = true, .has_vq6 = true, .version = MSS_SC7280, @@ -2216,6 +2286,7 @@ static const struct rproc_hexagon_res sdm845_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_SDM845, @@ -2247,6 +2318,7 @@ static const struct rproc_hexagon_res msm8998_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8998, @@ -2286,6 +2358,7 @@ static const struct rproc_hexagon_res msm8996_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8996, @@ -2320,6 +2393,7 @@ static const struct rproc_hexagon_res msm8909_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8909, @@ -2365,6 +2439,7 @@ static const struct rproc_hexagon_res msm8916_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8916, @@ -2400,6 +2475,7 @@ static const struct rproc_hexagon_res msm8953_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8953, @@ -2453,13 +2529,60 @@ static const struct rproc_hexagon_res msm8974_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8974, }; +static const struct rproc_hexagon_res msm8226_mss = { + .hexagon_mba_image = "mba.b00", + .proxy_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "pll", + .uA = 100000, + }, + { + .supply = "mx", + .uV = 1050000, + }, + {} + }, + .fallback_proxy_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "cx", + .uA = 100000, + }, + {} + }, + .proxy_clk_names = (char*[]){ + "xo", + NULL + }, + .active_clk_names = (char*[]){ + "iface", + "bus", + "mem", + NULL + }, + .proxy_pd_names = (char*[]){ + "cx", + NULL + }, + .need_mem_protection = false, + .has_alt_reset = false, + .has_mba_logs = false, + .has_spare_reg = false, + .has_qaccept_regs = false, + .has_ext_bhs_reg = true, + .has_ext_cntl_regs = false, + .has_vq6 = false, + .version = MSS_MSM8226, +}; + static const struct of_device_id q6v5_of_match[] = { { .compatible = "qcom,q6v5-pil", .data = &msm8916_mss}, + { .compatible = "qcom,msm8226-mss-pil", .data = &msm8226_mss}, { .compatible = "qcom,msm8909-mss-pil", .data = &msm8909_mss}, { .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss}, { .compatible = "qcom,msm8953-mss-pil", .data = &msm8953_mss}, -- 2.34.1