media: venus: hfi_venus: fix suspend function for venus 3xx versions
authorStanimir Varbanov <stanimir.varbanov@linaro.org>
Thu, 5 Jul 2018 13:03:42 +0000 (09:03 -0400)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Wed, 25 Jul 2018 12:45:27 +0000 (08:45 -0400)
This fixes the suspend function for Venus 3xx versions by
add a check for WFI (wait for interrupt) bit. This bit
is on when the ARM9 is idle and entered in low power mode.

Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
Reviewed-by: Tomasz Figa <tfiga@chromium.org>
Reviewed-by: Alexandre Courbot <acourbot@chromium.org>
Tested-by: Alexandre Courbot <acourbot@chromium.org>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/platform/qcom/venus/hfi_venus.c
drivers/media/platform/qcom/venus/hfi_venus_io.h

index 784b3ad..72a8547 100644 (file)
@@ -1444,13 +1444,40 @@ static int venus_suspend_1xx(struct venus_core *core)
        return 0;
 }
 
+static bool venus_cpu_and_video_core_idle(struct venus_hfi_device *hdev)
+{
+       u32 ctrl_status, cpu_status;
+
+       cpu_status = venus_readl(hdev, WRAPPER_CPU_STATUS);
+       ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
+
+       if (cpu_status & WRAPPER_CPU_STATUS_WFI &&
+           ctrl_status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK)
+               return true;
+
+       return false;
+}
+
+static bool venus_cpu_idle_and_pc_ready(struct venus_hfi_device *hdev)
+{
+       u32 ctrl_status, cpu_status;
+
+       cpu_status = venus_readl(hdev, WRAPPER_CPU_STATUS);
+       ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
+
+       if (cpu_status & WRAPPER_CPU_STATUS_WFI &&
+           ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)
+               return true;
+
+       return false;
+}
+
 static int venus_suspend_3xx(struct venus_core *core)
 {
        struct venus_hfi_device *hdev = to_hfi_priv(core);
        struct device *dev = core->dev;
-       u32 ctrl_status, wfi_status;
+       bool val;
        int ret;
-       int cnt = 100;
 
        if (!hdev->power_enabled || hdev->suspended)
                return 0;
@@ -1464,29 +1491,30 @@ static int venus_suspend_3xx(struct venus_core *core)
                return -EINVAL;
        }
 
-       ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
-       if (!(ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)) {
-               wfi_status = venus_readl(hdev, WRAPPER_CPU_STATUS);
-               ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
-
-               ret = venus_prepare_power_collapse(hdev, false);
-               if (ret) {
-                       dev_err(dev, "prepare for power collapse fail (%d)\n",
-                               ret);
-                       return ret;
-               }
+       /*
+        * Power collapse sequence for Venus 3xx and 4xx versions:
+        * 1. Check for ARM9 and video core to be idle by checking WFI bit
+        *    (bit 0) in CPU status register and by checking Idle (bit 30) in
+        *    Control status register for video core.
+        * 2. Send a command to prepare for power collapse.
+        * 3. Check for WFI and PC_READY bits.
+        */
+       ret = readx_poll_timeout(venus_cpu_and_video_core_idle, hdev, val, val,
+                                1500, 100 * 1500);
+       if (ret)
+               return ret;
 
-               cnt = 100;
-               while (cnt--) {
-                       wfi_status = venus_readl(hdev, WRAPPER_CPU_STATUS);
-                       ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
-                       if (ctrl_status & CPU_CS_SCIACMDARG0_PC_READY &&
-                           wfi_status & BIT(0))
-                               break;
-                       usleep_range(1000, 1500);
-               }
+       ret = venus_prepare_power_collapse(hdev, false);
+       if (ret) {
+               dev_err(dev, "prepare for power collapse fail (%d)\n", ret);
+               return ret;
        }
 
+       ret = readx_poll_timeout(venus_cpu_idle_and_pc_ready, hdev, val, val,
+                                1500, 100 * 1500);
+       if (ret)
+               return ret;
+
        mutex_lock(&hdev->lock);
 
        ret = venus_power_off(hdev);
index c0b18de..def0926 100644 (file)
 
 #define WRAPPER_CPU_CGC_DIS                    (WRAPPER_BASE + 0x2010)
 #define WRAPPER_CPU_STATUS                     (WRAPPER_BASE + 0x2014)
+#define WRAPPER_CPU_STATUS_WFI                 BIT(0)
 #define WRAPPER_SW_RESET                       (WRAPPER_BASE + 0x3000)
 
 /* Venus 4xx */