Loading drivers/media/platform/msm/vidc/venus_hfi.c +147 −182 Original line number Diff line number Diff line Loading @@ -76,13 +76,13 @@ struct tzbsp_video_set_state_req { u32 spare; /*reserved for future, should be zero*/ }; static void venus_hfi_pm_hndlr(struct work_struct *work); static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr); static int venus_hfi_power_enable(void *dev); static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device); static inline int venus_hfi_power_on( struct venus_hfi_device *device); static inline int venus_hfi_prepare_enable_clks( struct venus_hfi_device *device); static inline void venus_hfi_disable_unprepare_clks( struct venus_hfi_device *device); Loading Loading @@ -286,8 +286,6 @@ static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set) } packet_size_in_words = (*(u32 *)packet) >> 2; dprintk(VIDC_DBG, "Packet_size in words: %d\n", packet_size_in_words); if (packet_size_in_words == 0) { dprintk(VIDC_ERR, "Zero packet size\n"); return -ENODATA; Loading @@ -298,7 +296,6 @@ static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set) empty_space = (queue->qhdr_write_idx >= read_idx) ? (queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) : (read_idx - queue->qhdr_write_idx); dprintk(VIDC_DBG, "Empty_space: %d\n", empty_space); if (empty_space <= packet_size_in_words) { queue->qhdr_tx_req = 1; dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n", Loading @@ -311,7 +308,6 @@ static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set) new_write_idx = (queue->qhdr_write_idx + packet_size_in_words); write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + (queue->qhdr_write_idx << 2)); dprintk(VIDC_DBG, "Write Ptr: %d\n", new_write_idx); if (new_write_idx < queue->qhdr_q_size) { memcpy(write_ptr, packet, packet_size_in_words << 2); } else { Loading Loading @@ -405,6 +401,7 @@ static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set) struct hfi_queue_header *queue; u32 packet_size_in_words, new_read_idx; u32 *read_ptr; u32 receive_request = 0; struct vidc_iface_q_info *qinfo; int rc = 0; Loading @@ -428,23 +425,37 @@ static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set) return -ENOMEM; } /* * Do not set receive request for debug queue, if set, * Venus generates interrupt for debug messages even * when there is no response message available. * In general debug queue will not become full as it * is being emptied out for every interrupt from Venus. * Venus will anyway generates interrupt if it is full. */ if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q) receive_request = 1; if (queue->qhdr_read_idx == queue->qhdr_write_idx) { queue->qhdr_rx_req = 1; queue->qhdr_rx_req = receive_request; *pb_tx_req_is_set = 0; return -EPERM; dprintk(VIDC_DBG, "%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n", receive_request ? "message" : "debug", queue->qhdr_rx_req, queue->qhdr_tx_req, queue->qhdr_read_idx); return -ENODATA; } read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + (queue->qhdr_read_idx << 2)); packet_size_in_words = (*read_ptr) >> 2; dprintk(VIDC_DBG, "packet_size_in_words: %d\n", packet_size_in_words); if (packet_size_in_words == 0) { dprintk(VIDC_ERR, "Zero packet size\n"); return -ENODATA; } new_read_idx = queue->qhdr_read_idx + packet_size_in_words; dprintk(VIDC_DBG, "Read Ptr: %d\n", new_read_idx); if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) && queue->qhdr_read_idx <= queue->qhdr_q_size) { if (new_read_idx < queue->qhdr_q_size) { Loading Loading @@ -473,13 +484,15 @@ static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set) if (queue->qhdr_read_idx != queue->qhdr_write_idx) queue->qhdr_rx_req = 0; else queue->qhdr_rx_req = 1; queue->qhdr_rx_req = receive_request; *pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0; if (msm_vidc_debug & VIDC_PKT) { dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo); venus_hfi_dump_packet(packet); } return rc; } Loading Loading @@ -530,7 +543,10 @@ static void venus_hfi_free(struct venus_hfi_device *dev, struct msm_smem *mem) dprintk(VIDC_ERR, "invalid param %p %p\n", dev, mem); return; } venus_hfi_power_enable(dev); if (venus_hfi_power_on(dev)) dprintk(VIDC_ERR, "%s: Power on failed\n", __func__); msm_smem_free(dev->hal_client, mem); } Loading Loading @@ -574,6 +590,9 @@ static int venus_hfi_read_register(struct venus_hfi_device *device, u32 reg) rc = readl_relaxed(base_addr + reg); rmb(); dprintk(VIDC_DBG, "Base addr: 0x%p, read from: 0x%x, value: 0x%x...\n", base_addr, reg, rc); return rc; } Loading Loading @@ -893,9 +912,7 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, return -EINVAL; } mutex_lock(&device->write_lock); mutex_lock(&device->clk_pwr_lock); result = venus_hfi_iface_cmdq_write_nolock(device, pkt); mutex_unlock(&device->clk_pwr_lock); mutex_unlock(&device->write_lock); return result; } Loading Loading @@ -1171,8 +1188,6 @@ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); if (device->clk_state == ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks already enabled\n"); return 0; Loading Loading @@ -1218,8 +1233,6 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return; } WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); if (device->clk_state != ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks already disabled\n"); return; Loading Loading @@ -1260,12 +1273,11 @@ static int venus_hfi_halt_axi(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid input: %p\n", device); return -EINVAL; } mutex_lock(&device->clk_pwr_lock); if (venus_hfi_clk_gating_off(device)) { dprintk(VIDC_ERR, "Failed to turn off clk gating\n"); rc = -EIO; goto err_clk_gating_off; if (venus_hfi_power_enable(device)) { dprintk(VIDC_ERR, "%s: Failed to enable power\n", __func__); return 0; } /* Halt AXI and AXI OCMEM VBIF Access */ reg = venus_hfi_read_register(device, VENUS_VBIF_AXI_HALT_CTRL0); reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ; Loading @@ -1279,8 +1291,7 @@ static int venus_hfi_halt_axi(struct venus_hfi_device *device) VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US); if (rc) dprintk(VIDC_WARN, "AXI bus port halt timeout\n"); err_clk_gating_off: mutex_unlock(&device->clk_pwr_lock); return rc; } Loading @@ -1294,9 +1305,10 @@ static inline int venus_hfi_power_off(struct venus_hfi_device *device) } if (!device->power_enabled) { dprintk(VIDC_DBG, "Power already disabled\n"); goto already_disabled; return 0; } dprintk(VIDC_DBG, "Entering power collapse\n"); /*Temporarily enable clocks to make TZ call.*/ rc = venus_hfi_clk_enable(device); if (rc) { Loading Loading @@ -1327,8 +1339,8 @@ static inline int venus_hfi_power_off(struct venus_hfi_device *device) venus_hfi_unvote_buses(device); device->power_enabled = false; dprintk(VIDC_INFO, "entering power collapse\n"); already_disabled: dprintk(VIDC_INFO, "Venus power collapsed\n"); return rc; } Loading @@ -1340,7 +1352,10 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } if (device->power_enabled) return 0; dprintk(VIDC_DBG, "Resuming from power collapse\n"); rc = venus_hfi_vote_buses(device, device->bus_load, device->res->bus_set.count, 0); if (rc) { Loading Loading @@ -1410,6 +1425,12 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device) goto err_reset_core; } /* * set the flag here to skip venus_hfi_power_on() which is * being called again via __alloc_ocmem() if ocmem is enabled */ device->power_enabled = true; /* * write_lock is already acquired at this point, so to avoid * recursive lock in cmdq_write function, call nolock version Loading @@ -1421,8 +1442,8 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Failed to allocate OCMEM"); goto err_alloc_ocmem; } device->power_enabled = true; dprintk(VIDC_INFO, "resuming from power collapse\n"); dprintk(VIDC_INFO, "Resumed from power collapse\n"); return rc; err_alloc_ocmem: err_reset_core: Loading @@ -1436,6 +1457,8 @@ err_iommu_attach: err_enable_gdsc: venus_hfi_unvote_buses(device); err_vote_buses: device->power_enabled = false; dprintk(VIDC_ERR, "Failed to resume from power collapse\n"); return rc; } Loading @@ -1447,58 +1470,12 @@ static int venus_hfi_power_enable(void *dev) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } mutex_lock(&device->clk_pwr_lock); if (!device->power_enabled) { mutex_lock(&device->write_lock); rc = venus_hfi_power_on(device); if (rc) { dprintk(VIDC_ERR, "Failed venus power on"); goto fail_power_on; } } rc = venus_hfi_clk_gating_off(device); if (rc) dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); dprintk(VIDC_ERR, "%s: Failed to enable power\n", __func__); mutex_unlock(&device->write_lock); fail_power_on: mutex_unlock(&device->clk_pwr_lock); return rc; } static void venus_hfi_pm_hndlr(struct work_struct *work); static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr); static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device) { int rc = 0; if (!device) { dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } if (device->clk_state == ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks are already enabled\n"); goto already_enabled; } if (!device->power_enabled) { /*This will enable clocks as well*/ rc = venus_hfi_power_on(device); if (rc) { dprintk(VIDC_ERR, "Failed venus power on"); goto fail_clk_power_on; } } else { rc = venus_hfi_clk_enable(device); if (rc) { dprintk(VIDC_ERR, "Failed venus clock enable\n"); goto fail_clk_power_on; } venus_hfi_write_register(device, VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK); } already_enabled: device->clk_state = ENABLED_PREPARED; fail_clk_power_on: return rc; } Loading Loading @@ -1536,6 +1513,7 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, { u32 rx_req_is_set = 0; struct vidc_iface_q_info *q_info; struct vidc_hal_cmd_pkt_hdr *cmd_packet; int result = -EPERM; if (!device || !pkt) { Loading @@ -1550,6 +1528,9 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, goto err_q_null; } cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt; device->last_packet_type = cmd_packet->packet_type; q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX]; if (!q_info) { dprintk(VIDC_ERR, "cannot write to shared Q's\n"); Loading @@ -1564,16 +1545,12 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, venus_hfi_sim_modify_cmd_packet((u8 *)pkt, device); if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) { WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); result = venus_hfi_clk_gating_off(device); if (result) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); if (venus_hfi_power_on(device)) { dprintk(VIDC_ERR, "%s: Power on failed\n", __func__); goto err_q_write; } result = venus_hfi_scale_clocks(device, device->clk_load); if (result) { if (venus_hfi_scale_clocks(device, device->clk_load)) { dprintk(VIDC_ERR, "Clock scaling failed\n"); goto err_q_write; } Loading Loading @@ -1630,25 +1607,14 @@ static int venus_hfi_iface_msgq_read(struct venus_hfi_device *device, void *pkt) q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX]; if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { venus_hfi_hal_sim_modify_msg_packet((u8 *)pkt, device); mutex_lock(&device->clk_pwr_lock); rc = venus_hfi_clk_gating_off(device); if (rc) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); mutex_unlock(&device->clk_pwr_lock); goto read_error; } if (tx_req_is_set) venus_hfi_write_register( device, VIDC_CPU_IC_SOFTINT, 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT); rc = 0; mutex_unlock(&device->clk_pwr_lock); } else { dprintk(VIDC_INFO, "venus_hfi_iface_msgq_read:queue_empty\n"); } else rc = -ENODATA; } read_error: read_error_null: mutex_unlock(&device->read_lock); return rc; Loading Loading @@ -1678,25 +1644,14 @@ static int venus_hfi_iface_dbgq_read(struct venus_hfi_device *device, void *pkt) } q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX]; if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { mutex_lock(&device->clk_pwr_lock); rc = venus_hfi_clk_gating_off(device); if (rc) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); mutex_unlock(&device->clk_pwr_lock); goto dbg_error; } if (tx_req_is_set) venus_hfi_write_register( device, VIDC_CPU_IC_SOFTINT, 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT); rc = 0; mutex_unlock(&device->clk_pwr_lock); } else { dprintk(VIDC_INFO, "venus_hfi_iface_dbgq_read:queue_empty\n"); } else rc = -ENODATA; } dbg_error: dbg_error_null: mutex_unlock(&device->read_lock); return rc; Loading Loading @@ -1943,6 +1898,11 @@ static int venus_hfi_interface_queues_init(struct venus_hfi_device *dev) q_hdr = iface_q->q_hdr; q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr; q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q; /* * Set receive request to zero on debug queue as there is no * need of interrupt from video hardware for debug messages */ q_hdr->qhdr_rx_req = 0; if ((ion_phys_addr_t)q_hdr->qhdr_start_addr != iface_q->q_array.align_device_addr) { dprintk(VIDC_ERR, "Invalid DBGQ device address (0x%pa)", Loading Loading @@ -2163,7 +2123,7 @@ err_core_init: static int venus_hfi_core_release(void *device) { struct venus_hfi_device *dev; int rc = 0; if (device) { dev = device; } else { Loading @@ -2172,19 +2132,15 @@ static int venus_hfi_core_release(void *device) } if (dev->hal_client) { mutex_lock(&dev->clk_pwr_lock); rc = venus_hfi_clk_gating_off(device); if (rc) { if (venus_hfi_power_enable(device)) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); mutex_unlock(&dev->clk_pwr_lock); "%s: Power enable failed\n", __func__); return -EIO; } venus_hfi_write_register(dev, VIDC_CPU_CS_SCIACMDARG3, 0); if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) disable_irq_nosync(dev->hal_data->irq); dev->intr_status = 0; mutex_unlock(&dev->clk_pwr_lock); } venus_hfi_set_state(dev, VENUS_STATE_DEINIT); Loading Loading @@ -2223,44 +2179,13 @@ static int venus_hfi_get_q_size(struct venus_hfi_device *dev, return rc; } static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device) { if (!device) { dprintk(VIDC_ERR, "Invalid params: %p\n", device); return; } if (device->clk_state != ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks are already disabled\n"); goto already_disabled; } /*SYS Idle should be last message so mask any further interrupts * until clocks are enabled again.*/ if (!venus_hfi_get_q_size(device, VIDC_IFACEQ_MSGQ_IDX)) { venus_hfi_write_register(device, VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK | VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK); } venus_hfi_clk_disable(device); already_disabled: device->clk_state = DISABLED_PREPARED; } static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device) { u32 intr_status = 0; int rc = 0; if (!device->callback) if (!device) { dprintk(VIDC_ERR, "%s: NULL device\n", __func__); return; mutex_lock(&device->write_lock); mutex_lock(&device->clk_pwr_lock); rc = venus_hfi_clk_gating_off(device); if (rc) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); goto err_clk_gating_off; } intr_status = venus_hfi_read_register( Loading @@ -2286,9 +2211,6 @@ static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device) venus_hfi_write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR, 1); venus_hfi_write_register(device, VIDC_WRAPPER_INTR_CLEAR, intr_status); dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt\n"); err_clk_gating_off: mutex_unlock(&device->clk_pwr_lock); mutex_unlock(&device->write_lock); } static int venus_hfi_core_ping(void *device) Loading Loading @@ -2963,14 +2885,19 @@ err_pc_prep: static void venus_hfi_pm_hndlr(struct work_struct *work) { int rc = 0; u32 ctrl_status = 0; struct venus_hfi_device *device = list_first_entry( &hal_ctxt.dev_head, struct venus_hfi_device, list); mutex_lock(&device->clk_pwr_lock); if (!device) { dprintk(VIDC_ERR, "%s: NULL device\n", __func__); return; } if (!device->power_enabled) { dprintk(VIDC_DBG, "Power already disabled\n"); goto clks_enabled; dprintk(VIDC_DBG, "%s: Power already disabled\n", __func__); return; } mutex_unlock(&device->clk_pwr_lock); dprintk(VIDC_DBG, "Prepare for power collapse\n"); rc = venus_hfi_unset_free_ocmem(device); if (rc) { Loading @@ -2987,12 +2914,56 @@ static void venus_hfi_pm_hndlr(struct work_struct *work) return; } mutex_lock(&device->clk_pwr_lock); mutex_lock(&device->write_lock); if (device->last_packet_type != HFI_CMD_SYS_PC_PREP) { dprintk(VIDC_DBG, "Last command (0x%x) is not PC_PREP cmd\n", device->last_packet_type); goto skip_power_off; } if (venus_hfi_get_q_size(device, VIDC_IFACEQ_MSGQ_IDX) || venus_hfi_get_q_size(device, VIDC_IFACEQ_CMDQ_IDX)) { dprintk(VIDC_DBG, "Cmd/msg queues are not empty\n"); goto skip_power_off; } ctrl_status = venus_hfi_read_register(device, VIDC_CPU_CS_SCIACMDARG0); if (!(ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY)) { dprintk(VIDC_DBG, "Venus is not ready for power collapse (0x%x)\n", ctrl_status); goto skip_power_off; } rc = venus_hfi_power_off(device); if (rc) dprintk(VIDC_ERR, "Failed venus power off\n"); clks_enabled: mutex_unlock(&device->clk_pwr_lock); /* Cancel pending delayed works if any */ cancel_delayed_work(&venus_hfi_pm_work); mutex_unlock(&device->write_lock); return; skip_power_off: /* Reset PC_READY bit as power_off is skipped, if set by Venus */ ctrl_status = venus_hfi_read_register(device, VIDC_CPU_CS_SCIACMDARG0); if (ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY) { ctrl_status &= ~(VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY); venus_hfi_write_register(device, VIDC_CPU_CS_SCIACMDARG0, ctrl_status); } /* Cancel pending delayed works if any */ cancel_delayed_work(&venus_hfi_pm_work); dprintk(VIDC_WARN, "Power off skipped (0x%x, 0x%x)\n", device->last_packet_type, ctrl_status); mutex_unlock(&device->write_lock); return; } static void venus_hfi_process_msg_event_notify( Loading Loading @@ -3106,6 +3077,10 @@ static void venus_hfi_core_work_handler(struct work_struct *work) device); return; } if (venus_hfi_power_enable(device)) { dprintk(VIDC_ERR, "%s: Power enable failed\n", __func__); return; } if (device->res->sw_power_collapsible) { dprintk(VIDC_DBG, "Cancel and queue delayed work again.\n"); cancel_delayed_work(&venus_hfi_pm_work); Loading Loading @@ -3265,7 +3240,6 @@ static inline void venus_hfi_disable_unprepare_clks( dprintk(VIDC_ERR, "Invalid params: %p\n", device); return; } WARN_ON(!mutex_is_locked(&device->clk_pwr_lock)); venus_hfi_for_each_clock(device, cl) { if (device->clk_state == DISABLED_PREPARED) { dprintk(VIDC_DBG, Loading @@ -3274,6 +3248,8 @@ static inline void venus_hfi_disable_unprepare_clks( clk_unprepare(cl->clk); } else { usleep(100); dprintk(VIDC_DBG, "Clock: %s disable and unprepare\n", cl->name); clk_disable_unprepare(cl->clk); } } Loading @@ -3288,7 +3264,6 @@ static inline int venus_hfi_prepare_enable_clks(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } WARN_ON(!mutex_is_locked(&device->clk_pwr_lock)); if (device->clk_state == ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks already prepared and enabled\n"); Loading @@ -3302,7 +3277,7 @@ static inline int venus_hfi_prepare_enable_clks(struct venus_hfi_device *device) goto fail_clk_enable; } dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name); dprintk(VIDC_DBG, "Clock: %s prepared and enabled\n", cl->name); } device->clk_state = ENABLED_PREPARED; Loading @@ -3313,10 +3288,11 @@ fail_clk_enable: if (cl_fail == cl) break; usleep(100); dprintk(VIDC_ERR, "Clock: %s disable and unprepare\n", cl->name); clk_disable_unprepare(cl->clk); } device->clk_state = DISABLED_UNPREPARED; mutex_unlock(&device->clk_pwr_lock); return rc; } Loading Loading @@ -3802,11 +3778,9 @@ static int venus_hfi_load_fw(void *dev) goto fail_iommu_attach; } mutex_lock(&device->clk_pwr_lock); rc = venus_hfi_enable_regulators(device); if (rc) { dprintk(VIDC_ERR, "Failed to enable GDSC %d\n", rc); mutex_unlock(&device->clk_pwr_lock); goto fail_enable_gdsc; } Loading @@ -3819,7 +3793,6 @@ static int venus_hfi_load_fw(void *dev) if (IS_ERR_OR_NULL(device->resources.fw.cookie)) { dprintk(VIDC_ERR, "Failed to download firmware\n"); rc = -ENOMEM; mutex_unlock(&device->clk_pwr_lock); goto fail_load_fw; } } Loading @@ -3828,7 +3801,6 @@ static int venus_hfi_load_fw(void *dev) /* Clocks can be enabled only after pil_get since * gdsc is turned-on in pil_get*/ rc = venus_hfi_prepare_enable_clks(device); mutex_unlock(&device->clk_pwr_lock); if (rc) { dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc); goto fail_enable_clks; Loading @@ -3847,18 +3819,14 @@ static int venus_hfi_load_fw(void *dev) trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end"); return rc; fail_protect_mem: mutex_lock(&device->clk_pwr_lock); venus_hfi_disable_unprepare_clks(device); mutex_unlock(&device->clk_pwr_lock); fail_enable_clks: if (device->resources.fw.cookie) subsystem_put(device->resources.fw.cookie); fail_load_fw: mutex_lock(&device->clk_pwr_lock); device->resources.fw.cookie = NULL; venus_hfi_disable_regulators(device); device->power_enabled = false; mutex_unlock(&device->clk_pwr_lock); fail_enable_gdsc: venus_hfi_iommu_detach(device); fail_iommu_attach: Loading Loading @@ -3886,11 +3854,9 @@ static void venus_hfi_unload_fw(void *dev) */ if (venus_hfi_halt_axi(device)) dprintk(VIDC_WARN, "Failed to halt AXI\n"); mutex_lock(&device->clk_pwr_lock); venus_hfi_disable_unprepare_clks(device); venus_hfi_disable_regulators(device); device->power_enabled = false; mutex_unlock(&device->clk_pwr_lock); device->resources.fw.cookie = NULL; } } Loading Loading @@ -4047,7 +4013,6 @@ static void *venus_hfi_add_device(u32 device_id, mutex_init(&hdevice->read_lock); mutex_init(&hdevice->write_lock); mutex_init(&hdevice->session_lock); mutex_init(&hdevice->clk_pwr_lock); if (hal_ctxt.dev_count == 0) INIT_LIST_HEAD(&hal_ctxt.dev_head); Loading drivers/media/platform/msm/vidc/venus_hfi.h +1 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,7 @@ struct venus_hfi_device { u32 intr_status; u32 device_id; u32 clk_load; u32 last_packet_type; struct vidc_bus_vote_data *bus_load; enum clock_state clk_state; bool power_enabled; Loading drivers/media/platform/msm/vidc/vidc_hfi_helper.h +5 −0 Original line number Diff line number Diff line Loading @@ -807,6 +807,11 @@ struct hfi_mvc_buffer_layout_descp_type { #define HFI_TEST_SSR_SW_DIV_BY_ZERO 0x2 #define HFI_TEST_SSR_HW_WDOG_IRQ 0x3 struct vidc_hal_cmd_pkt_hdr { u32 size; u32 packet_type; }; struct vidc_hal_msg_pkt_hdr { u32 size; u32 packet; Loading Loading
drivers/media/platform/msm/vidc/venus_hfi.c +147 −182 Original line number Diff line number Diff line Loading @@ -76,13 +76,13 @@ struct tzbsp_video_set_state_req { u32 spare; /*reserved for future, should be zero*/ }; static void venus_hfi_pm_hndlr(struct work_struct *work); static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr); static int venus_hfi_power_enable(void *dev); static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device); static inline int venus_hfi_power_on( struct venus_hfi_device *device); static inline int venus_hfi_prepare_enable_clks( struct venus_hfi_device *device); static inline void venus_hfi_disable_unprepare_clks( struct venus_hfi_device *device); Loading Loading @@ -286,8 +286,6 @@ static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set) } packet_size_in_words = (*(u32 *)packet) >> 2; dprintk(VIDC_DBG, "Packet_size in words: %d\n", packet_size_in_words); if (packet_size_in_words == 0) { dprintk(VIDC_ERR, "Zero packet size\n"); return -ENODATA; Loading @@ -298,7 +296,6 @@ static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set) empty_space = (queue->qhdr_write_idx >= read_idx) ? (queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) : (read_idx - queue->qhdr_write_idx); dprintk(VIDC_DBG, "Empty_space: %d\n", empty_space); if (empty_space <= packet_size_in_words) { queue->qhdr_tx_req = 1; dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n", Loading @@ -311,7 +308,6 @@ static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set) new_write_idx = (queue->qhdr_write_idx + packet_size_in_words); write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + (queue->qhdr_write_idx << 2)); dprintk(VIDC_DBG, "Write Ptr: %d\n", new_write_idx); if (new_write_idx < queue->qhdr_q_size) { memcpy(write_ptr, packet, packet_size_in_words << 2); } else { Loading Loading @@ -405,6 +401,7 @@ static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set) struct hfi_queue_header *queue; u32 packet_size_in_words, new_read_idx; u32 *read_ptr; u32 receive_request = 0; struct vidc_iface_q_info *qinfo; int rc = 0; Loading @@ -428,23 +425,37 @@ static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set) return -ENOMEM; } /* * Do not set receive request for debug queue, if set, * Venus generates interrupt for debug messages even * when there is no response message available. * In general debug queue will not become full as it * is being emptied out for every interrupt from Venus. * Venus will anyway generates interrupt if it is full. */ if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q) receive_request = 1; if (queue->qhdr_read_idx == queue->qhdr_write_idx) { queue->qhdr_rx_req = 1; queue->qhdr_rx_req = receive_request; *pb_tx_req_is_set = 0; return -EPERM; dprintk(VIDC_DBG, "%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n", receive_request ? "message" : "debug", queue->qhdr_rx_req, queue->qhdr_tx_req, queue->qhdr_read_idx); return -ENODATA; } read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + (queue->qhdr_read_idx << 2)); packet_size_in_words = (*read_ptr) >> 2; dprintk(VIDC_DBG, "packet_size_in_words: %d\n", packet_size_in_words); if (packet_size_in_words == 0) { dprintk(VIDC_ERR, "Zero packet size\n"); return -ENODATA; } new_read_idx = queue->qhdr_read_idx + packet_size_in_words; dprintk(VIDC_DBG, "Read Ptr: %d\n", new_read_idx); if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) && queue->qhdr_read_idx <= queue->qhdr_q_size) { if (new_read_idx < queue->qhdr_q_size) { Loading Loading @@ -473,13 +484,15 @@ static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set) if (queue->qhdr_read_idx != queue->qhdr_write_idx) queue->qhdr_rx_req = 0; else queue->qhdr_rx_req = 1; queue->qhdr_rx_req = receive_request; *pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0; if (msm_vidc_debug & VIDC_PKT) { dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo); venus_hfi_dump_packet(packet); } return rc; } Loading Loading @@ -530,7 +543,10 @@ static void venus_hfi_free(struct venus_hfi_device *dev, struct msm_smem *mem) dprintk(VIDC_ERR, "invalid param %p %p\n", dev, mem); return; } venus_hfi_power_enable(dev); if (venus_hfi_power_on(dev)) dprintk(VIDC_ERR, "%s: Power on failed\n", __func__); msm_smem_free(dev->hal_client, mem); } Loading Loading @@ -574,6 +590,9 @@ static int venus_hfi_read_register(struct venus_hfi_device *device, u32 reg) rc = readl_relaxed(base_addr + reg); rmb(); dprintk(VIDC_DBG, "Base addr: 0x%p, read from: 0x%x, value: 0x%x...\n", base_addr, reg, rc); return rc; } Loading Loading @@ -893,9 +912,7 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device, return -EINVAL; } mutex_lock(&device->write_lock); mutex_lock(&device->clk_pwr_lock); result = venus_hfi_iface_cmdq_write_nolock(device, pkt); mutex_unlock(&device->clk_pwr_lock); mutex_unlock(&device->write_lock); return result; } Loading Loading @@ -1171,8 +1188,6 @@ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); if (device->clk_state == ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks already enabled\n"); return 0; Loading Loading @@ -1218,8 +1233,6 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return; } WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); if (device->clk_state != ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks already disabled\n"); return; Loading Loading @@ -1260,12 +1273,11 @@ static int venus_hfi_halt_axi(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid input: %p\n", device); return -EINVAL; } mutex_lock(&device->clk_pwr_lock); if (venus_hfi_clk_gating_off(device)) { dprintk(VIDC_ERR, "Failed to turn off clk gating\n"); rc = -EIO; goto err_clk_gating_off; if (venus_hfi_power_enable(device)) { dprintk(VIDC_ERR, "%s: Failed to enable power\n", __func__); return 0; } /* Halt AXI and AXI OCMEM VBIF Access */ reg = venus_hfi_read_register(device, VENUS_VBIF_AXI_HALT_CTRL0); reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ; Loading @@ -1279,8 +1291,7 @@ static int venus_hfi_halt_axi(struct venus_hfi_device *device) VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US); if (rc) dprintk(VIDC_WARN, "AXI bus port halt timeout\n"); err_clk_gating_off: mutex_unlock(&device->clk_pwr_lock); return rc; } Loading @@ -1294,9 +1305,10 @@ static inline int venus_hfi_power_off(struct venus_hfi_device *device) } if (!device->power_enabled) { dprintk(VIDC_DBG, "Power already disabled\n"); goto already_disabled; return 0; } dprintk(VIDC_DBG, "Entering power collapse\n"); /*Temporarily enable clocks to make TZ call.*/ rc = venus_hfi_clk_enable(device); if (rc) { Loading Loading @@ -1327,8 +1339,8 @@ static inline int venus_hfi_power_off(struct venus_hfi_device *device) venus_hfi_unvote_buses(device); device->power_enabled = false; dprintk(VIDC_INFO, "entering power collapse\n"); already_disabled: dprintk(VIDC_INFO, "Venus power collapsed\n"); return rc; } Loading @@ -1340,7 +1352,10 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } if (device->power_enabled) return 0; dprintk(VIDC_DBG, "Resuming from power collapse\n"); rc = venus_hfi_vote_buses(device, device->bus_load, device->res->bus_set.count, 0); if (rc) { Loading Loading @@ -1410,6 +1425,12 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device) goto err_reset_core; } /* * set the flag here to skip venus_hfi_power_on() which is * being called again via __alloc_ocmem() if ocmem is enabled */ device->power_enabled = true; /* * write_lock is already acquired at this point, so to avoid * recursive lock in cmdq_write function, call nolock version Loading @@ -1421,8 +1442,8 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Failed to allocate OCMEM"); goto err_alloc_ocmem; } device->power_enabled = true; dprintk(VIDC_INFO, "resuming from power collapse\n"); dprintk(VIDC_INFO, "Resumed from power collapse\n"); return rc; err_alloc_ocmem: err_reset_core: Loading @@ -1436,6 +1457,8 @@ err_iommu_attach: err_enable_gdsc: venus_hfi_unvote_buses(device); err_vote_buses: device->power_enabled = false; dprintk(VIDC_ERR, "Failed to resume from power collapse\n"); return rc; } Loading @@ -1447,58 +1470,12 @@ static int venus_hfi_power_enable(void *dev) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } mutex_lock(&device->clk_pwr_lock); if (!device->power_enabled) { mutex_lock(&device->write_lock); rc = venus_hfi_power_on(device); if (rc) { dprintk(VIDC_ERR, "Failed venus power on"); goto fail_power_on; } } rc = venus_hfi_clk_gating_off(device); if (rc) dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); dprintk(VIDC_ERR, "%s: Failed to enable power\n", __func__); mutex_unlock(&device->write_lock); fail_power_on: mutex_unlock(&device->clk_pwr_lock); return rc; } static void venus_hfi_pm_hndlr(struct work_struct *work); static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr); static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device) { int rc = 0; if (!device) { dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } if (device->clk_state == ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks are already enabled\n"); goto already_enabled; } if (!device->power_enabled) { /*This will enable clocks as well*/ rc = venus_hfi_power_on(device); if (rc) { dprintk(VIDC_ERR, "Failed venus power on"); goto fail_clk_power_on; } } else { rc = venus_hfi_clk_enable(device); if (rc) { dprintk(VIDC_ERR, "Failed venus clock enable\n"); goto fail_clk_power_on; } venus_hfi_write_register(device, VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK); } already_enabled: device->clk_state = ENABLED_PREPARED; fail_clk_power_on: return rc; } Loading Loading @@ -1536,6 +1513,7 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, { u32 rx_req_is_set = 0; struct vidc_iface_q_info *q_info; struct vidc_hal_cmd_pkt_hdr *cmd_packet; int result = -EPERM; if (!device || !pkt) { Loading @@ -1550,6 +1528,9 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, goto err_q_null; } cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt; device->last_packet_type = cmd_packet->packet_type; q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX]; if (!q_info) { dprintk(VIDC_ERR, "cannot write to shared Q's\n"); Loading @@ -1564,16 +1545,12 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, venus_hfi_sim_modify_cmd_packet((u8 *)pkt, device); if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) { WARN(!mutex_is_locked(&device->clk_pwr_lock), "Clock/power lock must be acquired"); result = venus_hfi_clk_gating_off(device); if (result) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); if (venus_hfi_power_on(device)) { dprintk(VIDC_ERR, "%s: Power on failed\n", __func__); goto err_q_write; } result = venus_hfi_scale_clocks(device, device->clk_load); if (result) { if (venus_hfi_scale_clocks(device, device->clk_load)) { dprintk(VIDC_ERR, "Clock scaling failed\n"); goto err_q_write; } Loading Loading @@ -1630,25 +1607,14 @@ static int venus_hfi_iface_msgq_read(struct venus_hfi_device *device, void *pkt) q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX]; if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { venus_hfi_hal_sim_modify_msg_packet((u8 *)pkt, device); mutex_lock(&device->clk_pwr_lock); rc = venus_hfi_clk_gating_off(device); if (rc) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); mutex_unlock(&device->clk_pwr_lock); goto read_error; } if (tx_req_is_set) venus_hfi_write_register( device, VIDC_CPU_IC_SOFTINT, 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT); rc = 0; mutex_unlock(&device->clk_pwr_lock); } else { dprintk(VIDC_INFO, "venus_hfi_iface_msgq_read:queue_empty\n"); } else rc = -ENODATA; } read_error: read_error_null: mutex_unlock(&device->read_lock); return rc; Loading Loading @@ -1678,25 +1644,14 @@ static int venus_hfi_iface_dbgq_read(struct venus_hfi_device *device, void *pkt) } q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX]; if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { mutex_lock(&device->clk_pwr_lock); rc = venus_hfi_clk_gating_off(device); if (rc) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); mutex_unlock(&device->clk_pwr_lock); goto dbg_error; } if (tx_req_is_set) venus_hfi_write_register( device, VIDC_CPU_IC_SOFTINT, 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT); rc = 0; mutex_unlock(&device->clk_pwr_lock); } else { dprintk(VIDC_INFO, "venus_hfi_iface_dbgq_read:queue_empty\n"); } else rc = -ENODATA; } dbg_error: dbg_error_null: mutex_unlock(&device->read_lock); return rc; Loading Loading @@ -1943,6 +1898,11 @@ static int venus_hfi_interface_queues_init(struct venus_hfi_device *dev) q_hdr = iface_q->q_hdr; q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr; q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q; /* * Set receive request to zero on debug queue as there is no * need of interrupt from video hardware for debug messages */ q_hdr->qhdr_rx_req = 0; if ((ion_phys_addr_t)q_hdr->qhdr_start_addr != iface_q->q_array.align_device_addr) { dprintk(VIDC_ERR, "Invalid DBGQ device address (0x%pa)", Loading Loading @@ -2163,7 +2123,7 @@ err_core_init: static int venus_hfi_core_release(void *device) { struct venus_hfi_device *dev; int rc = 0; if (device) { dev = device; } else { Loading @@ -2172,19 +2132,15 @@ static int venus_hfi_core_release(void *device) } if (dev->hal_client) { mutex_lock(&dev->clk_pwr_lock); rc = venus_hfi_clk_gating_off(device); if (rc) { if (venus_hfi_power_enable(device)) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); mutex_unlock(&dev->clk_pwr_lock); "%s: Power enable failed\n", __func__); return -EIO; } venus_hfi_write_register(dev, VIDC_CPU_CS_SCIACMDARG3, 0); if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) disable_irq_nosync(dev->hal_data->irq); dev->intr_status = 0; mutex_unlock(&dev->clk_pwr_lock); } venus_hfi_set_state(dev, VENUS_STATE_DEINIT); Loading Loading @@ -2223,44 +2179,13 @@ static int venus_hfi_get_q_size(struct venus_hfi_device *dev, return rc; } static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device) { if (!device) { dprintk(VIDC_ERR, "Invalid params: %p\n", device); return; } if (device->clk_state != ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks are already disabled\n"); goto already_disabled; } /*SYS Idle should be last message so mask any further interrupts * until clocks are enabled again.*/ if (!venus_hfi_get_q_size(device, VIDC_IFACEQ_MSGQ_IDX)) { venus_hfi_write_register(device, VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK | VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK); } venus_hfi_clk_disable(device); already_disabled: device->clk_state = DISABLED_PREPARED; } static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device) { u32 intr_status = 0; int rc = 0; if (!device->callback) if (!device) { dprintk(VIDC_ERR, "%s: NULL device\n", __func__); return; mutex_lock(&device->write_lock); mutex_lock(&device->clk_pwr_lock); rc = venus_hfi_clk_gating_off(device); if (rc) { dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__); goto err_clk_gating_off; } intr_status = venus_hfi_read_register( Loading @@ -2286,9 +2211,6 @@ static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device) venus_hfi_write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR, 1); venus_hfi_write_register(device, VIDC_WRAPPER_INTR_CLEAR, intr_status); dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt\n"); err_clk_gating_off: mutex_unlock(&device->clk_pwr_lock); mutex_unlock(&device->write_lock); } static int venus_hfi_core_ping(void *device) Loading Loading @@ -2963,14 +2885,19 @@ err_pc_prep: static void venus_hfi_pm_hndlr(struct work_struct *work) { int rc = 0; u32 ctrl_status = 0; struct venus_hfi_device *device = list_first_entry( &hal_ctxt.dev_head, struct venus_hfi_device, list); mutex_lock(&device->clk_pwr_lock); if (!device) { dprintk(VIDC_ERR, "%s: NULL device\n", __func__); return; } if (!device->power_enabled) { dprintk(VIDC_DBG, "Power already disabled\n"); goto clks_enabled; dprintk(VIDC_DBG, "%s: Power already disabled\n", __func__); return; } mutex_unlock(&device->clk_pwr_lock); dprintk(VIDC_DBG, "Prepare for power collapse\n"); rc = venus_hfi_unset_free_ocmem(device); if (rc) { Loading @@ -2987,12 +2914,56 @@ static void venus_hfi_pm_hndlr(struct work_struct *work) return; } mutex_lock(&device->clk_pwr_lock); mutex_lock(&device->write_lock); if (device->last_packet_type != HFI_CMD_SYS_PC_PREP) { dprintk(VIDC_DBG, "Last command (0x%x) is not PC_PREP cmd\n", device->last_packet_type); goto skip_power_off; } if (venus_hfi_get_q_size(device, VIDC_IFACEQ_MSGQ_IDX) || venus_hfi_get_q_size(device, VIDC_IFACEQ_CMDQ_IDX)) { dprintk(VIDC_DBG, "Cmd/msg queues are not empty\n"); goto skip_power_off; } ctrl_status = venus_hfi_read_register(device, VIDC_CPU_CS_SCIACMDARG0); if (!(ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY)) { dprintk(VIDC_DBG, "Venus is not ready for power collapse (0x%x)\n", ctrl_status); goto skip_power_off; } rc = venus_hfi_power_off(device); if (rc) dprintk(VIDC_ERR, "Failed venus power off\n"); clks_enabled: mutex_unlock(&device->clk_pwr_lock); /* Cancel pending delayed works if any */ cancel_delayed_work(&venus_hfi_pm_work); mutex_unlock(&device->write_lock); return; skip_power_off: /* Reset PC_READY bit as power_off is skipped, if set by Venus */ ctrl_status = venus_hfi_read_register(device, VIDC_CPU_CS_SCIACMDARG0); if (ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY) { ctrl_status &= ~(VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY); venus_hfi_write_register(device, VIDC_CPU_CS_SCIACMDARG0, ctrl_status); } /* Cancel pending delayed works if any */ cancel_delayed_work(&venus_hfi_pm_work); dprintk(VIDC_WARN, "Power off skipped (0x%x, 0x%x)\n", device->last_packet_type, ctrl_status); mutex_unlock(&device->write_lock); return; } static void venus_hfi_process_msg_event_notify( Loading Loading @@ -3106,6 +3077,10 @@ static void venus_hfi_core_work_handler(struct work_struct *work) device); return; } if (venus_hfi_power_enable(device)) { dprintk(VIDC_ERR, "%s: Power enable failed\n", __func__); return; } if (device->res->sw_power_collapsible) { dprintk(VIDC_DBG, "Cancel and queue delayed work again.\n"); cancel_delayed_work(&venus_hfi_pm_work); Loading Loading @@ -3265,7 +3240,6 @@ static inline void venus_hfi_disable_unprepare_clks( dprintk(VIDC_ERR, "Invalid params: %p\n", device); return; } WARN_ON(!mutex_is_locked(&device->clk_pwr_lock)); venus_hfi_for_each_clock(device, cl) { if (device->clk_state == DISABLED_PREPARED) { dprintk(VIDC_DBG, Loading @@ -3274,6 +3248,8 @@ static inline void venus_hfi_disable_unprepare_clks( clk_unprepare(cl->clk); } else { usleep(100); dprintk(VIDC_DBG, "Clock: %s disable and unprepare\n", cl->name); clk_disable_unprepare(cl->clk); } } Loading @@ -3288,7 +3264,6 @@ static inline int venus_hfi_prepare_enable_clks(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Invalid params: %p\n", device); return -EINVAL; } WARN_ON(!mutex_is_locked(&device->clk_pwr_lock)); if (device->clk_state == ENABLED_PREPARED) { dprintk(VIDC_DBG, "Clocks already prepared and enabled\n"); Loading @@ -3302,7 +3277,7 @@ static inline int venus_hfi_prepare_enable_clks(struct venus_hfi_device *device) goto fail_clk_enable; } dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name); dprintk(VIDC_DBG, "Clock: %s prepared and enabled\n", cl->name); } device->clk_state = ENABLED_PREPARED; Loading @@ -3313,10 +3288,11 @@ fail_clk_enable: if (cl_fail == cl) break; usleep(100); dprintk(VIDC_ERR, "Clock: %s disable and unprepare\n", cl->name); clk_disable_unprepare(cl->clk); } device->clk_state = DISABLED_UNPREPARED; mutex_unlock(&device->clk_pwr_lock); return rc; } Loading Loading @@ -3802,11 +3778,9 @@ static int venus_hfi_load_fw(void *dev) goto fail_iommu_attach; } mutex_lock(&device->clk_pwr_lock); rc = venus_hfi_enable_regulators(device); if (rc) { dprintk(VIDC_ERR, "Failed to enable GDSC %d\n", rc); mutex_unlock(&device->clk_pwr_lock); goto fail_enable_gdsc; } Loading @@ -3819,7 +3793,6 @@ static int venus_hfi_load_fw(void *dev) if (IS_ERR_OR_NULL(device->resources.fw.cookie)) { dprintk(VIDC_ERR, "Failed to download firmware\n"); rc = -ENOMEM; mutex_unlock(&device->clk_pwr_lock); goto fail_load_fw; } } Loading @@ -3828,7 +3801,6 @@ static int venus_hfi_load_fw(void *dev) /* Clocks can be enabled only after pil_get since * gdsc is turned-on in pil_get*/ rc = venus_hfi_prepare_enable_clks(device); mutex_unlock(&device->clk_pwr_lock); if (rc) { dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc); goto fail_enable_clks; Loading @@ -3847,18 +3819,14 @@ static int venus_hfi_load_fw(void *dev) trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end"); return rc; fail_protect_mem: mutex_lock(&device->clk_pwr_lock); venus_hfi_disable_unprepare_clks(device); mutex_unlock(&device->clk_pwr_lock); fail_enable_clks: if (device->resources.fw.cookie) subsystem_put(device->resources.fw.cookie); fail_load_fw: mutex_lock(&device->clk_pwr_lock); device->resources.fw.cookie = NULL; venus_hfi_disable_regulators(device); device->power_enabled = false; mutex_unlock(&device->clk_pwr_lock); fail_enable_gdsc: venus_hfi_iommu_detach(device); fail_iommu_attach: Loading Loading @@ -3886,11 +3854,9 @@ static void venus_hfi_unload_fw(void *dev) */ if (venus_hfi_halt_axi(device)) dprintk(VIDC_WARN, "Failed to halt AXI\n"); mutex_lock(&device->clk_pwr_lock); venus_hfi_disable_unprepare_clks(device); venus_hfi_disable_regulators(device); device->power_enabled = false; mutex_unlock(&device->clk_pwr_lock); device->resources.fw.cookie = NULL; } } Loading Loading @@ -4047,7 +4013,6 @@ static void *venus_hfi_add_device(u32 device_id, mutex_init(&hdevice->read_lock); mutex_init(&hdevice->write_lock); mutex_init(&hdevice->session_lock); mutex_init(&hdevice->clk_pwr_lock); if (hal_ctxt.dev_count == 0) INIT_LIST_HEAD(&hal_ctxt.dev_head); Loading
drivers/media/platform/msm/vidc/venus_hfi.h +1 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,7 @@ struct venus_hfi_device { u32 intr_status; u32 device_id; u32 clk_load; u32 last_packet_type; struct vidc_bus_vote_data *bus_load; enum clock_state clk_state; bool power_enabled; Loading
drivers/media/platform/msm/vidc/vidc_hfi_helper.h +5 −0 Original line number Diff line number Diff line Loading @@ -807,6 +807,11 @@ struct hfi_mvc_buffer_layout_descp_type { #define HFI_TEST_SSR_SW_DIV_BY_ZERO 0x2 #define HFI_TEST_SSR_HW_WDOG_IRQ 0x3 struct vidc_hal_cmd_pkt_hdr { u32 size; u32 packet_type; }; struct vidc_hal_msg_pkt_hdr { u32 size; u32 packet; Loading