From: Petr Hodina <[email protected]>

msm_spmi_write()/msm_spmi_read() busy-wait in inifinte loop.
Bound the wait with readl_poll_timeout() and return -ETIMEDOUT on
failure when the PMIC peripheral does not respond.

Signed-off-by: Petr Hodina <[email protected]>
---
Tested on Xiaomi Pad 5 (nabu) hardware: pm8150l's WLED node
on usid 5 never returns CMD_DONE.

msm_spmi_write()/msm_spmi_read() busy-wait on CMD_DONE with no
timeout. Therefore one unresponsive PMIC peripheral hangs boot
indefinitely.

Bound the wait with readl_poll_timeout() so DM can fail that one
device's probe instead of halting the whole boot.
---
 drivers/spmi/spmi-msm.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c
index b89dd0b406b..92cd42d8627 100644
--- a/drivers/spmi/spmi-msm.c
+++ b/drivers/spmi/spmi-msm.c
@@ -12,8 +12,11 @@
 #include <fdtdec.h>
 #include <asm/io.h>
 #include <dm/device_compat.h>
+#include <linux/iopoll.h>
 #include <spmi/spmi.h>
 
+#define SPMI_CMD_DONE_TIMEOUT_US 100000
+
 /* PMIC Arbiter configuration registers */
 #define PMIC_ARB_VERSION 0x0000
 #define PMIC_ARB_VERSION_V2_MIN 0x20010000
@@ -161,10 +164,10 @@ static int msm_spmi_write(struct udevice *dev, int usid, 
int pid, int off,
        writel(reg, priv->spmi_chnls + ch_offset + SPMI_REG_CMD0);
 
        /* Wait till CMD DONE status */
-       reg = 0;
-       while (!reg) {
-               reg = readl(priv->spmi_chnls + ch_offset +
-                           SPMI_REG_STATUS);
+       if (readl_poll_timeout(priv->spmi_chnls + ch_offset + SPMI_REG_STATUS,
+                              reg, reg, SPMI_CMD_DONE_TIMEOUT_US)) {
+               printf("SPMI write timeout (channel %#x).\n", ch_offset);
+               return -ETIMEDOUT;
        }
 
        if (reg ^ SPMI_STATUS_DONE) {
@@ -231,9 +234,10 @@ static int msm_spmi_read(struct udevice *dev, int usid, 
int pid, int off)
        writel(reg, priv->spmi_obs + ch_offset + SPMI_REG_CMD0);
 
        /* Wait till CMD DONE status */
-       reg = 0;
-       while (!reg) {
-               reg = readl(priv->spmi_obs + ch_offset + SPMI_REG_STATUS);
+       if (readl_poll_timeout(priv->spmi_obs + ch_offset + SPMI_REG_STATUS,
+                              reg, reg, SPMI_CMD_DONE_TIMEOUT_US)) {
+               printf("SPMI read timeout (channel %#x).\n", ch_offset);
+               return -ETIMEDOUT;
        }
 
        if (reg ^ SPMI_STATUS_DONE) {

---
base-commit: ece349ade2973e220f524ce59e59711cc919263f
change-id: 20261002-b4-qcom-spmi-a3c44ca5d952

Best regards,
--  
Petr Hodina <[email protected]>


Reply via email to