]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
media: iris: vpu3x: Add MNoC low power handshake during hardware power-off
authorDikshita Agarwal <quic_dikshita@quicinc.com>
Fri, 22 Aug 2025 05:53:30 +0000 (11:23 +0530)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Tue, 9 Sep 2025 13:59:20 +0000 (15:59 +0200)
Add the missing write to AON_WRAPPER_MVP_NOC_LPI_CONTROL before
reading the LPI status register. Introduce a handshake loop to ensure
MNoC enters low power mode reliably during VPU3 hardware power-off with
timeout handling.

Fixes: 02083a1e00ae ("media: platform: qcom/iris: add support for vpu33")
Cc: stable@vger.kernel.org
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-QRD
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-HDK
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
drivers/media/platform/qcom/iris/iris_vpu3x.c

index 9b7c9a1495ee2f51c60b1142b2ed4680ff798f0a..bfc52eb04ed0e1c88efe74a8d27bb95e8a0ca331 100644 (file)
@@ -19,6 +19,9 @@
 #define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL       (WRAPPER_BASE_OFFS + 0x5C)
 #define REQ_POWER_DOWN_PREP                    BIT(0)
 #define WRAPPER_IRIS_CPU_NOC_LPI_STATUS                (WRAPPER_BASE_OFFS + 0x60)
+#define NOC_LPI_STATUS_DONE                    BIT(0) /* Indicates the NOC handshake is complete */
+#define NOC_LPI_STATUS_DENY                    BIT(1) /* Indicates the NOC handshake is denied */
+#define NOC_LPI_STATUS_ACTIVE          BIT(2) /* Indicates the NOC is active */
 #define WRAPPER_CORE_CLOCK_CONFIG              (WRAPPER_BASE_OFFS + 0x88)
 #define CORE_CLK_RUN                           0x0
 
@@ -109,7 +112,9 @@ disable_power:
 
 static void iris_vpu33_power_off_hardware(struct iris_core *core)
 {
+       bool handshake_done = false, handshake_busy = false;
        u32 reg_val = 0, value, i;
+       u32 count = 0;
        int ret;
 
        if (iris_vpu3x_hw_power_collapsed(core))
@@ -128,13 +133,36 @@ static void iris_vpu33_power_off_hardware(struct iris_core *core)
                        goto disable_power;
        }
 
+       /* Retry up to 1000 times as recommended by hardware documentation */
+       do {
+               /* set MNoC to low power */
+               writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
+
+               udelay(15);
+
+               value = readl(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS);
+
+               handshake_done = value & NOC_LPI_STATUS_DONE;
+               handshake_busy = value & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE);
+
+               if (handshake_done || !handshake_busy)
+                       break;
+
+               writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
+
+               udelay(15);
+
+       } while (++count < 1000);
+
+       if (!handshake_done && handshake_busy)
+               dev_err(core->dev, "LPI handshake timeout\n");
+
        ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS,
                                 reg_val, reg_val & BIT(0), 200, 2000);
        if (ret)
                goto disable_power;
 
-       /* set MNoC to low power, set PD_NOC_QREQ (bit 0) */
-       writel(BIT(0), core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
+       writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
 
        writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE,
               core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);