aboutsummaryrefslogtreecommitdiffci
path: root/patches/remoteproc/0011-remoteproc-qcom_q6v5_pas-Attach-running-remoteproc-i.patch
blob: 66ecc0f50134e38c40ddd4682afbb480439c8ac0 (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
102
103
104
105
106
A remoteproc might be already running during boot, e.g. because it was
already started by the boot firmware. This is the case for example on X1E,
where the boot firmware starts a "lite" ADSP firmware that supports
charging and USB-CC detection, but is missing audio functionality. This
firmware uses the same interfaces as the full firmware and can be reused in
case the device-specific firmware is missing (e.g. in generic distro
installers).

The running remoteproc is currently not modelled at all - it is just killed
through qcom_pas_shutdown() without even using the SMP2P stop signal
beforehand. If the firmware is present the "lite" firmware is now stopped more
gracefully with the SMP2P stop signal.

diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 672af7336..3cf24f202 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -236,10 +237,13 @@
 	/* Store firmware handle to be used in qcom_pas_start() */
 	pas->firmware = fw;
 
-	if (pas->lite_pas_id)
-		qcom_scm_pas_shutdown(pas->lite_pas_id);
-	if (pas->lite_dtb_pas_id)
-		qcom_scm_pas_shutdown(pas->lite_dtb_pas_id);
+	/*
+	 * We don't support loading the "lite" firmware, so we don't need to
+	 * keep trying to shut it down. If it was running, it should have
+	 * already been stopped by adsp_stop().
+	 */
+	pas->lite_pas_id = 0;
+	pas->lite_dtb_pas_id = 0;
 
 	if (pas->dtb_pas_id) {
 		ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev);
@@ -401,6 +405,28 @@
 	qcom_pas_pds_disable(pas, pas->proxy_pds, pas->proxy_pd_count);
 }
 
+static int qcom_q6v5_pas_shutdown(int pas_id, int lite_pas_id)
+{
+	int ret, lite_ret = -ENODEV;
+
+	/*
+	 * We don't know if the boot firmware started the "full" or "lite"
+	 * firmware, so we don't know if we need to shutdown the lite_pas_id or
+	 * the normal pas_id. Unfortunately, the return codes of the SCM calls
+	 * are also not helpful to figure that out. Since shutting down a
+	 * stopped remoteproc is a no-op, we just shutdown both and if one of
+	 * the calls succeeds, we assume it's okay.
+	 */
+	if (lite_pas_id)
+		lite_ret = qcom_scm_pas_shutdown(lite_pas_id);
+
+	ret = qcom_scm_pas_shutdown(pas_id);
+	if (ret && lite_ret)
+		return ret;
+
+	return 0;
+}
+
 static int qcom_pas_stop(struct rproc *rproc)
 {
 	struct qcom_pas *pas = rproc->priv;
@@ -411,7 +437,7 @@
 	if (ret == -ETIMEDOUT)
 		dev_err(pas->dev, "timed out on wait\n");
 
-	ret = qcom_scm_pas_shutdown(pas->pas_id);
+	ret = qcom_q6v5_pas_shutdown(pas->pas_id, pas->lite_pas_id);
 	if (ret && pas->decrypt_shutdown)
 		ret = qcom_pas_shutdown_poll_decrypt(pas);
 
@@ -419,7 +445,7 @@
 		dev_err(pas->dev, "failed to shutdown: %d\n", ret);
 
 	if (pas->dtb_pas_id) {
-		ret = qcom_scm_pas_shutdown(pas->dtb_pas_id);
+		ret = qcom_q6v5_pas_shutdown(pas->dtb_pas_id, pas->lite_dtb_pas_id);
 		if (ret)
 			dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret);
 
@@ -428,9 +454,11 @@
 
 	qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size);
 
-	handover = qcom_q6v5_unprepare(&pas->q6v5);
-	if (handover)
-		qcom_pas_handover(&pas->q6v5);
+	if (rproc->state != RPROC_DETACHED) {
+		handover = qcom_q6v5_unprepare(&pas->q6v5);
+		if (handover)
+			qcom_pas_handover(&pas->q6v5);
+	}
 
 	if (pas->smem_host_id)
 		ret = qcom_smem_bust_hwspin_lock_by_host(pas->smem_host_id);
@@ -859,7 +890,7 @@
 
 	rproc->has_iommu = of_property_present(pdev->dev.of_node, "iommus");
 	if (desc->auto_boot)
-		rproc->auto_boot = RPROC_AUTO_BOOT_ATTACH_OR_START;
+		rproc->auto_boot = RPROC_AUTO_BOOT_RESTART_IF_FW_AVAILABLE;
 	else
 		rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
 	rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);