mirror of
https://github.com/torvalds/linux.git
synced 2025-01-01 15:51:46 +00:00
remoteproc: mss: q6v5-mss: Add modem support on SC7280
Add out of reset sequence support for modem sub-system on SC7280 SoCs. It requires access to an additional set of qaccept registers, external power/clk control registers and halt vq6 register to put the modem back into reset. Signed-off-by: Sibi Sankar <sibis@codeaurora.org> Reviewed-by: Stephen Boyd <swboyd@chromium.org> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Link: https://lore.kernel.org/r/1631886935-14691-6-git-send-email-sibis@codeaurora.org
This commit is contained in:
parent
c42c0a5e97
commit
c842379d00
@ -77,6 +77,14 @@
|
||||
|
||||
#define HALT_ACK_TIMEOUT_US 100000
|
||||
|
||||
/* QACCEPT Register Offsets */
|
||||
#define QACCEPT_ACCEPT_REG 0x0
|
||||
#define QACCEPT_ACTIVE_REG 0x4
|
||||
#define QACCEPT_DENY_REG 0x8
|
||||
#define QACCEPT_REQ_REG 0xC
|
||||
|
||||
#define QACCEPT_TIMEOUT_US 50
|
||||
|
||||
/* QDSP6SS_RESET */
|
||||
#define Q6SS_STOP_CORE BIT(0)
|
||||
#define Q6SS_CORE_ARES BIT(1)
|
||||
@ -143,6 +151,9 @@ struct rproc_hexagon_res {
|
||||
bool has_alt_reset;
|
||||
bool has_mba_logs;
|
||||
bool has_spare_reg;
|
||||
bool has_qaccept_regs;
|
||||
bool has_ext_cntl_regs;
|
||||
bool has_vq6;
|
||||
};
|
||||
|
||||
struct q6v5 {
|
||||
@ -158,8 +169,18 @@ struct q6v5 {
|
||||
u32 halt_q6;
|
||||
u32 halt_modem;
|
||||
u32 halt_nc;
|
||||
u32 halt_vq6;
|
||||
u32 conn_box;
|
||||
|
||||
u32 qaccept_mdm;
|
||||
u32 qaccept_cx;
|
||||
u32 qaccept_axi;
|
||||
|
||||
u32 axim1_clk_off;
|
||||
u32 crypto_clk_off;
|
||||
u32 force_clk_on;
|
||||
u32 rscc_disable;
|
||||
|
||||
struct reset_control *mss_restart;
|
||||
struct reset_control *pdc_reset;
|
||||
|
||||
@ -201,6 +222,9 @@ struct q6v5 {
|
||||
bool has_alt_reset;
|
||||
bool has_mba_logs;
|
||||
bool has_spare_reg;
|
||||
bool has_qaccept_regs;
|
||||
bool has_ext_cntl_regs;
|
||||
bool has_vq6;
|
||||
int mpss_perm;
|
||||
int mba_perm;
|
||||
const char *hexagon_mdt_image;
|
||||
@ -213,6 +237,7 @@ enum {
|
||||
MSS_MSM8996,
|
||||
MSS_MSM8998,
|
||||
MSS_SC7180,
|
||||
MSS_SC7280,
|
||||
MSS_SDM845,
|
||||
};
|
||||
|
||||
@ -473,6 +498,12 @@ static int q6v5_reset_assert(struct q6v5 *qproc)
|
||||
regmap_update_bits(qproc->conn_map, qproc->conn_box,
|
||||
AXI_GATING_VALID_OVERRIDE, 0);
|
||||
ret = reset_control_deassert(qproc->mss_restart);
|
||||
} else if (qproc->has_ext_cntl_regs) {
|
||||
regmap_write(qproc->conn_map, qproc->rscc_disable, 0);
|
||||
reset_control_assert(qproc->pdc_reset);
|
||||
reset_control_assert(qproc->mss_restart);
|
||||
reset_control_deassert(qproc->pdc_reset);
|
||||
ret = reset_control_deassert(qproc->mss_restart);
|
||||
} else {
|
||||
ret = reset_control_assert(qproc->mss_restart);
|
||||
}
|
||||
@ -490,7 +521,7 @@ static int q6v5_reset_deassert(struct q6v5 *qproc)
|
||||
ret = reset_control_reset(qproc->mss_restart);
|
||||
writel(0, qproc->rmb_base + RMB_MBA_ALT_RESET);
|
||||
reset_control_deassert(qproc->pdc_reset);
|
||||
} else if (qproc->has_spare_reg) {
|
||||
} else if (qproc->has_spare_reg || qproc->has_ext_cntl_regs) {
|
||||
ret = reset_control_reset(qproc->mss_restart);
|
||||
} else {
|
||||
ret = reset_control_deassert(qproc->mss_restart);
|
||||
@ -604,7 +635,7 @@ static int q6v5proc_reset(struct q6v5 *qproc)
|
||||
}
|
||||
|
||||
goto pbl_wait;
|
||||
} else if (qproc->version == MSS_SC7180) {
|
||||
} else if (qproc->version == MSS_SC7180 || qproc->version == MSS_SC7280) {
|
||||
val = readl(qproc->reg_base + QDSP6SS_SLEEP);
|
||||
val |= Q6SS_CBCR_CLKEN;
|
||||
writel(val, qproc->reg_base + QDSP6SS_SLEEP);
|
||||
@ -787,6 +818,89 @@ pbl_wait:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int q6v5proc_enable_qchannel(struct q6v5 *qproc, struct regmap *map, u32 offset)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
if (!qproc->has_qaccept_regs)
|
||||
return 0;
|
||||
|
||||
if (qproc->has_ext_cntl_regs) {
|
||||
regmap_write(qproc->conn_map, qproc->rscc_disable, 0);
|
||||
regmap_write(qproc->conn_map, qproc->force_clk_on, 1);
|
||||
|
||||
ret = regmap_read_poll_timeout(qproc->halt_map, qproc->axim1_clk_off, val,
|
||||
!val, 1, Q6SS_CBCR_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(qproc->dev, "failed to enable axim1 clock\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
regmap_write(map, offset + QACCEPT_REQ_REG, 1);
|
||||
|
||||
/* Wait for accept */
|
||||
ret = regmap_read_poll_timeout(map, offset + QACCEPT_ACCEPT_REG, val, val, 5,
|
||||
QACCEPT_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(qproc->dev, "qchannel enable failed\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void q6v5proc_disable_qchannel(struct q6v5 *qproc, struct regmap *map, u32 offset)
|
||||
{
|
||||
int ret;
|
||||
unsigned int val, retry;
|
||||
unsigned int nretry = 10;
|
||||
bool takedown_complete = false;
|
||||
|
||||
if (!qproc->has_qaccept_regs)
|
||||
return;
|
||||
|
||||
while (!takedown_complete && nretry) {
|
||||
nretry--;
|
||||
|
||||
/* Wait for active transactions to complete */
|
||||
regmap_read_poll_timeout(map, offset + QACCEPT_ACTIVE_REG, val, !val, 5,
|
||||
QACCEPT_TIMEOUT_US);
|
||||
|
||||
/* Request Q-channel transaction takedown */
|
||||
regmap_write(map, offset + QACCEPT_REQ_REG, 0);
|
||||
|
||||
/*
|
||||
* If the request is denied, reset the Q-channel takedown request,
|
||||
* wait for active transactions to complete and retry takedown.
|
||||
*/
|
||||
retry = 10;
|
||||
while (retry) {
|
||||
usleep_range(5, 10);
|
||||
retry--;
|
||||
ret = regmap_read(map, offset + QACCEPT_DENY_REG, &val);
|
||||
if (!ret && val) {
|
||||
regmap_write(map, offset + QACCEPT_REQ_REG, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = regmap_read(map, offset + QACCEPT_ACCEPT_REG, &val);
|
||||
if (!ret && !val) {
|
||||
takedown_complete = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!retry)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Rely on mss_restart to clear out pending transactions on takedown failure */
|
||||
if (!takedown_complete)
|
||||
dev_err(qproc->dev, "qchannel takedown failed\n");
|
||||
}
|
||||
|
||||
static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
|
||||
struct regmap *halt_map,
|
||||
u32 offset)
|
||||
@ -950,6 +1064,12 @@ static int q6v5_mba_load(struct q6v5 *qproc)
|
||||
goto assert_reset;
|
||||
}
|
||||
|
||||
ret = q6v5proc_enable_qchannel(qproc, qproc->halt_map, qproc->qaccept_axi);
|
||||
if (ret) {
|
||||
dev_err(qproc->dev, "failed to enable axi bridge\n");
|
||||
goto disable_active_clks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some versions of the MBA firmware will upon boot wipe the MPSS region as well, so provide
|
||||
* the Q6 access to this region.
|
||||
@ -996,8 +1116,13 @@ static int q6v5_mba_load(struct q6v5 *qproc)
|
||||
|
||||
halt_axi_ports:
|
||||
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
|
||||
if (qproc->has_vq6)
|
||||
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_vq6);
|
||||
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
|
||||
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
|
||||
q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_mdm);
|
||||
q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_cx);
|
||||
q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_axi);
|
||||
mba_load_err = true;
|
||||
reclaim_mba:
|
||||
xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true,
|
||||
@ -1047,6 +1172,8 @@ static void q6v5_mba_reclaim(struct q6v5 *qproc)
|
||||
qproc->dp_size = 0;
|
||||
|
||||
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
|
||||
if (qproc->has_vq6)
|
||||
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_vq6);
|
||||
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
|
||||
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
|
||||
if (qproc->version == MSS_MSM8996) {
|
||||
@ -1059,6 +1186,24 @@ static void q6v5_mba_reclaim(struct q6v5 *qproc)
|
||||
writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
|
||||
}
|
||||
|
||||
if (qproc->has_ext_cntl_regs) {
|
||||
regmap_write(qproc->conn_map, qproc->rscc_disable, 1);
|
||||
|
||||
ret = regmap_read_poll_timeout(qproc->halt_map, qproc->axim1_clk_off, val,
|
||||
!val, 1, Q6SS_CBCR_TIMEOUT_US);
|
||||
if (ret)
|
||||
dev_err(qproc->dev, "failed to enable axim1 clock\n");
|
||||
|
||||
ret = regmap_read_poll_timeout(qproc->halt_map, qproc->crypto_clk_off, val,
|
||||
!val, 1, Q6SS_CBCR_TIMEOUT_US);
|
||||
if (ret)
|
||||
dev_err(qproc->dev, "failed to enable crypto clock\n");
|
||||
}
|
||||
|
||||
q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_mdm);
|
||||
q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_cx);
|
||||
q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_axi);
|
||||
|
||||
q6v5_reset_assert(qproc);
|
||||
|
||||
q6v5_clk_disable(qproc->dev, qproc->reset_clks,
|
||||
@ -1471,6 +1616,7 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
|
||||
{
|
||||
struct of_phandle_args args;
|
||||
struct resource *res;
|
||||
int halt_cell_cnt = 3;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
|
||||
@ -1483,8 +1629,11 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
|
||||
if (IS_ERR(qproc->rmb_base))
|
||||
return PTR_ERR(qproc->rmb_base);
|
||||
|
||||
if (qproc->has_vq6)
|
||||
halt_cell_cnt++;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
|
||||
"qcom,halt-regs", 3, 0, &args);
|
||||
"qcom,halt-regs", halt_cell_cnt, 0, &args);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
|
||||
return -EINVAL;
|
||||
@ -1499,6 +1648,52 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
|
||||
qproc->halt_modem = args.args[1];
|
||||
qproc->halt_nc = args.args[2];
|
||||
|
||||
if (qproc->has_vq6)
|
||||
qproc->halt_vq6 = args.args[3];
|
||||
|
||||
if (qproc->has_qaccept_regs) {
|
||||
ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
|
||||
"qcom,qaccept-regs",
|
||||
3, 0, &args);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to parse qaccept-regs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qproc->qaccept_mdm = args.args[0];
|
||||
qproc->qaccept_cx = args.args[1];
|
||||
qproc->qaccept_axi = args.args[2];
|
||||
}
|
||||
|
||||
if (qproc->has_ext_cntl_regs) {
|
||||
ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
|
||||
"qcom,ext-regs",
|
||||
2, 0, &args);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to parse ext-regs 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->force_clk_on = args.args[0];
|
||||
qproc->rscc_disable = args.args[1];
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
|
||||
"qcom,ext-regs",
|
||||
2, 1, &args);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to parse ext-regs index 1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qproc->axim1_clk_off = args.args[0];
|
||||
qproc->crypto_clk_off = args.args[1];
|
||||
}
|
||||
|
||||
if (qproc->has_spare_reg) {
|
||||
ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
|
||||
"qcom,spare-regs",
|
||||
@ -1590,7 +1785,7 @@ static int q6v5_init_reset(struct q6v5 *qproc)
|
||||
return PTR_ERR(qproc->mss_restart);
|
||||
}
|
||||
|
||||
if (qproc->has_alt_reset || qproc->has_spare_reg) {
|
||||
if (qproc->has_alt_reset || qproc->has_spare_reg || qproc->has_ext_cntl_regs) {
|
||||
qproc->pdc_reset = devm_reset_control_get_exclusive(qproc->dev,
|
||||
"pdc_reset");
|
||||
if (IS_ERR(qproc->pdc_reset)) {
|
||||
@ -1697,6 +1892,9 @@ static int q6v5_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, qproc);
|
||||
|
||||
qproc->has_qaccept_regs = desc->has_qaccept_regs;
|
||||
qproc->has_ext_cntl_regs = desc->has_ext_cntl_regs;
|
||||
qproc->has_vq6 = desc->has_vq6;
|
||||
qproc->has_spare_reg = desc->has_spare_reg;
|
||||
ret = q6v5_init_mem(qproc, pdev);
|
||||
if (ret)
|
||||
@ -1857,9 +2055,40 @@ static const struct rproc_hexagon_res sc7180_mss = {
|
||||
.has_alt_reset = false,
|
||||
.has_mba_logs = true,
|
||||
.has_spare_reg = true,
|
||||
.has_qaccept_regs = false,
|
||||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_SC7180,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res sc7280_mss = {
|
||||
.hexagon_mba_image = "mba.mbn",
|
||||
.proxy_clk_names = (char*[]){
|
||||
"xo",
|
||||
"pka",
|
||||
NULL
|
||||
},
|
||||
.active_clk_names = (char*[]){
|
||||
"iface",
|
||||
"offline",
|
||||
"snoc_axi",
|
||||
NULL
|
||||
},
|
||||
.proxy_pd_names = (char*[]){
|
||||
"cx",
|
||||
"mss",
|
||||
NULL
|
||||
},
|
||||
.need_mem_protection = true,
|
||||
.has_alt_reset = false,
|
||||
.has_mba_logs = true,
|
||||
.has_spare_reg = false,
|
||||
.has_qaccept_regs = true,
|
||||
.has_ext_cntl_regs = true,
|
||||
.has_vq6 = true,
|
||||
.version = MSS_SC7280,
|
||||
};
|
||||
|
||||
static const struct rproc_hexagon_res sdm845_mss = {
|
||||
.hexagon_mba_image = "mba.mbn",
|
||||
.proxy_clk_names = (char*[]){
|
||||
@ -1889,6 +2118,9 @@ static const struct rproc_hexagon_res sdm845_mss = {
|
||||
.has_alt_reset = true,
|
||||
.has_mba_logs = false,
|
||||
.has_spare_reg = false,
|
||||
.has_qaccept_regs = false,
|
||||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_SDM845,
|
||||
};
|
||||
|
||||
@ -1917,6 +2149,9 @@ static const struct rproc_hexagon_res msm8998_mss = {
|
||||
.has_alt_reset = false,
|
||||
.has_mba_logs = false,
|
||||
.has_spare_reg = false,
|
||||
.has_qaccept_regs = false,
|
||||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8998,
|
||||
};
|
||||
|
||||
@ -1948,6 +2183,9 @@ static const struct rproc_hexagon_res msm8996_mss = {
|
||||
.has_alt_reset = false,
|
||||
.has_mba_logs = false,
|
||||
.has_spare_reg = false,
|
||||
.has_qaccept_regs = false,
|
||||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8996,
|
||||
};
|
||||
|
||||
@ -1990,6 +2228,9 @@ static const struct rproc_hexagon_res msm8916_mss = {
|
||||
.has_alt_reset = false,
|
||||
.has_mba_logs = false,
|
||||
.has_spare_reg = false,
|
||||
.has_qaccept_regs = false,
|
||||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8916,
|
||||
};
|
||||
|
||||
@ -2040,6 +2281,9 @@ static const struct rproc_hexagon_res msm8974_mss = {
|
||||
.has_alt_reset = false,
|
||||
.has_mba_logs = false,
|
||||
.has_spare_reg = false,
|
||||
.has_qaccept_regs = false,
|
||||
.has_ext_cntl_regs = false,
|
||||
.has_vq6 = false,
|
||||
.version = MSS_MSM8974,
|
||||
};
|
||||
|
||||
@ -2050,6 +2294,7 @@ static const struct of_device_id q6v5_of_match[] = {
|
||||
{ .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss},
|
||||
{ .compatible = "qcom,msm8998-mss-pil", .data = &msm8998_mss},
|
||||
{ .compatible = "qcom,sc7180-mss-pil", .data = &sc7180_mss},
|
||||
{ .compatible = "qcom,sc7280-mss-pil", .data = &sc7280_mss},
|
||||
{ .compatible = "qcom,sdm845-mss-pil", .data = &sdm845_mss},
|
||||
{ },
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user