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]>
