diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index 525d54d68d..cc808fe2c5 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -67,6 +67,7 @@ /* BL_FIFO configurations*/ #define CAM_CDM_BL_FIFO_LENGTH_MAX_DEFAULT 0x40 #define CAM_CDM_BL_FIFO_LENGTH_CFG_SHIFT 0x10 +#define CAM_CDM_BL_FIFO_FLUSH_SHIFT 0x3 #define CAM_CDM_BL_FIFO_REQ_SIZE_MAX 0x00 #define CAM_CDM_BL_FIFO_REQ_SIZE_MAX_DIV2 0x01 @@ -100,6 +101,7 @@ #define CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK 0x10000 #define CAM_CDM_IRQ_STATUS_ERROR_OVER_FLOW_MASK 0x20000 #define CAM_CDM_IRQ_STATUS_ERROR_AHB_BUS_MASK 0x40000 +#define CAM_CDM_IRQ_STATUS_USR_DATA_MASK 0xFF #define CAM_CDM_IRQ_STATUS_ERRORS \ (CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK | \ @@ -371,6 +373,7 @@ enum cam_cdm_hw_process_intf_cmd { CAM_CDM_HW_INTF_CMD_RESET_HW, CAM_CDM_HW_INTF_CMD_FLUSH_HW, CAM_CDM_HW_INTF_CMD_HANDLE_ERROR, + CAM_CDM_HW_INTF_CMD_HANG_DETECT, CAM_CDM_HW_INTF_CMD_INVALID, }; @@ -466,6 +469,8 @@ struct cam_cdm_bl_fifo { struct mutex fifo_lock; uint8_t bl_tag; uint32_t bl_depth; + uint8_t last_bl_tag_done; + uint32_t work_record; }; /** @@ -493,6 +498,7 @@ struct cam_cdm_bl_fifo { * @gen_irq: memory region in which gen_irq command will be written * @cpas_handle: handle for cpas driver * @arbitration: type of arbitration to be used for the CDM + * @rst_done_cnt: CMD reset done count */ struct cam_cdm { uint32_t index; @@ -515,6 +521,7 @@ struct cam_cdm { struct cam_cdm_hw_mem gen_irq[CAM_CDM_BL_FIFO_MAX]; uint32_t cpas_handle; enum cam_cdm_arbitration arbitration; + uint32_t rst_done_cnt; }; /* struct cam_cdm_private_dt_data - CDM hw custom dt data */ diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index 034fdb5fa4..e93e54f033 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -262,6 +262,47 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, } } +static int cam_cdm_stream_handle_init(void *hw_priv, bool init) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_cdm *core = NULL; + int rc = -EPERM; + + core = (struct cam_cdm *)cdm_hw->core_info; + + if (init) { + rc = cam_hw_cdm_init(hw_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_CDM, "CDM HW init failed"); + return rc; + } + + if (core->arbitration != + CAM_CDM_ARBITRATION_PRIORITY_BASED) { + rc = cam_hw_cdm_alloc_genirq_mem( + hw_priv); + if (rc) { + CAM_ERR(CAM_CDM, + "Genirqalloc failed"); + cam_hw_cdm_deinit(hw_priv, + NULL, 0); + } + } + } else { + rc = cam_hw_cdm_deinit(hw_priv, NULL, 0); + if (rc) + CAM_ERR(CAM_CDM, "Deinit failed in streamoff"); + + if (core->arbitration != + CAM_CDM_ARBITRATION_PRIORITY_BASED) { + if (cam_hw_cdm_release_genirq_mem(hw_priv)) + CAM_ERR(CAM_CDM, "Genirq release fail"); + } + } + + return rc; +} + int cam_cdm_stream_ops_internal(void *hw_priv, void *start_args, bool operation) { @@ -337,19 +378,7 @@ int cam_cdm_stream_ops_internal(void *hw_priv, rc = 0; } else { CAM_DBG(CAM_CDM, "CDM HW init first time"); - rc = cam_hw_cdm_init(hw_priv, NULL, 0); - if (rc == 0) { - rc = cam_hw_cdm_alloc_genirq_mem( - hw_priv); - if (rc != 0) { - CAM_ERR(CAM_CDM, - "Genirqalloc failed"); - cam_hw_cdm_deinit(hw_priv, - NULL, 0); - } - } else { - CAM_ERR(CAM_CDM, "CDM HW init failed"); - } + rc = cam_cdm_stream_handle_init(hw_priv, true); } if (rc == 0) { cdm_hw->open_count++; @@ -378,17 +407,10 @@ int cam_cdm_stream_ops_internal(void *hw_priv, rc = 0; } else { CAM_DBG(CAM_CDM, "CDM HW Deinit now"); - rc = cam_hw_cdm_deinit( - hw_priv, NULL, 0); - if (cam_hw_cdm_release_genirq_mem( - hw_priv)) - CAM_ERR(CAM_CDM, - "Genirq release fail"); + rc = cam_cdm_stream_handle_init(hw_priv, + false); } - if (rc) { - CAM_ERR(CAM_CDM, - "Deinit failed in streamoff"); - } else { + if (rc == 0) { client->stream_on = false; rc = cam_cpas_stop(core->cpas_handle); if (rc) @@ -763,6 +785,41 @@ int cam_cdm_process_cmd(void *hw_priv, mutex_unlock(&cdm_hw->hw_mutex); break; } + case CAM_CDM_HW_INTF_CMD_HANG_DETECT: { + uint32_t *handle = cmd_args; + int idx; + struct cam_cdm_client *client; + + if (sizeof(uint32_t) != arg_size) { + CAM_ERR(CAM_CDM, + "Invalid CDM cmd %d size=%x for handle=%x", + cmd, arg_size, *handle); + return -EINVAL; + } + + idx = CAM_CDM_GET_CLIENT_IDX(*handle); + mutex_lock(&cdm_hw->hw_mutex); + client = core->clients[idx]; + if (!client) { + CAM_ERR(CAM_CDM, + "Client not present for handle %d", + *handle); + mutex_unlock(&cdm_hw->hw_mutex); + break; + } + + if (*handle != client->handle) { + CAM_ERR(CAM_CDM, + "handle mismatch, client handle %d index %d received handle %d", + client->handle, idx, *handle); + mutex_unlock(&cdm_hw->hw_mutex); + break; + } + + rc = cam_hw_cdm_hang_detect(cdm_hw, *handle); + mutex_unlock(&cdm_hw->hw_mutex); + break; + } default: CAM_ERR(CAM_CDM, "CDM HW intf command not valid =%d", cmd); break; diff --git a/drivers/cam_cdm/cam_cdm_core_common.h b/drivers/cam_cdm/cam_cdm_core_common.h index 0f50165c7b..5545f15903 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.h +++ b/drivers/cam_cdm/cam_cdm_core_common.h @@ -50,6 +50,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, int cam_hw_cdm_reset_hw(struct cam_hw_info *cdm_hw, uint32_t handle); int cam_hw_cdm_flush_hw(struct cam_hw_info *cdm_hw, uint32_t handle); int cam_hw_cdm_handle_error(struct cam_hw_info *cdm_hw, uint32_t handle); +int cam_hw_cdm_hang_detect(struct cam_hw_info *cdm_hw, uint32_t handle); struct cam_cdm_bl_cb_request_entry *cam_cdm_find_request_by_bl_tag( uint32_t tag, struct list_head *bl_list); void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 998d3f6dc6..0ce4380bdd 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -129,26 +129,21 @@ static int cam_hw_cdm_enable_bl_done_irq(struct cam_hw_info *cdm_hw, return rc; } -static int cam_hw_cdm_enable_core(struct cam_hw_info *cdm_hw, bool enable) +static int cam_hw_cdm_pause_core(struct cam_hw_info *cdm_hw, bool pause) { int rc = 0; struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + uint32_t val = 0x1; - if (enable == true) { - if (cam_cdm_write_hw_reg(cdm_hw, - core->offsets->cmn_reg->core_en, - 0x01)) { - CAM_ERR(CAM_CDM, "Failed to Write CDM HW core enable"); - rc = -EIO; - } - } else { - if (cam_cdm_write_hw_reg(cdm_hw, - core->offsets->cmn_reg->core_en, - 0x02)) { - CAM_ERR(CAM_CDM, "Failed to Write CDM HW core disable"); - rc = -EIO; - } + if (pause) + val |= 0x2; + + if (cam_cdm_write_hw_reg(cdm_hw, + core->offsets->cmn_reg->core_en, val)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core_en"); + rc = -EIO; } + return rc; } @@ -307,10 +302,13 @@ void cam_hw_cdm_dump_core_debug_registers( struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->core_en, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW core status=%x", dump_reg); + CAM_INFO(CAM_CDM, "CDM HW core status=%x", dump_reg); - /* First pause CDM, If it fails still proceed to dump debug info */ - cam_hw_cdm_enable_core(cdm_hw, false); + cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->usr_data, + &dump_reg); + CAM_INFO(CAM_CDM, "CDM HW core userdata=0x%x", dump_reg); + + usleep_range(1000, 1010); cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->debug_status, @@ -379,8 +377,6 @@ void cam_hw_cdm_dump_core_debug_registers( core->offsets->cmn_reg->current_used_ahb_base, &dump_reg); CAM_INFO(CAM_CDM, "CDM HW current AHB base=%x", dump_reg); - /* Enable CDM back */ - cam_hw_cdm_enable_core(cdm_hw, true); } enum cam_cdm_arbitration cam_cdm_get_arbitration_type( @@ -633,10 +629,13 @@ int cam_hw_cdm_submit_gen_irq( int rc; bool bit_wr_enable = false; - if (core->bl_fifo[fifo_idx].bl_tag > 63) { + if (core->bl_fifo[fifo_idx].bl_tag > + (core->bl_fifo[fifo_idx].bl_depth - 1)) { CAM_ERR(CAM_CDM, - "bl_tag invalid =%d", - core->bl_fifo[fifo_idx].bl_tag); + "Invalid bl_tag=%d bl_depth=%d fifo_idx=%d", + core->bl_fifo[fifo_idx].bl_tag, + core->bl_fifo[fifo_idx].bl_depth, + fifo_idx); rc = -EINVAL; goto end; } @@ -742,6 +741,78 @@ end: return rc; } +static int cam_hw_cdm_arb_submit_bl(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, int i, + uint32_t fifo_idx, dma_addr_t hw_vaddr_ptr) +{ + struct cam_cdm_bl_request *cdm_cmd = req->data; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + uintptr_t cpu_addr; + struct cam_cdm_bl_cb_request_entry *node; + int rc = 0; + size_t len = 0; + + node = kzalloc(sizeof( + struct cam_cdm_bl_cb_request_entry), + GFP_KERNEL); + if (!node) + return -ENOMEM; + + node->request_type = CAM_HW_CDM_BL_CB_CLIENT; + node->client_hdl = req->handle; + node->cookie = req->data->cookie; + node->bl_tag = core->bl_fifo[fifo_idx].bl_tag - + 1; + node->userdata = req->data->userdata; + list_add_tail(&node->entry, + &core->bl_fifo[fifo_idx] + .bl_request_list); + cdm_cmd->cmd[i].arbitrate = true; + rc = cam_mem_get_cpu_buf( + cdm_cmd->cmd[i].bl_addr.mem_handle, + &cpu_addr, &len); + if (rc || !cpu_addr) { + CAM_ERR(CAM_OPE, "get cmd buffailed %x", + cdm_cmd->cmd[i].bl_addr + .mem_handle); + return rc; + } + core->ops->cdm_write_genirq( + ((uint32_t *)cpu_addr + + cdm_cmd->cmd[i].offset / 4 + + cdm_cmd->cmd[i].len / 4), + core->bl_fifo[fifo_idx].bl_tag - 1, + 1, fifo_idx); + rc = cam_hw_cdm_bl_write(cdm_hw, + (uint32_t)hw_vaddr_ptr + + cdm_cmd->cmd[i].offset, + cdm_cmd->cmd[i].len + 7, + core->bl_fifo[fifo_idx].bl_tag - 1, + 1, fifo_idx); + if (rc) { + CAM_ERR(CAM_CDM, + "CDM hw bl write failed tag=%d", + core->bl_fifo[fifo_idx].bl_tag - + 1); + list_del_init(&node->entry); + kfree(node); + return -EIO; + } + rc = cam_hw_cdm_commit_bl_write(cdm_hw, + fifo_idx); + if (rc) { + CAM_ERR(CAM_CDM, + "CDM hw commit failed tag=%d", + core->bl_fifo[fifo_idx].bl_tag - + 1); + list_del_init(&node->entry); + kfree(node); + return -EIO; + } + + return 0; +} + int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, struct cam_cdm_hw_intf_cmd_submit_bl *req, struct cam_cdm_client *client) @@ -771,13 +842,17 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, bl_fifo->bl_depth); } - if (test_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status) || - test_bit(CAM_CDM_RESET_HW_STATUS, &core->cdm_status)) - return -EAGAIN; mutex_lock(&core->bl_fifo[fifo_idx].fifo_lock); mutex_lock(&client->lock); + if (test_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status) || + test_bit(CAM_CDM_RESET_HW_STATUS, &core->cdm_status)) { + mutex_unlock(&client->lock); + mutex_unlock(&core->bl_fifo[fifo_idx].fifo_lock); + return -EAGAIN; + } + rc = cam_hw_cdm_bl_fifo_pending_bl_rb_in_fifo(cdm_hw, fifo_idx, &pending_bl); @@ -867,18 +942,28 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, if (core->bl_fifo[fifo_idx].bl_tag >= (bl_fifo->bl_depth - 1)) core->bl_fifo[fifo_idx].bl_tag = 0; - rc = cam_hw_cdm_bl_write(cdm_hw, - ((uint32_t)hw_vaddr_ptr + - cdm_cmd->cmd[i].offset), - (cdm_cmd->cmd[i].len - 1), - core->bl_fifo[fifo_idx].bl_tag, - cdm_cmd->cmd[i].arbitrate, - fifo_idx); - if (rc) { - CAM_ERR(CAM_CDM, "Hw bl write failed %d:%d", - i, req->data->cmd_arrary_count); - rc = -EIO; - break; + if (core->arbitration == + CAM_CDM_ARBITRATION_PRIORITY_BASED && + (req->data->flag == true) && + (i == (req->data->cmd_arrary_count - + 1))) { + CAM_DBG(CAM_CDM, + "GenIRQ in same bl, will sumbit later"); + } else { + rc = cam_hw_cdm_bl_write(cdm_hw, + ((uint32_t)hw_vaddr_ptr + + cdm_cmd->cmd[i].offset), + (cdm_cmd->cmd[i].len - 1), + core->bl_fifo[fifo_idx].bl_tag, + cdm_cmd->cmd[i].arbitrate, + fifo_idx); + if (rc) { + CAM_ERR(CAM_CDM, + "Hw bl write failed %d:%d", + i, req->data->cmd_arrary_count); + rc = -EIO; + break; + } } } else { CAM_ERR(CAM_CDM, @@ -893,20 +978,31 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, if (!rc) { CAM_DBG(CAM_CDM, - "write BL success for cnt=%d with tag=%d total_cnt=%d", + "write BL done cnt=%d with tag=%d total_cnt=%d", i, core->bl_fifo[fifo_idx].bl_tag, req->data->cmd_arrary_count); - CAM_DBG(CAM_CDM, "Now commit the BL"); - if (cam_hw_cdm_commit_bl_write(cdm_hw, fifo_idx)) { - CAM_ERR(CAM_CDM, - "Cannot commit the BL %d tag=%d", + if (core->arbitration == + CAM_CDM_ARBITRATION_PRIORITY_BASED && + (req->data->flag == true) && + (i == (req->data->cmd_arrary_count - + 1))) { + CAM_DBG(CAM_CDM, + "GenIRQ in same blcommit later"); + } else { + CAM_DBG(CAM_CDM, "Now commit the BL"); + if (cam_hw_cdm_commit_bl_write(cdm_hw, + fifo_idx)) { + CAM_ERR(CAM_CDM, + "commit failed BL %d tag=%d", + i, core->bl_fifo[fifo_idx] + .bl_tag); + rc = -EIO; + break; + } + CAM_DBG(CAM_CDM, "commit success BL %d tag=%d", i, core->bl_fifo[fifo_idx].bl_tag); - rc = -EIO; - break; } - CAM_DBG(CAM_CDM, "BL commit success BL %d tag=%d", i, - core->bl_fifo[fifo_idx].bl_tag); core->bl_fifo[fifo_idx].bl_tag++; if (cdm_cmd->cmd[i].enable_debug_gen_irq) { @@ -923,11 +1019,21 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, if ((req->data->flag == true) && (i == (req->data->cmd_arrary_count - 1))) { - rc = cam_hw_cdm_submit_gen_irq( - cdm_hw, req, fifo_idx, - cdm_cmd->gen_irq_arb); - if (rc == 0) - core->bl_fifo[fifo_idx].bl_tag++; + if (core->arbitration != + CAM_CDM_ARBITRATION_PRIORITY_BASED) { + rc = cam_hw_cdm_submit_gen_irq( + cdm_hw, req, fifo_idx, + cdm_cmd->gen_irq_arb); + if (rc == 0) + core->bl_fifo[fifo_idx] + .bl_tag++; + break; + } + + rc = cam_hw_cdm_arb_submit_bl(cdm_hw, req, i, + fifo_idx, hw_vaddr_ptr); + if (rc) + break; } } } @@ -971,6 +1077,8 @@ static void cam_hw_cdm_reset_cleanup( kfree(node); } core->bl_fifo[i].bl_tag = 0; + core->bl_fifo[i].last_bl_tag_done = -1; + core->bl_fifo[i].work_record = 0; } } @@ -985,14 +1093,22 @@ static void cam_hw_cdm_work(struct work_struct *work) if (payload) { cdm_hw = payload->hw; core = (struct cam_cdm *)cdm_hw->core_info; + if (payload->fifo_idx >= core->offsets->reg_data->num_bl_fifo) { + CAM_ERR(CAM_CDM, "Invalid fifo idx %d", + payload->fifo_idx); + kfree(payload); + return; + } CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); if (payload->irq_status & CAM_CDM_IRQ_STATUS_INLINE_IRQ_MASK) { struct cam_cdm_bl_cb_request_entry *node, *tnode; - CAM_DBG(CAM_CDM, "inline IRQ data=0x%x", - payload->irq_data); + CAM_DBG(CAM_CDM, "inline IRQ data=0x%x last tag: 0x%x", + payload->irq_data, + core->bl_fifo[payload->fifo_idx] + .last_bl_tag_done); if (payload->irq_data == 0xff) { CAM_INFO(CAM_CDM, "Debug genirq received"); @@ -1002,37 +1118,47 @@ static void cam_hw_cdm_work(struct work_struct *work) mutex_lock(&core->bl_fifo[payload->fifo_idx] .fifo_lock); - list_for_each_entry_safe(node, tnode, + + if (core->bl_fifo[payload->fifo_idx].work_record) + core->bl_fifo[payload->fifo_idx].work_record--; + + if (core->bl_fifo[payload->fifo_idx] + .last_bl_tag_done != + payload->irq_data) { + core->bl_fifo[payload->fifo_idx] + .last_bl_tag_done = + payload->irq_data; + list_for_each_entry_safe(node, tnode, &core->bl_fifo[payload->fifo_idx] .bl_request_list, entry) { - if (node->request_type == - CAM_HW_CDM_BL_CB_CLIENT) { - cam_cdm_notify_clients(cdm_hw, + if (node->request_type == + CAM_HW_CDM_BL_CB_CLIENT) { + cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_BL_SUCCESS, (void *)node); - } else if (node->request_type == - CAM_HW_CDM_BL_CB_INTERNAL) { - CAM_ERR(CAM_CDM, - "Invalid node=%pK %d", node, - node->request_type); + } else if (node->request_type == + CAM_HW_CDM_BL_CB_INTERNAL) { + CAM_ERR(CAM_CDM, + "Invalid node=%pK %d", + node, + node->request_type); + } + list_del_init(&node->entry); + if (node->bl_tag == payload->irq_data) { + kfree(node); + break; + } } - list_del_init(&node->entry); - if (node->bl_tag == payload->irq_data) { - kfree(node); - break; - } - kfree(node); + } else { + CAM_DBG(CAM_CDM, + "Skip GenIRQ, tag 0x%x fifo %d", + payload->irq_data, payload->fifo_idx); } mutex_unlock(&core->bl_fifo[payload->fifo_idx] .fifo_lock); } - if (payload->irq_status & - CAM_CDM_IRQ_STATUS_RST_DONE_MASK) { - CAM_DBG(CAM_CDM, "CDM HW reset done IRQ"); - complete(&core->reset_complete); - } if (payload->irq_status & CAM_CDM_IRQ_STATUS_BL_DONE_MASK) { if (test_bit(payload->fifo_idx, &core->cdm_status)) { @@ -1051,7 +1177,14 @@ static void cam_hw_cdm_work(struct work_struct *work) for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) mutex_lock(&core->bl_fifo[i].fifo_lock); + /* + * First pause CDM, If it fails still proceed + * to dump debug info + */ + cam_hw_cdm_pause_core(cdm_hw, true); cam_hw_cdm_dump_core_debug_registers(cdm_hw); + /* Resume CDM back */ + cam_hw_cdm_pause_core(cdm_hw, false); for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) mutex_unlock(&core->bl_fifo[i].fifo_lock); @@ -1083,7 +1216,17 @@ static void cam_hw_cdm_iommu_fault_handler(struct iommu_domain *domain, mutex_lock(&cdm_hw->hw_mutex); for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) mutex_lock(&core->bl_fifo[i].fifo_lock); - cam_hw_cdm_dump_core_debug_registers(cdm_hw); + if (cdm_hw->hw_state == CAM_HW_STATE_POWER_UP) { + /* + * First pause CDM, If it fails still proceed + * to dump debug info + */ + cam_hw_cdm_pause_core(cdm_hw, true); + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + /* Resume CDM back */ + cam_hw_cdm_pause_core(cdm_hw, false); + } else + CAM_INFO(CAM_CDM, "CDM hw is power in off state"); for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) mutex_unlock(&core->bl_fifo[i].fifo_lock); mutex_unlock(&cdm_hw->hw_mutex); @@ -1109,7 +1252,12 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) int i; CAM_DBG(CAM_CDM, "Got irq"); - + spin_lock(&cdm_hw->hw_lock); + if (cdm_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_DBG(CAM_CDM, "CDM is in power down state"); + spin_unlock(&cdm_hw->hw_lock); + return IRQ_HANDLED; + } for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo_irq; i++) { if (cam_cdm_read_hw_reg(cdm_hw, cdm_core->offsets->irq_reg[i]->irq_status, @@ -1126,35 +1274,46 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) if (cam_cdm_write_hw_reg(cdm_hw, cdm_core->offsets->irq_reg[0]->irq_clear_cmd, 0x01)) - CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ cmd 0"); + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ clr cmd"); + if (cam_cdm_read_hw_reg(cdm_hw, + cdm_core->offsets->cmn_reg->usr_data, + &user_data)) + CAM_ERR(CAM_CDM, "Failed to read CDM HW IRQ data"); + spin_unlock(&cdm_hw->hw_lock); for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo_irq; i++) { if (!irq_status[i]) continue; + if (irq_status[i] & CAM_CDM_IRQ_STATUS_RST_DONE_MASK) { + cdm_core->rst_done_cnt++; + continue; + } + payload[i] = kzalloc(sizeof(struct cam_cdm_work_payload), GFP_ATOMIC); - if (!payload[i]) + if (!payload[i]) { + CAM_ERR(CAM_CDM, + "failed to allocate memory for fifo %d payload", + i); continue; + } if (irq_status[i] & CAM_CDM_IRQ_STATUS_INLINE_IRQ_MASK) { - if (cam_cdm_read_hw_reg(cdm_hw, - cdm_core->offsets->cmn_reg->usr_data, - &user_data)) { - CAM_ERR(CAM_CDM, - "Failed to read CDM HW IRQ data"); - kfree(payload[i]); - return IRQ_HANDLED; - } - payload[i]->irq_data = user_data >> (i * 0x8); + payload[i]->irq_data = (user_data >> (i * 0x8)) & + CAM_CDM_IRQ_STATUS_USR_DATA_MASK; if (payload[i]->irq_data == CAM_CDM_DBG_GEN_IRQ_USR_DATA) CAM_INFO(CAM_CDM, "Debug gen_irq received"); } + CAM_DBG(CAM_CDM, + "Rcvd of fifo %d userdata 0x%x tag 0x%x irq_stat 0x%x", + i, user_data, payload[i]->irq_data, irq_status[i]); + payload[i]->fifo_idx = i; payload[i]->irq_status = irq_status[i]; payload[i]->hw = cdm_hw; @@ -1162,10 +1321,9 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) INIT_WORK((struct work_struct *)&payload[i]->work, cam_hw_cdm_work); - trace_cam_log_event("CDM_DONE", "CDM_DONE_IRQ", + trace_cam_log_event("CDM_DONE", "CDM_DONE_IRQ", payload[i]->irq_status, cdm_hw->soc_info.index); - if (cam_cdm_write_hw_reg(cdm_hw, cdm_core->offsets->irq_reg[i]->irq_clear, payload[i]->irq_status)) { @@ -1175,18 +1333,30 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) return IRQ_HANDLED; } - work_status = queue_work( + cdm_core->bl_fifo[i].work_record++; + work_status = queue_work( cdm_core->bl_fifo[i].work_queue, &payload[i]->work); if (work_status == false) { CAM_ERR(CAM_CDM, - "Failed to queue work for irq=0x%x", - payload[i]->irq_status); + "Failed to queue work for FIFO: %d irq=0x%x", + i, payload[i]->irq_status); kfree(payload[i]); } } - + if (cdm_core->rst_done_cnt == + cdm_core->offsets->reg_data->num_bl_fifo_irq) { + CAM_DBG(CAM_CDM, "CDM HW reset done IRQ"); + complete(&cdm_core->reset_complete); + } + if (cdm_core->rst_done_cnt && + cdm_core->rst_done_cnt != + cdm_core->offsets->reg_data->num_bl_fifo_irq) + CAM_INFO(CAM_CDM, + "Reset IRQ received for %d fifos instead of %d", + cdm_core->rst_done_cnt, + cdm_core->offsets->reg_data->num_bl_fifo_irq); return IRQ_HANDLED; } @@ -1254,16 +1424,24 @@ int cam_hw_cdm_reset_hw(struct cam_hw_info *cdm_hw, uint32_t handle) struct cam_cdm *cdm_core = NULL; long time_left; int i, rc = -EIO; + int reset_val = 1; cdm_core = (struct cam_cdm *)cdm_hw->core_info; - set_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); - reinit_completion(&cdm_core->reset_complete); - for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) mutex_lock(&cdm_core->bl_fifo[i].fifo_lock); + set_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); + cdm_core->rst_done_cnt = 0; + reinit_completion(&cdm_core->reset_complete); + + /* First pause CDM, If it fails still proceed to reset CDM HW */ + cam_hw_cdm_pause_core(cdm_hw, true); + usleep_range(1000, 1010); + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { + reset_val = reset_val | + (1 << (i + CAM_CDM_BL_FIFO_FLUSH_SHIFT)); if (cam_cdm_write_hw_reg(cdm_hw, cdm_core->offsets->irq_reg[i]->irq_mask, 0x70003)) { @@ -1273,7 +1451,7 @@ int cam_hw_cdm_reset_hw(struct cam_hw_info *cdm_hw, uint32_t handle) } if (cam_cdm_write_hw_reg(cdm_hw, - cdm_core->offsets->cmn_reg->rst_cmd, 0x9)) { + cdm_core->offsets->cmn_reg->rst_cmd, reset_val)) { CAM_ERR(CAM_CDM, "Failed to Write CDM HW reset"); goto end; } @@ -1318,16 +1496,21 @@ int cam_hw_cdm_handle_error_info( long time_left; int i, rc = -EIO, reset_hw_hdl = 0x0; uint32_t current_bl_data = 0, current_fifo = 0, current_tag = 0; + int reset_val = 1; cdm_core = (struct cam_cdm *)cdm_hw->core_info; - set_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); - set_bit(CAM_CDM_FLUSH_HW_STATUS, &cdm_core->cdm_status); - reinit_completion(&cdm_core->reset_complete); - for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) mutex_lock(&cdm_core->bl_fifo[i].fifo_lock); + cdm_core->rst_done_cnt = 0; + reinit_completion(&cdm_core->reset_complete); + set_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); + set_bit(CAM_CDM_FLUSH_HW_STATUS, &cdm_core->cdm_status); + + /* First pause CDM, If it fails still proceed to dump debug info */ + cam_hw_cdm_pause_core(cdm_hw, true); + rc = cam_cdm_read_hw_reg(cdm_hw, cdm_core->offsets->cmn_reg->current_bl_len, ¤t_bl_data); @@ -1349,6 +1532,8 @@ int cam_hw_cdm_handle_error_info( cam_hw_cdm_dump_core_debug_registers(cdm_hw); for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { + reset_val = reset_val | + (1 << (i + CAM_CDM_BL_FIFO_FLUSH_SHIFT)); if (cam_cdm_write_hw_reg(cdm_hw, cdm_core->offsets->irq_reg[i]->irq_mask, 0x70003)) { @@ -1358,7 +1543,7 @@ int cam_hw_cdm_handle_error_info( } if (cam_cdm_write_hw_reg(cdm_hw, - cdm_core->offsets->cmn_reg->rst_cmd, 0x9)) { + cdm_core->offsets->cmn_reg->rst_cmd, reset_val)) { CAM_ERR(CAM_CDM, "Failed to Write CDM HW reset"); goto end; } @@ -1437,14 +1622,38 @@ int cam_hw_cdm_handle_error( cdm_core = (struct cam_cdm *)cdm_hw->core_info; - /* First pause CDM, If it fails still proceed to dump debug info */ - cam_hw_cdm_enable_core(cdm_hw, false); - rc = cam_hw_cdm_handle_error_info(cdm_hw, handle); return rc; } +int cam_hw_cdm_hang_detect( + struct cam_hw_info *cdm_hw, + uint32_t handle) +{ + struct cam_cdm *cdm_core = NULL; + int i, rc = -1; + + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) + mutex_lock(&cdm_core->bl_fifo[i].fifo_lock); + + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) + if (cdm_core->bl_fifo[i].work_record) { + CAM_WARN(CAM_CDM, + "workqueue got delayed, work_record :%u", + cdm_core->bl_fifo[i].work_record); + rc = 0; + break; + } + + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) + mutex_unlock(&cdm_core->bl_fifo[i].fifo_lock); + + return rc; +} + int cam_hw_cdm_get_cdm_config(struct cam_hw_info *cdm_hw) { struct cam_hw_soc_info *soc_info = NULL; @@ -1517,6 +1726,7 @@ int cam_hw_cdm_init(void *hw_priv, struct cam_hw_soc_info *soc_info = NULL; struct cam_cdm *cdm_core = NULL; int rc, i, reset_hw_hdl = 0x0; + unsigned long flags; if (!hw_priv) return -EINVAL; @@ -1530,6 +1740,9 @@ int cam_hw_cdm_init(void *hw_priv, CAM_ERR(CAM_CDM, "Enable platform failed"); goto end; } + spin_lock_irqsave(&cdm_hw->hw_lock, flags); + cdm_hw->hw_state = CAM_HW_STATE_POWER_UP; + spin_unlock_irqrestore(&cdm_hw->hw_lock, flags); CAM_DBG(CAM_CDM, "Enable soc done"); @@ -1540,6 +1753,10 @@ int cam_hw_cdm_init(void *hw_priv, clear_bit(i, &cdm_core->cdm_status); reinit_completion(&cdm_core->bl_fifo[i].bl_complete); } + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { + cdm_core->bl_fifo[i].last_bl_tag_done = -1; + cdm_core->bl_fifo[i].work_record = 0; + } rc = cam_hw_cdm_reset_hw(cdm_hw, reset_hw_hdl); @@ -1548,7 +1765,6 @@ int cam_hw_cdm_init(void *hw_priv, goto disable_return; } else { CAM_DBG(CAM_CDM, "CDM Init success"); - cdm_hw->hw_state = CAM_HW_STATE_POWER_UP; for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) cam_cdm_write_hw_reg(cdm_hw, cdm_core->offsets->irq_reg[i]->irq_mask, @@ -1559,6 +1775,9 @@ int cam_hw_cdm_init(void *hw_priv, disable_return: rc = -EIO; + spin_lock_irqsave(&cdm_hw->hw_lock, flags); + cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + spin_unlock_irqrestore(&cdm_hw->hw_lock, flags); cam_soc_util_disable_platform_resource(soc_info, true, true); end: return rc; @@ -1570,19 +1789,74 @@ int cam_hw_cdm_deinit(void *hw_priv, struct cam_hw_info *cdm_hw = hw_priv; struct cam_hw_soc_info *soc_info = NULL; struct cam_cdm *cdm_core = NULL; - int rc = 0; + struct cam_cdm_bl_cb_request_entry *node, *tnode; + int rc = 0, i; + uint32_t reset_val = 1; + long time_left; + unsigned long flags; if (!hw_priv) return -EINVAL; soc_info = &cdm_hw->soc_info; - cdm_core = cdm_hw->core_info; + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) + mutex_lock(&cdm_core->bl_fifo[i].fifo_lock); + + /*clear bl request */ + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { + list_for_each_entry_safe(node, tnode, + &cdm_core->bl_fifo[i].bl_request_list, entry) { + list_del_init(&node->entry); + kfree(node); + } + } + + set_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); + cdm_core->rst_done_cnt = 0; + reinit_completion(&cdm_core->reset_complete); + + /* First pause CDM, If it fails still proceed to reset CDM HW */ + cam_hw_cdm_pause_core(cdm_hw, true); + usleep_range(1000, 1010); + + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { + reset_val = reset_val | + (1 << (i + CAM_CDM_BL_FIFO_FLUSH_SHIFT)); + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->irq_reg[i]->irq_mask, + 0x70003)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ mask"); + } + } + + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->cmn_reg->rst_cmd, reset_val)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW reset"); + } + + CAM_DBG(CAM_CDM, "Waiting for CDM HW reset done"); + time_left = wait_for_completion_timeout(&cdm_core->reset_complete, + msecs_to_jiffies(CAM_CDM_HW_RESET_TIMEOUT)); + + if (time_left <= 0) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_CDM, "CDM HW reset Wait failed rc=%d", rc); + } + + clear_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) + mutex_unlock(&cdm_core->bl_fifo[i].fifo_lock); + + spin_lock_irqsave(&cdm_hw->hw_lock, flags); + cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + spin_unlock_irqrestore(&cdm_hw->hw_lock, flags); rc = cam_soc_util_disable_platform_resource(soc_info, true, true); if (rc) { CAM_ERR(CAM_CDM, "disable platform failed"); } else { CAM_DBG(CAM_CDM, "CDM Deinit success"); - cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; } return rc; @@ -1653,6 +1927,7 @@ static int cam_hw_cdm_component_bind(struct device *dev, goto release_private_mem; } + cdm_core->rst_done_cnt = 0; init_completion(&cdm_core->reset_complete); cdm_hw_intf->hw_priv = cdm_hw; cdm_hw_intf->hw_ops.get_hw_caps = cam_cdm_get_caps; diff --git a/drivers/cam_cdm/cam_cdm_intf.c b/drivers/cam_cdm/cam_cdm_intf.c index 8f9c9ce0ec..8c7fcadc91 100644 --- a/drivers/cam_cdm/cam_cdm_intf.c +++ b/drivers/cam_cdm/cam_cdm_intf.c @@ -480,6 +480,33 @@ int cam_cdm_handle_error(uint32_t handle) } EXPORT_SYMBOL(cam_cdm_handle_error); +int cam_cdm_detect_hang_error(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_HANG_DETECT, + &handle, + sizeof(handle)); + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_detect_hang_error); + int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, uint32_t *index) diff --git a/drivers/cam_cdm/cam_cdm_intf_api.h b/drivers/cam_cdm/cam_cdm_intf_api.h index 37f1f1503c..58ffd4f8a0 100644 --- a/drivers/cam_cdm/cam_cdm_intf_api.h +++ b/drivers/cam_cdm/cam_cdm_intf_api.h @@ -280,4 +280,13 @@ int cam_cdm_handle_error(uint32_t handle); */ struct cam_cdm_utils_ops *cam_cdm_publish_ops(void); +/** + * @brief : API to detect hang in previously acquired CDM, + * this should be only performed only if the CDM is private. + * + * @handle : Input handle of the CDM to detect hang + * + * @return 0 on success + */ +int cam_cdm_detect_hang_error(uint32_t handle); #endif /* _CAM_CDM_API_H_ */ diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 936a5f7177..c7fa0c4fd6 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -462,7 +462,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( if (soc_private->control_camnoc_axi_clk) { struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; uint64_t required_camnoc_bw = 0, intermediate_result = 0; - int32_t clk_rate = 0; + int64_t clk_rate = 0; for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { tree_node = soc_private->tree_node[i]; @@ -511,7 +511,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( do_div(intermediate_result, soc_private->camnoc_bus_width); clk_rate = intermediate_result; - CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", + CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %lld", required_camnoc_bw, clk_rate); /* @@ -524,7 +524,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); if (rc) CAM_ERR(CAM_CPAS, - "Failed in setting camnoc axi clk %llu %d %d", + "Failed in setting camnoc axi clk %llu %lld %d", required_camnoc_bw, clk_rate, rc); cpas_core->applied_camnoc_axi_rate = clk_rate; diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 5bd654f442..3cb8200364 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -24,6 +24,7 @@ #include "cpastop_v480_100.h" #include "cpastop_v580_100.h" #include "cpastop_v540_100.h" +#include "cpastop_v520_100.h" struct cam_camnoc_info *camnoc_info; @@ -86,6 +87,25 @@ static const uint32_t cam_cpas_hw_version_map 0, 0, }, + /* for camera_520 */ + { + CAM_CPAS_TITAN_520_V100, + 0, + 0, + 0, + 0, + 0, + + }, + /* for camera_540 */ + { + CAM_CPAS_TITAN_540_V100, + 0, + 0, + 0, + 0, + 0, + }, }; static int cam_cpas_translate_camera_cpas_version_id( @@ -113,6 +133,14 @@ static int cam_cpas_translate_camera_cpas_version_id( *cam_version_id = CAM_CPAS_CAMERA_VERSION_ID_480; break; + case CAM_CPAS_CAMERA_VERSION_520: + *cam_version_id = CAM_CPAS_CAMERA_VERSION_ID_520; + break; + + case CAM_CPAS_CAMERA_VERSION_540: + *cam_version_id = CAM_CPAS_CAMERA_VERSION_ID_540; + break; + case CAM_CPAS_CAMERA_VERSION_580: *cam_version_id = CAM_CPAS_CAMERA_VERSION_ID_580; break; @@ -716,6 +744,9 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, case CAM_CPAS_TITAN_540_V100: camnoc_info = &cam540_cpas100_camnoc_info; break; + case CAM_CPAS_TITAN_520_V100: + camnoc_info = &cam520_cpas100_camnoc_info; + break; default: CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d", hw_caps->camera_version.major, diff --git a/drivers/cam_cpas/cpas_top/cpastop_v520_100.h b/drivers/cam_cpas/cpas_top/cpastop_v520_100.h new file mode 100644 index 0000000000..ec99574ebf --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v520_100.h @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V520_100_H_ +#define _CPASTOP_V520_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v520_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xA40, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + (TEST_IRQ_ENABLE ? + 0x2 : /* SBM_FAULTINEN0_LOW_PORT6_MASK */ + 0x0) /* SBM_FAULTINEN0_LOW_PORT1_MASK */, + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xA48, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xA80, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x3 : 0x1, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v520_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xD08, /* ERRORLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xD10, /* ERRORLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xD18, /* ERRORLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT6_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xA88, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xA90, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + + +static struct cam_camnoc_specific + cam_cpas_v520_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE30, /* CDM_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE34, /* CDM_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE38, /* CDM_URGENCY_LOW */ + .value = 0x00000003, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE40, /* CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE48, /* CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_TFE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_LOW */ + .offset = 0x30, + .value = 0x44443333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_HIGH */ + .offset = 0x34, + .value = 0x66665555, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x38, /* TFE_URGENCY_LOW */ + .value = 0x00001030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x40, /* TFE_DANGERLUT_LOW */ + .value = 0xffff0000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x48, /* TFE_SAFELUT_LOW */ + .value = 0x00000003, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_OPE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* OPE_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* OPE_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x438, /* OPE_URGENCY_LOW */ + .value = 0x00000033, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* OPE_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* OPE_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam520_cpas100_err_logger_offsets = { + .mainctrl = 0xD08, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0xD10, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0xD20, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0xD24, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0xD28, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0xD2C, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0xD30, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0xD34, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0xD38, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0xD3C, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_camnoc_info cam520_cpas100_camnoc_info = { + .specific = &cam_cpas_v520_100_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v520_100_camnoc_specific), + .irq_sbm = &cam_cpas_v520_100_irq_sbm, + .irq_err = &cam_cpas_v520_100_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v520_100_irq_err), + .err_logger = &cam520_cpas100_err_logger_offsets, + .errata_wa_list = NULL, +}; + +#endif /* _CPASTOP_V520_100_H_ */ diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index c13ac20e7b..9601166c2a 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -41,6 +41,8 @@ enum cam_cpas_camera_version { CAM_CPAS_CAMERA_VERSION_170 = 0x00010700, CAM_CPAS_CAMERA_VERSION_175 = 0x00010705, CAM_CPAS_CAMERA_VERSION_480 = 0x00040800, + CAM_CPAS_CAMERA_VERSION_520 = 0x00050200, + CAM_CPAS_CAMERA_VERSION_540 = 0x00050400, CAM_CPAS_CAMERA_VERSION_580 = 0x00050800, CAM_CPAS_CAMERA_VERSION_MAX }; @@ -69,6 +71,8 @@ enum cam_cpas_camera_version_map_id { CAM_CPAS_CAMERA_VERSION_ID_175 = 0x2, CAM_CPAS_CAMERA_VERSION_ID_480 = 0x3, CAM_CPAS_CAMERA_VERSION_ID_580 = 0x4, + CAM_CPAS_CAMERA_VERSION_ID_520 = 0x5, + CAM_CPAS_CAMERA_VERSION_ID_540 = 0x6, CAM_CPAS_CAMERA_VERSION_ID_MAX }; @@ -103,6 +107,7 @@ enum cam_cpas_hw_version { CAM_CPAS_TITAN_480_V100 = 0x480100, CAM_CPAS_TITAN_580_V100 = 0x580100, CAM_CPAS_TITAN_540_V100 = 0x540100, + CAM_CPAS_TITAN_520_V100 = 0x520100, CAM_CPAS_TITAN_MAX }; diff --git a/drivers/cam_icp/fw_inc/hfi_intf.h b/drivers/cam_icp/fw_inc/hfi_intf.h index afd42d23b9..6a5ec84824 100644 --- a/drivers/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/cam_icp/fw_inc/hfi_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _HFI_INTF_H_ diff --git a/drivers/cam_icp/fw_inc/hfi_reg.h b/drivers/cam_icp/fw_inc/hfi_reg.h index df4ae01d7e..200bfe6bc2 100644 --- a/drivers/cam_icp/fw_inc/hfi_reg.h +++ b/drivers/cam_icp/fw_inc/hfi_reg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_HFI_REG_H_ diff --git a/drivers/cam_icp/hfi.c b/drivers/cam_icp/hfi.c index 89a95aca62..b015d19d1e 100644 --- a/drivers/cam_icp/hfi.c +++ b/drivers/cam_icp/hfi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index a05e44221a..fd5c59fb47 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -26,6 +26,12 @@ */ #define CAM_ISP_CTX_RES_MAX 24 +/* + * Maximum configuration entry size - This is based on the + * worst case DUAL IFE use case plus some margin. + */ +#define CAM_ISP_CTX_CFG_MAX 25 + /* * Maximum entries in state monitoring array for error logging */ diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 7e62810609..bfdc76f930 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -4205,8 +4205,10 @@ static int cam_ife_mgr_reset_vfe_hw(struct cam_ife_hw_mgr *hw_mgr, vfe_reset_type = CAM_VFE_HW_RESET_HW; for (i = 0; i < CAM_VFE_HW_NUM_MAX; i++) { - if ((!hw_mgr->ife_devices[i]) || - (hw_idx != hw_mgr->ife_devices[i]->hw_idx)) + if (!hw_mgr->ife_devices[i]) + continue; + + if (hw_idx != hw_mgr->ife_devices[i]->hw_idx) continue; CAM_DBG(CAM_ISP, "VFE (id = %d) reset", hw_idx); vfe_hw_intf = hw_mgr->ife_devices[i]; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c index 02ca27f7f4..9d7ec3e038 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c @@ -54,7 +54,8 @@ static int cam_tfe_mgr_regspace_data_cb(uint32_t reg_base_type, *soc_info_ptr = NULL; list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { - if (hw_mgr_res->res_id != CAM_ISP_HW_TFE_IN_CAMIF) + if ((hw_mgr_res->res_id != CAM_ISP_HW_TFE_IN_CAMIF) && + !ctx->is_rdi_only_context) continue; switch (reg_base_type) { @@ -117,9 +118,11 @@ static int cam_tfe_mgr_regspace_data_cb(uint32_t reg_base_type, static int cam_tfe_mgr_handle_reg_dump(struct cam_tfe_hw_mgr_ctx *ctx, struct cam_cmd_buf_desc *reg_dump_buf_desc, uint32_t num_reg_dump_buf, - uint32_t meta_type) + uint32_t meta_type, + void *soc_dump_args, + bool user_triggered_dump) { - int rc = 0, i; + int rc = -EINVAL, i; if (!num_reg_dump_buf || !reg_dump_buf_desc) { CAM_DBG(CAM_ISP, @@ -141,8 +144,8 @@ static int cam_tfe_mgr_handle_reg_dump(struct cam_tfe_hw_mgr_ctx *ctx, ®_dump_buf_desc[i], ctx->applied_req_id, cam_tfe_mgr_regspace_data_cb, - NULL, - false); + soc_dump_args, + user_triggered_dump); if (rc) { CAM_ERR(CAM_ISP, "Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %u", @@ -152,7 +155,7 @@ static int cam_tfe_mgr_handle_reg_dump(struct cam_tfe_hw_mgr_ctx *ctx, } } - return 0; + return rc; } static int cam_tfe_mgr_get_hw_caps(void *hw_mgr_priv, @@ -678,7 +681,7 @@ static void cam_tfe_hw_mgr_dump_all_ctx(void) list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, list) { for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (hw_mgr_res->hw_res[i]) + if (!hw_mgr_res->hw_res[i]) continue; CAM_INFO_RATE_LIMIT(CAM_ISP, @@ -693,7 +696,7 @@ static void cam_tfe_hw_mgr_dump_all_ctx(void) list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (hw_mgr_res->hw_res[i]) + if (!hw_mgr_res->hw_res[i]) continue; CAM_INFO_RATE_LIMIT(CAM_ISP, @@ -1232,7 +1235,7 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl( if (i == CAM_TFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { CAM_ERR(CAM_ISP, - "Can not acquire tfe csid path resource %d", + "Can not acquire left tfe csid path resource %d", path_res_id); goto put_res; } @@ -1330,6 +1333,8 @@ acquire_successful: goto end; } csid_res_temp->hw_res[1] = csid_acquire.node_res; + tfe_ctx->slave_hw_idx = + csid_res_temp->hw_res[1]->hw_intf->hw_idx; CAM_DBG(CAM_ISP, "CSID right acquired success is_dual %d", in_port->usage_type); } @@ -1654,7 +1659,8 @@ static int cam_tfe_mgr_acquire_hw_for_ctx( in_port); if (rc) { CAM_ERR(CAM_ISP, - "Acquire TFE CSID IPP resource Failed"); + "Acquire TFE CSID IPP resource Failed dual:%d", + in_port->usage_type); goto err; } } @@ -1664,7 +1670,8 @@ static int cam_tfe_mgr_acquire_hw_for_ctx( rc = cam_tfe_hw_mgr_acquire_res_tfe_csid_rdi(tfe_ctx, in_port); if (rc) { CAM_ERR(CAM_ISP, - "Acquire TFE CSID RDI resource Failed"); + "Acquire TFE CSID RDI resource Failed dual:%d", + in_port->usage_type); goto err; } } @@ -1672,14 +1679,15 @@ static int cam_tfe_mgr_acquire_hw_for_ctx( rc = cam_tfe_hw_mgr_acquire_res_tfe_in(tfe_ctx, in_port, pdaf_enable); if (rc) { CAM_ERR(CAM_ISP, - "Acquire TFE IN resource Failed"); + "Acquire TFE IN resource Failed dual:%d", in_port->usage_type); goto err; } CAM_DBG(CAM_ISP, "Acquiring TFE OUT resource..."); rc = cam_tfe_hw_mgr_acquire_res_tfe_out(tfe_ctx, in_port); if (rc) { - CAM_ERR(CAM_ISP, "Acquire TFE OUT resource Failed"); + CAM_ERR(CAM_ISP, "Acquire TFE OUT resource Failed dual:%d", + in_port->usage_type); goto err; } @@ -1713,7 +1721,8 @@ void cam_tfe_cam_cdm_callback(uint32_t handle, void *userdata, cam_tfe_mgr_handle_reg_dump(ctx, hw_update_data->reg_dump_buf_desc, hw_update_data->num_reg_dump_buf, - CAM_ISP_TFE_PACKET_META_REG_DUMP_PER_REQUEST); + CAM_ISP_TFE_PACKET_META_REG_DUMP_PER_REQUEST, + NULL, false); CAM_DBG(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", handle, userdata, status, cookie, ctx->ctx_index); @@ -1933,6 +1942,7 @@ static int cam_tfe_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) acquire_args->ctxt_to_hw_map = tfe_ctx; tfe_ctx->ctx_in_use = 1; + tfe_ctx->num_reg_dump_buf = 0; cam_tfe_hw_mgr_put_ctx(&tfe_hw_mgr->used_ctx_list, &tfe_ctx); @@ -2697,6 +2707,9 @@ static int cam_tfe_mgr_reset_tfe_hw(struct cam_tfe_hw_mgr *hw_mgr, tfe_reset_type = CAM_TFE_HW_RESET_HW; for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) { + if (!hw_mgr->tfe_devices[i]) + continue; + if (hw_idx != hw_mgr->tfe_devices[i]->hw_idx) continue; CAM_DBG(CAM_ISP, "TFE (id = %d) reset", hw_idx); @@ -2985,6 +2998,159 @@ static int cam_tfe_mgr_write(void *hw_mgr_priv, void *write_args) return -EPERM; } +static int cam_tfe_mgr_user_dump_hw( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_hw_dump_args *dump_args) +{ + int rc = 0; + struct cam_hw_soc_dump_args soc_dump_args; + + if (!tfe_ctx || !dump_args) { + CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK", + tfe_ctx, dump_args); + return -EINVAL; + } + soc_dump_args.buf_handle = dump_args->buf_handle; + soc_dump_args.request_id = dump_args->request_id; + soc_dump_args.offset = dump_args->offset; + + rc = cam_tfe_mgr_handle_reg_dump(tfe_ctx, + tfe_ctx->reg_dump_buf_desc, + tfe_ctx->num_reg_dump_buf, + CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR, + &soc_dump_args, + true); + if (rc) { + CAM_DBG(CAM_ISP, + "Dump failed req: %lld handle %u offset %u rc %d", + dump_args->request_id, + dump_args->buf_handle, + dump_args->offset, + rc); + return rc; + } + dump_args->offset = soc_dump_args.offset; + return rc; +} + +static int cam_tfe_mgr_dump(void *hw_mgr_priv, void *args) +{ + + struct cam_isp_hw_dump_args isp_hw_dump_args; + struct cam_hw_dump_args *dump_args = (struct cam_hw_dump_args *)args; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_tfe_hw_mgr_ctx *tfe_ctx = (struct cam_tfe_hw_mgr_ctx *) + dump_args->ctxt_to_hw_map; + int i; + int rc = 0; + + /* for some targets, information about the TFE registers to be dumped + * is already submitted with the hw manager. In this case, we + * can dump just the related registers and skip going to core files. + * If dump to this buffer falis due to any reason, fallback to dump + * to the LDAR buffer + */ + isp_hw_dump_args.is_dump_all = true; + if (tfe_ctx->num_reg_dump_buf) { + rc = cam_tfe_mgr_user_dump_hw(tfe_ctx, dump_args); + if (!rc) + isp_hw_dump_args.is_dump_all = false; + } + + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &isp_hw_dump_args.cpu_addr, + &isp_hw_dump_args.buf_len); + + if (rc) { + CAM_ERR(CAM_ISP, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + + isp_hw_dump_args.offset = dump_args->offset; + isp_hw_dump_args.req_id = dump_args->request_id; + + list_for_each_entry(hw_mgr_res, &tfe_ctx->res_list_tfe_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + switch (hw_mgr_res->hw_res[i]->res_id) { + case CAM_TFE_CSID_PATH_RES_RDI_0: + case CAM_TFE_CSID_PATH_RES_RDI_1: + case CAM_TFE_CSID_PATH_RES_RDI_2: + if (tfe_ctx->is_rdi_only_context && + hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + + case CAM_TFE_CSID_PATH_RES_IPP: + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + default: + CAM_DBG(CAM_ISP, "not a valid res %d", + hw_mgr_res->res_id); + break; + } + } + } + + list_for_each_entry(hw_mgr_res, &tfe_ctx->res_list_tfe_in, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + switch (hw_mgr_res->hw_res[i]->res_id) { + case CAM_ISP_HW_TFE_IN_RDI0: + case CAM_ISP_HW_TFE_IN_RDI1: + case CAM_ISP_HW_TFE_IN_RDI2: + if (tfe_ctx->is_rdi_only_context && + hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + + case CAM_ISP_HW_TFE_IN_CAMIF: + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + default: + CAM_DBG(CAM_ISP, "not a valid res %d", + hw_mgr_res->res_id); + break; + } + } + } + dump_args->offset = isp_hw_dump_args.offset; + CAM_DBG(CAM_ISP, "offset %u", dump_args->offset); + return rc; +} + static int cam_tfe_mgr_reset(void *hw_mgr_priv, void *hw_reset_args) { struct cam_tfe_hw_mgr *hw_mgr = hw_mgr_priv; @@ -3023,6 +3189,7 @@ static int cam_tfe_mgr_reset(void *hw_mgr_priv, void *hw_reset_args) } } + atomic_set(&ctx->overflow_pending, 0); end: return rc; } @@ -3072,6 +3239,7 @@ static int cam_tfe_mgr_release_hw(void *hw_mgr_priv, ctx->init_done = false; ctx->is_dual = false; ctx->is_tpg = false; + ctx->num_reg_dump_buf = 0; ctx->res_list_tpg.res_type = CAM_ISP_RESOURCE_MAX; atomic_set(&ctx->overflow_pending, 0); for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) { @@ -3463,7 +3631,8 @@ static int cam_isp_tfe_packet_generic_blob_handler(void *user_data, return -EINVAL; } - if (bw_config->num_paths > CAM_ISP_MAX_PER_PATH_VOTES) { + if ((bw_config->num_paths > CAM_ISP_MAX_PER_PATH_VOTES) || + !bw_config->num_paths) { CAM_ERR(CAM_ISP, "Invalid num paths %d", bw_config->num_paths); return -EINVAL; @@ -3790,6 +3959,7 @@ int cam_tfe_add_command_buffers( break; case CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_FLUSH: case CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_ERROR: + case CAM_ISP_TFE_PACKET_META_REG_DUMP_PER_REQUEST: if (split_id == CAM_ISP_HW_SPLIT_LEFT) { if (prepare->num_reg_dump_buf >= CAM_REG_DUMP_MAX_BUF_ENTRIES) { @@ -3934,24 +4104,50 @@ static int cam_tfe_mgr_prepare_hw_update(void *hw_mgr_priv, fill_fence = false; } - ctx->num_reg_dump_buf = prepare->num_reg_dump_buf; - if ((ctx->num_reg_dump_buf) && (ctx->num_reg_dump_buf < - CAM_REG_DUMP_MAX_BUF_ENTRIES)) { - memcpy(ctx->reg_dump_buf_desc, - prepare->reg_dump_buf_desc, - sizeof(struct cam_cmd_buf_desc) * - prepare->num_reg_dump_buf); - } + CAM_DBG(CAM_ISP, + "num_reg_dump_buf=%d ope code:%d", + prepare->num_reg_dump_buf, prepare->packet->header.op_code); /* reg update will be done later for the initial configure */ if (((prepare->packet->header.op_code) & 0xF) == CAM_ISP_PACKET_INIT_DEV) { prepare_hw_data->packet_opcode_type = CAM_ISP_TFE_PACKET_INIT_DEV; + + if ((!prepare->num_reg_dump_buf) || (prepare->num_reg_dump_buf > + CAM_REG_DUMP_MAX_BUF_ENTRIES)) + goto end; + + if (!ctx->num_reg_dump_buf) { + ctx->num_reg_dump_buf = + prepare->num_reg_dump_buf; + memcpy(ctx->reg_dump_buf_desc, + prepare->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + prepare->num_reg_dump_buf); + } else { + prepare_hw_data->num_reg_dump_buf = + prepare->num_reg_dump_buf; + memcpy(prepare_hw_data->reg_dump_buf_desc, + prepare->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + prepare_hw_data->num_reg_dump_buf); + } + goto end; - } else + } else { prepare_hw_data->packet_opcode_type = CAM_ISP_TFE_PACKET_CONFIG_DEV; + prepare_hw_data->num_reg_dump_buf = prepare->num_reg_dump_buf; + if ((prepare_hw_data->num_reg_dump_buf) && + (prepare_hw_data->num_reg_dump_buf < + CAM_REG_DUMP_MAX_BUF_ENTRIES)) { + memcpy(prepare_hw_data->reg_dump_buf_desc, + prepare->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + prepare_hw_data->num_reg_dump_buf); + } + } /* add reg update commands */ for (i = 0; i < ctx->num_base; i++) { @@ -4142,6 +4338,7 @@ static int cam_tfe_mgr_cmd(void *hw_mgr_priv, void *cmd_args) struct cam_tfe_hw_mgr_ctx *ctx = (struct cam_tfe_hw_mgr_ctx *) hw_cmd_args->ctxt_to_hw_map; struct cam_isp_hw_cmd_args *isp_hw_cmd_args = NULL; + struct cam_packet *packet; if (!hw_mgr_priv || !cmd_args) { CAM_ERR(CAM_ISP, "Invalid arguments"); @@ -4180,6 +4377,17 @@ static int cam_tfe_mgr_cmd(void *hw_mgr_priv, void *cmd_args) else isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_PIX; break; + case CAM_ISP_HW_MGR_GET_PACKET_OPCODE: + packet = (struct cam_packet *) + isp_hw_cmd_args->cmd_data; + if ((packet->header.op_code & 0xF) == + CAM_ISP_TFE_PACKET_INIT_DEV) + isp_hw_cmd_args->u.packet_op_code = + CAM_ISP_TFE_PACKET_INIT_DEV; + else + isp_hw_cmd_args->u.packet_op_code = + CAM_ISP_TFE_PACKET_CONFIG_DEV; + break; default: CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", hw_cmd_args->cmd_type); @@ -4203,11 +4411,12 @@ static int cam_tfe_mgr_cmd(void *hw_mgr_priv, void *cmd_args) rc = cam_tfe_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, ctx->num_reg_dump_buf, - CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_FLUSH); + CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_FLUSH, + NULL, false); if (rc) { CAM_ERR(CAM_ISP, - "Reg dump on flush failed req id: %llu rc: %d", - ctx->applied_req_id, rc); + "Reg dump on flush failed req id: %llu num_reg_dump:0x%x rc: %d", + ctx->applied_req_id, ctx->num_reg_dump_buf, rc); return rc; } @@ -4219,15 +4428,15 @@ static int cam_tfe_mgr_cmd(void *hw_mgr_priv, void *cmd_args) ctx->last_dump_err_req_id = ctx->applied_req_id; rc = cam_tfe_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, ctx->num_reg_dump_buf, - CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_ERROR); + CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_ERROR, + NULL, false); if (rc) { CAM_ERR(CAM_ISP, - "Reg dump on error failed req id: %llu rc: %d", - ctx->applied_req_id, rc); + "Reg dump on error failed req id:%llu num_reg_dump:0x%x rc: %d", + ctx->applied_req_id, ctx->num_reg_dump_buf, rc); return rc; } break; - default: CAM_ERR(CAM_ISP, "Invalid cmd"); } @@ -4695,12 +4904,15 @@ static int cam_tfe_hw_mgr_check_irq_for_dual_tfe( { int32_t rc = -EINVAL; uint32_t *event_cnt = NULL; - uint32_t core_idx0 = 0; - uint32_t core_idx1 = 1; + uint32_t master_hw_idx; + uint32_t slave_hw_idx; if (!tfe_hw_mgr_ctx->is_dual) return 0; + master_hw_idx = tfe_hw_mgr_ctx->master_hw_idx; + slave_hw_idx = tfe_hw_mgr_ctx->slave_hw_idx; + switch (hw_event_type) { case CAM_ISP_HW_EVENT_SOF: event_cnt = tfe_hw_mgr_ctx->sof_cnt; @@ -4715,19 +4927,18 @@ static int cam_tfe_hw_mgr_check_irq_for_dual_tfe( return 0; } - if (event_cnt[core_idx0] == event_cnt[core_idx1]) { + if (event_cnt[master_hw_idx] == event_cnt[slave_hw_idx]) { - event_cnt[core_idx0] = 0; - event_cnt[core_idx1] = 0; + event_cnt[master_hw_idx] = 0; + event_cnt[slave_hw_idx] = 0; - rc = 0; - return rc; + return 0; } - if ((event_cnt[core_idx0] && - (event_cnt[core_idx0] - event_cnt[core_idx1] > 1)) || - (event_cnt[core_idx1] && - (event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) { + if ((event_cnt[master_hw_idx] && + (event_cnt[master_hw_idx] - event_cnt[slave_hw_idx] > 1)) || + (event_cnt[slave_hw_idx] && + (event_cnt[slave_hw_idx] - event_cnt[master_hw_idx] > 1))) { if (tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt > 10) { rc = -1; @@ -4735,15 +4946,15 @@ static int cam_tfe_hw_mgr_check_irq_for_dual_tfe( } CAM_ERR_RATE_LIMIT(CAM_ISP, - "One TFE could not generate hw event %d id0:%d id1:%d", - hw_event_type, event_cnt[core_idx0], - event_cnt[core_idx1]); - if (event_cnt[core_idx0] >= 2) { - event_cnt[core_idx0]--; + "One TFE could not generate hw event %d master id :%d slave id:%d", + hw_event_type, event_cnt[master_hw_idx], + event_cnt[slave_hw_idx]); + if (event_cnt[master_hw_idx] >= 2) { + event_cnt[master_hw_idx]--; tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt++; } - if (event_cnt[core_idx1] >= 2) { - event_cnt[core_idx1]--; + if (event_cnt[slave_hw_idx] >= 2) { + event_cnt[slave_hw_idx]--; tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt++; } @@ -5078,7 +5289,7 @@ static int cam_tfe_hw_mgr_debug_register(void) goto err; } - if (!debugfs_create_bool("enable_reg_dump", + if (!debugfs_create_u32("enable_reg_dump", 0644, g_tfe_hw_mgr.debug_cfg.dentry, &g_tfe_hw_mgr.debug_cfg.enable_reg_dump)) { @@ -5094,7 +5305,7 @@ static int cam_tfe_hw_mgr_debug_register(void) goto err; } - if (!debugfs_create_bool("per_req_reg_dump", + if (!debugfs_create_u32("per_req_reg_dump", 0644, g_tfe_hw_mgr.debug_cfg.dentry, &g_tfe_hw_mgr.debug_cfg.per_req_reg_dump)) { @@ -5285,6 +5496,7 @@ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) hw_mgr_intf->hw_config = cam_tfe_mgr_config_hw; hw_mgr_intf->hw_cmd = cam_tfe_mgr_cmd; hw_mgr_intf->hw_reset = cam_tfe_mgr_reset; + hw_mgr_intf->hw_dump = cam_tfe_mgr_dump; if (iommu_hdl) *iommu_hdl = g_tfe_hw_mgr.mgr_common.img_iommu_hdl; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h index 8aefaa7acf..5b9ca51365 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h @@ -37,8 +37,8 @@ struct cam_tfe_hw_mgr_debug { uint64_t csid_debug; uint32_t enable_recovery; uint32_t camif_debug; - bool enable_reg_dump; - bool per_req_reg_dump; + uint32_t enable_reg_dump; + uint32_t per_req_reg_dump; }; /** @@ -79,6 +79,7 @@ struct cam_tfe_hw_mgr_debug { * @is_dual indicate whether context is in dual TFE mode * @is_tpg indicate whether context use tpg * @master_hw_idx master hardware index in dual tfe case + * @slave_hw_idx slave hardware index in dual tfe case * @dual_tfe_irq_mismatch_cnt irq mismatch count value per core, used for * dual TFE */ @@ -122,6 +123,7 @@ struct cam_tfe_hw_mgr_ctx { bool is_dual; bool is_tpg; uint32_t master_hw_idx; + uint32_t slave_hw_idx; uint32_t dual_tfe_irq_mismatch_cnt; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 25697c9d64..22a75b9120 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -278,6 +278,7 @@ struct cam_isp_hw_dual_isp_update_args { * @ buf_len: buf len * @ offset: offset of buffer * @ ctxt_to_hw_map: ctx to hw map + * @ is_dump_all: flag to indicate if all information or just bw/clk rate */ struct cam_isp_hw_dump_args { uint64_t req_id; @@ -285,6 +286,7 @@ struct cam_isp_hw_dump_args { size_t buf_len; size_t offset; void *ctxt_to_hw_map; + bool is_dump_all; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c index e1925e9d13..ddad24cd23 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c @@ -1275,6 +1275,18 @@ static int cam_tfe_csid_disable_pxl_path( pxl_reg->csid_pxl_ctrl_addr); } + if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE && + stop_cmd == CAM_TFE_CSID_HALT_IMMEDIATELY) { + /* configure Halt for slave */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0xF; + val |= stop_cmd; + val |= (TFE_CSID_HALT_MODE_MASTER << 2); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + return rc; } @@ -1822,6 +1834,10 @@ static int cam_tfe_csid_reset_retain_sw_reg( struct cam_hw_soc_info *soc_info; soc_info = &csid_hw->hw_info->soc_info; + + /* Mask top interrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); /* clear the top interrupt first */ cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); @@ -1841,7 +1857,6 @@ static int cam_tfe_csid_reset_retain_sw_reg( status = cam_io_r(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_status_addr); CAM_DBG(CAM_ISP, "Status reg %d", status); - rc = 0; } else { CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d", csid_hw->hw_intf->hw_idx, rc); @@ -1875,6 +1890,7 @@ static int cam_tfe_csid_init_hw(void *hw_priv, csid_hw_info = (struct cam_hw_info *)hw_priv; csid_hw = (struct cam_tfe_csid_hw *)csid_hw_info->core_info; res = (struct cam_isp_resource_node *)init_args; + csid_reg = csid_hw->csid_info->csid_reg; if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH) { CAM_ERR(CAM_ISP, "CSID:%d Invalid res type state %d", @@ -1883,8 +1899,6 @@ static int cam_tfe_csid_init_hw(void *hw_priv, return -EINVAL; } - csid_reg = csid_hw->csid_info->csid_reg; - mutex_lock(&csid_hw->hw_info->hw_mutex); if (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && res->res_id >= CAM_TFE_CSID_PATH_RES_MAX) { @@ -1947,19 +1961,18 @@ static int cam_tfe_csid_deinit_hw(void *hw_priv, return -EINVAL; } + CAM_DBG(CAM_ISP, "Enter"); res = (struct cam_isp_resource_node *)deinit_args; csid_hw_info = (struct cam_hw_info *)hw_priv; csid_hw = (struct cam_tfe_csid_hw *)csid_hw_info->core_info; - if (res->res_type == CAM_ISP_RESOURCE_PIX_PATH) { + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH) { CAM_ERR(CAM_ISP, "CSID:%d Invalid Res type %d", csid_hw->hw_intf->hw_idx, res->res_type); return -EINVAL; } - CAM_DBG(CAM_ISP, "Enter"); - mutex_lock(&csid_hw->hw_info->hw_mutex); if (res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in De-init state", @@ -2287,6 +2300,106 @@ static int cam_tfe_csid_get_regdump(struct cam_tfe_csid_hw *csid_hw, return 0; } +static int cam_tfe_csid_dump_hw( + struct cam_tfe_csid_hw *csid_hw, void *cmd_args) +{ + int i; + uint8_t *dst; + uint32_t *addr, *start; + uint64_t *clk_addr, *clk_start; + uint32_t min_len; + uint32_t num_reg; + uint32_t reg_size = 0; + size_t remain_len; + struct cam_isp_hw_dump_header *hdr; + struct cam_isp_hw_dump_args *dump_args = + (struct cam_isp_hw_dump_args *)cmd_args; + struct cam_hw_soc_info *soc_info; + + if (!dump_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + if (!dump_args->cpu_addr || !dump_args->buf_len) { + CAM_ERR(CAM_ISP, + "Invalid params %pK %zu", + (void *)dump_args->cpu_addr, + dump_args->buf_len); + return -EINVAL; + } + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_ISP, + "Dump offset overshoot offset %zu buf_len %zu", + dump_args->offset, dump_args->buf_len); + return -ENOSPC; + } + + soc_info = &csid_hw->hw_info->soc_info; + if (dump_args->is_dump_all) + reg_size = soc_info->reg_map[0].size; + + min_len = reg_size + + sizeof(struct cam_isp_hw_dump_header) + + (sizeof(uint32_t) * CAM_TFE_CSID_DUMP_MISC_NUM_WORDS); + remain_len = dump_args->buf_len - dump_args->offset; + + if (remain_len < min_len) { + CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu, min %u", + remain_len, min_len); + return -ENOSPC; + } + + mutex_lock(&csid_hw->hw_info->hw_mutex); + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid HW State:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return -EINVAL; + } + + if (!dump_args->is_dump_all) + goto dump_bw; + + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "CSID_REG:"); + addr = (uint32_t *)(dst + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + num_reg = soc_info->reg_map[0].size/4; + hdr->word_size = sizeof(uint32_t); + *addr = soc_info->index; + addr++; + + for (i = 0; i < num_reg; i++) { + addr[0] = soc_info->mem_block[0]->start + (i*4); + addr[1] = cam_io_r(soc_info->reg_map[0].mem_base + + (i*4)); + addr += 2; + } + + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); +dump_bw: + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "CSID_CLK_RATE:"); + clk_addr = (uint64_t *)(dst + + sizeof(struct cam_isp_hw_dump_header)); + clk_start = clk_addr; + hdr->word_size = sizeof(uint64_t); + *clk_addr++ = csid_hw->clk_rate; + hdr->size = hdr->word_size * (clk_addr - clk_start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + CAM_DBG(CAM_ISP, "offset %zu", dump_args->offset); + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return 0; +} + static int cam_tfe_csid_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -2318,6 +2431,9 @@ static int cam_tfe_csid_process_cmd(void *hw_priv, case CAM_TFE_CSID_CMD_GET_REG_DUMP: rc = cam_tfe_csid_get_regdump(csid_hw, cmd_args); break; + case CAM_ISP_HW_CMD_DUMP_HW: + rc = cam_tfe_csid_dump_hw(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); @@ -2335,7 +2451,7 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) const struct cam_tfe_csid_reg_offset *csid_reg; const struct cam_tfe_csid_csi2_rx_reg_offset *csi2_reg; uint32_t irq_status[TFE_CSID_IRQ_REG_MAX]; - bool fatal_err_detected = false; + bool fatal_err_detected = false, is_error_irq = false; uint32_t sof_irq_debug_en = 0; unsigned long flags; uint32_t i, val; @@ -2392,14 +2508,6 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); - CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID %d irq status 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", - csid_hw->hw_intf->hw_idx, irq_status[TFE_CSID_IRQ_REG_TOP], - irq_status[TFE_CSID_IRQ_REG_RX], - irq_status[TFE_CSID_IRQ_REG_IPP], - irq_status[TFE_CSID_IRQ_REG_RDI0], - irq_status[TFE_CSID_IRQ_REG_RDI1], - irq_status[TFE_CSID_IRQ_REG_RDI2]); /* Software register reset complete*/ if (irq_status[TFE_CSID_IRQ_REG_TOP]) @@ -2446,25 +2554,29 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) TFE_CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) csid_hw->error_irq_count++; + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_CRC) + is_error_irq = true; + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_ECC) + is_error_irq = true; + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) + is_error_irq = true; } spin_unlock_irqrestore(&csid_hw->spin_lock, flags); + if (csid_hw->error_irq_count || fatal_err_detected) + is_error_irq = true; + if (csid_hw->error_irq_count > CAM_TFE_CSID_MAX_IRQ_ERROR_COUNT) { fatal_err_detected = true; csid_hw->error_irq_count = 0; } - CAM_INFO(CAM_ISP, - "CSID %d irq status 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", - csid_hw->hw_intf->hw_idx, - irq_status[TFE_CSID_IRQ_REG_TOP], - irq_status[TFE_CSID_IRQ_REG_RX], - irq_status[TFE_CSID_IRQ_REG_IPP], - irq_status[TFE_CSID_IRQ_REG_RDI0], - irq_status[TFE_CSID_IRQ_REG_RDI1], - irq_status[TFE_CSID_IRQ_REG_RDI2]); - if (fatal_err_detected) { /* Reset the Rx CFG registers */ cam_io_w_mb(0, soc_info->reg_map[0].mem_base + @@ -2580,6 +2692,23 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); } + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_RST_IRQ_LOG) { + + if (irq_status[TFE_CSID_IRQ_REG_IPP] & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID IPP reset complete"); + + if (irq_status[TFE_CSID_IRQ_REG_TOP]) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID TOP reset complete"); + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RX reset complete"); + } + /* read the IPP errors */ if (csid_hw->pxl_pipe_enable) { /* IPP reset done bit */ @@ -2611,10 +2740,24 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) cam_io_w_mb(CAM_TFE_CSID_HALT_IMMEDIATELY, soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_pxl_ctrl_addr); + is_error_irq = true; } + + if (irq_status[TFE_CSID_IRQ_REG_IPP] & + TFE_CSID_PATH_IPP_ERROR_CCIF_VIOLATION) + is_error_irq = true; + } for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + + if ((irq_status[i] & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) && + (csid_hw->csid_debug & + TFE_CSID_DEBUG_ENABLE_RST_IRQ_LOG)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI%d reset complete", i); + if (irq_status[i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID RDI%d reset complete", i); @@ -2637,12 +2780,29 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) if (irq_status[i] & TFE_CSID_PATH_ERROR_FIFO_OVERFLOW) { /* Stop RDI path immediately */ + is_error_irq = true; cam_io_w_mb(CAM_TFE_CSID_HALT_IMMEDIATELY, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_ctrl_addr); } + + if ((irq_status[i] & TFE_CSID_PATH_RDI_OVERFLOW_IRQ) || + (irq_status[i] & + TFE_CSID_PATH_RDI_ERROR_CCIF_VIOLATION)) + is_error_irq = true; } + if (is_error_irq) + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID %d irq status TOP: 0x%x RX: 0x%x IPP: 0x%x RDI0: 0x%x RDI1: 0x%x RDI2: 0x%x", + csid_hw->hw_intf->hw_idx, + irq_status[TFE_CSID_IRQ_REG_TOP], + irq_status[TFE_CSID_IRQ_REG_RX], + irq_status[TFE_CSID_IRQ_REG_IPP], + irq_status[TFE_CSID_IRQ_REG_RDI0], + irq_status[TFE_CSID_IRQ_REG_RDI1], + irq_status[TFE_CSID_IRQ_REG_RDI2]); + if (csid_hw->irq_debug_cnt >= CAM_TFE_CSID_IRQ_SOF_DEBUG_CNT_MAX) { cam_tfe_csid_sof_irq_debug(csid_hw, &sof_irq_debug_en); csid_hw->irq_debug_cnt = 0; @@ -2734,7 +2894,15 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, csid_reg->cmn_reg->top_tfe2_fuse_reg); if (val) { CAM_INFO(CAM_ISP, "TFE 2 is not supported by hardware"); - rc = -EINVAL; + + rc = cam_tfe_csid_disable_soc_resources( + &tfe_csid_hw->hw_info->soc_info); + if (rc) + CAM_ERR(CAM_ISP, + "CSID:%d Disable CSID SOC failed", + tfe_csid_hw->hw_intf->hw_idx); + else + rc = -EINVAL; goto err; } } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h index 1e23f2aa95..fc0b72677a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h @@ -12,6 +12,12 @@ #define CAM_TFE_CSID_CID_MAX 4 +/* Each word is taken as uint32_t, for dumping uint64_t count as 2 words + * 1. soc_index + * 2. clk_rate --> uint64_t -> 2 words + */ +#define CAM_TFE_CSID_DUMP_MISC_NUM_WORDS 3 + #define TFE_CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED BIT(0) #define TFE_CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED BIT(1) #define TFE_CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED BIT(2) @@ -65,6 +71,7 @@ #define TFE_CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE BIT(6) #define TFE_CSID_DEBUG_ENABLE_HBI_VBI_INFO BIT(7) #define TFE_CSID_DEBUG_DISABLE_EARLY_EOF BIT(8) +#define TFE_CSID_DEBUG_ENABLE_RST_IRQ_LOG BIT(9) /* enum cam_csid_path_halt_mode select the path halt mode control */ enum cam_tfe_csid_path_halt_mode { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe530.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe530.h index 229f756307..d22836edc9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe530.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe530.h @@ -66,6 +66,7 @@ static struct cam_tfe_camif_reg_data tfe530_camif_reg_data = { .extern_reg_update_shift = 0x0, .camif_pd_rdi2_src_sel_shift = 0x2, .dual_tfe_sync_sel_shift = 18, + .delay_line_en_shift = 8, .pixel_pattern_shift = 24, .pixel_pattern_mask = 0x7000000, .module_enable_shift = 0, @@ -202,6 +203,65 @@ static struct cam_tfe_rdi_reg_data tfe530_rdi2_reg_data = { .enable_diagnostic_hw = 0x1, }; +static struct cam_tfe_clc_hw_status tfe530_clc_hw_info[CAM_TFE_MAX_CLC] = { + { + .name = "CLC_CAMIF", + .hw_status_reg = 0x1204, + }, + { + .name = "CLC_RDI0_CAMIF", + .hw_status_reg = 0x1404, + }, + { + .name = "CLC_RDI1_CAMIF", + .hw_status_reg = 0x1604, + }, + { + .name = "CLC_RDI2_CAMIF", + .hw_status_reg = 0x1804, + }, + { + .name = "CLC_CHANNEL_GAIN", + .hw_status_reg = 0x2604, + }, + { + .name = "CLC_LENS_ROLL_OFF", + .hw_status_reg = 0x2804, + }, + { + .name = "CLC_WB_BDS", + .hw_status_reg = 0x2A04, + }, + { + .name = "CLC_STATS_BHIST", + .hw_status_reg = 0x2C04, + }, + { + .name = "CLC_STATS_TINTLESS_BG", + .hw_status_reg = 0x2E04, + }, + { + .name = "CLC_STATS_BAF", + .hw_status_reg = 0x3004, + }, + { + .name = "CLC_STATS_AWB_BG", + .hw_status_reg = 0x3204, + }, + { + .name = "CLC_STATS_AEC_BG", + .hw_status_reg = 0x3404, + }, + { + .name = "CLC_STATS_RAW_OUT", + .hw_status_reg = 0x3604, + }, + { + .name = "CLC_STATS_CROP_POST_BDS", + .hw_status_reg = 0x3804, + }, +}; + static struct cam_tfe_top_hw_info tfe530_top_hw_info = { .common_reg = &tfe530_top_commong_reg, .camif_hw_info = { @@ -385,6 +445,9 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { 0x00001A2C, }, .irq_cmd = 0x00001A30, + .cons_violation_shift = 28, + .violation_shift = 30, + .image_size_violation = 31, }, .num_client = CAM_TFE_BUS_MAX_CLIENTS, .bus_client_reg = { @@ -414,6 +477,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x00001C7C, .debug_status_1 = 0x00001C80, .comp_group = CAM_TFE_BUS_COMP_GRP_0, + .client_name = "BAYER", }, /* BUS Client 1 IDEAL RAW*/ { @@ -441,6 +505,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x00001D7C, .debug_status_1 = 0x00001D80, .comp_group = CAM_TFE_BUS_COMP_GRP_1, + .client_name = "IDEAL_RAW", }, /* BUS Client 2 Stats BE Tintless */ { @@ -468,6 +533,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x00001E7C, .debug_status_1 = 0x00001E80, .comp_group = CAM_TFE_BUS_COMP_GRP_2, + .client_name = "STATS BE TINTLESS", }, /* BUS Client 3 Stats Bhist */ { @@ -495,6 +561,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x00001F7C, .debug_status_1 = 0x00001F80, .comp_group = CAM_TFE_BUS_COMP_GRP_2, + .client_name = "STATS BHIST", }, /* BUS Client 4 Stats AWB BG */ { @@ -522,6 +589,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x0000207C, .debug_status_1 = 0x00002080, .comp_group = CAM_TFE_BUS_COMP_GRP_3, + .client_name = "STATS AWB BG", }, /* BUS Client 5 Stats AEC BG */ { @@ -549,6 +617,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x0000217C, .debug_status_1 = 0x00002180, .comp_group = CAM_TFE_BUS_COMP_GRP_3, + .client_name = "STATS AEC BG", }, /* BUS Client 6 Stats BAF */ { @@ -576,6 +645,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x0000227C, .debug_status_1 = 0x00002280, .comp_group = CAM_TFE_BUS_COMP_GRP_4, + .client_name = "STATS BAF", }, /* BUS Client 7 RDI0 */ { @@ -603,6 +673,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x0000237C, .debug_status_1 = 0x00002380, .comp_group = CAM_TFE_BUS_COMP_GRP_5, + .client_name = "RDI0", }, /* BUS Client 8 RDI1 */ { @@ -630,6 +701,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x0000247C, .debug_status_1 = 0x00002480, .comp_group = CAM_TFE_BUS_COMP_GRP_6, + .client_name = "RDI1", }, /* BUS Client 9 PDAF/RDI2*/ { @@ -657,6 +729,7 @@ static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { .debug_status_0 = 0x0000257C, .debug_status_1 = 0x00002580, .comp_group = CAM_TFE_BUS_COMP_GRP_7, + .client_name = "RDI2/PADF", }, }, .num_out = CAM_TFE_BUS_TFE_OUT_MAX, @@ -800,9 +873,14 @@ struct cam_tfe_hw_info cam_tfe530 = { .bus_reg_irq_mask = { 0x00000002, 0x00000000, + }, + .bus_error_irq_mask = { + 0xC0000000, 0x00000000, }, + .num_clc = 14, + .clc_hw_status_info = tfe530_clc_hw_info, .bus_version = CAM_TFE_BUS_1_0, .bus_hw_info = &tfe530_bus_hw_info, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c index 36980990f8..01ffb90d74 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c @@ -87,6 +87,7 @@ struct cam_tfe_bus_wm_resource_data { uint32_t format; uint32_t pack_fmt; uint32_t burst_len; + uint32_t mode; uint32_t irq_subsample_period; uint32_t irq_subsample_pattern; @@ -95,6 +96,10 @@ struct cam_tfe_bus_wm_resource_data { uint32_t en_cfg; uint32_t is_dual; + + uint32_t acquired_width; + uint32_t acquired_height; + uint32_t acquired_stride; }; struct cam_tfe_bus_comp_grp_data { @@ -449,6 +454,137 @@ static enum cam_tfe_bus_packer_format } } +static int cam_tfe_bus_acquire_rdi_wm( + struct cam_tfe_bus_wm_resource_data *rsrc_data) +{ + switch (rsrc_data->format) { + case CAM_FORMAT_MIPI_RAW_6: + rsrc_data->pack_fmt = 0xA; + if (rsrc_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE) { + rsrc_data->width = + ALIGNUP(rsrc_data->width * 6, 64) / 64; + rsrc_data->en_cfg = 0x1; + } else { + rsrc_data->width = + CAM_TFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = + CAM_TFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } + break; + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_PLAIN8: + rsrc_data->pack_fmt = 0xA; + if (rsrc_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE) { + rsrc_data->width = + ALIGNUP(rsrc_data->width * 8, 64) / 64; + + rsrc_data->en_cfg = 0x1; + } else { + rsrc_data->width = + CAM_TFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = + CAM_TFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } + break; + case CAM_FORMAT_MIPI_RAW_10: + rsrc_data->pack_fmt = 0xA; + if (rsrc_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE) { + rsrc_data->width = + ALIGNUP(rsrc_data->width * 10, 64) / 64; + + rsrc_data->en_cfg = 0x1; + } else { + rsrc_data->width = + CAM_TFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = + CAM_TFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } + break; + case CAM_FORMAT_MIPI_RAW_12: + rsrc_data->pack_fmt = 0xA; + if (rsrc_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE) { + rsrc_data->width = + ALIGNUP(rsrc_data->width * 12, 64) / 64; + + rsrc_data->en_cfg = 0x1; + } else { + rsrc_data->width = + CAM_TFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = + CAM_TFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } + break; + case CAM_FORMAT_MIPI_RAW_14: + rsrc_data->pack_fmt = 0xA; + if (rsrc_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE) { + rsrc_data->width = + ALIGNUP(rsrc_data->width * 14, 64) / 64; + + rsrc_data->en_cfg = 0x1; + } else { + rsrc_data->width = + CAM_TFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = + CAM_TFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } + break; + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_PLAIN16_16: + rsrc_data->pack_fmt = 0xA; + if (rsrc_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE) { + rsrc_data->width = + ALIGNUP(rsrc_data->width * 16, 64) / 64; + + rsrc_data->en_cfg = 0x1; + } else { + rsrc_data->width = + CAM_TFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = + CAM_TFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } + break; + + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PLAIN64: + rsrc_data->pack_fmt = 0xA; + if (rsrc_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE) { + rsrc_data->width = + ALIGNUP(rsrc_data->width * 64, 64) / 64; + + rsrc_data->en_cfg = 0x1; + } else { + rsrc_data->width = + CAM_TFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = + CAM_TFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } + break; + default: + CAM_ERR(CAM_ISP, "Unsupported RDI:%d format %d", + rsrc_data->index, rsrc_data->format); + return -EINVAL; + } + + return 0; +} + static int cam_tfe_bus_acquire_wm( struct cam_tfe_bus_priv *bus_priv, struct cam_isp_tfe_out_port_info *out_port_info, @@ -463,9 +599,9 @@ static int cam_tfe_bus_acquire_wm( struct cam_isp_resource_node *wm_res_local = NULL; struct cam_tfe_bus_wm_resource_data *rsrc_data = NULL; uint32_t wm_idx = 0; + int rc = 0; *wm_res = NULL; - /* No need to allocate for BUS TFE OUT to WM is fixed. */ wm_idx = cam_tfe_bus_get_wm_idx(tfe_out_res_id, plane); if (wm_idx < 0 || wm_idx >= bus_priv->num_client) { @@ -491,50 +627,26 @@ static int cam_tfe_bus_acquire_wm( rsrc_data->width = out_port_info->width; rsrc_data->height = out_port_info->height; rsrc_data->stride = out_port_info->stride; + rsrc_data->mode = out_port_info->wm_mode; + + /* + * Store the acquire width, height separately. For frame based ports + * width and height modified again + */ + rsrc_data->acquired_width = out_port_info->width; + rsrc_data->acquired_height = out_port_info->height; + rsrc_data->acquired_stride = out_port_info->stride; + rsrc_data->is_dual = is_dual; /* Set WM offset value to default */ rsrc_data->offset = 0; if (rsrc_data->index > 6) { /* WM 7-9 refers to RDI 0/ RDI 1/RDI 2 */ - switch (rsrc_data->format) { - case CAM_FORMAT_MIPI_RAW_6: - case CAM_FORMAT_MIPI_RAW_8: - case CAM_FORMAT_MIPI_RAW_10: - case CAM_FORMAT_MIPI_RAW_12: - case CAM_FORMAT_MIPI_RAW_14: - case CAM_FORMAT_MIPI_RAW_16: - case CAM_FORMAT_PLAIN128: - rsrc_data->width = CAM_TFE_RDI_BUS_DEFAULT_WIDTH; - rsrc_data->height = 0; - rsrc_data->stride = CAM_TFE_RDI_BUS_DEFAULT_STRIDE; - rsrc_data->pack_fmt = 0xA; - rsrc_data->en_cfg = (0x1 << 16) | 0x1; - break; - case CAM_FORMAT_PLAIN8: - rsrc_data->en_cfg = 0x1; - rsrc_data->pack_fmt = 0xA; - rsrc_data->stride = rsrc_data->width * 2; - break; - case CAM_FORMAT_PLAIN16_10: - case CAM_FORMAT_PLAIN16_12: - case CAM_FORMAT_PLAIN16_14: - case CAM_FORMAT_PLAIN16_16: - rsrc_data->width = CAM_TFE_RDI_BUS_DEFAULT_WIDTH; - rsrc_data->height = 0; - rsrc_data->stride = CAM_TFE_RDI_BUS_DEFAULT_STRIDE; - rsrc_data->pack_fmt = 0xA; - rsrc_data->en_cfg = (0x1 << 16) | 0x1; - break; - case CAM_FORMAT_PLAIN64: - rsrc_data->en_cfg = 0x1; - rsrc_data->pack_fmt = 0xA; - break; - default: - CAM_ERR(CAM_ISP, "Unsupported RDI format %d", - rsrc_data->format); - return -EINVAL; - } + rc = cam_tfe_bus_acquire_rdi_wm(rsrc_data); + if (rc) + return rc; + } else if (rsrc_data->index == 0 || rsrc_data->index == 1) { /* WM 0 FULL_OUT */ switch (rsrc_data->format) { @@ -581,9 +693,10 @@ static int cam_tfe_bus_acquire_wm( *client_done_mask |= (1 << wm_idx); CAM_DBG(CAM_ISP, - "WM:%d processed width:%d height:%d format:0x%x comp_group:%d packt format:0x%x", + "WM:%d processed width:%d height:%d format:0x%x comp_group:%d packt format:0x%x wm mode:%d", rsrc_data->index, rsrc_data->width, rsrc_data->height, - rsrc_data->format, *comp_grp_id, rsrc_data->pack_fmt); + rsrc_data->format, *comp_grp_id, rsrc_data->pack_fmt, + rsrc_data->mode); return 0; } @@ -630,7 +743,8 @@ static int cam_tfe_bus_start_wm(struct cam_isp_resource_node *wm_res) common_data->mem_base + rsrc_data->hw_regs->packer_cfg); /* Configure stride for RDIs on full TFE and TFE lite */ - if (rsrc_data->index > 6) + if ((rsrc_data->index > 6) && + (rsrc_data->mode != CAM_ISP_TFE_WM_LINE_BASED_MODE)) cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + rsrc_data->hw_regs->image_cfg_2)); @@ -1573,8 +1687,108 @@ static int cam_tfe_bus_bufdone_bottom_half( return 0; } +static void cam_tfe_bus_error_bottom_half( + struct cam_tfe_bus_priv *bus_priv, + struct cam_tfe_irq_evt_payload *evt_payload) +{ + struct cam_tfe_bus_wm_resource_data *rsrc_data; + struct cam_tfe_bus_reg_offset_common *common_reg; + uint32_t i, overflow_status, image_size_violation_status; + uint32_t ccif_violation_status; + + common_reg = bus_priv->common_data.common_reg; + + CAM_INFO(CAM_ISP, "BUS IRQ[0]:0x%x BUS IRQ[1]:0x%x", + evt_payload->bus_irq_val[0], evt_payload->bus_irq_val[1]); + + overflow_status = cam_io_r_mb(bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->overflow_status); + + image_size_violation_status = cam_io_r_mb( + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->image_size_violation_status); + + ccif_violation_status = cam_io_r_mb(bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->ccif_violation_status); + + CAM_INFO(CAM_ISP, + "ccif violation status:0x%x image size violation:0x%x overflow status:0x%x", + ccif_violation_status, + image_size_violation_status, + overflow_status); + + /* Check the bus errors */ + if (evt_payload->bus_irq_val[0] & BIT(common_reg->cons_violation_shift)) + CAM_INFO(CAM_ISP, "CONS_VIOLATION"); + + if (evt_payload->bus_irq_val[0] & BIT(common_reg->violation_shift)) + CAM_INFO(CAM_ISP, "VIOLATION"); + + if (evt_payload->bus_irq_val[0] & + BIT(common_reg->image_size_violation)) { + CAM_INFO(CAM_ISP, "IMAGE_SIZE_VIOLATION val :0x%x", + evt_payload->image_size_violation_status); + + for (i = 0; i < CAM_TFE_BUS_MAX_CLIENTS; i++) { + if (!(evt_payload->image_size_violation_status >> i)) + break; + + if (evt_payload->image_size_violation_status & BIT(i)) { + rsrc_data = bus_priv->bus_client[i].res_priv; + CAM_INFO(CAM_ISP, + "WM:%d width 0x%x height:0x%x format:%d stride:0x%x offset:0x%x encfg:0x%x", + i, + rsrc_data->acquired_width, + rsrc_data->acquired_height, + rsrc_data->format, + rsrc_data->acquired_stride, + rsrc_data->offset, + rsrc_data->en_cfg); + + CAM_INFO(CAM_ISP, + "WM:%d current width 0x%x height:0x%x stride:0x%x", + i, + rsrc_data->width, + rsrc_data->height, + rsrc_data->stride); + + } + } + } + + if (overflow_status) { + for (i = 0; i < CAM_TFE_BUS_MAX_CLIENTS; i++) { + + if (!(evt_payload->overflow_status >> i)) + break; + + if (evt_payload->overflow_status & BIT(i)) { + rsrc_data = bus_priv->bus_client[i].res_priv; + CAM_INFO(CAM_ISP, + "WM:%d %s BUS OVERFLOW width0x%x height:0x%x format:%d stride:0x%x offset:0x%x encfg:%x", + i, + rsrc_data->hw_regs->client_name, + rsrc_data->acquired_width, + rsrc_data->acquired_height, + rsrc_data->format, + rsrc_data->acquired_stride, + rsrc_data->offset, + rsrc_data->en_cfg); + + CAM_INFO(CAM_ISP, + "WM:%d current width:0x%x height:0x%x stride:0x%x", + i, + rsrc_data->width, + rsrc_data->height, + rsrc_data->stride); + } + } + } +} + static int cam_tfe_bus_bottom_half(void *priv, - bool rup_process, struct cam_tfe_irq_evt_payload *evt_payload) + bool rup_process, struct cam_tfe_irq_evt_payload *evt_payload, + bool error_process) { struct cam_tfe_bus_priv *bus_priv; uint32_t val; @@ -1585,6 +1799,11 @@ static int cam_tfe_bus_bottom_half(void *priv, } bus_priv = (struct cam_tfe_bus_priv *) priv; + if (error_process) { + cam_tfe_bus_error_bottom_half(bus_priv, evt_payload); + goto end; + } + /* if bus errors are there, mask all bus errors */ if (evt_payload->bus_irq_val[0] & bus_priv->bus_irq_error_mask[0]) { val = cam_io_r(bus_priv->common_data.mem_base + @@ -1592,6 +1811,7 @@ static int cam_tfe_bus_bottom_half(void *priv, val &= ~bus_priv->bus_irq_error_mask[0]; cam_io_w(val, bus_priv->common_data.mem_base + bus_priv->common_data.common_reg->irq_mask[0]); + } if (rup_process) { @@ -1604,6 +1824,7 @@ static int cam_tfe_bus_bottom_half(void *priv, cam_tfe_bus_bufdone_bottom_half(bus_priv, evt_payload); } +end: return 0; } @@ -1657,21 +1878,14 @@ static int cam_tfe_bus_update_wm(void *priv, void *cmd_args, CAM_DBG(CAM_ISP, "WM:%d image height and width 0x%x", wm_data->index, reg_val_pair[j-1]); - val = io_cfg->planes[i].plane_stride; - CAM_DBG(CAM_ISP, "before stride 0x%x", val); - val = ALIGNUP(val, 16); - if (val != io_cfg->planes[i].plane_stride && - val != wm_data->stride) - CAM_WARN(CAM_ISP, "Warning stride %u expected %u", - io_cfg->planes[i].plane_stride, val); - val = wm_data->offset; CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_cfg_1, val); CAM_DBG(CAM_ISP, "WM:%d xinit 0x%x", wm_data->index, reg_val_pair[j-1]); - if (wm_data->index < 7) { + if ((wm_data->index < 7) || ((wm_data->index >= 7) && + (wm_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE))) { CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_cfg_2, io_cfg->planes[i].plane_stride); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.h index 3a62806f97..db34083ede 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.h @@ -11,10 +11,11 @@ #include "cam_isp_hw.h" #include "cam_tfe_hw_intf.h" -#define CAM_TFE_BUS_MAX_CLIENTS 10 -#define CAM_TFE_BUS_MAX_SUB_GRPS 4 -#define CAM_TFE_BUS_MAX_PERF_CNT_REG 8 -#define CAM_TFE_BUS_MAX_IRQ_REGISTERS 2 +#define CAM_TFE_BUS_MAX_CLIENTS 10 +#define CAM_TFE_BUS_MAX_SUB_GRPS 4 +#define CAM_TFE_BUS_MAX_PERF_CNT_REG 8 +#define CAM_TFE_BUS_MAX_IRQ_REGISTERS 2 +#define CAM_TFE_BUS_CLIENT_NAME_MAX_LENGTH 32 #define CAM_TFE_BUS_1_0 0x1000 @@ -29,7 +30,8 @@ ((value + alignment - 1) / alignment * alignment) typedef int (*CAM_BUS_HANDLER_BOTTOM_HALF)(void *bus_priv, - bool rup_process, struct cam_tfe_irq_evt_payload *evt_payload); + bool rup_process, struct cam_tfe_irq_evt_payload *evt_payload, + bool error_process); enum cam_tfe_bus_plane_type { PLANE_Y, @@ -106,6 +108,10 @@ struct cam_tfe_bus_reg_offset_common { uint32_t irq_clear[CAM_TFE_BUS_IRQ_REGISTERS_MAX]; uint32_t irq_status[CAM_TFE_BUS_IRQ_REGISTERS_MAX]; uint32_t irq_cmd; + /* common register data */ + uint32_t cons_violation_shift; + uint32_t violation_shift; + uint32_t image_size_violation; }; /* @@ -138,6 +144,8 @@ struct cam_tfe_bus_reg_offset_bus_client { uint32_t debug_status_0; uint32_t debug_status_1; uint32_t comp_group; + /*bus data */ + uint8_t client_name[CAM_TFE_BUS_CLIENT_NAME_MAX_LENGTH]; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c index 8ebabf1f15..9c82d7cbca 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c @@ -48,6 +48,10 @@ struct cam_tfe_top_priv { axi_vote_control[CAM_TFE_TOP_IN_PORT_MAX]; uint32_t irq_prepared_mask[3]; void *tasklet_info; + struct timeval sof_ts; + struct timeval epoch_ts; + struct timeval eof_ts; + struct timeval error_ts; }; struct cam_tfe_camif_data { @@ -64,9 +68,11 @@ struct cam_tfe_camif_data { enum cam_isp_hw_sync_mode sync_mode; uint32_t dsp_mode; uint32_t pix_pattern; - uint32_t first_pixel; + uint32_t left_first_pixel; + uint32_t left_last_pixel; + uint32_t right_first_pixel; + uint32_t right_last_pixel; uint32_t first_line; - uint32_t last_pixel; uint32_t last_line; bool enable_sof_irq_debug; uint32_t irq_debug_cnt; @@ -85,6 +91,10 @@ struct cam_tfe_rdi_data { void *priv; enum cam_isp_hw_sync_mode sync_mode; uint32_t pix_pattern; + uint32_t left_first_pixel; + uint32_t left_last_pixel; + uint32_t first_line; + uint32_t last_line; }; static int cam_tfe_validate_pix_pattern(uint32_t pattern) @@ -211,68 +221,15 @@ int cam_tfe_irq_config(void *tfe_core_data, return 0; } -static void cam_tfe_log_error_irq_status( - struct cam_tfe_hw_core_info *core_info, - struct cam_tfe_top_priv *top_priv, - struct cam_tfe_irq_evt_payload *evt_payload) +static void cam_tfe_log_tfe_in_debug_status( + struct cam_tfe_top_priv *top_priv) { - struct cam_tfe_hw_info *hw_info; void __iomem *mem_base; - struct cam_hw_soc_info *soc_info; - struct cam_tfe_soc_private *soc_private; struct cam_tfe_camif_data *camif_data; struct cam_tfe_rdi_data *rdi_data; - uint32_t i, val_0, val_1, val_2, val_3; + uint32_t i, val_0, val_1; - hw_info = core_info->tfe_hw_info; mem_base = top_priv->common_data.soc_info->reg_map[0].mem_base; - soc_info = top_priv->common_data.soc_info; - soc_private = top_priv->common_data.soc_info->soc_private; - - val_0 = cam_io_r(mem_base + - top_priv->common_data.common_reg->debug_0); - val_1 = cam_io_r(mem_base + - top_priv->common_data.common_reg->debug_1); - val_2 = cam_io_r(mem_base + - top_priv->common_data.common_reg->debug_2); - val_3 = cam_io_r(mem_base + - top_priv->common_data.common_reg->debug_3); - - CAM_INFO(CAM_ISP, "TOP IRQ[0]:0x%x IRQ[1]:0x%x IRQ[2]:0x%x", - evt_payload->irq_reg_val[0], evt_payload->irq_reg_val[1], - evt_payload->irq_reg_val[2]); - - CAM_INFO(CAM_ISP, "BUS IRQ[0]:0x%x BUS IRQ[1]:0x%x", - evt_payload->bus_irq_val[0], evt_payload->bus_irq_val[1]); - - CAM_INFO(CAM_ISP, "ccif violation:0x%x image size:0x%x overflow:0x%x", - evt_payload->ccif_violation_status, - evt_payload->image_size_violation_status, - evt_payload->overflow_status); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x20, true, &val_0); - CAM_INFO(CAM_ISP, "tfe_niu_MaxWr_Low offset 0x20 val 0x%x", - val_0); - - CAM_INFO(CAM_ISP, "Top debug [0]:0x%x [1]:0x%x [2]:0x%x [3]:0x%x", - val_0, val_1, val_2, val_3); - - val_0 = cam_io_r(mem_base + - top_priv->common_data.common_reg->perf_pixel_count); - - val_1 = cam_io_r(mem_base + - top_priv->common_data.common_reg->perf_line_count); - - val_2 = cam_io_r(mem_base + - top_priv->common_data.common_reg->perf_stall_count); - - val_3 = cam_io_r(mem_base + - top_priv->common_data.common_reg->perf_always_count); - - CAM_INFO(CAM_ISP, - "Top perf cnt pix:0x%x line:0x%x stall:0x%x always:0x%x", - val_0, val_1, val_2, val_3); for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { if ((top_priv->in_rsrc[i].res_state != @@ -291,6 +248,23 @@ static void cam_tfe_log_error_irq_status( val_1, ((val_0 >> 16) & 0x1FFF), (val_0 & 0x1FFF)); + CAM_INFO(CAM_ISP, + "Acquired sync mode:%d left start pxl:0x%x end_pixel:0x%x", + camif_data->sync_mode, + camif_data->left_first_pixel, + camif_data->left_last_pixel); + + if (camif_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + CAM_INFO(CAM_ISP, + "sync mode:%d right start pxl:0x%x end_pixel:0x%x", + camif_data->sync_mode, + camif_data->right_first_pixel, + camif_data->right_last_pixel); + + CAM_INFO(CAM_ISP, + "Acquired line start:0x%x line end:0x%x", + camif_data->first_line, + camif_data->last_line); } else if ((top_priv->in_rsrc[i].res_id >= CAM_ISP_HW_TFE_IN_RDI0) || (top_priv->in_rsrc[i].res_id <= @@ -306,11 +280,104 @@ static void cam_tfe_log_error_irq_status( top_priv->in_rsrc[i].res_id, val_1, ((val_0 >> 16) & 0x1FFF), (val_0 & 0x1FFF)); + CAM_INFO(CAM_ISP, + "sync mode:%d left start pxl:0x%x end_pixel:0x%x", + rdi_data->sync_mode, + rdi_data->left_first_pixel, + rdi_data->left_last_pixel); + CAM_INFO(CAM_ISP, + "sync mode:%d line start:0x%x line end:0x%x", + rdi_data->sync_mode, + rdi_data->first_line, + rdi_data->last_line); } } +} +static void cam_tfe_log_error_irq_status( + struct cam_tfe_hw_core_info *core_info, + struct cam_tfe_top_priv *top_priv, + struct cam_tfe_irq_evt_payload *evt_payload) +{ + struct cam_tfe_hw_info *hw_info; + void __iomem *mem_base; + struct cam_hw_soc_info *soc_info; + struct cam_tfe_soc_private *soc_private; + + struct cam_tfe_clc_hw_status *clc_hw_status; + struct timespec64 ts; + uint32_t i, val_0, val_1, val_2, val_3; + + + ktime_get_boottime_ts64(&ts); + hw_info = core_info->tfe_hw_info; + mem_base = top_priv->common_data.soc_info->reg_map[0].mem_base; + soc_info = top_priv->common_data.soc_info; + soc_private = top_priv->common_data.soc_info->soc_private; + + CAM_INFO(CAM_ISP, "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + CAM_INFO(CAM_ISP, + "ERROR time %lld:%lld SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + top_priv->error_ts.tv_sec, + top_priv->error_ts.tv_usec, + top_priv->sof_ts.tv_sec, + top_priv->sof_ts.tv_usec, + top_priv->epoch_ts.tv_sec, + top_priv->epoch_ts.tv_usec, + top_priv->eof_ts.tv_sec, + top_priv->eof_ts.tv_usec); + val_0 = cam_io_r(mem_base + + top_priv->common_data.common_reg->debug_0); + val_1 = cam_io_r(mem_base + + top_priv->common_data.common_reg->debug_1); + val_2 = cam_io_r(mem_base + + top_priv->common_data.common_reg->debug_2); + val_3 = cam_io_r(mem_base + + top_priv->common_data.common_reg->debug_3); + + CAM_INFO(CAM_ISP, "TOP IRQ[0]:0x%x IRQ[1]:0x%x IRQ[2]:0x%x", + evt_payload->irq_reg_val[0], evt_payload->irq_reg_val[1], + evt_payload->irq_reg_val[2]); + + CAM_INFO(CAM_ISP, "Top debug [0]:0x%x [1]:0x%x [2]:0x%x [3]:0x%x", + val_0, val_1, val_2, val_3); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x20, true, &val_0); + CAM_INFO(CAM_ISP, "tfe_niu_MaxWr_Low offset 0x20 val 0x%x", + val_0); + + val_0 = cam_io_r(mem_base + + top_priv->common_data.common_reg->perf_pixel_count); + + val_1 = cam_io_r(mem_base + + top_priv->common_data.common_reg->perf_line_count); + + val_2 = cam_io_r(mem_base + top_priv->common_data.common_reg->perf_stall_count); + val_3 = cam_io_r(mem_base + + top_priv->common_data.common_reg->perf_always_count); + + CAM_INFO(CAM_ISP, + "Top perf cnt pix:0x%x line:0x%x stall:0x%x always:0x%x", + val_0, val_1, val_2, val_3); + + clc_hw_status = hw_info->clc_hw_status_info; + for (i = 0; i < hw_info->num_clc; i++) { + val_0 = cam_io_r(mem_base + + clc_hw_status[i].hw_status_reg); + if (val_0) + CAM_INFO(CAM_ISP, + "CLC HW status :name:%s offset:0x%x value:0x%x", + clc_hw_status[i].name, + clc_hw_status[i].hw_status_reg, + val_0); + } + + cam_tfe_log_tfe_in_debug_status(top_priv); + /* Check the overflow errors */ if (evt_payload->irq_reg_val[0] & hw_info->error_irq_mask[0]) { if (evt_payload->irq_reg_val[0] & BIT(8)) @@ -363,22 +430,13 @@ static void cam_tfe_log_error_irq_status( CAM_INFO(CAM_ISP, "TOP Violation status:0x%x", val_0); } - /* Check the bus errors */ - if (evt_payload->bus_irq_val[0] & BIT(29)) - CAM_INFO(CAM_ISP, "CONS_VIOLATION"); + core_info->tfe_bus->bottom_half_handler( + core_info->tfe_bus->bus_priv, false, evt_payload, true); - if (evt_payload->bus_irq_val[0] & BIT(30)) - CAM_INFO(CAM_ISP, "VIOLATION val 0x%x", - evt_payload->ccif_violation_status); - - if (evt_payload->bus_irq_val[0] & BIT(31)) - CAM_INFO(CAM_ISP, "IMAGE_SIZE_VIOLATION val :0x%x", - evt_payload->image_size_violation_status); - - /* clear the bus irq overflow status*/ - if (evt_payload->overflow_status) - cam_io_w_mb(1, mem_base + - core_info->tfe_hw_info->bus_overflow_clear_cmd); + CAM_INFO(CAM_ISP, + "TFE clock rate:%d TFE total bw applied:%lld", + top_priv->hw_clk_rate, + top_priv->total_bw_applied); } @@ -391,33 +449,31 @@ static int cam_tfe_error_irq_bottom_half( { struct cam_isp_hw_event_info evt_info; struct cam_tfe_hw_info *hw_info; + uint32_t error_detected = 0; hw_info = core_info->tfe_hw_info; evt_info.hw_idx = core_info->core_index; evt_info.res_type = CAM_ISP_RESOURCE_TFE_IN; if (evt_payload->irq_reg_val[0] & hw_info->error_irq_mask[0]) { - CAM_ERR(CAM_ISP, "TFE:%d Overflow error irq_status[0]:%x", - core_info->core_index, - evt_payload->irq_reg_val[0]); - evt_info.err_type = CAM_TFE_IRQ_STATUS_OVERFLOW; - cam_tfe_log_error_irq_status(core_info, top_priv, evt_payload); - if (event_cb) - event_cb(event_cb_priv, - CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); - else - CAM_ERR(CAM_ISP, "TFE:%d invalid eventcb:", - core_info->core_index); + error_detected = 1; } - if (evt_payload->irq_reg_val[2] & hw_info->error_irq_mask[2]) { - CAM_ERR(CAM_ISP, "TFE:%d Violation error irq_status[2]:%x", - core_info->core_index, evt_payload->irq_reg_val[2]); - + if ((evt_payload->bus_irq_val[0] & hw_info->bus_error_irq_mask[0]) || + (evt_payload->irq_reg_val[2] & hw_info->error_irq_mask[2])) { evt_info.err_type = CAM_TFE_IRQ_STATUS_VIOLATION; - cam_tfe_log_error_irq_status(core_info, top_priv, evt_payload); + error_detected = 1; + } + if (error_detected) { + evt_info.err_type = CAM_TFE_IRQ_STATUS_OVERFLOW; + top_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + top_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + + cam_tfe_log_error_irq_status(core_info, top_priv, evt_payload); if (event_cb) event_cb(event_cb_priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); @@ -430,6 +486,7 @@ static int cam_tfe_error_irq_bottom_half( } static int cam_tfe_rdi_irq_bottom_half( + struct cam_tfe_top_priv *top_priv, struct cam_isp_resource_node *rdi_node, bool epoch_process, struct cam_tfe_irq_evt_payload *evt_payload) @@ -448,6 +505,11 @@ static int cam_tfe_rdi_irq_bottom_half( if ((!epoch_process) && (evt_payload->irq_reg_val[1] & rdi_priv->reg_data->eof_irq_mask)) { CAM_DBG(CAM_ISP, "Received EOF"); + top_priv->eof_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + top_priv->eof_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + if (rdi_priv->event_cb) rdi_priv->event_cb(rdi_priv->priv, CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); @@ -456,6 +518,11 @@ static int cam_tfe_rdi_irq_bottom_half( if ((!epoch_process) && (evt_payload->irq_reg_val[1] & rdi_priv->reg_data->sof_irq_mask)) { CAM_DBG(CAM_ISP, "Received SOF"); + top_priv->sof_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + top_priv->sof_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + if (rdi_priv->event_cb) rdi_priv->event_cb(rdi_priv->priv, CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); @@ -464,6 +531,10 @@ static int cam_tfe_rdi_irq_bottom_half( if (epoch_process && (evt_payload->irq_reg_val[1] & rdi_priv->reg_data->epoch0_irq_mask)) { CAM_DBG(CAM_ISP, "Received EPOCH0"); + top_priv->epoch_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + top_priv->epoch_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; if (rdi_priv->event_cb) rdi_priv->event_cb(rdi_priv->priv, @@ -474,6 +545,7 @@ static int cam_tfe_rdi_irq_bottom_half( } static int cam_tfe_camif_irq_bottom_half( + struct cam_tfe_top_priv *top_priv, struct cam_isp_resource_node *camif_node, bool epoch_process, struct cam_tfe_irq_evt_payload *evt_payload) @@ -493,6 +565,11 @@ static int cam_tfe_camif_irq_bottom_half( camif_priv->reg_data->eof_irq_mask)) { CAM_DBG(CAM_ISP, "Received EOF"); + top_priv->eof_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + top_priv->eof_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); @@ -515,6 +592,11 @@ static int cam_tfe_camif_irq_bottom_half( } else CAM_DBG(CAM_ISP, "Received SOF"); + top_priv->sof_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + top_priv->sof_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); @@ -524,6 +606,11 @@ static int cam_tfe_camif_irq_bottom_half( camif_priv->reg_data->epoch0_irq_mask)) { CAM_DBG(CAM_ISP, "Received EPOCH"); + top_priv->epoch_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + top_priv->epoch_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); @@ -575,7 +662,7 @@ static int cam_tfe_irq_bottom_half(void *handler_priv, if (camif_priv->reg_data->subscribe_irq_mask[1] & evt_payload->irq_reg_val[1]) - cam_tfe_camif_irq_bottom_half( + cam_tfe_camif_irq_bottom_half(top_priv, &top_priv->in_rsrc[i], false, evt_payload); @@ -584,7 +671,8 @@ static int cam_tfe_irq_bottom_half(void *handler_priv, (top_priv->in_rsrc[i].res_id <= CAM_ISP_HW_TFE_IN_RDI2) && (top_priv->in_rsrc[i].res_state == - CAM_ISP_RESOURCE_STATE_STREAMING)) { + CAM_ISP_RESOURCE_STATE_STREAMING) && + top_priv->in_rsrc[i].rdi_only_ctx) { rdi_priv = (struct cam_tfe_rdi_data *) top_priv->in_rsrc[i].res_priv; event_cb = rdi_priv->event_cb; @@ -592,7 +680,7 @@ static int cam_tfe_irq_bottom_half(void *handler_priv, if (rdi_priv->reg_data->subscribe_irq_mask[1] & evt_payload->irq_reg_val[1]) - cam_tfe_rdi_irq_bottom_half( + cam_tfe_rdi_irq_bottom_half(top_priv, &top_priv->in_rsrc[i], false, evt_payload); } @@ -606,7 +694,7 @@ static int cam_tfe_irq_bottom_half(void *handler_priv, if (evt_payload->irq_reg_val[0] & core_info->tfe_hw_info->bus_reg_irq_mask[0]) { core_info->tfe_bus->bottom_half_handler( - core_info->tfe_bus->bus_priv, true, evt_payload); + core_info->tfe_bus->bus_priv, true, evt_payload, false); } /* process the epoch */ @@ -619,7 +707,7 @@ static int cam_tfe_irq_bottom_half(void *handler_priv, top_priv->in_rsrc[i].res_priv; if (camif_priv->reg_data->subscribe_irq_mask[1] & evt_payload->irq_reg_val[1]) - cam_tfe_camif_irq_bottom_half( + cam_tfe_camif_irq_bottom_half(top_priv, &top_priv->in_rsrc[i], true, evt_payload); } else if ((top_priv->in_rsrc[i].res_id >= @@ -632,7 +720,7 @@ static int cam_tfe_irq_bottom_half(void *handler_priv, top_priv->in_rsrc[i].res_priv; if (rdi_priv->reg_data->subscribe_irq_mask[1] & evt_payload->irq_reg_val[1]) - cam_tfe_rdi_irq_bottom_half( + cam_tfe_rdi_irq_bottom_half(top_priv, &top_priv->in_rsrc[i], true, evt_payload); } @@ -642,7 +730,8 @@ static int cam_tfe_irq_bottom_half(void *handler_priv, if (evt_payload->irq_reg_val[0] & core_info->tfe_hw_info->bus_reg_irq_mask[0]) { core_info->tfe_bus->bottom_half_handler( - core_info->tfe_bus->bus_priv, false, evt_payload); + core_info->tfe_bus->bus_priv, false, evt_payload, + false); } cam_tfe_put_evt_payload(core_info, &evt_payload); @@ -653,16 +742,24 @@ static int cam_tfe_irq_bottom_half(void *handler_priv, static int cam_tfe_irq_err_top_half( struct cam_tfe_hw_core_info *core_info, void __iomem *mem_base, - uint32_t *irq_status) + uint32_t *top_irq_status, + uint32_t *bus_irq_status) { uint32_t i; - if (irq_status[0] & core_info->tfe_hw_info->error_irq_mask[0] || - irq_status[2] & core_info->tfe_hw_info->error_irq_mask[2]) { + if ((top_irq_status[0] & core_info->tfe_hw_info->error_irq_mask[0]) || + (top_irq_status[2] & + core_info->tfe_hw_info->error_irq_mask[2]) || + (bus_irq_status[0] & + core_info->tfe_hw_info->bus_error_irq_mask[0])) { CAM_ERR(CAM_ISP, "Encountered Error: tfe:%d: Irq_status0=0x%x status2=0x%x", - core_info->core_index, irq_status[0], - irq_status[2]); + core_info->core_index, top_irq_status[0], + top_irq_status[2]); + CAM_ERR(CAM_ISP, + "Encountered Error: tfe:%d:BUS Irq_status0=0x%x", + core_info->core_index, bus_irq_status[0]); + for (i = 0; i < CAM_TFE_TOP_IRQ_REG_NUM; i++) cam_io_w(0, mem_base + core_info->tfe_hw_info->top_irq_mask[i]); @@ -755,7 +852,8 @@ irqreturn_t cam_tfe_irq(int irq_num, void *data) } /* Check the irq errors */ - cam_tfe_irq_err_top_half(core_info, mem_base, top_irq_status); + cam_tfe_irq_err_top_half(core_info, mem_base, top_irq_status, + bus_irq_status); rc = cam_tfe_get_evt_payload(core_info, &evt_payload); if (rc) { @@ -877,7 +975,7 @@ static int cam_tfe_top_set_axi_bw_vote( struct cam_tfe_top_priv *top_priv, bool start_stop) { - struct cam_axi_vote agg_vote = {0}; + struct cam_axi_vote *agg_vote = NULL; struct cam_axi_vote *to_be_applied_axi_vote = NULL; struct cam_hw_soc_info *soc_info = top_priv->common_data.soc_info; struct cam_tfe_soc_private *soc_private = soc_info->soc_private; @@ -893,6 +991,12 @@ static int cam_tfe_top_set_axi_bw_vote( return -EINVAL; } + agg_vote = kzalloc(sizeof(struct cam_axi_vote), GFP_KERNEL); + if (!agg_vote) { + CAM_ERR(CAM_ISP, "Out of memory"); + return -ENOMEM; + } + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { if (top_priv->axi_vote_control[i] == CAM_TFE_BW_CONTROL_INCLUDE) { @@ -904,10 +1008,11 @@ static int cam_tfe_top_set_axi_bw_vote( num_paths + top_priv->req_axi_vote[i].num_paths, CAM_CPAS_MAX_PATHS_PER_CLIENT); - return -EINVAL; + rc = -EINVAL; + goto free_mem; } - memcpy(&agg_vote.axi_path[num_paths], + memcpy(&agg_vote->axi_path[num_paths], &top_priv->req_axi_vote[i].axi_path[0], top_priv->req_axi_vote[i].num_paths * sizeof( @@ -916,31 +1021,31 @@ static int cam_tfe_top_set_axi_bw_vote( } } - agg_vote.num_paths = num_paths; + agg_vote->num_paths = num_paths; - for (i = 0; i < agg_vote.num_paths; i++) { + for (i = 0; i < agg_vote->num_paths; i++) { CAM_DBG(CAM_PERF, "tfe[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]", top_priv->common_data.hw_intf->hw_idx, top_priv->last_counter, cam_cpas_axi_util_path_type_to_string( - agg_vote.axi_path[i].path_data_type), + agg_vote->axi_path[i].path_data_type), cam_cpas_axi_util_trans_type_to_string( - agg_vote.axi_path[i].transac_type), - agg_vote.axi_path[i].camnoc_bw, - agg_vote.axi_path[i].mnoc_ab_bw, - agg_vote.axi_path[i].mnoc_ib_bw); + agg_vote->axi_path[i].transac_type), + agg_vote->axi_path[i].camnoc_bw, + agg_vote->axi_path[i].mnoc_ab_bw, + agg_vote->axi_path[i].mnoc_ib_bw); - total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw; + total_bw_new_vote += agg_vote->axi_path[i].camnoc_bw; } - memcpy(&top_priv->last_vote[top_priv->last_counter], &agg_vote, + memcpy(&top_priv->last_vote[top_priv->last_counter], agg_vote, sizeof(struct cam_axi_vote)); top_priv->last_counter = (top_priv->last_counter + 1) % (CAM_TFE_TOP_IN_PORT_MAX * CAM_TFE_DELAY_BW_REDUCTION_NUM_FRAMES); - if ((agg_vote.num_paths != top_priv->applied_axi_vote.num_paths) || + if ((agg_vote->num_paths != top_priv->applied_axi_vote.num_paths) || (total_bw_new_vote != top_priv->total_bw_applied)) bw_unchanged = false; @@ -952,18 +1057,19 @@ static int cam_tfe_top_set_axi_bw_vote( if (bw_unchanged) { CAM_DBG(CAM_ISP, "BW config unchanged"); - return 0; + rc = 0; + goto free_mem; } if (start_stop) { /* need to vote current request immediately */ - to_be_applied_axi_vote = &agg_vote; + to_be_applied_axi_vote = agg_vote; /* Reset everything, we can start afresh */ memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * (CAM_TFE_TOP_IN_PORT_MAX * CAM_TFE_DELAY_BW_REDUCTION_NUM_FRAMES)); top_priv->last_counter = 0; - top_priv->last_vote[top_priv->last_counter] = agg_vote; + top_priv->last_vote[top_priv->last_counter] = *agg_vote; top_priv->last_counter = (top_priv->last_counter + 1) % (CAM_TFE_TOP_IN_PORT_MAX * CAM_TFE_DELAY_BW_REDUCTION_NUM_FRAMES); @@ -977,7 +1083,8 @@ static int cam_tfe_top_set_axi_bw_vote( &total_bw_new_vote); if (!to_be_applied_axi_vote) { CAM_ERR(CAM_ISP, "to_be_applied_axi_vote is NULL"); - return -EINVAL; + rc = -EINVAL; + goto free_mem; } } @@ -1018,6 +1125,9 @@ static int cam_tfe_top_set_axi_bw_vote( } } +free_mem: + kzfree(agg_vote); + agg_vote = NULL; return rc; } @@ -1381,6 +1491,234 @@ static int cam_tfe_top_get_reg_dump( return 0; } +static int cam_tfe_hw_dump( + struct cam_tfe_hw_core_info *core_info, + void *cmd_args, + uint32_t arg_size) +{ + int i, j; + uint8_t *dst; + uint32_t reg_start_offset; + uint32_t reg_dump_size = 0; + uint32_t lut_dump_size = 0; + uint32_t num_lut_dump_entries = 0; + uint32_t num_reg; + uint32_t lut_word_size, lut_size; + uint32_t lut_bank_sel, lut_dmi_reg; + uint32_t val; + void __iomem *reg_base; + void __iomem *mem_base; + uint32_t *addr, *start; + uint64_t *clk_waddr, *clk_wstart; + size_t remain_len; + uint32_t min_len; + struct cam_hw_info *tfe_hw_info; + struct cam_hw_soc_info *soc_info; + struct cam_tfe_top_priv *top_priv; + struct cam_tfe_soc_private *soc_private; + struct cam_tfe_reg_dump_data *reg_dump_data; + struct cam_isp_hw_dump_header *hdr; + struct cam_isp_hw_dump_args *dump_args = + (struct cam_isp_hw_dump_args *)cmd_args; + + if (!dump_args || !core_info) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + if (!dump_args->cpu_addr || !dump_args->buf_len) { + CAM_ERR(CAM_ISP, + "Invalid params %pK %zu", + (void *)dump_args->cpu_addr, + dump_args->buf_len); + return -EINVAL; + } + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_ISP, + "Dump offset overshoot offset %zu buf_len %zu", + dump_args->offset, dump_args->buf_len); + return -ENOSPC; + } + + top_priv = (struct cam_tfe_top_priv *)core_info->top_priv; + tfe_hw_info = + (struct cam_hw_info *)(top_priv->common_data.hw_intf->hw_priv); + reg_dump_data = top_priv->common_data.reg_dump_data; + soc_info = top_priv->common_data.soc_info; + soc_private = top_priv->common_data.soc_info->soc_private; + mem_base = soc_info->reg_map[TFE_CORE_BASE_IDX].mem_base; + + if (dump_args->is_dump_all) { + + /*Dump registers size*/ + for (i = 0; i < reg_dump_data->num_reg_dump_entries; i++) + reg_dump_size += + (reg_dump_data->reg_entry[i].end_offset - + reg_dump_data->reg_entry[i].start_offset); + + /* + * We dump the offset as well, so the total size dumped becomes + * multiplied by 2 + */ + reg_dump_size *= 2; + + /* LUT dump size */ + for (i = 0; i < reg_dump_data->num_lut_dump_entries; i++) + lut_dump_size += + ((reg_dump_data->lut_entry[i].lut_addr_size) * + (reg_dump_data->lut_entry[i].lut_word_size/8)); + + num_lut_dump_entries = reg_dump_data->num_lut_dump_entries; + } + + /*Minimum len comprises of: + * lut_dump_size + reg_dump_size + sizeof dump_header + + * (num_lut_dump_entries--> represents number of banks) + + * (misc number of words) * sizeof(uint32_t) + */ + min_len = lut_dump_size + reg_dump_size + + sizeof(struct cam_isp_hw_dump_header) + + (num_lut_dump_entries * sizeof(uint32_t)) + + (sizeof(uint32_t) * CAM_TFE_CORE_DUMP_MISC_NUM_WORDS); + + remain_len = dump_args->buf_len - dump_args->offset; + if (remain_len < min_len) { + CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu, min %u", + remain_len, min_len); + return -ENOSPC; + } + + mutex_lock(&tfe_hw_info->hw_mutex); + if (tfe_hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "TFE:%d HW not powered up", + core_info->core_index); + mutex_unlock(&tfe_hw_info->hw_mutex); + return -EPERM; + } + + if (!dump_args->is_dump_all) + goto dump_bw; + + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + hdr->word_size = sizeof(uint32_t); + scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "TFE_REG:"); + addr = (uint32_t *)(dst + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + for (i = 0; i < reg_dump_data->num_reg_dump_entries; i++) { + num_reg = (reg_dump_data->reg_entry[i].end_offset - + reg_dump_data->reg_entry[i].start_offset)/4; + reg_start_offset = reg_dump_data->reg_entry[i].start_offset; + reg_base = mem_base + reg_start_offset; + for (j = 0; j < num_reg; j++) { + addr[0] = + soc_info->mem_block[TFE_CORE_BASE_IDX]->start + + reg_start_offset + (j*4); + addr[1] = cam_io_r(reg_base + (j*4)); + addr += 2; + } + } + + /*Dump bus top registers*/ + num_reg = (reg_dump_data->bus_write_top_end_addr - + reg_dump_data->bus_start_addr)/4; + reg_base = mem_base + reg_dump_data->bus_start_addr; + reg_start_offset = soc_info->mem_block[TFE_CORE_BASE_IDX]->start + + reg_dump_data->bus_start_addr; + for (i = 0; i < num_reg; i++) { + addr[0] = reg_start_offset + (i*4); + addr[1] = cam_io_r(reg_base + (i*4)); + addr += 2; + } + + /* Dump bus clients */ + reg_base = mem_base + reg_dump_data->bus_client_start_addr; + reg_start_offset = soc_info->mem_block[TFE_CORE_BASE_IDX]->start + + reg_dump_data->bus_client_start_addr; + for (j = 0; j < reg_dump_data->num_bus_clients; j++) { + + for (i = 0; i <= 0x3c; i += 4) { + addr[0] = reg_start_offset + i; + addr[1] = cam_io_r(reg_base + i); + addr += 2; + } + for (i = 0x60; i <= 0x80; i += 4) { + addr[0] = reg_start_offset + (i*4); + addr[1] = cam_io_r(reg_base + (i*4)); + addr += 2; + } + reg_base += reg_dump_data->bus_client_offset; + reg_start_offset += reg_dump_data->bus_client_offset; + } + + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + + /* Dump LUT entries */ + for (i = 0; i < reg_dump_data->num_lut_dump_entries; i++) { + + lut_bank_sel = reg_dump_data->lut_entry[i].lut_bank_sel; + lut_size = reg_dump_data->lut_entry[i].lut_addr_size; + lut_word_size = reg_dump_data->lut_entry[i].lut_word_size; + lut_dmi_reg = reg_dump_data->lut_entry[i].dmi_reg_offset; + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "LUT_REG:"); + hdr->word_size = lut_word_size/8; + addr = (uint32_t *)(dst + + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + *addr++ = lut_bank_sel; + cam_io_w_mb(lut_bank_sel, mem_base + lut_dmi_reg + 4); + cam_io_w_mb(0, mem_base + 0xC28); + for (j = 0; j < lut_size; j++) { + *addr = cam_io_r_mb(mem_base + 0xc30); + addr++; + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + } + cam_io_w_mb(0, mem_base + 0xC24); + cam_io_w_mb(0, mem_base + 0xC28); + +dump_bw: + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "TFE_CLK_RATE_BW:"); + clk_waddr = (uint64_t *)(dst + + sizeof(struct cam_isp_hw_dump_header)); + clk_wstart = clk_waddr; + hdr->word_size = sizeof(uint64_t); + *clk_waddr++ = top_priv->hw_clk_rate; + *clk_waddr++ = top_priv->total_bw_applied; + + hdr->size = hdr->word_size * (clk_waddr - clk_wstart); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "TFE_NIU_MAXWR:"); + addr = (uint32_t *)(dst + + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + hdr->word_size = sizeof(uint32_t); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x20, true, &val); + *addr++ = val; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + mutex_unlock(&tfe_hw_info->hw_mutex); + + CAM_DBG(CAM_ISP, "offset %zu", dump_args->offset); + return 0; +} + static int cam_tfe_camif_irq_reg_dump( struct cam_tfe_hw_core_info *core_info, void *cmd_args, uint32_t arg_size) @@ -1465,10 +1803,14 @@ int cam_tfe_top_reserve(void *device_priv, acquire_args->in_port->pix_pattern; camif_data->dsp_mode = acquire_args->in_port->dsp_mode; - camif_data->first_pixel = + camif_data->left_first_pixel = acquire_args->in_port->left_start; - camif_data->last_pixel = + camif_data->left_last_pixel = acquire_args->in_port->left_end; + camif_data->right_first_pixel = + acquire_args->in_port->right_start; + camif_data->right_last_pixel = + acquire_args->in_port->right_end; camif_data->first_line = acquire_args->in_port->line_start; camif_data->last_line = @@ -1494,6 +1836,14 @@ int cam_tfe_top_reserve(void *device_priv, rdi_data->sync_mode = acquire_args->sync_mode; rdi_data->event_cb = args->event_cb; rdi_data->priv = args->priv; + rdi_data->left_first_pixel = + acquire_args->in_port->left_start; + rdi_data->left_last_pixel = + acquire_args->in_port->left_end; + rdi_data->first_line = + acquire_args->in_port->line_start; + rdi_data->last_line = + acquire_args->in_port->line_end; } top_priv->in_rsrc[i].cdm_ops = acquire_args->cdm_ops; @@ -1604,6 +1954,9 @@ static int cam_tfe_camif_resource_start( if (!rsrc_data->camif_pd_enable) val |= (1 << rsrc_data->reg_data->camif_pd_rdi2_src_sel_shift); + /* enables the Delay Line CLC in the pixel pipeline */ + val |= BIT(rsrc_data->reg_data->delay_line_en_shift); + cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg_0); @@ -1755,10 +2108,19 @@ int cam_tfe_top_start(struct cam_tfe_hw_core_info *core_info, } core_info->irq_err_config_cnt++; - if (core_info->irq_err_config_cnt == 1) + if (core_info->irq_err_config_cnt == 1) { cam_tfe_irq_config(core_info, core_info->tfe_hw_info->error_irq_mask, CAM_TFE_TOP_IRQ_REG_NUM, true); + top_priv->error_ts.tv_sec = 0; + top_priv->error_ts.tv_usec = 0; + top_priv->sof_ts.tv_sec = 0; + top_priv->sof_ts.tv_usec = 0; + top_priv->epoch_ts.tv_sec = 0; + top_priv->epoch_ts.tv_usec = 0; + top_priv->eof_ts.tv_sec = 0; + top_priv->eof_ts.tv_usec = 0; + } end: return rc; @@ -2079,8 +2441,9 @@ int cam_tfe_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) CAM_DBG(CAM_ISP, "TFE:%d waiting for tfe reset complete", core_info->core_index); - /* Wait for Completion or Timeout of 500ms */ - rc = wait_for_completion_timeout(&core_info->reset_complete, 500); + /* Wait for Completion or Timeout of 100ms */ + rc = wait_for_completion_timeout(&core_info->reset_complete, + msecs_to_jiffies(100)); if (rc <= 0) { CAM_ERR(CAM_ISP, "TFE:%d Error Reset Timeout", core_info->core_index); @@ -2436,6 +2799,10 @@ int cam_tfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA: *((struct cam_hw_soc_info **)cmd_args) = soc_info; break; + case CAM_ISP_HW_CMD_DUMP_HW: + rc = cam_tfe_hw_dump(core_info, + cmd_args, arg_size); + break; case CAM_ISP_HW_CMD_GET_BUF_UPDATE: case CAM_ISP_HW_CMD_GET_HFR_UPDATE: case CAM_ISP_HW_CMD_STRIPE_UPDATE: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h index d98a919011..2418831d00 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h @@ -25,6 +25,17 @@ #define CAM_TFE_MAX_REG_DUMP_ENTRIES 20 #define CAM_TFE_MAX_LUT_DUMP_ENTRIES 10 +#define CAM_TFE_MAX_CLC 30 +#define CAM_TFE_CLC_NAME_LENGTH_MAX 32 + +/*we take each word as uint32_t, for dumping uint64_t count as 2 words + * soc index + * clk_rate--> uint64_t--> count as 2 words + * BW--> uint64_t --> count as 2 words + * MAX_NIU + */ +#define CAM_TFE_CORE_DUMP_MISC_NUM_WORDS 4 + enum cam_tfe_lut_word_size { CAM_TFE_LUT_WORD_SIZE_32, CAM_TFE_LUT_WORD_SIZE_64, @@ -112,6 +123,7 @@ struct cam_tfe_camif_reg_data { uint32_t extern_reg_update_shift; uint32_t camif_pd_rdi2_src_sel_shift; uint32_t dual_tfe_sync_sel_shift; + uint32_t delay_line_en_shift; uint32_t pixel_pattern_shift; uint32_t pixel_pattern_mask; @@ -180,6 +192,11 @@ struct cam_tfe_rdi_reg_data { uint32_t enable_diagnostic_hw; }; +struct cam_tfe_clc_hw_status { + uint8_t name[CAM_TFE_CLC_NAME_LENGTH_MAX]; + uint32_t hw_status_reg; +}; + struct cam_tfe_rdi_hw_info { struct cam_tfe_rdi_reg *rdi_reg; struct cam_tfe_rdi_reg_data *reg_data; @@ -194,32 +211,36 @@ struct cam_tfe_top_hw_info { }; struct cam_tfe_hw_info { - uint32_t top_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM]; - uint32_t top_irq_clear[CAM_TFE_TOP_IRQ_REG_NUM]; - uint32_t top_irq_status[CAM_TFE_TOP_IRQ_REG_NUM]; - uint32_t top_irq_cmd; - uint32_t global_clear_bitmask; + uint32_t top_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM]; + uint32_t top_irq_clear[CAM_TFE_TOP_IRQ_REG_NUM]; + uint32_t top_irq_status[CAM_TFE_TOP_IRQ_REG_NUM]; + uint32_t top_irq_cmd; + uint32_t global_clear_bitmask; - uint32_t bus_irq_mask[CAM_TFE_BUS_MAX_IRQ_REGISTERS]; - uint32_t bus_irq_clear[CAM_TFE_BUS_MAX_IRQ_REGISTERS]; - uint32_t bus_irq_status[CAM_TFE_BUS_MAX_IRQ_REGISTERS]; - uint32_t bus_irq_cmd; + uint32_t bus_irq_mask[CAM_TFE_BUS_MAX_IRQ_REGISTERS]; + uint32_t bus_irq_clear[CAM_TFE_BUS_MAX_IRQ_REGISTERS]; + uint32_t bus_irq_status[CAM_TFE_BUS_MAX_IRQ_REGISTERS]; + uint32_t bus_irq_cmd; - uint32_t bus_violation_reg; - uint32_t bus_overflow_reg; - uint32_t bus_image_size_vilation_reg; - uint32_t bus_overflow_clear_cmd; - uint32_t debug_status_top; + uint32_t bus_violation_reg; + uint32_t bus_overflow_reg; + uint32_t bus_image_size_vilation_reg; + uint32_t bus_overflow_clear_cmd; + uint32_t debug_status_top; - uint32_t reset_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM]; - uint32_t error_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM]; - uint32_t bus_reg_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM]; + uint32_t reset_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM]; + uint32_t error_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM]; + uint32_t bus_reg_irq_mask[CAM_TFE_BUS_MAX_IRQ_REGISTERS]; + uint32_t bus_error_irq_mask[CAM_TFE_BUS_MAX_IRQ_REGISTERS]; - uint32_t top_version; - void *top_hw_info; + uint32_t num_clc; + struct cam_tfe_clc_hw_status *clc_hw_status_info; - uint32_t bus_version; - void *bus_hw_info; + uint32_t top_version; + void *top_hw_info; + + uint32_t bus_version; + void *bus_hw_info; }; struct cam_tfe_hw_core_info { diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index b9329a8173..c0cfbe7a76 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -42,6 +42,7 @@ int cam_jpeg_enc_init_hw(void *device_priv, struct cam_jpeg_enc_device_core_info *core_info = NULL; struct cam_ahb_vote ahb_vote; struct cam_axi_vote axi_vote = {0}; + unsigned long flags; int rc; if (!device_priv) { @@ -92,6 +93,9 @@ int cam_jpeg_enc_init_hw(void *device_priv, CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc); goto soc_failed; } + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_UP; + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); mutex_unlock(&core_info->core_mutex); @@ -112,6 +116,7 @@ int cam_jpeg_enc_deinit_hw(void *device_priv, struct cam_hw_info *jpeg_enc_dev = device_priv; struct cam_hw_soc_info *soc_info = NULL; struct cam_jpeg_enc_device_core_info *core_info = NULL; + unsigned long flags; int rc; if (!device_priv) { @@ -141,6 +146,9 @@ int cam_jpeg_enc_deinit_hw(void *device_priv, return -EFAULT; } + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); rc = cam_jpeg_enc_disable_soc_resources(soc_info); if (rc) CAM_ERR(CAM_JPEG, "soc disable failed %d", rc); @@ -174,12 +182,19 @@ irqreturn_t cam_jpeg_enc_irq(int irq_num, void *data) hw_info = core_info->jpeg_enc_hw_info; mem_base = soc_info->reg_map[0].mem_base; + spin_lock(&jpeg_enc_dev->hw_lock); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock(&jpeg_enc_dev->hw_lock); + return IRQ_HANDLED; + } irq_status = cam_io_r_mb(mem_base + core_info->jpeg_enc_hw_info->reg_offset.int_status); cam_io_w_mb(irq_status, soc_info->reg_map[0].mem_base + core_info->jpeg_enc_hw_info->reg_offset.int_clr); + spin_unlock(&jpeg_enc_dev->hw_lock); CAM_DBG(CAM_JPEG, "irq_num %d irq_status = %x , core_state %d", irq_num, irq_status, core_info->core_state); @@ -255,6 +270,7 @@ int cam_jpeg_enc_reset_hw(void *data, struct cam_jpeg_enc_device_hw_info *hw_info = NULL; void __iomem *mem_base; unsigned long rem_jiffies; + unsigned long flags; if (!jpeg_enc_dev) { CAM_ERR(CAM_JPEG, "Invalid args"); @@ -268,17 +284,23 @@ int cam_jpeg_enc_reset_hw(void *data, mem_base = soc_info->reg_map[0].mem_base; mutex_lock(&core_info->core_mutex); - spin_lock(&jpeg_enc_dev->hw_lock); + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); + mutex_unlock(&core_info->core_mutex); + return -EINVAL; + } if (core_info->core_state == CAM_JPEG_ENC_CORE_RESETTING) { CAM_ERR(CAM_JPEG, "alrady resetting"); - spin_unlock(&jpeg_enc_dev->hw_lock); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); mutex_unlock(&core_info->core_mutex); return 0; } reinit_completion(&jpeg_enc_dev->hw_complete); core_info->core_state = CAM_JPEG_ENC_CORE_RESETTING; - spin_unlock(&jpeg_enc_dev->hw_lock); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); cam_io_w_mb(hw_info->reg_val.int_mask_disable_all, mem_base + hw_info->reg_offset.int_mask); @@ -308,6 +330,7 @@ int cam_jpeg_enc_start_hw(void *data, struct cam_hw_soc_info *soc_info = NULL; struct cam_jpeg_enc_device_hw_info *hw_info = NULL; void __iomem *mem_base; + unsigned long flags; if (!jpeg_enc_dev) { CAM_ERR(CAM_JPEG, "Invalid args"); @@ -320,10 +343,18 @@ int cam_jpeg_enc_start_hw(void *data, hw_info = core_info->jpeg_enc_hw_info; mem_base = soc_info->reg_map[0].mem_base; - if (core_info->core_state != CAM_JPEG_ENC_CORE_READY) { - CAM_ERR(CAM_JPEG, "Error not ready"); + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); return -EINVAL; } + if (core_info->core_state != CAM_JPEG_ENC_CORE_READY) { + CAM_ERR(CAM_JPEG, "Error not ready: %d", core_info->core_state); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); cam_io_w_mb(hw_info->reg_val.hw_cmd_start, mem_base + hw_info->reg_offset.hw_cmd); @@ -340,6 +371,7 @@ int cam_jpeg_enc_stop_hw(void *data, struct cam_jpeg_enc_device_hw_info *hw_info = NULL; void __iomem *mem_base; unsigned long rem_jiffies; + unsigned long flags; if (!jpeg_enc_dev) { CAM_ERR(CAM_JPEG, "Invalid args"); @@ -352,17 +384,23 @@ int cam_jpeg_enc_stop_hw(void *data, mem_base = soc_info->reg_map[0].mem_base; mutex_lock(&core_info->core_mutex); - spin_lock(&jpeg_enc_dev->hw_lock); + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); + mutex_unlock(&core_info->core_mutex); + return -EINVAL; + } if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { CAM_ERR(CAM_JPEG, "alrady stopping"); - spin_unlock(&jpeg_enc_dev->hw_lock); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); mutex_unlock(&core_info->core_mutex); return 0; } reinit_completion(&jpeg_enc_dev->hw_complete); core_info->core_state = CAM_JPEG_ENC_CORE_ABORTING; - spin_unlock(&jpeg_enc_dev->hw_lock); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); cam_io_w_mb(hw_info->reg_val.hw_cmd_stop, mem_base + hw_info->reg_offset.hw_cmd); diff --git a/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c b/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c index 2671b95ff4..45ba114cc1 100644 --- a/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c +++ b/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c @@ -85,6 +85,7 @@ static int cam_ope_mgr_process_cmd(void *priv, void *data) struct ope_cmd_work_data *task_data = NULL; struct cam_ope_ctx *ctx_data; struct cam_cdm_bl_request *cdm_cmd; + struct cam_ope_hw_mgr *hw_mgr = ope_hw_mgr; if (!data || !priv) { CAM_ERR(CAM_OPE, "Invalid params%pK %pK", data, priv); @@ -95,8 +96,23 @@ static int cam_ope_mgr_process_cmd(void *priv, void *data) task_data = (struct ope_cmd_work_data *)data; cdm_cmd = task_data->data; - CAM_DBG(CAM_OPE, "cam_cdm_submit_bls: handle = %u", - ctx_data->ope_cdm.cdm_handle); + CAM_DBG(CAM_OPE, + "cam_cdm_submit_bls: handle 0x%x, ctx_id %d req %d cookie %d", + ctx_data->ope_cdm.cdm_handle, ctx_data->ctx_id, + task_data->req_id, cdm_cmd->cookie); + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (task_data->req_id <= ctx_data->last_flush_req) { + CAM_WARN(CAM_OPE, + "request %lld has been flushed, reject packet", + task_data->req_id, ctx_data->last_flush_req); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + if (task_data->req_id > ctx_data->last_flush_req) + ctx_data->last_flush_req = 0; + rc = cam_cdm_submit_bls(ctx_data->ope_cdm.cdm_handle, cdm_cmd); if (!rc) @@ -104,6 +120,8 @@ static int cam_ope_mgr_process_cmd(void *priv, void *data) else CAM_ERR(CAM_OPE, "submit failed for %lld", cdm_cmd->cookie); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; } @@ -125,6 +143,20 @@ static int cam_ope_mgr_reset_hw(void) return rc; } +static void cam_ope_free_io_config(struct cam_ope_request *req) +{ + int i, j; + + for (i = 0; i < OPE_MAX_BATCH_SIZE; i++) { + for (j = 0; j < OPE_MAX_IO_BUFS; j++) { + if (req->io_buf[i][j]) { + kzfree(req->io_buf[i][j]); + req->io_buf[i][j] = NULL; + } + } + } +} + static void cam_ope_device_timer_stop(struct cam_ope_hw_mgr *hw_mgr) { if (hw_mgr->clk_info.watch_dog) { @@ -213,10 +245,363 @@ static bool cam_ope_is_pending_request(struct cam_ope_ctx *ctx_data) return !bitmap_empty(ctx_data->bitmap, CAM_CTX_REQ_MAX); } +static int cam_get_valid_ctx_id(void) +{ + struct cam_ope_hw_mgr *hw_mgr = ope_hw_mgr; + int i; + + for (i = 0; i < OPE_CTX_MAX; i++) { + if (hw_mgr->ctx[i].ctx_state == OPE_CTX_STATE_ACQUIRED) + break; + } + + if (i == OPE_CTX_MAX) + return -EINVAL; + + return i; +} + +static int32_t cam_ope_mgr_process_msg(void *priv, void *data) +{ + struct ope_msg_work_data *task_data; + struct cam_ope_hw_mgr *hw_mgr; + struct cam_ope_ctx *ctx; + uint32_t irq_status; + int32_t ctx_id; + int rc = 0, i; + + if (!data || !priv) { + CAM_ERR(CAM_OPE, "Invalid data"); + return -EINVAL; + } + + task_data = data; + hw_mgr = priv; + irq_status = task_data->irq_status; + ctx_id = cam_get_valid_ctx_id(); + if (ctx_id < 0) { + CAM_ERR(CAM_OPE, "No valid context to handle error"); + return ctx_id; + } + + ctx = &hw_mgr->ctx[ctx_id]; + + /* Indicate about this error to CDM and reset OPE*/ + rc = cam_cdm_handle_error(ctx->ope_cdm.cdm_handle); + + mutex_lock(&ctx->ctx_mutex); + if (ctx->ctx_state != OPE_CTX_STATE_ACQUIRED) { + CAM_DBG(CAM_OPE, "ctx id: %d not in right state: %d", + ctx_id, ctx->ctx_state); + mutex_unlock(&ctx->ctx_mutex); + return -EINVAL; + } + + for (i = 0; i < hw_mgr->num_ope; i++) { + rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( + hw_mgr->ope_dev_intf[i]->hw_priv, OPE_HW_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_OPE, "OPE Dev acquire failed: %d", rc); + } + + mutex_unlock(&ctx->ctx_mutex); + return rc; +} + +static int cam_ope_dump_hang_patches(struct cam_packet *packet, + struct cam_ope_hang_dump *dump) +{ + struct cam_patch_desc *patch_desc = NULL; + dma_addr_t iova_addr; + size_t src_buf_size; + int i, rc = 0; + int32_t iommu_hdl = ope_hw_mgr->iommu_hdl; + + /* process patch descriptor */ + patch_desc = (struct cam_patch_desc *) + ((uint32_t *) &packet->payload + + packet->patch_offset/4); + + for (i = 0; i < packet->num_patches; i++) { + rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl, + iommu_hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, + "get src buf address failed for handle 0x%x", + patch_desc[i].src_buf_hdl); + return rc; + } + dump->entries[dump->num_bufs].memhdl = + patch_desc[i].src_buf_hdl; + dump->entries[dump->num_bufs].iova = iova_addr; + dump->entries[dump->num_bufs].offset = patch_desc[i].src_offset; + dump->entries[dump->num_bufs].len = 0; + dump->entries[dump->num_bufs].size = src_buf_size; + dump->num_bufs++; + } + return rc; +} + +static int cam_ope_dump_direct(struct ope_cmd_buf_info *cmd_buf_info, + struct cam_ope_hang_dump *dump) +{ + dma_addr_t iova_addr; + size_t size; + int rc = 0; + + rc = cam_mem_get_io_buf(cmd_buf_info->mem_handle, + ope_hw_mgr->iommu_hdl, &iova_addr, &size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, "get cmd buf addressfailed for handle 0x%x", + cmd_buf_info->mem_handle); + return rc; + } + dump->entries[dump->num_bufs].memhdl = cmd_buf_info->mem_handle; + dump->entries[dump->num_bufs].iova = iova_addr; + dump->entries[dump->num_bufs].offset = cmd_buf_info->offset; + dump->entries[dump->num_bufs].len = cmd_buf_info->length; + dump->entries[dump->num_bufs].size = size; + dump->num_bufs++; + return 0; +} + +static void cam_ope_dump_dmi(struct cam_ope_hang_dump *dump, uint32_t addr, + uint32_t length) +{ + int i; + uint32_t memhdl = 0, iova = 0, size; + + for (i = 0; i < dump->num_bufs; i++) { + if (dump->entries[i].iova + dump->entries[i].offset == addr) { + if (dump->entries[i].len == length) + goto end; + else if (dump->entries[i].len == 0) { + dump->entries[i].len = length; + goto end; + } else { + iova = dump->entries[i].iova; + memhdl = dump->entries[i].memhdl; + size = dump->entries[i].size; + } + } + } + if (memhdl && iova) { + dump->entries[dump->num_bufs].memhdl = memhdl; + dump->entries[dump->num_bufs].iova = iova; + dump->entries[dump->num_bufs].offset = addr - iova; + dump->entries[dump->num_bufs].len = length; + dump->entries[dump->num_bufs].size = size; + dump->num_bufs++; + } +end: + return; +} + +static int cam_ope_dump_indirect(struct ope_cmd_buf_info *cmd_buf_info, + struct cam_ope_hang_dump *dump) +{ + int rc = 0; + uintptr_t cpu_addr; + size_t buf_len; + uint32_t num_dmi; + struct cdm_dmi_cmd dmi_cmd; + uint32_t *print_ptr, print_idx; + + rc = cam_mem_get_cpu_buf(cmd_buf_info->mem_handle, + &cpu_addr, &buf_len); + if (rc || !cpu_addr) { + CAM_ERR(CAM_OPE, "get cmd buf fail 0x%x", + cmd_buf_info->mem_handle); + return rc; + } + cpu_addr = cpu_addr + cmd_buf_info->offset; + + num_dmi = cmd_buf_info->length / + sizeof(struct cdm_dmi_cmd); + print_ptr = (uint32_t *)cpu_addr; + for (print_idx = 0; print_idx < num_dmi; print_idx++) { + memcpy(&dmi_cmd, (const void *)print_ptr, + sizeof(struct cdm_dmi_cmd)); + cam_ope_dump_dmi(dump, dmi_cmd.addr, dmi_cmd.length+1); + print_ptr += sizeof(struct cdm_dmi_cmd) / + sizeof(uint32_t); + } + return rc; +} + +static int cam_ope_mgr_dump_cmd_buf(uintptr_t frame_process_addr, + struct cam_ope_hang_dump *dump) +{ + int rc = 0; + int i, j; + struct ope_frame_process *frame_process; + struct ope_cmd_buf_info *cmd_buf; + + frame_process = (struct ope_frame_process *)frame_process_addr; + for (i = 0; i < frame_process->batch_size; i++) { + for (j = 0; j < frame_process->num_cmd_bufs[i]; j++) { + cmd_buf = &frame_process->cmd_buf[i][j]; + if (cmd_buf->type == OPE_CMD_BUF_TYPE_DIRECT) { + if (cmd_buf->cmd_buf_usage == OPE_CMD_BUF_DEBUG) + continue; + cam_ope_dump_direct(cmd_buf, dump); + } else if (cmd_buf->type == OPE_CMD_BUF_TYPE_INDIRECT) + cam_ope_dump_indirect(cmd_buf, dump); + } + } + return rc; +} + +static int cam_ope_mgr_dump_frame_set(uintptr_t frame_process_addr, + struct cam_ope_hang_dump *dump) +{ + int i, j, rc = 0; + dma_addr_t iova_addr; + size_t size; + struct ope_frame_process *frame_process; + struct ope_io_buf_info *io_buf; + struct cam_ope_buf_entry *buf_entry; + struct cam_ope_output_info *output_info; + + frame_process = (struct ope_frame_process *)frame_process_addr; + for (j = 0; j < frame_process->batch_size; j++) { + for (i = 0; i < frame_process->frame_set[j].num_io_bufs; i++) { + io_buf = &frame_process->frame_set[j].io_buf[i]; + rc = cam_mem_get_io_buf(io_buf->mem_handle[0], + ope_hw_mgr->iommu_hdl, &iova_addr, &size); + if (rc) { + CAM_ERR(CAM_OPE, "get io buf fail 0x%x", + io_buf->mem_handle[0]); + return rc; + } + buf_entry = &dump->entries[dump->num_bufs]; + buf_entry->memhdl = io_buf->mem_handle[0]; + buf_entry->iova = iova_addr; + buf_entry->offset = io_buf->plane_offset[0]; + buf_entry->len = size - io_buf->plane_offset[0]; + buf_entry->size = size; + dump->num_bufs++; + if (io_buf->direction == 2) { + output_info = + &dump->outputs[dump->num_outputs]; + output_info->iova = iova_addr; + output_info->offset = io_buf->plane_offset[0]; + output_info->len = size - + io_buf->plane_offset[0]; + dump->num_outputs++; + } + } + } + return rc; +} + +static int cam_ope_dump_frame_process(struct cam_packet *packet, + struct cam_ope_hang_dump *dump) +{ + int rc = 0; + int i; + size_t len; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t cpu_addr = 0; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + for (i = 0; i < packet->num_cmd_buf; i++) { + if (cmd_desc[i].type != CAM_CMD_BUF_GENERIC || + cmd_desc[i].meta_data == OPE_CMD_META_GENERIC_BLOB) + continue; + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &cpu_addr, &len); + if (rc || !cpu_addr) { + CAM_ERR(CAM_OPE, "get cmd buf failed %x", + cmd_desc[i].mem_handle); + return rc; + } + cpu_addr = cpu_addr + cmd_desc[i].offset; + break; + } + + if (!cpu_addr) { + CAM_ERR(CAM_OPE, "invalid number of cmd buf"); + return -EINVAL; + } + + cam_ope_mgr_dump_cmd_buf(cpu_addr, dump); + cam_ope_mgr_dump_frame_set(cpu_addr, dump); + return rc; +} + +static int cam_ope_dump_bls(struct cam_ope_request *ope_req, + struct cam_ope_hang_dump *dump) +{ + struct cam_cdm_bl_request *cdm_cmd; + int i; + + cdm_cmd = ope_req->cdm_cmd; + for (i = 0; i < cdm_cmd->cmd_arrary_count; i++) { + dump->bl_entries[dump->num_bls].base = + (uint32_t)cdm_cmd->cmd[i].bl_addr.hw_iova + + cdm_cmd->cmd[i].offset; + dump->bl_entries[dump->num_bls].len = cdm_cmd->cmd[i].len; + dump->bl_entries[dump->num_bls].arbitration = + cdm_cmd->cmd[i].arbitrate; + dump->num_bls++; + } + return 0; +} + +static void cam_ope_dump_req_data(struct cam_ope_request *ope_req) +{ + struct cam_ope_hang_dump *dump; + struct cam_packet *packet = + (struct cam_packet *)ope_req->hang_data.packet; + + if (!ope_req->ope_debug_buf.cpu_addr || + ope_req->ope_debug_buf.len < sizeof(struct cam_ope_hang_dump) || + (ope_req->ope_debug_buf.offset + ope_req->ope_debug_buf.len) + > ope_req->ope_debug_buf.size) { + CAM_ERR(CAM_OPE, "Invalid debug buf, size %d %d len %d off %d", + sizeof(struct cam_ope_hang_dump), + ope_req->ope_debug_buf.size, + ope_req->ope_debug_buf.len, + ope_req->ope_debug_buf.offset); + return; + } + dump = (struct cam_ope_hang_dump *)ope_req->ope_debug_buf.cpu_addr; + memset(dump, 0, sizeof(struct cam_ope_hang_dump)); + dump->num_bufs = 0; + cam_ope_dump_hang_patches(packet, dump); + cam_ope_dump_frame_process(packet, dump); + cam_ope_dump_bls(ope_req, dump); +} + +static bool cam_ope_check_req_delay(struct cam_ope_ctx *ctx_data, + uint64_t req_time) +{ + struct timespec64 ts; + uint64_t ts_ns; + + get_monotonic_boottime64(&ts); + ts_ns = (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + + if (ts_ns - req_time < + ((OPE_REQUEST_TIMEOUT - + OPE_REQUEST_TIMEOUT / 10) * 1000000)) { + CAM_INFO(CAM_OPE, "ctx: %d, ts_ns : %llu", + ctx_data->ctx_id, ts_ns); + cam_ope_req_timer_reset(ctx_data); + return true; + } + + return false; +} + static int32_t cam_ope_process_request_timer(void *priv, void *data) { - struct ope_clk_work_data *task_data = (struct ope_clk_work_data *)data; - struct cam_ope_ctx *ctx_data = (struct cam_ope_ctx *)task_data->data; + struct ope_clk_work_data *clk_data = (struct ope_clk_work_data *)data; + struct cam_ope_ctx *ctx_data = (struct cam_ope_ctx *)clk_data->data; struct cam_ope_hw_mgr *hw_mgr = ope_hw_mgr; uint32_t id; struct cam_hw_intf *dev_intf = NULL; @@ -225,6 +610,8 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) int i = 0; int device_share_ratio = 1; int path_index; + struct crm_workq_task *task; + struct ope_msg_work_data *task_data; if (!ctx_data) { CAM_ERR(CAM_OPE, "ctx_data is NULL, failed to update clk"); @@ -241,8 +628,61 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) } if (cam_ope_is_pending_request(ctx_data)) { - CAM_DBG(CAM_OPE, "pending requests means, issue is with HW"); - cam_cdm_handle_error(ctx_data->ope_cdm.cdm_handle); + + if (cam_ope_check_req_delay(ctx_data, + ctx_data->last_req_time)) { + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + if (cam_ope_check_req_delay(ctx_data, + ope_hw_mgr->last_callback_time)) { + CAM_WARN(CAM_OPE, + "ope ctx: %d stuck due to other contexts", + ctx_data->ctx_id); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + if (!cam_cdm_detect_hang_error(ctx_data->ope_cdm.cdm_handle)) { + cam_ope_req_timer_reset(ctx_data); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + /* Try checking ctx struck again */ + if (cam_ope_check_req_delay(ctx_data, + ope_hw_mgr->last_callback_time)) { + CAM_WARN(CAM_OPE, + "ope ctx: %d stuck due to other contexts", + ctx_data->ctx_id); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + CAM_ERR(CAM_OPE, + "pending requests means, issue is with HW for ctx %d", + ctx_data->ctx_id); + CAM_ERR(CAM_OPE, "ctx: %d, lrt: %llu, lct: %llu", + ctx_data->ctx_id, ctx_data->last_req_time, + ope_hw_mgr->last_callback_time); + hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( + hw_mgr->ope_dev_intf[i]->hw_priv, + OPE_HW_DUMP_DEBUG, + NULL, 0); + task = cam_req_mgr_workq_get_task(ope_hw_mgr->msg_work); + if (!task) { + CAM_ERR(CAM_OPE, "no empty task"); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + task_data = (struct ope_msg_work_data *)task->payload; + task_data->data = hw_mgr; + task_data->irq_status = 1; + task_data->type = OPE_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_ope_mgr_process_msg; + cam_req_mgr_workq_enqueue_task(task, ope_hw_mgr, + CRM_TASK_PRIORITY_0); cam_ope_req_timer_reset(ctx_data); mutex_unlock(&ctx_data->ctx_mutex); return 0; @@ -372,7 +812,7 @@ static int cam_ope_start_req_timer(struct cam_ope_ctx *ctx_data) int rc = 0; rc = crm_timer_init(&ctx_data->req_watch_dog, - 200, ctx_data, &cam_ope_req_timer_cb); + OPE_REQUEST_TIMEOUT, ctx_data, &cam_ope_req_timer_cb); if (rc) CAM_ERR(CAM_OPE, "Failed to start timer"); @@ -525,19 +965,6 @@ static int cam_ope_device_timer_start(struct cam_ope_hw_mgr *hw_mgr) return rc; } -static int cam_get_valid_ctx_id(void) -{ - struct cam_ope_hw_mgr *hw_mgr = ope_hw_mgr; - int i; - - for (i = 0; i < OPE_CTX_MAX; i++) { - if (hw_mgr->ctx[i].ctx_state == OPE_CTX_STATE_ACQUIRED) - break; - } - - return i; -} - static int cam_ope_get_actual_clk_rate_idx( struct cam_ope_ctx *ctx_data, uint32_t base_clk) { @@ -1091,6 +1518,7 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, struct cam_ope_ctx *ctx; struct cam_ope_request *ope_req; struct cam_hw_done_event_data buf_data; + struct timespec64 ts; bool flag = false; if (!userdata) { @@ -1098,15 +1526,35 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, return; } - CAM_DBG(CAM_FD, "CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", - handle, userdata, status, cookie); + if (cookie >= CAM_CTX_REQ_MAX) { + CAM_ERR(CAM_OPE, "Invalid reqIdx = %llu", cookie); + return; + } ctx = userdata; + mutex_lock(&ctx->ctx_mutex); + + if (!test_bit(cookie, ctx->bitmap)) { + CAM_ERR(CAM_OPE, "Req not present reqIdx = %d for ctx_id = %d", + cookie, ctx->ctx_id); + goto end; + } + ope_req = ctx->req_list[cookie]; - mutex_lock(&ctx->ctx_mutex); + get_monotonic_boottime64(&ts); + ope_hw_mgr->last_callback_time = (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + + CAM_DBG(CAM_REQ, + "hdl=%x, udata=%pK, status=%d, cookie=%d", + handle, userdata, status, cookie); + CAM_DBG(CAM_REQ, "req_id= %llu ctx_id= %d lcb=%llu", + ope_req->request_id, ctx->ctx_id, + ope_hw_mgr->last_callback_time); + if (ctx->ctx_state != OPE_CTX_STATE_ACQUIRED) { - CAM_DBG(CAM_OPE, "ctx %u is in %d state", + CAM_ERR(CAM_OPE, "ctx %u is in %d state", ctx->ctx_id, ctx->ctx_state); mutex_unlock(&ctx->ctx_mutex); return; @@ -1126,10 +1574,13 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, goto end; } else { CAM_ERR(CAM_OPE, - "CDM hdl=%x, udata=%pK, status=%d, cookie=%d req_id = %llu", - handle, userdata, status, cookie, ope_req->request_id); + "CDM hdl=%x, udata=%pK, status=%d, cookie=%d req_id = %llu ctx_id=%d", + handle, userdata, status, cookie, + ope_req->request_id, ctx->ctx_id); CAM_ERR(CAM_OPE, "Rst of CDM and OPE for error reqid = %lld", ope_req->request_id); + if (status != CAM_CDM_CB_STATUS_HW_FLUSH) + cam_ope_dump_req_data(ope_req); rc = cam_ope_mgr_reset_hw(); flag = true; } @@ -1140,6 +1591,7 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, ope_req->request_id = 0; kzfree(ctx->req_list[cookie]->cdm_cmd); ctx->req_list[cookie]->cdm_cmd = NULL; + cam_ope_free_io_config(ctx->req_list[cookie]); kzfree(ctx->req_list[cookie]); ctx->req_list[cookie] = NULL; clear_bit(cookie, ctx->bitmap); @@ -1149,45 +1601,6 @@ end: mutex_unlock(&ctx->ctx_mutex); } -static int32_t cam_ope_mgr_process_msg(void *priv, void *data) -{ - struct ope_msg_work_data *task_data; - struct cam_ope_hw_mgr *hw_mgr; - struct cam_ope_ctx *ctx; - uint32_t irq_status; - int32_t ctx_id; - int rc = 0, i; - - if (!data || !priv) { - CAM_ERR(CAM_OPE, "Invalid data"); - return -EINVAL; - } - - task_data = data; - hw_mgr = priv; - irq_status = task_data->irq_status; - ctx_id = cam_get_valid_ctx_id(); - if (ctx_id < 0) { - CAM_ERR(CAM_OPE, "No valid context to handle error"); - return ctx_id; - } - - ctx = &hw_mgr->ctx[ctx_id]; - - /* Indicate about this error to CDM and reset OPE*/ - rc = cam_cdm_handle_error(ctx->ope_cdm.cdm_handle); - - for (i = 0; i < hw_mgr->num_ope; i++) { - rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( - hw_mgr->ope_dev_intf[i]->hw_priv, OPE_HW_RESET, - NULL, 0); - if (rc) - CAM_ERR(CAM_OPE, "OPE Dev acquire failed: %d", rc); - } - - return rc; -} - int32_t cam_ope_hw_mgr_cb(uint32_t irq_status, void *data) { int32_t rc = 0; @@ -1273,7 +1686,7 @@ static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, for (i = 0; i < ope_request->num_batch; i++) { for (l = 0; l < ope_request->num_io_bufs[i]; l++) { - io_buf = &ope_request->io_buf[i][l]; + io_buf = ope_request->io_buf[i][l]; if (io_buf->direction == CAM_BUF_INPUT) { if (io_buf->fence != -1) { sync_in_obj[j++] = io_buf->fence; @@ -1290,9 +1703,13 @@ static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, k++; prep_args->num_out_map_entries++; } else { - CAM_ERR(CAM_OPE, "Invalid fence %d %d", + if (io_buf->resource_type + != OPE_OUT_RES_STATS_LTM) { + CAM_ERR(CAM_OPE, + "Invalid fence %d %d", io_buf->resource_type, ope_request->request_id); + } } } CAM_DBG(CAM_REQ, @@ -1305,12 +1722,14 @@ static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, } } - if (prep_args->num_in_map_entries > 1) + if (prep_args->num_in_map_entries > 1 && + prep_args->num_in_map_entries <= CAM_MAX_IN_RES) prep_args->num_in_map_entries = cam_common_util_remove_duplicate_arr( sync_in_obj, prep_args->num_in_map_entries); - if (prep_args->num_in_map_entries > 1) { + if (prep_args->num_in_map_entries > 1 && + prep_args->num_in_map_entries <= CAM_MAX_IN_RES) { rc = cam_sync_merge(&sync_in_obj[0], prep_args->num_in_map_entries, &merged_sync_in_obj); if (rc) { @@ -1332,7 +1751,8 @@ static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, ope_request->in_resource = 0; CAM_DBG(CAM_OPE, "fence = %d", sync_in_obj[0]); } else { - CAM_DBG(CAM_OPE, "No input fences"); + CAM_DBG(CAM_OPE, "Invalid count of input fences, count: %d", + prep_args->num_in_map_entries); prep_args->num_in_map_entries = 0; ope_request->in_resource = 0; rc = -EINVAL; @@ -1433,7 +1853,15 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, for (j = 0; j < in_frame_set->num_io_bufs; j++) { in_io_buf = &in_frame_set->io_buf[j]; - io_buf = &ope_request->io_buf[i][j]; + ope_request->io_buf[i][j] = + kzalloc(sizeof(struct ope_io_buf), GFP_KERNEL); + if (!ope_request->io_buf[i][j]) { + CAM_ERR(CAM_OPE, + "IO config allocation failure"); + cam_ope_free_io_config(ope_request); + return -ENOMEM; + } + io_buf = ope_request->io_buf[i][j]; if (in_io_buf->num_planes > OPE_MAX_PLANES) { CAM_ERR(CAM_OPE, "wrong number of planes: %u", in_io_buf->num_planes); @@ -1510,7 +1938,7 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, stripe_info->width = in_stripe_info->width; stripe_info->height = - in_io_buf->height[k]; + in_stripe_info->height; stripe_info->stride = in_io_buf->plane_stride[k]; stripe_info->x_init = @@ -1634,6 +2062,8 @@ static int cam_ope_mgr_process_cmd_buf_req(struct cam_ope_hw_mgr *hw_mgr, ope_request->ope_kmd_buf.iova_cdm_addr = iova_cdm_addr; ope_request->ope_kmd_buf.len = len; + ope_request->ope_kmd_buf.offset = + cmd_buf->offset; ope_request->ope_kmd_buf.size = cmd_buf->size; is_kmd_buf_valid = true; @@ -1649,9 +2079,11 @@ static int cam_ope_mgr_process_cmd_buf_req(struct cam_ope_hw_mgr *hw_mgr, ope_request->ope_debug_buf.iova_addr = iova_addr; ope_request->ope_debug_buf.len = - len; + cmd_buf->length; ope_request->ope_debug_buf.size = - cmd_buf->size; + len; + ope_request->ope_debug_buf.offset = + cmd_buf->offset; CAM_DBG(CAM_OPE, "dbg buf = %x", ope_request->ope_debug_buf.cpu_addr); break; @@ -2043,10 +2475,10 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) struct cam_hw_acquire_args *args = hw_acquire_args; struct cam_ope_dev_acquire ope_dev_acquire; struct cam_ope_dev_release ope_dev_release; - struct cam_cdm_acquire_data cdm_acquire; + struct cam_cdm_acquire_data *cdm_acquire; struct cam_ope_dev_init init; struct cam_ope_dev_clk_update clk_update; - struct cam_ope_dev_bw_update bw_update; + struct cam_ope_dev_bw_update *bw_update; struct cam_ope_set_irq_cb irq_cb; if ((!hw_priv) || (!hw_acquire_args)) { @@ -2072,6 +2504,42 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) goto end; } + cdm_acquire = kzalloc(sizeof(struct cam_cdm_acquire_data), GFP_KERNEL); + if (!cdm_acquire) { + CAM_ERR(CAM_ISP, "Out of memory"); + goto end; + } + strlcpy(cdm_acquire->identifier, "ope", sizeof("ope")); + if (ctx->ope_acquire.dev_type == OPE_DEV_TYPE_OPE_RT) + cdm_acquire->priority = CAM_CDM_BL_FIFO_3; + else if (ctx->ope_acquire.dev_type == + OPE_DEV_TYPE_OPE_NRT) + cdm_acquire->priority = CAM_CDM_BL_FIFO_0; + else + goto free_cdm_acquire; + + cdm_acquire->cell_index = 0; + cdm_acquire->handle = 0; + cdm_acquire->userdata = ctx; + cdm_acquire->cam_cdm_callback = cam_ope_ctx_cdm_callback; + cdm_acquire->id = CAM_CDM_VIRTUAL; + cdm_acquire->base_array_cnt = 1; + cdm_acquire->base_array[0] = hw_mgr->cdm_reg_map[OPE_DEV_OPE][0]; + + rc = cam_cdm_acquire(cdm_acquire); + if (rc) { + CAM_ERR(CAM_OPE, "cdm_acquire is failed: %d", rc); + goto cdm_acquire_failed; + } + + ctx->ope_cdm.cdm_ops = cdm_acquire->ops; + ctx->ope_cdm.cdm_handle = cdm_acquire->handle; + + rc = cam_cdm_stream_on(cdm_acquire->handle); + if (rc) { + CAM_ERR(CAM_OPE, "cdm stream on failure: %d", rc); + goto cdm_stream_on_failure; + } if (!hw_mgr->ope_ctx_cnt) { for (i = 0; i < ope_hw_mgr->num_ope; i++) { @@ -2081,7 +2549,7 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) sizeof(init)); if (rc) { CAM_ERR(CAM_OPE, "OPE Dev init failed: %d", rc); - goto end; + goto ope_dev_init_failure; } } @@ -2099,6 +2567,19 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) goto ope_irq_set_failed; } } + + hw_mgr->clk_info.base_clk = 600000000; + hw_mgr->clk_info.curr_clk = 600000000; + hw_mgr->clk_info.threshold = 5; + hw_mgr->clk_info.over_clked = 0; + + for (i = 0; i < CAM_OPE_MAX_PER_PATH_VOTES; i++) { + hw_mgr->clk_info.axi_path[i].camnoc_bw = 0; + hw_mgr->clk_info.axi_path[i].mnoc_ab_bw = 0; + hw_mgr->clk_info.axi_path[i].mnoc_ib_bw = 0; + hw_mgr->clk_info.axi_path[i].ddr_ab_bw = 0; + hw_mgr->clk_info.axi_path[i].ddr_ib_bw = 0; + } } ope_dev_acquire.ctx_id = ctx_id; @@ -2114,39 +2595,6 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) } } - memset(&cdm_acquire, 0, sizeof(cdm_acquire)); - strlcpy(cdm_acquire.identifier, "ope", sizeof("ope")); - if (ctx->ope_acquire.dev_type == OPE_DEV_TYPE_OPE_RT) - cdm_acquire.priority = CAM_CDM_BL_FIFO_3; - else if (ctx->ope_acquire.dev_type == - OPE_DEV_TYPE_OPE_NRT) - cdm_acquire.priority = CAM_CDM_BL_FIFO_0; - else - goto ope_dev_acquire_failed; - - cdm_acquire.cell_index = 0; - cdm_acquire.handle = 0; - cdm_acquire.userdata = ctx; - cdm_acquire.cam_cdm_callback = cam_ope_ctx_cdm_callback; - cdm_acquire.id = CAM_CDM_VIRTUAL; - cdm_acquire.base_array_cnt = 1; - cdm_acquire.base_array[0] = hw_mgr->cdm_reg_map[OPE_DEV_OPE][0]; - - rc = cam_cdm_acquire(&cdm_acquire); - if (rc) { - CAM_ERR(CAM_OPE, "cdm_acquire is failed: %d", rc); - goto cdm_acquire_failed; - } - - ctx->ope_cdm.cdm_ops = cdm_acquire.ops; - ctx->ope_cdm.cdm_handle = cdm_acquire.handle; - - rc = cam_cdm_stream_on(cdm_acquire.handle); - if (rc) { - CAM_ERR(CAM_OPE, "cdm stream on failure: %d", rc); - goto cdm_stream_on_failure; - } - for (i = 0; i < ope_hw_mgr->num_ope; i++) { clk_update.clk_rate = 600000000; rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( @@ -2158,25 +2606,30 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) } } - bw_update.ahb_vote_valid = false; + bw_update = kzalloc(sizeof(struct cam_ope_dev_bw_update), GFP_KERNEL); + if (!bw_update) { + CAM_ERR(CAM_ISP, "Out of memory"); + goto ope_clk_update_failed; + } + bw_update->ahb_vote_valid = false; for (i = 0; i < ope_hw_mgr->num_ope; i++) { - bw_update.axi_vote.num_paths = 1; - bw_update.axi_vote_valid = true; - bw_update.axi_vote.axi_path[0].camnoc_bw = 600000000; - bw_update.axi_vote.axi_path[0].mnoc_ab_bw = 600000000; - bw_update.axi_vote.axi_path[0].mnoc_ib_bw = 600000000; - bw_update.axi_vote.axi_path[0].ddr_ab_bw = 600000000; - bw_update.axi_vote.axi_path[0].ddr_ib_bw = 600000000; - bw_update.axi_vote.axi_path[0].transac_type = + bw_update->axi_vote.num_paths = 1; + bw_update->axi_vote_valid = true; + bw_update->axi_vote.axi_path[0].camnoc_bw = 600000000; + bw_update->axi_vote.axi_path[0].mnoc_ab_bw = 600000000; + bw_update->axi_vote.axi_path[0].mnoc_ib_bw = 600000000; + bw_update->axi_vote.axi_path[0].ddr_ab_bw = 600000000; + bw_update->axi_vote.axi_path[0].ddr_ib_bw = 600000000; + bw_update->axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; - bw_update.axi_vote.axi_path[0].path_data_type = + bw_update->axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( hw_mgr->ope_dev_intf[i]->hw_priv, OPE_HW_BW_UPDATE, - &bw_update, sizeof(bw_update)); + bw_update, sizeof(*bw_update)); if (rc) { CAM_ERR(CAM_OPE, "OPE Dev clk update failed: %d", rc); - goto ope_bw_update_failed; + goto free_bw_update; } } @@ -2192,53 +2645,122 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) mutex_unlock(&ctx->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_INFO(CAM_OPE, "OPE: %d acquire succesfull rc %d", ctx_id, rc); return rc; +free_bw_update: + kzfree(bw_update); + bw_update = NULL; ope_clk_update_failed: -ope_bw_update_failed: -cdm_stream_on_failure: - cam_cdm_release(cdm_acquire.handle); - ctx->ope_cdm.cdm_ops = NULL; - ctx->ope_cdm.cdm_handle = 0; -cdm_acquire_failed: ope_dev_release.ctx_id = ctx_id; for (i = 0; i < ope_hw_mgr->num_ope; i++) { - rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( + if (hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( hw_mgr->ope_dev_intf[i]->hw_priv, OPE_HW_RELEASE, - &ope_dev_release, sizeof(ope_dev_release)); - if (rc) - CAM_ERR(CAM_OPE, "OPE Dev release failed: %d", rc); + &ope_dev_release, sizeof(ope_dev_release))) + CAM_ERR(CAM_OPE, "OPE Dev release failed"); } - ope_dev_acquire_failed: if (!hw_mgr->ope_ctx_cnt) { irq_cb.ope_hw_mgr_cb = NULL; irq_cb.data = hw_mgr; for (i = 0; i < ope_hw_mgr->num_ope; i++) { init.hfi_en = ope_hw_mgr->hfi_en; - rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( + if (hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( hw_mgr->ope_dev_intf[i]->hw_priv, OPE_HW_SET_IRQ_CB, - &irq_cb, sizeof(irq_cb)); - CAM_ERR(CAM_OPE, "OPE IRQ de register failed"); + &irq_cb, sizeof(irq_cb))) + CAM_ERR(CAM_OPE, + "OPE IRQ de register failed"); } } ope_irq_set_failed: if (!hw_mgr->ope_ctx_cnt) { for (i = 0; i < ope_hw_mgr->num_ope; i++) { - rc = hw_mgr->ope_dev_intf[i]->hw_ops.deinit( - hw_mgr->ope_dev_intf[i]->hw_priv, NULL, 0); - if (rc) - CAM_ERR(CAM_OPE, "OPE deinit fail: %d", rc); + if (hw_mgr->ope_dev_intf[i]->hw_ops.deinit( + hw_mgr->ope_dev_intf[i]->hw_priv, NULL, 0)) + CAM_ERR(CAM_OPE, "OPE deinit fail"); + if (hw_mgr->ope_dev_intf[i]->hw_ops.stop( + hw_mgr->ope_dev_intf[i]->hw_priv, + NULL, 0)) + CAM_ERR(CAM_OPE, "OPE stop fail"); } } +ope_dev_init_failure: +cdm_stream_on_failure: + cam_cdm_release(cdm_acquire->handle); + ctx->ope_cdm.cdm_ops = NULL; + ctx->ope_cdm.cdm_handle = 0; + +cdm_acquire_failed: +free_cdm_acquire: + kzfree(cdm_acquire); + cdm_acquire = NULL; end: + args->ctxt_to_hw_map = NULL; cam_ope_put_free_ctx(hw_mgr, ctx_id); mutex_unlock(&ctx->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); return rc; } +static int cam_ope_mgr_remove_bw(struct cam_ope_hw_mgr *hw_mgr, int ctx_id) +{ + int i, path_index, rc = 0; + struct cam_ope_ctx *ctx_data = NULL; + struct cam_ope_clk_info *hw_mgr_clk_info; + + ctx_data = &hw_mgr->ctx[ctx_id]; + hw_mgr_clk_info = &hw_mgr->clk_info; + + for (i = 0; i < ctx_data->clk_info.num_paths; i++) { + path_index = + ctx_data->clk_info.axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_OPE_START_OFFSET; + + if (path_index >= CAM_OPE_MAX_PER_PATH_VOTES) { + CAM_WARN(CAM_OPE, + "Invalid path %d, start offset=%d, max=%d", + ctx_data->clk_info.axi_path[i].path_data_type, + CAM_AXI_PATH_DATA_OPE_START_OFFSET, + CAM_OPE_MAX_PER_PATH_VOTES); + continue; + } + + hw_mgr_clk_info->axi_path[path_index].camnoc_bw -= + ctx_data->clk_info.axi_path[i].camnoc_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ab_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ab_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ib_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ib_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ab_bw -= + ctx_data->clk_info.axi_path[i].ddr_ab_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ib_bw -= + ctx_data->clk_info.axi_path[i].ddr_ib_bw; + } + + rc = cam_ope_update_cpas_vote(hw_mgr, ctx_data); + + return rc; +} + +static int cam_ope_mgr_ope_clk_remove(struct cam_ope_hw_mgr *hw_mgr, int ctx_id) +{ + struct cam_ope_ctx *ctx_data = NULL; + struct cam_ope_clk_info *hw_mgr_clk_info; + + ctx_data = &hw_mgr->ctx[ctx_id]; + hw_mgr_clk_info = &hw_mgr->clk_info; + + if (hw_mgr_clk_info->base_clk >= ctx_data->clk_info.base_clk) + hw_mgr_clk_info->base_clk -= ctx_data->clk_info.base_clk; + + /* reset clock info */ + ctx_data->clk_info.curr_fc = 0; + ctx_data->clk_info.base_clk = 0; + + return 0; +} + static int cam_ope_mgr_release_ctx(struct cam_ope_hw_mgr *hw_mgr, int ctx_id) { int i = 0, rc = 0; @@ -2286,6 +2808,7 @@ static int cam_ope_mgr_release_ctx(struct cam_ope_hw_mgr *hw_mgr, int ctx_id) kzfree(hw_mgr->ctx[ctx_id].req_list[i]->cdm_cmd); hw_mgr->ctx[ctx_id].req_list[i]->cdm_cmd = NULL; } + cam_ope_free_io_config(hw_mgr->ctx[ctx_id].req_list[i]); kzfree(hw_mgr->ctx[ctx_id].req_list[i]); hw_mgr->ctx[ctx_id].req_list[i] = NULL; clear_bit(i, hw_mgr->ctx[ctx_id].bitmap); @@ -2294,7 +2817,13 @@ static int cam_ope_mgr_release_ctx(struct cam_ope_hw_mgr *hw_mgr, int ctx_id) cam_ope_req_timer_stop(&hw_mgr->ctx[ctx_id]); hw_mgr->ctx[ctx_id].ope_cdm.cdm_handle = 0; hw_mgr->ctx[ctx_id].req_cnt = 0; + hw_mgr->ctx[ctx_id].last_flush_req = 0; cam_ope_put_free_ctx(hw_mgr, ctx_id); + + rc = cam_ope_mgr_ope_clk_remove(hw_mgr, ctx_id); + if (rc) + CAM_ERR(CAM_OPE, "OPE clk update failed: %d", rc); + hw_mgr->ope_ctx_cnt--; mutex_unlock(&hw_mgr->ctx[ctx_id].ctx_mutex); CAM_DBG(CAM_OPE, "X: ctx_id = %d", ctx_id); @@ -2363,6 +2892,21 @@ static int cam_ope_mgr_release_hw(void *hw_priv, void *hw_release_args) cam_ope_device_timer_stop(hw_mgr); } + rc = cam_ope_mgr_remove_bw(hw_mgr, ctx_id); + if (rc) + CAM_ERR(CAM_OPE, "OPE remove bw failed: %d", rc); + + if (!hw_mgr->ope_ctx_cnt) { + for (i = 0; i < ope_hw_mgr->num_ope; i++) { + dev_intf = hw_mgr->ope_dev_intf[i]; + rc = dev_intf->hw_ops.stop( + hw_mgr->ope_dev_intf[i]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_OPE, "stop failed: %d", rc); + } + } + mutex_unlock(&hw_mgr->hw_mgr_mutex); CAM_DBG(CAM_OPE, "Release done for ctx_id %d", ctx_id); @@ -2498,6 +3042,7 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, uintptr_t ope_cmd_buf_addr; uint32_t request_idx = 0; struct cam_ope_request *ope_req; + struct timespec64 ts; if ((!prepare_args) || (!hw_mgr) || (!prepare_args->packet)) { CAM_ERR(CAM_OPE, "Invalid args: %x %x", @@ -2523,14 +3068,18 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, rc = cam_packet_util_validate_packet(packet, prepare_args->remain_len); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); - CAM_ERR(CAM_OPE, "packet validation is failed: %d", rc); + CAM_ERR(CAM_OPE, + "packet validation failed: %d req_id: %d ctx: %d", + rc, packet->header.request_id, ctx_data->ctx_id); return rc; } rc = cam_ope_mgr_pkt_validation(packet); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); - CAM_ERR(CAM_OPE, "ope packet validation is failed"); + CAM_ERR(CAM_OPE, + "ope packet validation failed: %d req_id: %d ctx: %d", + rc, packet->header.request_id, ctx_data->ctx_id); return -EINVAL; } @@ -2538,7 +3087,8 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, hw_mgr->iommu_sec_cdm_hdl); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); - CAM_ERR(CAM_OPE, "Patching is failed: %d", rc); + CAM_ERR(CAM_OPE, "Patching failed: %d req_id: %d ctx: %d", + rc, packet->header.request_id, ctx_data->ctx_id); return -EINVAL; } @@ -2548,11 +3098,19 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, CAM_ERR(CAM_OPE, "Invalid ctx req slot = %d", request_idx); return -EINVAL; } + get_monotonic_boottime64(&ts); + ctx_data->last_req_time = (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + CAM_DBG(CAM_REQ, "req_id= %llu ctx_id= %d lrt=%llu", + packet->header.request_id, ctx_data->ctx_id, + ctx_data->last_req_time); + cam_ope_req_timer_modify(ctx_data, OPE_REQUEST_TIMEOUT); set_bit(request_idx, ctx_data->bitmap); - cam_ope_req_timer_reset(ctx_data); ctx_data->req_list[request_idx] = kzalloc(sizeof(struct cam_ope_request), GFP_KERNEL); if (!ctx_data->req_list[request_idx]) { + CAM_ERR(CAM_OPE, "mem allocation failed ctx:%d req_idx:%d", + ctx_data->ctx_id, request_idx); rc = -ENOMEM; mutex_unlock(&ctx_data->ctx_mutex); goto req_mem_alloc_failed; @@ -2565,6 +3123,8 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); if (!ope_req->cdm_cmd) { + CAM_ERR(CAM_OPE, "Cdm mem alloc failed ctx:%d req_idx:%d", + ctx_data->ctx_id, request_idx); rc = -ENOMEM; mutex_unlock(&ctx_data->ctx_mutex); goto req_cdm_mem_alloc_failed; @@ -2574,7 +3134,9 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, ctx_data, &ope_cmd_buf_addr, request_idx); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); - CAM_ERR(CAM_OPE, "cmd desc processing failed: %d", rc); + CAM_ERR(CAM_OPE, + "cmd desc processing failed :%d ctx: %d req_id:%d", + rc, ctx_data->ctx_id, packet->header.request_id); goto end; } @@ -2582,7 +3144,9 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, ctx_data, request_idx); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); - CAM_ERR(CAM_OPE, "IO cfg processing failed: %d", rc); + CAM_ERR(CAM_OPE, + "IO cfg processing failed: %d ctx: %d req_id:%d", + rc, ctx_data->ctx_id, packet->header.request_id); goto end; } @@ -2590,7 +3154,9 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, ctx_data, request_idx, ope_cmd_buf_addr); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); - CAM_ERR(CAM_OPE, "cam_ope_mgr_create_kmd_buf failed: %d", rc); + CAM_ERR(CAM_OPE, + "create kmd buf failed: %d ctx: %d request_id:%d", + rc, ctx_data->ctx_id, packet->header.request_id); goto end; } @@ -2598,16 +3164,21 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, request_idx, NULL); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); - CAM_ERR(CAM_OPE, "Failed: %d", rc); + CAM_ERR(CAM_OPE, "Failed: %d ctx: %d req_id: %d req_idx: %d", + rc, ctx_data->ctx_id, packet->header.request_id, + request_idx); goto end; } prepare_args->num_hw_update_entries = 1; prepare_args->hw_update_entries[0].addr = (uintptr_t)ctx_data->req_list[request_idx]->cdm_cmd; prepare_args->priv = ctx_data->req_list[request_idx]; - + prepare_args->pf_data->packet = packet; + ope_req->hang_data.packet = packet; mutex_unlock(&ctx_data->ctx_mutex); + CAM_DBG(CAM_REQ, "Prepare Hw update Successful request_id: %d ctx: %d", + packet->header.request_id, ctx_data->ctx_id); return rc; end: @@ -2638,6 +3209,7 @@ static int cam_ope_mgr_handle_config_err( ope_req->request_id = 0; kzfree(ctx_data->req_list[req_idx]->cdm_cmd); ctx_data->req_list[req_idx]->cdm_cmd = NULL; + cam_ope_free_io_config(ctx_data->req_list[req_idx]); kzfree(ctx_data->req_list[req_idx]); ctx_data->req_list[req_idx] = NULL; clear_bit(req_idx, ctx_data->bitmap); @@ -2657,8 +3229,9 @@ static int cam_ope_mgr_enqueue_config(struct cam_ope_hw_mgr *hw_mgr, struct cam_ope_request *ope_req = NULL; ope_req = config_args->priv; - request_id = ope_req->request_id; + request_id = config_args->request_id; hw_update_entries = config_args->hw_update_entries; + CAM_DBG(CAM_OPE, "req_id = %lld %pK", request_id, config_args->priv); task = cam_req_mgr_workq_get_task(ope_hw_mgr->cmd_work); @@ -2717,11 +3290,18 @@ static int cam_ope_mgr_config_hw(void *hw_priv, void *hw_config_args) cam_ope_mgr_ope_clk_update(hw_mgr, ctx_data, ope_req->req_idx); + if (ope_req->request_id <= ctx_data->last_flush_req) + CAM_WARN(CAM_OPE, + "Anomaly submitting flushed req %llu [last_flush %llu] in ctx %u", + ope_req->request_id, ctx_data->last_flush_req, + ctx_data->ctx_id); + rc = cam_ope_mgr_enqueue_config(hw_mgr, ctx_data, config_args); if (rc) goto config_err; - CAM_DBG(CAM_OPE, "req_id %llu, io config", ope_req->request_id); + CAM_DBG(CAM_REQ, "req_id %llu, ctx_id %u io config", + ope_req->request_id, ctx_data->ctx_id); mutex_unlock(&ctx_data->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); @@ -2793,6 +3373,7 @@ static int cam_ope_mgr_flush_req(struct cam_ope_ctx *ctx_data, ctx_data->req_list[idx]->request_id = 0; kzfree(ctx_data->req_list[idx]->cdm_cmd); ctx_data->req_list[idx]->cdm_cmd = NULL; + cam_ope_free_io_config(ctx_data->req_list[idx]); kzfree(ctx_data->req_list[idx]); ctx_data->req_list[idx] = NULL; clear_bit(idx, ctx_data->bitmap); @@ -2825,6 +3406,7 @@ static int cam_ope_mgr_flush_all(struct cam_ope_ctx *ctx_data, ctx_data->req_list[i]->request_id = 0; kzfree(ctx_data->req_list[i]->cdm_cmd); ctx_data->req_list[i]->cdm_cmd = NULL; + cam_ope_free_io_config(ctx_data->req_list[i]); kzfree(ctx_data->req_list[i]); ctx_data->req_list[i] = NULL; clear_bit(i, ctx_data->bitmap); @@ -2838,6 +3420,7 @@ static int cam_ope_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; struct cam_ope_ctx *ctx_data; + struct cam_ope_hw_mgr *hw_mgr = ope_hw_mgr; if ((!hw_priv) || (!hw_flush_args)) { CAM_ERR(CAM_OPE, "Input params are Null"); @@ -2857,12 +3440,17 @@ static int cam_ope_mgr_hw_flush(void *hw_priv, void *hw_flush_args) return -EINVAL; } - CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d", - ctx_data->ctx_id, flush_args->flush_type); - switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: + mutex_lock(&hw_mgr->hw_mgr_mutex); + ctx_data->last_flush_req = flush_args->last_flush_req; + + CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d last_flush_req %u", + ctx_data->ctx_id, flush_args->flush_type, + ctx_data->last_flush_req); + cam_ope_mgr_flush_all(ctx_data, flush_args); + mutex_unlock(&hw_mgr->hw_mgr_mutex); break; case CAM_FLUSH_TYPE_REQ: mutex_lock(&ctx_data->ctx_mutex); diff --git a/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h b/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h index f7dcf9139d..07ef8203bb 100644 --- a/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h +++ b/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h @@ -60,6 +60,8 @@ #define CLK_HW_MAX 0x1 #define OPE_DEVICE_IDLE_TIMEOUT 400 +#define OPE_REQUEST_TIMEOUT 200 + /** @@ -223,12 +225,14 @@ struct cdm_dmi_cmd { * @iova_addr: IOVA address * @len: Buffer length * @size: Buffer Size + * @offset: buffer offset */ struct ope_debug_buffer { uintptr_t cpu_addr; dma_addr_t iova_addr; size_t len; uint32_t size; + uint32_t offset; }; /** @@ -238,6 +242,7 @@ struct ope_debug_buffer { * @cpu_addr: CPU address * @iova_addr: IOVA address * @iova_cdm_addr: CDM IOVA address + * @offset: Offset of buffer * @len: Buffer length * @size: Buffer Size */ @@ -246,6 +251,7 @@ struct ope_kmd_buffer { uintptr_t cpu_addr; dma_addr_t iova_addr; dma_addr_t iova_cdm_addr; + uint32_t offset; size_t len; uint32_t size; }; @@ -383,6 +389,7 @@ struct ope_io_buf { * @cdm_cmd: CDM command for OPE CDM * @clk_info: Clock Info V1 * @clk_info_v2: Clock Info V2 + * @hang_data: Debug data for HW error */ struct cam_ope_request { uint64_t request_id; @@ -398,10 +405,11 @@ struct cam_ope_request { uint8_t num_stripe_cmd_bufs[OPE_MAX_BATCH_SIZE][OPE_MAX_STRIPES]; struct ope_kmd_buffer ope_kmd_buf; struct ope_debug_buffer ope_debug_buf; - struct ope_io_buf io_buf[OPE_MAX_BATCH_SIZE][OPE_MAX_IO_BUFS]; + struct ope_io_buf *io_buf[OPE_MAX_BATCH_SIZE][OPE_MAX_IO_BUFS]; struct cam_cdm_bl_request *cdm_cmd; struct cam_ope_clk_bw_request clk_info; struct cam_ope_clk_bw_req_internal_v2 clk_info_v2; + struct cam_hw_mgr_dump_pf_data hang_data; }; /** @@ -431,11 +439,13 @@ struct cam_ope_cdm { * @ctxt_event_cb: Callback of a context * @req_list: Request List * @ope_cdm: OPE CDM info + * @last_req_time: Timestamp of last request * @req_watch_dog: Watchdog for requests * @req_watch_dog_reset_counter: Request reset counter * @clk_info: OPE Ctx clock info * @clk_watch_dog: Clock watchdog * @clk_watch_dog_reset_counter: Reset counter + * @last_flush_req: last flush req for this ctx */ struct cam_ope_ctx { void *context_priv; @@ -451,11 +461,13 @@ struct cam_ope_ctx { cam_hw_event_cb_func ctxt_event_cb; struct cam_ope_request *req_list[CAM_CTX_REQ_MAX]; struct cam_ope_cdm ope_cdm; + uint64_t last_req_time; struct cam_req_mgr_timer *req_watch_dog; uint32_t req_watch_dog_reset_counter; struct cam_ctx_clk_info clk_info; struct cam_req_mgr_timer *clk_watch_dog; uint32_t clk_watch_dog_reset_counter; + uint64_t last_flush_req; }; /** @@ -506,6 +518,7 @@ struct cam_ope_hw_mgr { struct cam_ope_ctx ctx[OPE_CTX_MAX]; struct cam_hw_intf **devices[OPE_DEV_MAX]; struct ope_query_cap_cmd ope_caps; + uint64_t last_callback_time; struct cam_req_mgr_core_workq *cmd_work; struct cam_req_mgr_core_workq *msg_work; @@ -518,4 +531,68 @@ struct cam_ope_hw_mgr { struct cam_ope_clk_info clk_info; }; +/** + * struct cam_ope_buf_entry + * + * @fd: FD of cmd buffer + * @memhdl: Memhandle of cmd buffer + * @iova: IOVA address of cmd buffer + * @offset: Offset of cmd buffer + * @len: Length of cmd buffer + * @size: Size of cmd buffer + */ +struct cam_ope_buf_entry { + uint32_t fd; + uint64_t memhdl; + uint64_t iova; + uint64_t offset; + uint64_t len; + uint64_t size; +}; + +/** + * struct cam_ope_bl_entry + * + * @base: Base IOVA address of BL + * @len: Length of BL + * @arbitration: Arbitration bit + */ +struct cam_ope_bl_entry { + uint32_t base; + uint32_t len; + uint32_t arbitration; +}; + +/** + * struct cam_ope_output_info + * + * @iova: IOVA address of output buffer + * @offset: Offset of buffer + * @len: Length of buffer + */ +struct cam_ope_output_info { + uint64_t iova; + uint64_t offset; + uint64_t len; +}; + +/** + * struct cam_ope_hang_dump + * + * @num_bls: count of BLs for request + * @num_bufs: Count of buffer related to request + * @num_outputs: Count of output beffers + * @entries: Buffers info + * @bl_entries: BLs info + * @outputs: Output info + */ +struct cam_ope_hang_dump { + uint32_t num_bls; + uint32_t num_bufs; + uint64_t num_outputs; + struct cam_ope_buf_entry entries[OPE_MAX_BATCH_SIZE * OPE_MAX_CMD_BUFS]; + struct cam_ope_bl_entry bl_entries[OPE_MAX_CDM_BLS]; + struct cam_ope_output_info outputs + [OPE_MAX_BATCH_SIZE * OPE_OUT_RES_MAX]; +}; #endif /* CAM_OPE_HW_MGR_H */ diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c index 346016d2aa..d58d4dd5e9 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c @@ -29,6 +29,29 @@ static struct ope_bus_rd *bus_rd; +enum cam_ope_bus_unpacker_format { + UNPACKER_FMT_PLAIN_128 = 0x0, + UNPACKER_FMT_PLAIN_8 = 0x1, + UNPACKER_FMT_PLAIN_16_10BPP = 0x2, + UNPACKER_FMT_PLAIN_16_12BPP = 0x3, + UNPACKER_FMT_PLAIN_16_14BPP = 0x4, + UNPACKER_FMT_PLAIN_32_20BPP = 0x5, + UNPACKER_FMT_ARGB_16_10BPP = 0x6, + UNPACKER_FMT_ARGB_16_12BPP = 0x7, + UNPACKER_FMT_ARGB_16_14BPP = 0x8, + UNPACKER_FMT_PLAIN_32 = 0x9, + UNPACKER_FMT_PLAIN_64 = 0xA, + UNPACKER_FMT_TP_10 = 0xB, + UNPACKER_FMT_MIPI_8 = 0xC, + UNPACKER_FMT_MIPI_10 = 0xD, + UNPACKER_FMT_MIPI_12 = 0xE, + UNPACKER_FMT_MIPI_14 = 0xF, + UNPACKER_FMT_PLAIN_16_16BPP = 0x10, + UNPACKER_FMT_PLAIN_128_ODD_EVEN = 0x11, + UNPACKER_FMT_PLAIN_8_ODD_EVEN = 0x12, + UNPACKER_FMT_MAX = 0x13, +}; + static int cam_ope_bus_rd_in_port_idx(uint32_t input_port_id) { int i; @@ -98,12 +121,16 @@ static int cam_ope_bus_is_rm_enabled( } for (i = 0; i < ope_request->num_io_bufs[batch_idx]; i++) { - io_buf = &ope_request->io_buf[batch_idx][i]; + io_buf = ope_request->io_buf[batch_idx][i]; if (io_buf->direction != CAM_BUF_INPUT) continue; in_port_to_rm = &bus_rd->in_port_to_rm[io_buf->resource_type - 1]; combo_idx = cam_ope_bus_rd_combo_idx(io_buf->format); + if (combo_idx < 0) { + CAM_ERR(CAM_OPE, "Invalid combo_idx"); + return -EINVAL; + } for (k = 0; k < io_buf->num_planes; k++) { if (rm_id == in_port_to_rm->rm_port_id[combo_idx][k]) @@ -171,7 +198,7 @@ static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, rd_reg = ope_hw_info->bus_rd_reg; rd_reg_val = ope_hw_info->bus_rd_reg_val; - io_buf = &ope_request->io_buf[batch_idx][io_idx]; + io_buf = ope_request->io_buf[batch_idx][io_idx]; CAM_DBG(CAM_OPE, "batch:%d iobuf:%d direction:%d", batch_idx, io_idx, io_buf->direction); @@ -239,6 +266,14 @@ static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, rd_reg_client->stride; temp_reg[count++] = stripe_io->stride; + /* + * In case of NV12, change the unpacker format of + * chroma plane to odd even byte swapped format. + */ + if (k == 1 && stripe_io->format == CAM_FORMAT_NV12) + stripe_io->unpack_format = + UNPACKER_FMT_PLAIN_8_ODD_EVEN; + /* Unpack cfg : Mode and alignment */ temp_reg[count++] = rd_reg->offset + rd_reg_client->unpack_cfg; @@ -324,6 +359,11 @@ static uint32_t *cam_ope_bus_rm_disable(struct ope_hw *ope_hw_info, return NULL; } + if (rm_idx >= MAX_RD_CLIENTS) { + CAM_ERR(CAM_OPE, "Invalid read client: %d", rm_idx); + return NULL; + } + ctx_data = prepare->ctx_data; req_idx = prepare->req_idx; cdm_ops = ctx_data->ope_cdm.cdm_ops; @@ -403,9 +443,9 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, struct cam_ope_bus_rd_reg *rd_reg; struct cam_ope_bus_rd_reg_val *rd_reg_val; struct ope_bus_rd_io_port_cdm_batch *io_port_cdm_batch; - struct ope_bus_rd_io_port_cdm_info *io_port_cdm; + struct ope_bus_rd_io_port_cdm_info *io_port_cdm = NULL; struct cam_cdm_utils_ops *cdm_ops; - int32_t num_stripes; + int32_t num_stripes = 0; if (ctx_id < 0 || !data) { CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data); @@ -434,7 +474,7 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, for (i = 0; i < ope_request->num_batch; i++) { for (j = 0; j < ope_request->num_io_bufs[i]; j++) { - io_buf = &ope_request->io_buf[i][j]; + io_buf = ope_request->io_buf[i][j]; if (io_buf->direction != CAM_BUF_INPUT) continue; @@ -469,12 +509,20 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, for (j = 0; j < rd_reg_val->num_clients; j++) { is_rm_enabled = cam_ope_bus_is_rm_enabled( ope_request, i, j); + if (is_rm_enabled < 0) { + rc = -EINVAL; + goto end; + } if (is_rm_enabled) continue; kmd_buf = cam_ope_bus_rm_disable(ope_hw_info, ctx_id, prepare, i, j, kmd_buf, num_stripes); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } } } @@ -772,7 +820,7 @@ static int cam_ope_bus_rd_isr(struct ope_hw *ope_hw_info, if (irq_status & bus_rd_reg_val->rst_done) { complete(&bus_rd->reset_complete); - CAM_ERR(CAM_OPE, "ope bus rd reset done"); + CAM_DBG(CAM_OPE, "ope bus rd reset done"); } if ((irq_status & bus_rd_reg_val->violation) == diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c index 75d7339e0b..bade41972a 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c @@ -29,6 +29,24 @@ static struct ope_bus_wr *wr_info; +enum cam_ope_bus_packer_format { + PACKER_FMT_PLAIN_128 = 0x0, + PACKER_FMT_PLAIN_8 = 0x1, + PACKER_FMT_PLAIN_8_ODD_EVEN = 0x2, + PACKER_FMT_PLAIN_8_LSB_MSB_10 = 0x3, + PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN = 0x4, + PACKER_FMT_PLAIN_16_10BPP = 0x5, + PACKER_FMT_PLAIN_16_12BPP = 0x6, + PACKER_FMT_PLAIN_16_14BPP = 0x7, + PACKER_FMT_PLAIN_16_16BPP = 0x8, + PACKER_FMT_PLAIN_32 = 0x9, + PACKER_FMT_PLAIN_64 = 0xA, + PACKER_FMT_TP_10 = 0xB, + PACKER_FMT_MIPI_10 = 0xC, + PACKER_FMT_MIPI_12 = 0xD, + PACKER_FMT_MAX = 0xE, +}; + static int cam_ope_bus_en_port_idx( struct cam_ope_request *ope_request, uint32_t batch_idx, @@ -43,7 +61,7 @@ static int cam_ope_bus_en_port_idx( } for (i = 0; i < ope_request->num_io_bufs[batch_idx]; i++) { - io_buf = &ope_request->io_buf[batch_idx][i]; + io_buf = ope_request->io_buf[batch_idx][i]; if (io_buf->direction != CAM_BUF_OUTPUT) continue; if (io_buf->resource_type == output_port_id) @@ -133,25 +151,15 @@ static int cam_ope_bus_wr_subsample( static int cam_ope_bus_wr_release(struct ope_hw *ope_hw_info, int32_t ctx_id, void *data) { - int rc = 0, i; - struct ope_acquire_dev_info *in_acquire; - struct ope_bus_wr_ctx *bus_wr_ctx; + int rc = 0; - if (ctx_id < 0) { + if (ctx_id < 0 || ctx_id >= OPE_CTX_MAX) { CAM_ERR(CAM_OPE, "Invalid data: %d", ctx_id); return -EINVAL; } - in_acquire = wr_info->bus_wr_ctx[ctx_id].ope_acquire; - wr_info->bus_wr_ctx[ctx_id].ope_acquire = NULL; - bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id]; - bus_wr_ctx->num_out_ports = 0; - - for (i = 0; i < bus_wr_ctx->num_out_ports; i++) { - bus_wr_ctx->io_port_info.output_port_id[i] = 0; - bus_wr_ctx->io_port_info.output_format_type[i - 1] = 0; - bus_wr_ctx->io_port_info.pixel_pattern[i - 1] = 0; - } + vfree(wr_info->bus_wr_ctx[ctx_id]); + wr_info->bus_wr_ctx[ctx_id] = NULL; return rc; } @@ -208,7 +216,7 @@ static uint32_t *cam_ope_bus_wr_update(struct ope_hw *ope_hw_info, cdm_ops = ctx_data->ope_cdm.cdm_ops; ope_request = ctx_data->req_list[req_idx]; - bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id]; + bus_wr_ctx = wr_info->bus_wr_ctx[ctx_id]; io_port_cdm_batch = &bus_wr_ctx->io_port_cdm_batch; wr_reg = ope_hw_info->bus_wr_reg; wr_reg_val = ope_hw_info->bus_wr_reg_val; @@ -217,7 +225,7 @@ static uint32_t *cam_ope_bus_wr_update(struct ope_hw *ope_hw_info, kmd_buf, req_idx, ope_request->request_id, prepare->kmd_buf_offset); - io_buf = &ope_request->io_buf[batch_idx][io_idx]; + io_buf = ope_request->io_buf[batch_idx][io_idx]; CAM_DBG(CAM_OPE, "batch = %d io buf num = %d dir = %d", batch_idx, io_idx, io_buf->direction); @@ -286,6 +294,16 @@ static uint32_t *cam_ope_bus_wr_update(struct ope_hw *ope_hw_info, temp_reg[count++] = wr_reg->offset + wr_reg_client->pack_cfg; temp = 0; + + /* + * In case of NV12, change the packer format of chroma + * plane to odd even byte swapped format + */ + + if (k == 1 && stripe_io->format == CAM_FORMAT_NV12) + stripe_io->pack_format = + PACKER_FMT_PLAIN_8_ODD_EVEN; + temp |= ((stripe_io->pack_format & wr_res_val_client->format_mask) << wr_res_val_client->format_shift); @@ -376,7 +394,7 @@ static uint32_t *cam_ope_bus_wm_disable(struct ope_hw *ope_hw_info, req_idx = prepare->req_idx; cdm_ops = ctx_data->ope_cdm.cdm_ops; - bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id]; + bus_wr_ctx = wr_info->bus_wr_ctx[ctx_id]; io_port_cdm_batch = &bus_wr_ctx->io_port_cdm_batch; wr_reg = ope_hw_info->bus_wr_reg; @@ -466,7 +484,7 @@ static int cam_ope_bus_wr_prepare(struct ope_hw *ope_hw_info, prepare = data; ctx_data = prepare->ctx_data; req_idx = prepare->req_idx; - bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id]; + bus_wr_ctx = wr_info->bus_wr_ctx[ctx_id]; ope_request = ctx_data->req_list[req_idx]; kmd_buf = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr + @@ -477,13 +495,13 @@ static int cam_ope_bus_wr_prepare(struct ope_hw *ope_hw_info, kmd_buf, req_idx, ope_request->request_id, prepare->kmd_buf_offset); - io_port_cdm_batch = &wr_info->bus_wr_ctx[ctx_id].io_port_cdm_batch; + io_port_cdm_batch = &wr_info->bus_wr_ctx[ctx_id]->io_port_cdm_batch; memset(io_port_cdm_batch, 0, sizeof(struct ope_bus_wr_io_port_cdm_batch)); for (i = 0; i < ope_request->num_batch; i++) { for (j = 0; j < ope_request->num_io_bufs[i]; j++) { - io_buf = &ope_request->io_buf[i][j]; + io_buf = ope_request->io_buf[i][j]; CAM_DBG(CAM_OPE, "batch = %d io buf num = %d dir = %d", i, j, io_buf->direction); if (io_buf->direction != CAM_BUF_OUTPUT) @@ -533,14 +551,20 @@ static int cam_ope_bus_wr_acquire(struct ope_hw *ope_hw_info, int combo_idx; int out_port_idx; - if (ctx_id < 0 || !data) { + if (ctx_id < 0 || !data || ctx_id >= OPE_CTX_MAX) { CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data); return -EINVAL; } - wr_info->bus_wr_ctx[ctx_id].ope_acquire = data; + wr_info->bus_wr_ctx[ctx_id] = vzalloc(sizeof(struct ope_bus_wr_ctx)); + if (!wr_info->bus_wr_ctx[ctx_id]) { + CAM_ERR(CAM_OPE, "Out of memory"); + return -ENOMEM; + } + + wr_info->bus_wr_ctx[ctx_id]->ope_acquire = data; in_acquire = data; - bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id]; + bus_wr_ctx = wr_info->bus_wr_ctx[ctx_id]; bus_wr_ctx->num_out_ports = in_acquire->num_out_res; bus_wr_ctx->security_flag = in_acquire->secure_mode; @@ -688,11 +712,12 @@ static int cam_ope_bus_wr_isr(struct ope_hw *ope_hw_info, int32_t ctx_id, void *data) { int rc = 0; - uint32_t irq_status_0, irq_status_1; + uint32_t irq_status_0, irq_status_1, violation_status; struct cam_ope_bus_wr_reg *bus_wr_reg; struct cam_ope_bus_wr_reg_val *bus_wr_reg_val; + struct cam_ope_irq_data *irq_data = data; - if (!ope_hw_info) { + if (!ope_hw_info || !irq_data) { CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); return -EINVAL; } @@ -712,15 +737,26 @@ static int cam_ope_bus_wr_isr(struct ope_hw *ope_hw_info, bus_wr_reg->base + bus_wr_reg->irq_cmd); if (irq_status_0 & bus_wr_reg_val->cons_violation) { + irq_data->error = 1; CAM_ERR(CAM_OPE, "ope bus wr cons_violation"); } if (irq_status_0 & bus_wr_reg_val->violation) { - CAM_ERR(CAM_OPE, "ope bus wr vioalation"); + irq_data->error = 1; + violation_status = cam_io_r_mb(bus_wr_reg->base + + bus_wr_reg->violation_status); + CAM_ERR(CAM_OPE, + "ope bus wr violation, violation_status 0x%x", + violation_status); } if (irq_status_0 & bus_wr_reg_val->img_size_violation) { - CAM_ERR(CAM_OPE, "ope bus wr img_size_violation"); + irq_data->error = 1; + violation_status = cam_io_r_mb(bus_wr_reg->base + + bus_wr_reg->image_size_violation_status); + CAM_ERR(CAM_OPE, + "ope bus wr img_size_violation, violation_status 0x%x", + violation_status); } return rc; @@ -769,7 +805,7 @@ int cam_ope_bus_wr_process(struct ope_hw *ope_hw_info, CAM_DBG(CAM_OPE, "Unhandled cmds: %d", cmd_id); break; case OPE_HW_ISR: - rc = cam_ope_bus_wr_isr(ope_hw_info, 0, NULL); + rc = cam_ope_bus_wr_isr(ope_hw_info, 0, data); break; default: CAM_ERR(CAM_OPE, "Unsupported cmd: %d", cmd_id); diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.h b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.h index 0eb052b168..ed9b8cca68 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.h +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.h @@ -130,7 +130,7 @@ struct ope_bus_wr_ctx { struct ope_bus_wr { struct ope_hw *ope_hw_info; struct ope_bus_out_port_to_wm out_port_to_wm[OPE_OUT_RES_MAX]; - struct ope_bus_wr_ctx bus_wr_ctx[OPE_CTX_MAX]; + struct ope_bus_wr_ctx *bus_wr_ctx[OPE_CTX_MAX]; }; #endif /* OPE_BUS_WR_H */ diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c index 1fc49cebbb..8a46b71241 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c @@ -96,7 +96,29 @@ int cam_ope_start(void *hw_priv, void *start_args, uint32_t arg_size) int cam_ope_stop(void *hw_priv, void *start_args, uint32_t arg_size) { - return 0; + struct cam_hw_info *ope_dev = hw_priv; + struct cam_ope_device_core_info *core_info = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_OPE, "Invalid cam_dev_info"); + return -EINVAL; + } + + core_info = (struct cam_ope_device_core_info *)ope_dev->core_info; + if (!core_info) { + CAM_ERR(CAM_OPE, "core_info = %pK", core_info); + return -EINVAL; + } + + if (core_info->cpas_start) { + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_OPE, "cpas stop is failed"); + else + core_info->cpas_start = false; + } + + return rc; } int cam_ope_flush(void *hw_priv, void *flush_args, uint32_t arg_size) @@ -149,14 +171,15 @@ int cam_ope_init_hw(void *device_priv, struct cam_hw_info *ope_dev = device_priv; struct cam_hw_soc_info *soc_info = NULL; struct cam_ope_device_core_info *core_info = NULL; - struct cam_ope_cpas_vote cpas_vote; + struct cam_ope_cpas_vote *cpas_vote; int rc = 0; struct cam_ope_dev_init *init; struct ope_hw *ope_hw; if (!device_priv) { CAM_ERR(CAM_OPE, "Invalid cam_dev_info"); - return -EINVAL; + rc = -EINVAL; + goto end; } soc_info = &ope_dev->soc_info; @@ -164,55 +187,72 @@ int cam_ope_init_hw(void *device_priv, if ((!soc_info) || (!core_info)) { CAM_ERR(CAM_OPE, "soc_info = %pK core_info = %pK", soc_info, core_info); - return -EINVAL; + rc = -EINVAL; + goto end; } ope_hw = core_info->ope_hw_info->ope_hw; + cpas_vote = kzalloc(sizeof(struct cam_ope_cpas_vote), GFP_KERNEL); + if (!cpas_vote) { + CAM_ERR(CAM_ISP, "Out of memory"); + rc = -ENOMEM; + goto end; + } - cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; - cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; - cpas_vote.axi_vote.num_paths = 1; - cpas_vote.axi_vote.axi_path[0].path_data_type = + cpas_vote->ahb_vote.type = CAM_VOTE_ABSOLUTE; + cpas_vote->ahb_vote.vote.level = CAM_SVS_VOTE; + cpas_vote->axi_vote.num_paths = 1; + cpas_vote->axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; - cpas_vote.axi_vote.axi_path[0].transac_type = + cpas_vote->axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; - cpas_vote.axi_vote.axi_path[0].camnoc_bw = + cpas_vote->axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; - cpas_vote.axi_vote.axi_path[0].mnoc_ab_bw = + cpas_vote->axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; - cpas_vote.axi_vote.axi_path[0].mnoc_ib_bw = + cpas_vote->axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; - cpas_vote.axi_vote.axi_path[0].ddr_ab_bw = + cpas_vote->axi_vote.axi_path[0].ddr_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; - cpas_vote.axi_vote.axi_path[0].ddr_ib_bw = + cpas_vote->axi_vote.axi_path[0].ddr_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; rc = cam_cpas_start(core_info->cpas_handle, - &cpas_vote.ahb_vote, &cpas_vote.axi_vote); + &cpas_vote->ahb_vote, &cpas_vote->axi_vote); if (rc) { CAM_ERR(CAM_OPE, "cpass start failed: %d", rc); - return rc; + goto free_cpas_vote; } core_info->cpas_start = true; rc = cam_ope_enable_soc_resources(soc_info); - if (rc) { - CAM_ERR(CAM_OPE, "soc enable is failed : %d", rc); - if (cam_cpas_stop(core_info->cpas_handle)) - CAM_ERR(CAM_OPE, "cpas stop is failed"); - else - core_info->cpas_start = false; - } else { + if (rc) + goto enable_soc_resource_failed; + else core_info->clk_enable = true; - } init = init_hw_args; core_info->ope_hw_info->hfi_en = init->hfi_en; init->core_info = core_info; - rc = cam_ope_process_init(ope_hw, init_hw_args, init->hfi_en); + if (rc) + goto process_init_failed; + else + goto free_cpas_vote; +process_init_failed: + if (cam_ope_disable_soc_resources(soc_info, core_info->clk_enable)) + CAM_ERR(CAM_OPE, "disable soc resource failed"); +enable_soc_resource_failed: + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_OPE, "cpas stop is failed"); + else + core_info->cpas_start = false; +free_cpas_vote: + kzfree(cpas_vote); + cpas_vote = NULL; +end: return rc; } @@ -242,12 +282,15 @@ int cam_ope_deinit_hw(void *device_priv, CAM_ERR(CAM_OPE, "soc disable is failed : %d", rc); core_info->clk_enable = false; - if (core_info->cpas_start) { - if (cam_cpas_stop(core_info->cpas_handle)) - CAM_ERR(CAM_OPE, "cpas stop is failed"); - else - core_info->cpas_start = false; - } + return rc; +} + +static int cam_ope_dev_process_dump_debug_reg(struct ope_hw *ope_hw) +{ + int rc = 0; + + rc = cam_ope_top_process(ope_hw, -1, + OPE_HW_DUMP_DEBUG, NULL); return rc; } @@ -310,14 +353,11 @@ static int cam_ope_dev_process_acquire(struct ope_hw *ope_hw, void *cmd_args) return 0; bus_wr_acquire_fail: - rc = cam_ope_bus_rd_process(ope_hw, ope_dev_acquire->ctx_id, + cam_ope_bus_rd_process(ope_hw, ope_dev_acquire->ctx_id, OPE_HW_RELEASE, ope_dev_acquire->ope_acquire); bus_rd_acquire_fail: - rc = cam_ope_top_process(ope_hw, ope_dev_acquire->ctx_id, + cam_ope_top_process(ope_hw, ope_dev_acquire->ctx_id, OPE_HW_RELEASE, ope_dev_acquire->ope_acquire); - if (rc) - goto top_acquire_fail; - top_acquire_fail: return rc; } @@ -340,16 +380,17 @@ static int cam_ope_dev_prepare_cdm_request( kmd_buf = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr + kmd_buf_offset; - cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_HW_IOVA; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; cdm_cmd->flag = true; cdm_cmd->userdata = ctx_data; cdm_cmd->cookie = req_idx; cdm_cmd->gen_irq_arb = true; i = cdm_cmd->cmd_arrary_count; - cdm_cmd->cmd[i].bl_addr.hw_iova = - (uint32_t *)ope_request->ope_kmd_buf.iova_cdm_addr; - cdm_cmd->cmd[i].offset = kmd_buf_offset; + cdm_cmd->cmd[i].bl_addr.mem_handle = + ope_request->ope_kmd_buf.mem_handle; + cdm_cmd->cmd[i].offset = kmd_buf_offset + + ope_request->ope_kmd_buf.offset; cdm_cmd->cmd[i].len = len; cdm_cmd->cmd[i].arbitrate = arbitrate; @@ -365,6 +406,7 @@ static int cam_ope_dev_prepare_cdm_request( return 0; } + static int dump_dmi_cmd(uint32_t print_idx, uint32_t *print_ptr, struct cdm_dmi_cmd *dmi_cmd, uint32_t *temp) @@ -449,119 +491,6 @@ static int dump_stripe_cmd(struct ope_frame_process *frm_proc, return 0; } -static uint32_t *ope_create_frame_cmd_prefetch_dis( - struct cam_ope_hw_mgr *hw_mgr, - struct cam_ope_ctx *ctx_data, uint32_t req_idx, - uint32_t *kmd_buf, uint32_t buffered, int batch_idx, - struct cam_ope_dev_prepare_req *ope_dev_prepare_req) -{ - int rc = 0, i, j; - uint32_t temp[3]; - struct cam_ope_request *ope_request; - struct cdm_dmi_cmd *dmi_cmd; - struct ope_bus_wr_io_port_cdm_info *wr_cdm_info; - struct ope_bus_rd_io_port_cdm_info *rd_cdm_info; - struct ope_frame_process *frm_proc; - dma_addr_t iova_addr; - uintptr_t cpu_addr; - size_t buf_len; - uint32_t print_idx; - uint32_t *print_ptr; - int num_dmi = 0; - struct cam_cdm_utils_ops *cdm_ops; - - frm_proc = ope_dev_prepare_req->frame_process; - ope_request = ctx_data->req_list[req_idx]; - cdm_ops = ctx_data->ope_cdm.cdm_ops; - wr_cdm_info = - &ope_dev_prepare_req->wr_cdm_batch->io_port_cdm[0]; - rd_cdm_info = - &ope_dev_prepare_req->rd_cdm_batch->io_port_cdm[0]; - - if (batch_idx >= OPE_MAX_BATCH_SIZE) { - CAM_ERR(CAM_OPE, "Invalid input: %d", batch_idx); - return NULL; - } - - i = batch_idx; - - for (j = 0; j < frm_proc->num_cmd_bufs[i]; j++) { - if (frm_proc->cmd_buf[i][j].cmd_buf_scope != - OPE_CMD_BUF_SCOPE_FRAME) - continue; - - if (frm_proc->cmd_buf[i][j].cmd_buf_usage == - OPE_CMD_BUF_KMD || - frm_proc->cmd_buf[i][j].cmd_buf_usage == - OPE_CMD_BUF_DEBUG) - continue; - - if (frm_proc->cmd_buf[i][j].prefetch_disable && - frm_proc->cmd_buf[i][j].cmd_buf_buffered != - buffered) - continue; - - if (!frm_proc->cmd_buf[i][j].mem_handle) - continue; - - rc = cam_mem_get_io_buf( - frm_proc->cmd_buf[i][j].mem_handle, - hw_mgr->iommu_cdm_hdl, &iova_addr, &buf_len); - if (rc) { - CAM_ERR(CAM_OPE, "get cmd buf failed %x", - hw_mgr->iommu_hdl); - return NULL; - } - iova_addr = iova_addr + frm_proc->cmd_buf[i][j].offset; - - rc = cam_mem_get_cpu_buf( - frm_proc->cmd_buf[i][j].mem_handle, - &cpu_addr, &buf_len); - if (rc || !cpu_addr) { - CAM_ERR(CAM_OPE, "get cmd buf failed %x", - hw_mgr->iommu_hdl); - return NULL; - } - - cpu_addr = cpu_addr + frm_proc->cmd_buf[i][j].offset; - if (frm_proc->cmd_buf[i][j].type == - OPE_CMD_BUF_TYPE_DIRECT) { - kmd_buf = cdm_ops->cdm_write_indirect(kmd_buf, - iova_addr, - frm_proc->cmd_buf[i][j].length); - print_ptr = (uint32_t *)cpu_addr; - dump_frame_direct(print_idx, print_ptr, - frm_proc, i, j); - } else { - num_dmi = frm_proc->cmd_buf[i][j].length / - sizeof(struct cdm_dmi_cmd); - CAM_DBG(CAM_OPE, "Frame DB : In direct: E"); - print_ptr = (uint32_t *)cpu_addr; - for (print_idx = 0; - print_idx < num_dmi; print_idx++) { - memcpy(temp, (const void *)print_ptr, - sizeof(struct cdm_dmi_cmd)); - dmi_cmd = (struct cdm_dmi_cmd *)temp; - kmd_buf = cdm_ops->cdm_write_dmi( - kmd_buf, - 0, dmi_cmd->DMIAddr, - dmi_cmd->DMISel, dmi_cmd->addr, - dmi_cmd->length); - dump_dmi_cmd(print_idx, - print_ptr, dmi_cmd, temp); - print_ptr += - sizeof(struct cdm_dmi_cmd) / - sizeof(uint32_t); - } - CAM_DBG(CAM_OPE, "Frame DB : In direct: X"); - } - dump_frame_cmd(frm_proc, i, j, - iova_addr, kmd_buf, buf_len); - } - return kmd_buf; - -} - static uint32_t *ope_create_frame_cmd_batch(struct cam_ope_hw_mgr *hw_mgr, struct cam_ope_ctx *ctx_data, uint32_t req_idx, uint32_t *kmd_buf, uint32_t buffered, int batch_idx, @@ -1372,15 +1301,6 @@ static int cam_ope_dev_create_kmd_buf_batch(struct cam_ope_hw_mgr *hw_mgr, /* After second batch DB programming add prefecth dis */ if (i) { - /* program db buffered prefecth disable cmds */ - kmd_buf = ope_create_frame_cmd_prefetch_dis(hw_mgr, - ctx_data, req_idx, - kmd_buf, OPE_CMD_BUF_DOUBLE_BUFFERED, i, - ope_dev_prepare_req); - if (!kmd_buf) { - rc = -EINVAL; - goto end; - } kmd_buf = cdm_ops->cdm_write_wait_prefetch_disable( kmd_buf, 0x0, @@ -1621,6 +1541,15 @@ static int cam_ope_process_probe(struct ope_hw *ope_hw, return -EINVAL; } +static int cam_ope_process_dump_debug_reg(struct ope_hw *ope_hw, + bool hfi_en) +{ + if (!hfi_en) + return cam_ope_dev_process_dump_debug_reg(ope_hw); + + return -EINVAL; +} + static int cam_ope_process_reset(struct ope_hw *ope_hw, void *cmd_args, bool hfi_en) { @@ -1762,6 +1691,9 @@ int cam_ope_process_cmd(void *device_priv, uint32_t cmd_type, spin_unlock_irqrestore(&ope_dev->hw_lock, flags); } break; + case OPE_HW_DUMP_DEBUG: + rc = cam_ope_process_dump_debug_reg(ope_hw, hfi_en); + break; default: break; } diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev_intf.h b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev_intf.h index 9e35fb8061..1e191961b5 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev_intf.h +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev_intf.h @@ -28,6 +28,7 @@ #define OPE_HW_SET_IRQ_CB 0xE #define OPE_HW_CLK_DISABLE 0xF #define OPE_HW_CLK_ENABLE 0x10 +#define OPE_HW_DUMP_DEBUG 0x11 /** * struct cam_ope_dev_probe diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h index 28c1a4d5e2..2890f1579e 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h @@ -49,6 +49,8 @@ #define OPE_WAIT_COMP_IDLE 0x4 #define OPE_WAIT_COMP_GEN_IRQ 0x8 +#define OPE_MAX_DEBUG_REGISTER 30 + struct cam_ope_common { uint32_t mode[CAM_FORMAT_MAX]; }; @@ -68,6 +70,9 @@ struct cam_ope_top_reg { uint32_t irq_cmd; uint32_t violation_status; uint32_t throttle_cnt_cfg; + uint32_t debug_cfg; + uint32_t num_debug_registers; + struct cam_ope_debug_register *debug_regs; }; struct cam_ope_top_reg_val { @@ -103,6 +108,7 @@ struct cam_ope_top_reg_val { uint32_t fe_done; uint32_t ope_violation; uint32_t idle; + uint32_t debug_cfg_val; }; struct cam_ope_qos_reg { @@ -375,6 +381,10 @@ struct cam_ope_bus_wr_reg_val { struct cam_ope_bus_wr_client_reg_val wr_clients[MAX_WR_CLIENTS]; }; +struct cam_ope_debug_register { + uint32_t offset; +}; + struct ope_hw { struct cam_ope_top_reg *top_reg; struct cam_ope_top_reg_val *top_reg_val; diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h index 0970fc3816..95ae384161 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h @@ -42,6 +42,36 @@ enum cam_ope_bus_rd_unpacker_format { BUS_RD_VER1_PACKER_FMT_MAX = 0x13, }; +static struct cam_ope_debug_register ope_debug_regs[OPE_MAX_DEBUG_REGISTER] = { + { + .offset = 0xA0, + }, + { + .offset = 0xA4 + }, + { + .offset = 0xA8, + }, + { + .offset = 0xAC, + }, + { + .offset = 0xB0, + }, + { + .offset = 0xB4, + }, + { + .offset = 0xB8, + }, + { + .offset = 0xBC, + }, + { + .offset = 0xD0, + }, +}; + static struct cam_ope_top_reg ope_top_reg = { .offset = 0x400, .hw_version = 0x0, @@ -56,6 +86,9 @@ static struct cam_ope_top_reg ope_top_reg = { .irq_cmd = 0x24, .violation_status = 0x28, .throttle_cnt_cfg = 0x2C, + .debug_cfg = 0xDC, + .num_debug_registers = 9, + .debug_regs = ope_debug_regs, }; static struct cam_ope_top_reg_val ope_top_reg_val = { @@ -75,6 +108,7 @@ static struct cam_ope_top_reg_val ope_top_reg_val = { .fe_done = 0x4, .ope_violation = 0x8, .idle = 0x10, + .debug_cfg_val = 0x1, }; diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c index 4d1547352c..becfa63540 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c @@ -29,12 +29,27 @@ static struct ope_top ope_top_info; +static int cam_ope_top_dump_debug_reg(struct ope_hw *ope_hw_info) +{ + uint32_t i, val; + struct cam_ope_top_reg *top_reg; + + top_reg = ope_hw_info->top_reg; + for (i = 0; i < top_reg->num_debug_registers; i++) { + val = cam_io_r_mb(top_reg->base + + top_reg->debug_regs[i].offset); + CAM_INFO(CAM_OPE, "Debug_status_%d val: 0x%x", i, val); + } + return 0; +} + static int cam_ope_top_reset(struct ope_hw *ope_hw_info, int32_t ctx_id, void *data) { int rc = 0; struct cam_ope_top_reg *top_reg; struct cam_ope_top_reg_val *top_reg_val; + uint32_t irq_mask, irq_status; if (!ope_hw_info) { CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); @@ -44,7 +59,8 @@ static int cam_ope_top_reset(struct ope_hw *ope_hw_info, top_reg = ope_hw_info->top_reg; top_reg_val = ope_hw_info->top_reg_val; - init_completion(&ope_top_info.reset_complete); + mutex_lock(&ope_top_info.ope_hw_mutex); + reinit_completion(&ope_top_info.reset_complete); /* enable interrupt mask */ cam_io_w_mb(top_reg_val->irq_mask, @@ -58,10 +74,19 @@ static int cam_ope_top_reset(struct ope_hw *ope_hw_info, &ope_top_info.reset_complete, msecs_to_jiffies(30)); + cam_io_w_mb(top_reg_val->debug_cfg_val, + top_reg->base + top_reg->debug_cfg); + if (!rc || rc < 0) { CAM_ERR(CAM_OPE, "reset error result = %d", rc); - if (!rc) - rc = -ETIMEDOUT; + irq_mask = cam_io_r_mb(ope_hw_info->top_reg->base + + top_reg->irq_mask); + irq_status = cam_io_r_mb(ope_hw_info->top_reg->base + + top_reg->irq_status); + CAM_ERR(CAM_OPE, "irq mask 0x%x irq status 0x%x", + irq_mask, irq_status); + cam_ope_top_dump_debug_reg(ope_hw_info); + rc = -ETIMEDOUT; } else { rc = 0; } @@ -70,6 +95,7 @@ static int cam_ope_top_reset(struct ope_hw *ope_hw_info, cam_io_w_mb(top_reg_val->irq_mask, ope_hw_info->top_reg->base + top_reg->irq_mask); + mutex_unlock(&ope_top_info.ope_hw_mutex); return rc; } @@ -110,6 +136,7 @@ static int cam_ope_top_init(struct ope_hw *ope_hw_info, struct cam_ope_top_reg *top_reg; struct cam_ope_top_reg_val *top_reg_val; struct cam_ope_dev_init *dev_init = data; + uint32_t irq_mask, irq_status; if (!ope_hw_info) { CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); @@ -121,13 +148,13 @@ static int cam_ope_top_init(struct ope_hw *ope_hw_info, top_reg->base = dev_init->core_info->ope_hw_info->ope_top_base; + mutex_init(&ope_top_info.ope_hw_mutex); /* OPE SW RESET */ init_completion(&ope_top_info.reset_complete); /* enable interrupt mask */ cam_io_w_mb(top_reg_val->irq_mask, ope_hw_info->top_reg->base + top_reg->irq_mask); - cam_io_w_mb(top_reg_val->sw_reset_cmd, ope_hw_info->top_reg->base + top_reg->reset_cmd); @@ -135,18 +162,27 @@ static int cam_ope_top_init(struct ope_hw *ope_hw_info, &ope_top_info.reset_complete, msecs_to_jiffies(30)); - /* enable interrupt mask */ - cam_io_w_mb(top_reg_val->irq_mask, - ope_hw_info->top_reg->base + top_reg->irq_mask); + cam_io_w_mb(top_reg_val->debug_cfg_val, + top_reg->base + top_reg->debug_cfg); if (!rc || rc < 0) { CAM_ERR(CAM_OPE, "reset error result = %d", rc); - if (!rc) - rc = -ETIMEDOUT; + irq_mask = cam_io_r_mb(ope_hw_info->top_reg->base + + top_reg->irq_mask); + irq_status = cam_io_r_mb(ope_hw_info->top_reg->base + + top_reg->irq_status); + CAM_ERR(CAM_OPE, "irq mask 0x%x irq status 0x%x", + irq_mask, irq_status); + cam_ope_top_dump_debug_reg(ope_hw_info); + rc = -ETIMEDOUT; } else { rc = 0; } + /* enable interrupt mask */ + cam_io_w_mb(top_reg_val->irq_mask, + ope_hw_info->top_reg->base + top_reg->irq_mask); + return rc; } @@ -246,6 +282,8 @@ int cam_ope_top_process(struct ope_hw *ope_hw_info, case OPE_HW_RESET: rc = cam_ope_top_reset(ope_hw_info, 0, 0); break; + case OPE_HW_DUMP_DEBUG: + rc - cam_ope_top_dump_debug_reg(ope_hw_info); default: break; } diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.h b/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.h index 6fd935c46e..428d66f7e9 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.h +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.h @@ -32,10 +32,12 @@ struct ope_top_ctx { * @ope_hw_info: OPE hardware info * @top_ctx: OPE top context * @reset_complete: Reset complete flag + * @ope_mutex: OPE hardware mutex */ struct ope_top { struct ope_hw *ope_hw_info; struct ope_top_ctx top_ctx[OPE_CTX_MAX]; struct completion reset_complete; + struct mutex ope_hw_mutex; }; #endif /* OPE_TOP_H */ diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 5359cf1e7f..63294dfb2c 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -4027,7 +4027,7 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) spin_unlock_bh(&link->link_state_spin_lock); /* Start SOF watchdog timer */ rc = crm_timer_init(&link->watchdog, - CAM_REQ_MGR_WATCHDOG_TIMEOUT, link, + CAM_REQ_MGR_WATCHDOG_TIMEOUT_DEFAULT, link, &__cam_req_mgr_sof_freeze); if (rc < 0) { CAM_ERR(CAM_CRM, diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index e406590c94..9b7724c4c1 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -13,10 +13,11 @@ #define CAM_REQ_MGR_MAX_LINKED_DEV 16 #define MAX_REQ_SLOTS 48 -#define CAM_REQ_MGR_WATCHDOG_TIMEOUT 5000 -#define CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX 50000 -#define CAM_REQ_MGR_SCHED_REQ_TIMEOUT 1000 -#define CAM_REQ_MGR_SIMULATE_SCHED_REQ 30 +#define CAM_REQ_MGR_WATCHDOG_TIMEOUT 1000 +#define CAM_REQ_MGR_WATCHDOG_TIMEOUT_DEFAULT 5000 +#define CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX 50000 +#define CAM_REQ_MGR_SCHED_REQ_TIMEOUT 1000 +#define CAM_REQ_MGR_SIMULATE_SCHED_REQ 30 #define FORCE_DISABLE_RECOVERY 2 #define FORCE_ENABLE_RECOVERY 1 diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index fcdee4e50c..84fe16cca4 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1544,6 +1544,76 @@ static int32_t cam_cci_i2c_write_async(struct v4l2_subdev *sd, return rc; } +static int32_t cam_cci_read_bytes_v_1_2(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev = NULL; + enum cci_i2c_master_t master; + struct cam_cci_read_cfg *read_cfg = NULL; + uint16_t read_bytes = 0; + + if (!sd || !c_ctrl) { + CAM_ERR(CAM_CCI, "sd %pK c_ctrl %pK", sd, c_ctrl); + return -EINVAL; + } + if (!c_ctrl->cci_info) { + CAM_ERR(CAM_CCI, "cci_info NULL"); + return -EINVAL; + } + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev) { + CAM_ERR(CAM_CCI, "cci_dev NULL"); + return -EINVAL; + } + if (cci_dev->cci_state != CCI_STATE_ENABLED) { + CAM_ERR(CAM_CCI, "invalid cci state %d", cci_dev->cci_state); + return -EINVAL; + } + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) { + CAM_ERR(CAM_CCI, "read num bytes 0"); + rc = -EINVAL; + goto ERROR; + } + + read_bytes = read_cfg->num_byte; + CAM_DBG(CAM_CCI, "Bytes to read %u", read_bytes); + do { + if (read_bytes >= CCI_READ_MAX_V_1_2) + read_cfg->num_byte = CCI_READ_MAX_V_1_2; + else + read_cfg->num_byte = read_bytes; + + cci_dev->is_burst_read = false; + rc = cam_cci_read(sd, c_ctrl); + if (rc) { + CAM_ERR(CAM_CCI, "failed to read rc:%d", rc); + goto ERROR; + } + + if (read_bytes >= CCI_READ_MAX_V_1_2) { + read_cfg->addr += CCI_READ_MAX_V_1_2; + read_cfg->data += CCI_READ_MAX_V_1_2; + read_bytes -= CCI_READ_MAX_V_1_2; + } else { + read_bytes = 0; + } + } while (read_bytes); + +ERROR: + cci_dev->is_burst_read = false; + return rc; +} + static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, struct cam_cci_ctrl *c_ctrl) { @@ -1770,7 +1840,16 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_I2C_READ: - rc = cam_cci_read_bytes(sd, cci_ctrl); + /* + * CCI version 1.2 does not support burst read + * due to the absence of the read threshold register + */ + if (cci_dev->hw_version == CCI_VERSION_1_2_9) { + CAM_DBG(CAM_CCI, "cci-v1.2 no burst read"); + rc = cam_cci_read_bytes_v_1_2(sd, cci_ctrl); + } else { + rc = cam_cci_read_bytes(sd, cci_ctrl); + } break; case MSM_CCI_I2C_WRITE: case MSM_CCI_I2C_WRITE_SEQ: diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h index fbf1834d60..8dd50aa408 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -57,6 +57,7 @@ /* Max bytes that can be read per CCI read transaction */ #define CCI_READ_MAX 256 +#define CCI_READ_MAX_V_1_2 0xE #define CCI_I2C_READ_MAX_RETRIES 3 #define CCI_I2C_MAX_READ 10240 #define CCI_I2C_MAX_WRITE 10240 @@ -69,6 +70,7 @@ #define PRIORITY_QUEUE (QUEUE_0) #define SYNC_QUEUE (QUEUE_1) +#define CCI_VERSION_1_2_9 0x10020009 enum cci_i2c_sync { MSM_SYNC_DISABLE, MSM_SYNC_ENABLE, diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index 66fe66b005..ac37cb2a9f 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -119,8 +119,7 @@ int cam_cci_init(struct v4l2_subdev *sd, MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; cci_dev->support_seq_write = 1; - if (of_device_is_compatible(soc_info->dev->of_node, - "qcom,cci-v1.2")) { + if (cci_dev->hw_version == CCI_VERSION_1_2_9) { max_queue_0_size = CCI_I2C_QUEUE_0_SIZE_V_1_2; max_queue_1_size = CCI_I2C_QUEUE_1_SIZE_V_1_2; } else { @@ -180,10 +179,12 @@ int cam_cci_init(struct v4l2_subdev *sd, } /* Set RD FIFO threshold for M0 & M1 */ - cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, - base + CCI_I2C_M0_RD_THRESHOLD_ADDR); - cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, - base + CCI_I2C_M1_RD_THRESHOLD_ADDR); + if (cci_dev->hw_version != CCI_VERSION_1_2_9) { + cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, + base + CCI_I2C_M0_RD_THRESHOLD_ADDR); + cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, + base + CCI_I2C_M1_RD_THRESHOLD_ADDR); + } cci_dev->cci_state = CCI_STATE_ENABLED; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 60ebe51726..01c54cdd6c 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -15,6 +15,11 @@ #include "cam_packet_util.h" #include "cam_mem_mgr.h" #include "cam_cpas_api.h" +#include "cam_compat.h" + +#define SCM_SVC_CAMERASS 0x18 +#define SECURE_SYSCALL_ID 0x6 +#define SECURE_SYSCALL_ID_2 0x7 #define LANE_MASK_2PH 0x1F #define LANE_MASK_3PH 0x7 @@ -834,6 +839,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, } break; case CAM_RELEASE_DEV: { + int32_t offset; struct cam_release_dev_cmd release; if (!csiphy_dev->acquire_count) { @@ -849,6 +855,23 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } + offset = cam_csiphy_get_instance_offset(csiphy_dev, + release.dev_handle); + if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid offset"); + goto release_mutex; + } + + if (csiphy_dev->csiphy_info.secure_mode[offset]) + cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, offset); + + csiphy_dev->csiphy_info.secure_mode[offset] = + CAM_SECURE_MODE_NON_SECURE; + + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0x0; + rc = cam_destroy_device_hdl(release.dev_handle); if (rc < 0) CAM_ERR(CAM_CSIPHY, "destroying the device hdl"); diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 781baa499c..89686a3b00 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -322,11 +322,11 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2; csiphy_dev->ctrl_reg->csiphy_common_reg = - csiphy_common_reg_1_2; + csiphy_common_reg_1_2_2; csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_2; csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; - csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2_2; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->is_divisor_32_comp = false; csiphy_dev->hw_version = CSIPHY_VERSION_V12; diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h index dd88ba7cca..119b6b575b 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_2_2_HWREG_H_ @@ -8,6 +8,29 @@ #include "../cam_csiphy_dev.h" +struct csiphy_reg_parms_t csiphy_v1_2_2 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 8, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 18, + .csiphy_3ph_config_array_size = 33, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_1_2_2[] = { + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x5A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x088C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0824, 0x72, 0x00, CSIPHY_2PH_REGS}, +}; + struct csiphy_reg_t csiphy_2ph_v1_2_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index adc7f0d86c..3212c79547 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -1827,7 +1827,11 @@ void cam_flash_shutdown(struct cam_flash_ctrl *fctrl) if ((fctrl->flash_state == CAM_FLASH_STATE_CONFIG) || (fctrl->flash_state == CAM_FLASH_STATE_START)) { fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); - cam_flash_off(fctrl); + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "LED OFF FAILED: %d", rc); + } if (fctrl->func_tbl.power_ops) { rc = fctrl->func_tbl.power_ops(fctrl, false); if (rc) diff --git a/drivers/cam_smmu/cam_smmu_api.h b/drivers/cam_smmu/cam_smmu_api.h index d89cba1510..472d95c443 100644 --- a/drivers/cam_smmu/cam_smmu_api.h +++ b/drivers/cam_smmu/cam_smmu_api.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SMMU_API_H_ diff --git a/drivers/cam_utils/cam_compat.h b/drivers/cam_utils/cam_compat.h index ae3cd2a3d3..f4299e0826 100644 --- a/drivers/cam_utils/cam_compat.h +++ b/drivers/cam_utils/cam_compat.h @@ -37,9 +37,9 @@ int cam_reserve_icp_fw(struct cam_fw_alloc_info *icp_fw, size_t fw_length); void cam_unreserve_icp_fw(struct cam_fw_alloc_info *icp_fw, size_t fw_length); void cam_cpastop_scm_write(struct cam_cpas_hw_errata_wa *errata_wa); int cam_ife_notify_safe_lut_scm(bool safe_trigger); -int cam_csiphy_notify_secure_mode(struct csiphy_device *csiphy_dev, - bool protect, int32_t offset); int camera_component_match_add_drivers(struct device *master_dev, struct component_match **match_list); +int cam_csiphy_notify_secure_mode(struct csiphy_device *csiphy_dev, + bool protect, int32_t offset); #endif /* _CAM_COMPAT_H_ */ diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 73077a799d..39da1d20e3 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -17,7 +17,7 @@ static char supported_clk_info[256]; static char debugfs_dir_name[64]; int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, - int32_t clk_rate, int clk_idx, int32_t *clk_lvl) + int64_t clk_rate, int clk_idx, int32_t *clk_lvl) { int i; long clk_rate_round; @@ -41,9 +41,9 @@ int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, (soc_info->clk_rate[i][clk_idx] >= clk_rate_round)) { CAM_DBG(CAM_UTIL, - "soc = %d round rate = %ld actual = %d", + "soc = %d round rate = %ld actual = %lld", soc_info->clk_rate[i][clk_idx], - clk_rate_round, clk_rate); + clk_rate_round, clk_rate); *clk_lvl = i; return 0; } @@ -380,7 +380,7 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, * @return: Success or failure */ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, - int32_t clk_rate) + int64_t clk_rate) { int rc = 0; long clk_rate_round; @@ -388,7 +388,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, if (!clk || !clk_name) return -EINVAL; - CAM_DBG(CAM_UTIL, "set %s, rate %d", clk_name, clk_rate); + CAM_DBG(CAM_UTIL, "set %s, rate %lld", clk_name, clk_rate); if (clk_rate > 0) { clk_rate_round = clk_round_rate(clk, clk_rate); CAM_DBG(CAM_UTIL, "new_rate %ld", clk_rate_round); @@ -424,7 +424,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, } int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate) + int64_t clk_rate) { int rc = 0; int i = 0; @@ -452,13 +452,13 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, &apply_level); if (rc || (apply_level < 0) || (apply_level >= CAM_MAX_VOTE)) { CAM_ERR(CAM_UTIL, - "set %s, rate %d dev_name = %s apply level = %d", + "set %s, rate %lld dev_name = %s apply level = %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, apply_level); return -EINVAL; } - CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s apply level = %d", + CAM_DBG(CAM_UTIL, "set %s, rate %lld dev_name = %s apply level = %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, apply_level); @@ -471,7 +471,7 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, soc_info->clk_name[src_clk_idx], clk_rate); if (rc) { CAM_ERR(CAM_UTIL, - "SET_RATE Failed: src clk: %s, rate %d, dev_name = %s rc: %d", + "SET_RATE Failed: src clk: %s, rate %lld, dev_name = %s rc: %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, rc); return rc; diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index 1f795b07e9..1e4d1bbce4 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -415,7 +415,7 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, * @return: success or failure */ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate); + int64_t clk_rate); /** * cam_soc_util_get_option_clk_by_name() @@ -657,7 +657,7 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, enum cam_vote_level clk_level); int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, - int32_t clk_rate, int clk_idx, int32_t *clk_lvl); + int64_t clk_rate, int clk_idx, int32_t *clk_lvl); /* Callback to get reg space data for specific HW */ typedef int (*cam_soc_util_regspace_data_cb)(uint32_t reg_base_type, diff --git a/include/uapi/camera/media/cam_ope.h b/include/uapi/camera/media/cam_ope.h index 9ddf3c8004..fd6e30ca30 100644 --- a/include/uapi/camera/media/cam_ope.h +++ b/include/uapi/camera/media/cam_ope.h @@ -73,7 +73,7 @@ #define OPE_MAX_IO_BUFS (OPE_OUT_RES_MAX + OPE_IN_RES_MAX) #define OPE_MAX_PASS 1 #define OPE_MAX_PLANES 2 -#define OPE_MAX_STRIPES 32 +#define OPE_MAX_STRIPES 48 #define OPE_MAX_BATCH_SIZE 16 /** @@ -83,6 +83,7 @@ * @x_init: X_init * @stripe_location: Stripe location (OPE_STRIPE_XXX) * @width: Width of a stripe + * @height: Height of a stripe * @disable_bus: Flag to disable BUS master * @reserved: Reserved * diff --git a/include/uapi/camera/media/cam_tfe.h b/include/uapi/camera/media/cam_tfe.h index 26573c33a4..dcb254c86e 100644 --- a/include/uapi/camera/media/cam_tfe.h +++ b/include/uapi/camera/media/cam_tfe.h @@ -83,6 +83,11 @@ #define CAM_ISP_TFE_USAGE_RIGHT_PX 2 #define CAM_ISP_TFE_USAGE_RDI 3 +/* Bus write master modes */ +#define CAM_ISP_TFE_WM_FRAME_BASED_MODE 0 +#define CAM_ISP_TFE_WM_LINE_BASED_MODE 1 +#define CAM_ISP_TFE_WM_INDEX_BASED_MODE 2 + /* Query devices */ /** * struct cam_isp_tfe_dev_cap_info - A cap info for particular hw type