From: Alexey Minnekhanov <[email protected]>

In the Linux driver, depending on which GDSC flags are set, a different
status register is checked when powering it on/off. And on top of that,
a different bit inside that register is tested. Currently qcom clk
implementation in U-Boot lacks this functionality, so adjust logic when
checking GDSC status to match one in Linux driver.

This fixes problems on e.g. MSM8998 and SDM660's with USB_30_GDSC to be
forever stuck during power on, since unlike e.g SDM845 one it doesn't
have POLL_CFG_GDSCR flag (only VOTABLE).

With this change all GDSCs that have POLL_CFG_GDSCR in their flags
keep old behaviour (same as before this patch).

Signed-off-by: Alexey Minnekhanov <[email protected]>
Signed-off-by: Luca Weiss <[email protected]>
---
 drivers/clk/qcom/clock-qcom.c | 42 +++++++++++++++++++++++++++++-------------
 1 file changed, 29 insertions(+), 13 deletions(-)

diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
index 557f30d54d4..4e391187080 100644
--- a/drivers/clk/qcom/clock-qcom.c
+++ b/drivers/clk/qcom/clock-qcom.c
@@ -527,19 +527,35 @@ static int qcom_power_set(struct power_domain *pwr, bool 
on)
 
        writel(value, base + map->reg);
 
-       if (on)
-               ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
-                                        value,
-                                        (value & GDSC_POWER_UP_COMPLETE) ||
-                                        (value & GDSC_PWR_ON_MASK),
-                                        GDSC_STATUS_POLL_TIMEOUT_US);
-
-       else
-               ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
-                                        value,
-                                        (value & GDSC_POWER_DOWN_COMPLETE) ||
-                                        !(value & GDSC_PWR_ON_MASK),
-                                        GDSC_STATUS_POLL_TIMEOUT_US);
+       /*
+        * Depending on the type of GDSC the status register is different,
+        * and we need to check different status bit (condition passed to
+        * readl_poll_timeout() is different too).
+        * See Linux src: drivers/clk/qcom/gdsc.c @ gdsc_check_status() func
+        */
+       if (map->flags & POLL_CFG_GDSCR) {
+               if (on)
+                       ret = readl_poll_timeout(base + map->reg + 
CFG_GDSCR_OFFSET,
+                                                value,
+                                                (value & 
GDSC_POWER_UP_COMPLETE),
+                                                GDSC_STATUS_POLL_TIMEOUT_US);
+               else
+                       ret = readl_poll_timeout(base + map->reg + 
CFG_GDSCR_OFFSET,
+                                                value,
+                                                (value & 
GDSC_POWER_DOWN_COMPLETE),
+                                                GDSC_STATUS_POLL_TIMEOUT_US);
+       } else {
+               if (on)
+                       ret = readl_poll_timeout(base + map->reg,
+                                                value,
+                                                (value & GDSC_PWR_ON_MASK),
+                                                GDSC_STATUS_POLL_TIMEOUT_US);
+               else
+                       ret = readl_poll_timeout(base + map->reg,
+                                                value,
+                                                !(value & GDSC_PWR_ON_MASK),
+                                                GDSC_STATUS_POLL_TIMEOUT_US);
+       }
 
        if (ret == -ETIMEDOUT)
                printf("WARNING: GDSC %lu is stuck during power o%s\n",

-- 
2.55.0

Reply via email to