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);
|