firmware: qcom_scm: disable SDI if required
authorRobert Marko <robimarko@gmail.com>
Wed, 16 Aug 2023 16:45:39 +0000 (18:45 +0200)
committerBjorn Andersson <andersson@kernel.org>
Wed, 20 Sep 2023 18:00:08 +0000 (11:00 -0700)
IPQ5018 has SDI (Secure Debug Image) enabled by TZ by default, and that
means that WDT being asserted or just trying to reboot will hang the board
in the debug mode and only pulling the power and repowering will help.
Some IPQ4019 boards like Google WiFI have it enabled as well.

Luckily, SDI can be disabled via an SCM call.

So, lets use the boolean DT property to identify boards that have SDI
enabled by default and use the SCM call to disable SDI during SCM probe.
It is important to disable it as soon as possible as we might have a WDT
assertion at any time which would then leave the board in debug mode,
thus disabling it during SCM removal is not enough.

Signed-off-by: Robert Marko <robimarko@gmail.com>
Reviewed-by: Guru Das Srinagesh <quic_gurus@quicinc.com>
Link: https://lore.kernel.org/r/20230816164641.3371878-2-robimarko@gmail.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
drivers/firmware/qcom_scm.c
drivers/firmware/qcom_scm.h

index ca52618e2a8d4409e9e2ee5534edb8b57ea4d6da..c2c7fafef34be46263b09774e57c2f9d2baeed48 100644 (file)
@@ -451,6 +451,29 @@ int qcom_scm_set_remote_state(u32 state, u32 id)
 }
 EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
 
+static int qcom_scm_disable_sdi(void)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_SDI_CONFIG,
+               .args[0] = 1, /* Disable watchdog debug */
+               .args[1] = 0, /* Disable SDI */
+               .arginfo = QCOM_SCM_ARGS(2),
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       qcom_scm_clk_disable();
+
+       return ret ? : res.result[0];
+}
+
 static int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
 {
        struct qcom_scm_desc desc = {
@@ -1850,6 +1873,13 @@ static int qcom_scm_probe(struct platform_device *pdev)
        if (download_mode)
                qcom_scm_set_download_mode(true);
 
+
+       /*
+        * Disable SDI if indicated by DT that it is enabled by default.
+        */
+       if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled"))
+               qcom_scm_disable_sdi();
+
        /*
         * Initialize the QSEECOM interface.
         *
index e6e512bd57d1b95d77735400c669a9832def8768..7b68fa820495c0c916b0942dd3319c0bf6812963 100644 (file)
@@ -80,6 +80,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
 #define QCOM_SCM_SVC_BOOT              0x01
 #define QCOM_SCM_BOOT_SET_ADDR         0x01
 #define QCOM_SCM_BOOT_TERMINATE_PC     0x02
+#define QCOM_SCM_BOOT_SDI_CONFIG       0x09
 #define QCOM_SCM_BOOT_SET_DLOAD_MODE   0x10
 #define QCOM_SCM_BOOT_SET_ADDR_MC      0x11
 #define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a