Loading drivers/media/platform/msm/vidc/msm_cvp.c +59 −0 Original line number Diff line number Diff line Loading @@ -311,8 +311,29 @@ static int msm_cvp_request_power(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "%s: failed to scale clocks and bus for inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); goto exit; } if (!inst->clk_data.min_freq && !inst->clk_data.ddr_bw && !inst->clk_data.sys_cache_bw) { rc = msm_cvp_inst_pause(inst); if (rc) { dprintk(VIDC_ERR, "%s: failed to pause inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); goto exit; } } else { rc = msm_cvp_inst_resume(inst); if (rc) { dprintk(VIDC_ERR, "%s: failed to resume inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); goto exit; } } exit: return rc; } Loading Loading @@ -515,6 +536,44 @@ int msm_cvp_ctrl_init(struct msm_vidc_inst *inst, ARRAY_SIZE(msm_cvp_ctrls), ctrl_ops); } int msm_cvp_inst_pause(struct msm_vidc_inst *inst) { int rc; struct hfi_device *hdev; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } hdev = inst->core->device; rc = call_hfi_op(hdev, session_pause, (void *)inst->session); if (rc) dprintk(VIDC_ERR, "%s: failed to pause inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); return rc; } int msm_cvp_inst_resume(struct msm_vidc_inst *inst) { int rc; struct hfi_device *hdev; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } hdev = inst->core->device; rc = call_hfi_op(hdev, session_resume, (void *)inst->session); if (rc) dprintk(VIDC_ERR, "%s: failed to resume inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); return rc; } int msm_cvp_inst_deinit(struct msm_vidc_inst *inst) { int rc = 0; Loading drivers/media/platform/msm/vidc/msm_cvp.h +2 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ void handle_session_unregister_buffer_done(enum hal_command_response cmd, int msm_vidc_cvp(struct msm_vidc_inst *inst, struct msm_vidc_arg *arg); int msm_cvp_inst_init(struct msm_vidc_inst *inst); int msm_cvp_inst_deinit(struct msm_vidc_inst *inst); int msm_cvp_inst_pause(struct msm_vidc_inst *inst); int msm_cvp_inst_resume(struct msm_vidc_inst *inst); int msm_cvp_ctrl_init(struct msm_vidc_inst *inst, const struct v4l2_ctrl_ops *ctrl_ops); #endif drivers/media/platform/msm/vidc/venus_hfi.c +284 −22 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <linux/soc/qcom/smem.h> #include <soc/qcom/subsystem_restart.h> #include <linux/dma-mapping.h> #include <linux/fastcvpd.h> #include "hfi_packetization.h" #include "msm_vidc_debug.h" #include "venus_hfi.h" Loading Loading @@ -104,6 +105,7 @@ static int __enable_subcaches(struct venus_hfi_device *device); static int __set_subcaches(struct venus_hfi_device *device); static int __release_subcaches(struct venus_hfi_device *device); static int __disable_subcaches(struct venus_hfi_device *device); static int __power_collapse(struct venus_hfi_device *device, bool force); static int venus_hfi_noc_error_info(void *dev); /** Loading Loading @@ -252,6 +254,216 @@ static void __sim_modify_cmd_packet(u8 *packet, struct venus_hfi_device *device) } } static int __dsp_send_hfi_queue(struct venus_hfi_device *device) { int rc; if (!device->res->domain_cvp) return 0; if (!device->dsp_iface_q_table.mem_data.dma_handle) { dprintk(VIDC_ERR, "%s: invalid dsm_handle\n", __func__); return -EINVAL; } if (device->dsp_flags & DSP_INIT) { dprintk(VIDC_DBG, "%s: dsp already inited\n"); return 0; } dprintk(VIDC_DBG, "%s: hfi queue %#x size %d\n", __func__, device->dsp_iface_q_table.mem_data.dma_handle, device->dsp_iface_q_table.mem_data.size); rc = fastcvpd_video_send_cmd_hfi_queue( (phys_addr_t *)device->dsp_iface_q_table.mem_data.dma_handle, device->dsp_iface_q_table.mem_data.size); if (rc) { dprintk(VIDC_ERR, "%s: dsp init failed\n", __func__); return rc; } device->dsp_flags |= DSP_INIT; dprintk(VIDC_DBG, "%s: dsp inited\n", __func__); return rc; } static int __dsp_suspend(struct venus_hfi_device *device, bool force, u32 flags) { int rc; struct hal_session *temp; if (!device->res->domain_cvp) return 0; if (!(device->dsp_flags & DSP_INIT)) return 0; if (device->dsp_flags & DSP_SUSPEND) return 0; list_for_each_entry(temp, &device->sess_head, list) { /* if forceful suspend, don't check session pause info */ if (force) continue; if (temp->domain == HAL_VIDEO_DOMAIN_CVP) { /* don't suspend if cvp session is not paused */ if (!(temp->flags & SESSION_PAUSE)) { dprintk(VIDC_DBG, "%s: cvp session %x not paused\n", __func__, hash32_ptr(temp)); return -EBUSY; } } } dprintk(VIDC_DBG, "%s: suspend dsp\n", __func__); rc = fastcvpd_video_suspend(flags); if (rc) { dprintk(VIDC_ERR, "%s: dsp suspend failed with error %d\n", __func__, rc); return -EINVAL; } device->dsp_flags |= DSP_SUSPEND; dprintk(VIDC_DBG, "%s: dsp suspended\n", __func__); return 0; } static int __dsp_resume(struct venus_hfi_device *device, u32 flags) { int rc; if (!device->res->domain_cvp) return 0; if (!(device->dsp_flags & DSP_SUSPEND)) { dprintk(VIDC_DBG, "%s: dsp not suspended\n", __func__); return 0; } dprintk(VIDC_DBG, "%s: resume dsp\n", __func__); rc = fastcvpd_video_resume(flags); if (rc) { dprintk(VIDC_ERR, "%s: dsp resume failed with error %d\n", __func__, rc); return rc; } device->dsp_flags &= ~DSP_SUSPEND; dprintk(VIDC_DBG, "%s: dsp resumed\n", __func__); return rc; } static int __dsp_shutdown(struct venus_hfi_device *device, u32 flags) { int rc; if (!device->res->domain_cvp) return 0; if (!(device->dsp_flags & DSP_INIT)) { dprintk(VIDC_DBG, "%s: dsp not inited\n", __func__); return 0; } dprintk(VIDC_DBG, "%s: shutdown dsp\n", __func__); rc = fastcvpd_video_shutdown(flags); if (rc) { dprintk(VIDC_ERR, "%s: dsp shutdown failed with error %d\n", __func__, rc); WARN_ON(1); } device->dsp_flags &= ~DSP_INIT; dprintk(VIDC_DBG, "%s: dsp shutdown successful\n", __func__); return rc; } static int __session_pause(struct venus_hfi_device *device, struct hal_session *session) { int rc = 0; /* ignore if session paused already */ if (session->flags & SESSION_PAUSE) return 0; session->flags |= SESSION_PAUSE; dprintk(VIDC_DBG, "%s: cvp session %x paused\n", __func__, hash32_ptr(session)); return rc; } static int __session_resume(struct venus_hfi_device *device, struct hal_session *session) { int rc = 0; /* ignore if session already resumed */ if (!(session->flags & SESSION_PAUSE)) return 0; session->flags &= ~SESSION_PAUSE; dprintk(VIDC_DBG, "%s: cvp session %x resumed\n", __func__, hash32_ptr(session)); rc = __resume(device); if (rc) { dprintk(VIDC_ERR, "%s: resume failed\n", __func__); goto exit; } if (device->dsp_flags & DSP_SUSPEND) { dprintk(VIDC_ERR, "%s: dsp not resumed\n", __func__); rc = -EINVAL; goto exit; } exit: return rc; } static int venus_hfi_session_pause(void *sess) { int rc; struct hal_session *session = sess; struct venus_hfi_device *device; if (!session || !session->device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } device = session->device; mutex_lock(&device->lock); rc = __session_pause(device, session); mutex_unlock(&device->lock); return rc; } static int venus_hfi_session_resume(void *sess) { int rc; struct hal_session *session = sess; struct venus_hfi_device *device; if (!session || !session->device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } device = session->device; mutex_lock(&device->lock); rc = __session_resume(device, session); mutex_unlock(&device->lock); return rc; } static int __acquire_regulator(struct regulator_info *rinfo, struct venus_hfi_device *device) { Loading Loading @@ -1098,14 +1310,18 @@ static int venus_hfi_suspend(void *dev) } dprintk(VIDC_DBG, "Suspending Venus\n"); flush_delayed_work(&venus_hfi_pm_work); mutex_lock(&device->lock); if (device->power_enabled) { rc = __power_collapse(device, true); if (rc) { dprintk(VIDC_WARN, "%s: Venus is busy\n", __func__); rc = -EBUSY; } mutex_unlock(&device->lock); /* Cancel pending delayed works if any */ if (!rc) cancel_delayed_work(&venus_hfi_pm_work); return rc; } Loading Loading @@ -1957,6 +2173,7 @@ static int venus_hfi_core_init(void *device) __enable_subcaches(device); __set_subcaches(device); __dsp_send_hfi_queue(device); if (dev->res->pm_qos_latency_us) { #ifdef CONFIG_SMP Loading Loading @@ -1998,6 +2215,8 @@ static int venus_hfi_core_release(void *dev) __resume(device); __set_state(device, VENUS_STATE_DEINIT); __dsp_shutdown(device, 0); __unload_fw(device); /* unlink all sessions from device */ Loading Loading @@ -2986,9 +3205,6 @@ static int __prepare_pc(struct venus_hfi_device *device) static void venus_hfi_pm_handler(struct work_struct *work) { int rc = 0; u32 wfi_status = 0, idle_status = 0, pc_ready = 0; int count = 0; const int max_tries = 10; struct venus_hfi_device *device = list_first_entry( &hal_ctxt.dev_head, struct venus_hfi_device, list); Loading @@ -3010,7 +3226,51 @@ static void venus_hfi_pm_handler(struct work_struct *work) __process_fatal_error(device); return; } mutex_lock(&device->lock); rc = __power_collapse(device, false); mutex_unlock(&device->lock); switch (rc) { case 0: device->skip_pc_count = 0; /* Cancel pending delayed works if any */ cancel_delayed_work(&venus_hfi_pm_work); dprintk(VIDC_PROF, "%s: power collapse successful!\n", __func__); break; case -EBUSY: device->skip_pc_count = 0; dprintk(VIDC_DBG, "%s: retry PC as dsp is busy\n", __func__); queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work, msecs_to_jiffies( device->res->msm_vidc_pwr_collapse_delay)); break; case -EAGAIN: device->skip_pc_count++; dprintk(VIDC_WARN, "%s: retry power collapse (count %d)\n", __func__, device->skip_pc_count); queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work, msecs_to_jiffies( device->res->msm_vidc_pwr_collapse_delay)); break; default: dprintk(VIDC_ERR, "%s: power collapse failed\n", __func__); break; } } static int __power_collapse(struct venus_hfi_device *device, bool force) { int rc = 0; u32 wfi_status = 0, idle_status = 0, pc_ready = 0; u32 flags = 0; int count = 0; const int max_tries = 10; if (!device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } if (!device->power_enabled) { dprintk(VIDC_DBG, "%s: Power already disabled\n", __func__); Loading @@ -3021,8 +3281,15 @@ static void venus_hfi_pm_handler(struct work_struct *work) if (!rc) { dprintk(VIDC_WARN, "Core is in bad state, Skipping power collapse\n"); goto skip_power_off; return -EINVAL; } rc = __dsp_suspend(device, force, flags); if (rc == -EBUSY) goto exit; else if (rc) goto skip_power_off; pc_ready = __read_register(device, VIDC_CTRL_STATUS) & VIDC_CTRL_STATUS_PC_READY; if (!pc_ready) { Loading Loading @@ -3075,23 +3342,14 @@ static void venus_hfi_pm_handler(struct work_struct *work) if (rc) dprintk(VIDC_ERR, "Failed __suspend\n"); /* Cancel pending delayed works if any */ cancel_delayed_work(&venus_hfi_pm_work); device->skip_pc_count = 0; mutex_unlock(&device->lock); return; exit: return rc; skip_power_off: device->skip_pc_count++; dprintk(VIDC_WARN, "Skip PC(%d, %#x, %#x, %#x)\n", device->skip_pc_count, wfi_status, idle_status, pc_ready); queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work, msecs_to_jiffies( device->res->msm_vidc_pwr_collapse_delay)); exit: mutex_unlock(&device->lock); dprintk(VIDC_WARN, "Skip PC(%#x, %#x, %#x)\n", wfi_status, idle_status, pc_ready); return -EAGAIN; } static void __process_sys_error(struct venus_hfi_device *device) Loading Loading @@ -4415,6 +4673,7 @@ static inline int __suspend(struct venus_hfi_device *device) static inline int __resume(struct venus_hfi_device *device) { int rc = 0; u32 flags = 0; if (!device) { dprintk(VIDC_ERR, "Invalid params: %pK\n", device); Loading Loading @@ -4467,6 +4726,7 @@ static inline int __resume(struct venus_hfi_device *device) __enable_subcaches(device); __set_subcaches(device); __dsp_resume(device, flags); dprintk(VIDC_PROF, "Resumed from power collapse\n"); exit: Loading Loading @@ -4885,6 +5145,8 @@ static void venus_init_hfi_callbacks(struct hfi_device *hdev) hdev->session_flush = venus_hfi_session_flush; hdev->session_set_property = venus_hfi_session_set_property; hdev->session_get_property = venus_hfi_session_get_property; hdev->session_pause = venus_hfi_session_pause; hdev->session_resume = venus_hfi_session_resume; hdev->scale_clocks = venus_hfi_scale_clocks; hdev->vote_bus = venus_hfi_vote_buses; hdev->get_fw_info = venus_hfi_get_fw_info; Loading drivers/media/platform/msm/vidc/venus_hfi.h +6 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,11 @@ struct venus_resources { struct msm_vidc_fw fw; }; enum dsp_flag { DSP_INIT = BIT(0), DSP_SUSPEND = BIT(1), }; enum venus_hfi_state { VENUS_STATE_DEINIT = 1, VENUS_STATE_INIT, Loading @@ -245,6 +250,7 @@ struct venus_hfi_device { struct vidc_mem_addr mem_addr; struct vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ]; struct vidc_iface_q_info dsp_iface_queues[VIDC_IFACEQ_NUMQ]; u32 dsp_flags; struct hal_data *hal_data; struct workqueue_struct *vidc_workq; struct workqueue_struct *venus_pm_workq; Loading drivers/media/platform/msm/vidc/vidc_hfi.h +5 −0 Original line number Diff line number Diff line Loading @@ -829,12 +829,17 @@ struct hfi_cmd_session_continue_packet { u32 session_id; }; enum session_flags { SESSION_PAUSE = BIT(1), }; struct hal_session { struct list_head list; void *session_id; bool is_decoder; enum hal_video_codec codec; enum hal_domain domain; u32 flags; void *device; }; Loading Loading
drivers/media/platform/msm/vidc/msm_cvp.c +59 −0 Original line number Diff line number Diff line Loading @@ -311,8 +311,29 @@ static int msm_cvp_request_power(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "%s: failed to scale clocks and bus for inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); goto exit; } if (!inst->clk_data.min_freq && !inst->clk_data.ddr_bw && !inst->clk_data.sys_cache_bw) { rc = msm_cvp_inst_pause(inst); if (rc) { dprintk(VIDC_ERR, "%s: failed to pause inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); goto exit; } } else { rc = msm_cvp_inst_resume(inst); if (rc) { dprintk(VIDC_ERR, "%s: failed to resume inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); goto exit; } } exit: return rc; } Loading Loading @@ -515,6 +536,44 @@ int msm_cvp_ctrl_init(struct msm_vidc_inst *inst, ARRAY_SIZE(msm_cvp_ctrls), ctrl_ops); } int msm_cvp_inst_pause(struct msm_vidc_inst *inst) { int rc; struct hfi_device *hdev; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } hdev = inst->core->device; rc = call_hfi_op(hdev, session_pause, (void *)inst->session); if (rc) dprintk(VIDC_ERR, "%s: failed to pause inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); return rc; } int msm_cvp_inst_resume(struct msm_vidc_inst *inst) { int rc; struct hfi_device *hdev; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } hdev = inst->core->device; rc = call_hfi_op(hdev, session_resume, (void *)inst->session); if (rc) dprintk(VIDC_ERR, "%s: failed to resume inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); return rc; } int msm_cvp_inst_deinit(struct msm_vidc_inst *inst) { int rc = 0; Loading
drivers/media/platform/msm/vidc/msm_cvp.h +2 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ void handle_session_unregister_buffer_done(enum hal_command_response cmd, int msm_vidc_cvp(struct msm_vidc_inst *inst, struct msm_vidc_arg *arg); int msm_cvp_inst_init(struct msm_vidc_inst *inst); int msm_cvp_inst_deinit(struct msm_vidc_inst *inst); int msm_cvp_inst_pause(struct msm_vidc_inst *inst); int msm_cvp_inst_resume(struct msm_vidc_inst *inst); int msm_cvp_ctrl_init(struct msm_vidc_inst *inst, const struct v4l2_ctrl_ops *ctrl_ops); #endif
drivers/media/platform/msm/vidc/venus_hfi.c +284 −22 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <linux/soc/qcom/smem.h> #include <soc/qcom/subsystem_restart.h> #include <linux/dma-mapping.h> #include <linux/fastcvpd.h> #include "hfi_packetization.h" #include "msm_vidc_debug.h" #include "venus_hfi.h" Loading Loading @@ -104,6 +105,7 @@ static int __enable_subcaches(struct venus_hfi_device *device); static int __set_subcaches(struct venus_hfi_device *device); static int __release_subcaches(struct venus_hfi_device *device); static int __disable_subcaches(struct venus_hfi_device *device); static int __power_collapse(struct venus_hfi_device *device, bool force); static int venus_hfi_noc_error_info(void *dev); /** Loading Loading @@ -252,6 +254,216 @@ static void __sim_modify_cmd_packet(u8 *packet, struct venus_hfi_device *device) } } static int __dsp_send_hfi_queue(struct venus_hfi_device *device) { int rc; if (!device->res->domain_cvp) return 0; if (!device->dsp_iface_q_table.mem_data.dma_handle) { dprintk(VIDC_ERR, "%s: invalid dsm_handle\n", __func__); return -EINVAL; } if (device->dsp_flags & DSP_INIT) { dprintk(VIDC_DBG, "%s: dsp already inited\n"); return 0; } dprintk(VIDC_DBG, "%s: hfi queue %#x size %d\n", __func__, device->dsp_iface_q_table.mem_data.dma_handle, device->dsp_iface_q_table.mem_data.size); rc = fastcvpd_video_send_cmd_hfi_queue( (phys_addr_t *)device->dsp_iface_q_table.mem_data.dma_handle, device->dsp_iface_q_table.mem_data.size); if (rc) { dprintk(VIDC_ERR, "%s: dsp init failed\n", __func__); return rc; } device->dsp_flags |= DSP_INIT; dprintk(VIDC_DBG, "%s: dsp inited\n", __func__); return rc; } static int __dsp_suspend(struct venus_hfi_device *device, bool force, u32 flags) { int rc; struct hal_session *temp; if (!device->res->domain_cvp) return 0; if (!(device->dsp_flags & DSP_INIT)) return 0; if (device->dsp_flags & DSP_SUSPEND) return 0; list_for_each_entry(temp, &device->sess_head, list) { /* if forceful suspend, don't check session pause info */ if (force) continue; if (temp->domain == HAL_VIDEO_DOMAIN_CVP) { /* don't suspend if cvp session is not paused */ if (!(temp->flags & SESSION_PAUSE)) { dprintk(VIDC_DBG, "%s: cvp session %x not paused\n", __func__, hash32_ptr(temp)); return -EBUSY; } } } dprintk(VIDC_DBG, "%s: suspend dsp\n", __func__); rc = fastcvpd_video_suspend(flags); if (rc) { dprintk(VIDC_ERR, "%s: dsp suspend failed with error %d\n", __func__, rc); return -EINVAL; } device->dsp_flags |= DSP_SUSPEND; dprintk(VIDC_DBG, "%s: dsp suspended\n", __func__); return 0; } static int __dsp_resume(struct venus_hfi_device *device, u32 flags) { int rc; if (!device->res->domain_cvp) return 0; if (!(device->dsp_flags & DSP_SUSPEND)) { dprintk(VIDC_DBG, "%s: dsp not suspended\n", __func__); return 0; } dprintk(VIDC_DBG, "%s: resume dsp\n", __func__); rc = fastcvpd_video_resume(flags); if (rc) { dprintk(VIDC_ERR, "%s: dsp resume failed with error %d\n", __func__, rc); return rc; } device->dsp_flags &= ~DSP_SUSPEND; dprintk(VIDC_DBG, "%s: dsp resumed\n", __func__); return rc; } static int __dsp_shutdown(struct venus_hfi_device *device, u32 flags) { int rc; if (!device->res->domain_cvp) return 0; if (!(device->dsp_flags & DSP_INIT)) { dprintk(VIDC_DBG, "%s: dsp not inited\n", __func__); return 0; } dprintk(VIDC_DBG, "%s: shutdown dsp\n", __func__); rc = fastcvpd_video_shutdown(flags); if (rc) { dprintk(VIDC_ERR, "%s: dsp shutdown failed with error %d\n", __func__, rc); WARN_ON(1); } device->dsp_flags &= ~DSP_INIT; dprintk(VIDC_DBG, "%s: dsp shutdown successful\n", __func__); return rc; } static int __session_pause(struct venus_hfi_device *device, struct hal_session *session) { int rc = 0; /* ignore if session paused already */ if (session->flags & SESSION_PAUSE) return 0; session->flags |= SESSION_PAUSE; dprintk(VIDC_DBG, "%s: cvp session %x paused\n", __func__, hash32_ptr(session)); return rc; } static int __session_resume(struct venus_hfi_device *device, struct hal_session *session) { int rc = 0; /* ignore if session already resumed */ if (!(session->flags & SESSION_PAUSE)) return 0; session->flags &= ~SESSION_PAUSE; dprintk(VIDC_DBG, "%s: cvp session %x resumed\n", __func__, hash32_ptr(session)); rc = __resume(device); if (rc) { dprintk(VIDC_ERR, "%s: resume failed\n", __func__); goto exit; } if (device->dsp_flags & DSP_SUSPEND) { dprintk(VIDC_ERR, "%s: dsp not resumed\n", __func__); rc = -EINVAL; goto exit; } exit: return rc; } static int venus_hfi_session_pause(void *sess) { int rc; struct hal_session *session = sess; struct venus_hfi_device *device; if (!session || !session->device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } device = session->device; mutex_lock(&device->lock); rc = __session_pause(device, session); mutex_unlock(&device->lock); return rc; } static int venus_hfi_session_resume(void *sess) { int rc; struct hal_session *session = sess; struct venus_hfi_device *device; if (!session || !session->device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } device = session->device; mutex_lock(&device->lock); rc = __session_resume(device, session); mutex_unlock(&device->lock); return rc; } static int __acquire_regulator(struct regulator_info *rinfo, struct venus_hfi_device *device) { Loading Loading @@ -1098,14 +1310,18 @@ static int venus_hfi_suspend(void *dev) } dprintk(VIDC_DBG, "Suspending Venus\n"); flush_delayed_work(&venus_hfi_pm_work); mutex_lock(&device->lock); if (device->power_enabled) { rc = __power_collapse(device, true); if (rc) { dprintk(VIDC_WARN, "%s: Venus is busy\n", __func__); rc = -EBUSY; } mutex_unlock(&device->lock); /* Cancel pending delayed works if any */ if (!rc) cancel_delayed_work(&venus_hfi_pm_work); return rc; } Loading Loading @@ -1957,6 +2173,7 @@ static int venus_hfi_core_init(void *device) __enable_subcaches(device); __set_subcaches(device); __dsp_send_hfi_queue(device); if (dev->res->pm_qos_latency_us) { #ifdef CONFIG_SMP Loading Loading @@ -1998,6 +2215,8 @@ static int venus_hfi_core_release(void *dev) __resume(device); __set_state(device, VENUS_STATE_DEINIT); __dsp_shutdown(device, 0); __unload_fw(device); /* unlink all sessions from device */ Loading Loading @@ -2986,9 +3205,6 @@ static int __prepare_pc(struct venus_hfi_device *device) static void venus_hfi_pm_handler(struct work_struct *work) { int rc = 0; u32 wfi_status = 0, idle_status = 0, pc_ready = 0; int count = 0; const int max_tries = 10; struct venus_hfi_device *device = list_first_entry( &hal_ctxt.dev_head, struct venus_hfi_device, list); Loading @@ -3010,7 +3226,51 @@ static void venus_hfi_pm_handler(struct work_struct *work) __process_fatal_error(device); return; } mutex_lock(&device->lock); rc = __power_collapse(device, false); mutex_unlock(&device->lock); switch (rc) { case 0: device->skip_pc_count = 0; /* Cancel pending delayed works if any */ cancel_delayed_work(&venus_hfi_pm_work); dprintk(VIDC_PROF, "%s: power collapse successful!\n", __func__); break; case -EBUSY: device->skip_pc_count = 0; dprintk(VIDC_DBG, "%s: retry PC as dsp is busy\n", __func__); queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work, msecs_to_jiffies( device->res->msm_vidc_pwr_collapse_delay)); break; case -EAGAIN: device->skip_pc_count++; dprintk(VIDC_WARN, "%s: retry power collapse (count %d)\n", __func__, device->skip_pc_count); queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work, msecs_to_jiffies( device->res->msm_vidc_pwr_collapse_delay)); break; default: dprintk(VIDC_ERR, "%s: power collapse failed\n", __func__); break; } } static int __power_collapse(struct venus_hfi_device *device, bool force) { int rc = 0; u32 wfi_status = 0, idle_status = 0, pc_ready = 0; u32 flags = 0; int count = 0; const int max_tries = 10; if (!device) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } if (!device->power_enabled) { dprintk(VIDC_DBG, "%s: Power already disabled\n", __func__); Loading @@ -3021,8 +3281,15 @@ static void venus_hfi_pm_handler(struct work_struct *work) if (!rc) { dprintk(VIDC_WARN, "Core is in bad state, Skipping power collapse\n"); goto skip_power_off; return -EINVAL; } rc = __dsp_suspend(device, force, flags); if (rc == -EBUSY) goto exit; else if (rc) goto skip_power_off; pc_ready = __read_register(device, VIDC_CTRL_STATUS) & VIDC_CTRL_STATUS_PC_READY; if (!pc_ready) { Loading Loading @@ -3075,23 +3342,14 @@ static void venus_hfi_pm_handler(struct work_struct *work) if (rc) dprintk(VIDC_ERR, "Failed __suspend\n"); /* Cancel pending delayed works if any */ cancel_delayed_work(&venus_hfi_pm_work); device->skip_pc_count = 0; mutex_unlock(&device->lock); return; exit: return rc; skip_power_off: device->skip_pc_count++; dprintk(VIDC_WARN, "Skip PC(%d, %#x, %#x, %#x)\n", device->skip_pc_count, wfi_status, idle_status, pc_ready); queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work, msecs_to_jiffies( device->res->msm_vidc_pwr_collapse_delay)); exit: mutex_unlock(&device->lock); dprintk(VIDC_WARN, "Skip PC(%#x, %#x, %#x)\n", wfi_status, idle_status, pc_ready); return -EAGAIN; } static void __process_sys_error(struct venus_hfi_device *device) Loading Loading @@ -4415,6 +4673,7 @@ static inline int __suspend(struct venus_hfi_device *device) static inline int __resume(struct venus_hfi_device *device) { int rc = 0; u32 flags = 0; if (!device) { dprintk(VIDC_ERR, "Invalid params: %pK\n", device); Loading Loading @@ -4467,6 +4726,7 @@ static inline int __resume(struct venus_hfi_device *device) __enable_subcaches(device); __set_subcaches(device); __dsp_resume(device, flags); dprintk(VIDC_PROF, "Resumed from power collapse\n"); exit: Loading Loading @@ -4885,6 +5145,8 @@ static void venus_init_hfi_callbacks(struct hfi_device *hdev) hdev->session_flush = venus_hfi_session_flush; hdev->session_set_property = venus_hfi_session_set_property; hdev->session_get_property = venus_hfi_session_get_property; hdev->session_pause = venus_hfi_session_pause; hdev->session_resume = venus_hfi_session_resume; hdev->scale_clocks = venus_hfi_scale_clocks; hdev->vote_bus = venus_hfi_vote_buses; hdev->get_fw_info = venus_hfi_get_fw_info; Loading
drivers/media/platform/msm/vidc/venus_hfi.h +6 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,11 @@ struct venus_resources { struct msm_vidc_fw fw; }; enum dsp_flag { DSP_INIT = BIT(0), DSP_SUSPEND = BIT(1), }; enum venus_hfi_state { VENUS_STATE_DEINIT = 1, VENUS_STATE_INIT, Loading @@ -245,6 +250,7 @@ struct venus_hfi_device { struct vidc_mem_addr mem_addr; struct vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ]; struct vidc_iface_q_info dsp_iface_queues[VIDC_IFACEQ_NUMQ]; u32 dsp_flags; struct hal_data *hal_data; struct workqueue_struct *vidc_workq; struct workqueue_struct *venus_pm_workq; Loading
drivers/media/platform/msm/vidc/vidc_hfi.h +5 −0 Original line number Diff line number Diff line Loading @@ -829,12 +829,17 @@ struct hfi_cmd_session_continue_packet { u32 session_id; }; enum session_flags { SESSION_PAUSE = BIT(1), }; struct hal_session { struct list_head list; void *session_id; bool is_decoder; enum hal_video_codec codec; enum hal_domain domain; u32 flags; void *device; }; Loading