aboutsummaryrefslogtreecommitdiffci
path: root/patches/remoteproc/0012-remoteproc-qcom_q6v5_pas-Avoid-using-broken-reset.patch
blob: f580ea58631c58fc8970c2e383261ac641e6ca5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
Some firmware versions have a split design where firmware authentication is
implemented in the TZ firmware, but the remoteproc reset sequence appears
to be triggered by the hypervisor firmware. When running bare-metal without
the hypervisor only the firmware authentication functionality is present.
Without knowledge of the exact hardware reset register sequence, we cannot
(re)start the remoteproc from Linux.

This does not make the qcom_q6v5_pas driver useless. In case the remoteproc
is already running during boot, we can attach to it as usual and keep using
it until it crashes or is manually stopped. Not being able to restart it is
not ideal, but not a big loss: A remoteproc should rarely (if ever) crash
during normal use. Also, currently most drivers upstream cannot properly
handle a remoteproc crash anyway (without full system restart).

Detecting this case automatically is tricky since all the PAS related calls
still succeed, it will just not release the remoteproc from reset. Also, on
SC7180, MPSS does always work correctly, only ADSP and CDSP are broken.
Look for a new "qcom,broken-reset" property so we can check which of the
remoteprocs are affected.

Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
---
 drivers/remoteproc/qcom_q6v5_pas.c | 32 +++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 3cf24f202..c80af9654 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -455,6 +455,13 @@ static const struct rproc_ops qcom_pas_minidump_ops = {
 	.coredump = qcom_pas_minidump,
 };
 
+static const struct rproc_ops qcom_pas_ops_no_reset = {
+	.attach = qcom_pas_attach,
+	.da_to_va = qcom_pas_da_to_va,
+	.stop = qcom_pas_stop,
+	.panic = qcom_pas_panic,
+};
+
 static int qcom_pas_init_clock(struct qcom_pas *pas)
 {
 	pas->xo = devm_clk_get(pas->dev, "xo");
@@ -664,6 +671,7 @@
 	struct rproc *rproc;
 	const char *fw_name, *dtb_fw_name = NULL;
 	const struct rproc_ops *ops = &qcom_pas_ops;
+	bool recovery_disabled = false;
 	int ret;
 
 	desc = of_device_get_match_data(&pdev->dev);
@@ -690,6 +698,11 @@
 	if (desc->minidump_id)
 		ops = &qcom_pas_minidump_ops;
 
+	if (device_property_read_bool(&pdev->dev, "qcom,broken-reset")) {
+		ops = &qcom_pas_ops_no_reset;
+		recovery_disabled = true;
+	}
+
 	rproc = devm_rproc_alloc(&pdev->dev, desc->sysmon_name, ops, fw_name, sizeof(*pas));
 
 	if (!rproc) {
@@ -752,10 +762,15 @@ static int qcom_pas_probe(struct platform_device *pdev)
 	}
 
 	rproc->has_iommu = of_property_present(pdev->dev.of_node, "iommus");
-	if (desc->auto_boot)
-		rproc->auto_boot = RPROC_AUTO_BOOT_RESTART_IF_FW_AVAILABLE;
-	else
+	rproc->recovery_disabled = recovery_disabled;
+	if (desc->auto_boot) {
+		if (ops->start)
+			rproc->auto_boot = RPROC_AUTO_BOOT_RESTART_IF_FW_AVAILABLE;
+		else
+			rproc->auto_boot = RPROC_AUTO_BOOT_ATTACH_OR_START;
+	} else {
 		rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
+	}
 	rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
 
 	pas = rproc->priv;
@@ -846,6 +868,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
 	qcom_pas_unassign_memory_region(pas);
 free_rproc:
 	device_init_wakeup(pas->dev, false);
+	pas->rproc = NULL;
 
 	return ret;
 }
@@ -854,6 +877,9 @@ static void qcom_pas_remove(struct platform_device *pdev)
 {
 	struct qcom_pas *pas = platform_get_drvdata(pdev);
 
+	if (!pas->rproc)
+		return;
+
 	rproc_del(pas->rproc);
 
 	qcom_q6v5_deinit(&pas->q6v5);