video: rockchip: vpu: introduce safe reset method
authorRandy Li <randy.li@rock-chips.com>
Fri, 21 Apr 2017 09:39:05 +0000 (17:39 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 6 Jun 2017 09:44:31 +0000 (17:44 +0800)
Even the same type video IP would request a different numbers
of reset control.

From the RK3328 times, the video IP also request decrease the
frequency of the clock to lower than 300 MHZ before resetting.
It seems no hard to apply it into the previous platform.

Change-Id: Iacf1accf24c8776bb8b425b613e6e34215380203
Signed-off-by: Randy Li <randy.li@rock-chips.com>
drivers/video/rockchip/vcodec/vcodec_service.c

index 03ef51341d91f66971387698b2c051435fee8399..13a0adc31958519bf9d26051fe87cd9d35ca342e 100644 (file)
@@ -405,6 +405,8 @@ struct vpu_service_info {
        struct reset_control *rst_a;
        struct reset_control *rst_h;
        struct reset_control *rst_v;
+       struct reset_control *rst_niu_a;
+       struct reset_control *rst_niu_h;
 #endif
        struct device *dev;
 
@@ -479,6 +481,20 @@ static void time_diff(struct vpu_task_info *task)
                  (task->end.tv_usec - task->start.tv_usec) / 1000);
 }
 
+static inline int try_reset_assert(struct reset_control *rst)
+{
+       if (rst)
+               return reset_control_assert(rst);
+       return -EINVAL;
+}
+
+static inline int try_reset_deassert(struct reset_control *rst)
+{
+       if (rst)
+               return reset_control_deassert(rst);
+       return -EINVAL;
+}
+
 static inline int grf_combo_switch(const struct vpu_subdev_data *data)
 {
        struct vpu_service_info *pservice = data->pservice;
@@ -658,10 +674,7 @@ static int vpu_get_clk(struct vpu_service_info *pservice)
 static void _vpu_reset(struct vpu_subdev_data *data)
 {
        struct vpu_service_info *pservice = data->pservice;
-       enum pmu_idle_req type = IDLE_REQ_VIDEO;
-
-       if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC)
-               type = IDLE_REQ_HEVC;
+       unsigned long rate = 0;
 
        dev_info(pservice->dev, "resetting...\n");
        WARN_ON(pservice->reg_codec != NULL);
@@ -672,31 +685,31 @@ static void _vpu_reset(struct vpu_subdev_data *data)
        pservice->reg_resev = NULL;
 
 #ifdef CONFIG_RESET_CONTROLLER
-       dev_info(pservice->dev, "for 3288/3368...");
-       if (of_machine_is_compatible("rockchip,rk3288"))
-               rockchip_pmu_idle_request(pservice->dev, true);
-       if (pservice->rst_a && pservice->rst_h) {
-               dev_info(pservice->dev, "vpu reset in\n");
-
-               if (pservice->rst_v)
-                       reset_control_assert(pservice->rst_v);
-               reset_control_assert(pservice->rst_a);
-               reset_control_assert(pservice->rst_h);
-               udelay(5);
-
-               reset_control_deassert(pservice->rst_h);
-               reset_control_deassert(pservice->rst_a);
-               if (pservice->rst_v)
-                       reset_control_deassert(pservice->rst_v);
-       } else if (pservice->rst_v) {
-               dev_info(pservice->dev, "hevc reset in\n");
-               reset_control_assert(pservice->rst_v);
-               udelay(5);
-
-               reset_control_deassert(pservice->rst_v);
-       }
-       if (of_machine_is_compatible("rockchip,rk3288"))
-               rockchip_pmu_idle_request(pservice->dev, false);
+       rockchip_pmu_idle_request(pservice->dev, true);
+       rate = clk_get_rate(pservice->aclk_vcodec);
+       /*
+        * Some old platforms can't run at 300MHZ, they don't request
+        * decrease the frequency at resetting either. It is safe to
+        * keep here in 200 MHZ.
+        */
+       clk_set_rate(pservice->aclk_vcodec, 200 * MHZ);
+
+       try_reset_assert(pservice->rst_niu_a);
+       try_reset_assert(pservice->rst_niu_h);
+       try_reset_assert(pservice->rst_v);
+       try_reset_assert(pservice->rst_a);
+       try_reset_assert(pservice->rst_h);
+       udelay(5);
+
+       try_reset_deassert(pservice->rst_h);
+       try_reset_deassert(pservice->rst_a);
+       try_reset_deassert(pservice->rst_v);
+       try_reset_deassert(pservice->rst_niu_h);
+       try_reset_deassert(pservice->rst_niu_a);
+
+       rockchip_pmu_idle_request(pservice->dev, false);
+       clk_set_rate(pservice->aclk_vcodec, rate);
+       dev_info(pservice->dev, "reset done\n");
 #endif
 }
 
@@ -2536,21 +2549,33 @@ static void vcodec_read_property(struct device_node *np,
        pservice->rst_a = devm_reset_control_get(pservice->dev, "video_a");
        pservice->rst_h = devm_reset_control_get(pservice->dev, "video_h");
        pservice->rst_v = devm_reset_control_get(pservice->dev, "video");
+       pservice->rst_niu_a = devm_reset_control_get(pservice->dev, "niu_a");
+       pservice->rst_niu_h = devm_reset_control_get(pservice->dev, "niu_h");
 
        if (IS_ERR_OR_NULL(pservice->rst_a)) {
-               dev_warn(pservice->dev, "No aclk reset resource define\n");
+               dev_dbg(pservice->dev, "No aclk reset resource define\n");
                pservice->rst_a = NULL;
        }
 
        if (IS_ERR_OR_NULL(pservice->rst_h)) {
-               dev_warn(pservice->dev, "No hclk reset resource define\n");
+               dev_dbg(pservice->dev, "No hclk reset resource define\n");
                pservice->rst_h = NULL;
        }
 
        if (IS_ERR_OR_NULL(pservice->rst_v)) {
-               dev_warn(pservice->dev, "No core reset resource define\n");
+               dev_dbg(pservice->dev, "No core reset resource define\n");
                pservice->rst_v = NULL;
        }
+
+       if (IS_ERR_OR_NULL(pservice->rst_niu_a)) {
+               dev_dbg(pservice->dev, "No NIU aclk reset resource define\n");
+               pservice->rst_niu_a = NULL;
+       }
+
+       if (IS_ERR_OR_NULL(pservice->rst_niu_h)) {
+               dev_dbg(pservice->dev, "No NIU hclk reset resource define\n");
+               pservice->rst_niu_h = NULL;
+       }
 #endif
 
        of_property_read_string(np, "name", (const char **)&pservice->name);