| /* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include "cam_lrme_hw_core.h" |
| #include "cam_lrme_hw_soc.h" |
| #include "cam_smmu_api.h" |
| |
| static void cam_lrme_dump_registers(void __iomem *base) |
| { |
| /* dump the clc registers */ |
| cam_io_dump(base, 0x60, (0xc0 - 0x60) / 0x4); |
| /* dump the fe and we registers */ |
| cam_io_dump(base, 0x200, (0x29c - 0x200) / 0x4); |
| cam_io_dump(base, 0x2f0, (0x330 - 0x2f0) / 0x4); |
| cam_io_dump(base, 0x500, (0x5b4 - 0x500) / 0x4); |
| cam_io_dump(base, 0x700, (0x778 - 0x700) / 0x4); |
| cam_io_dump(base, 0x800, (0x878 - 0x800) / 0x4); |
| /* dump lrme sw registers, interrupts */ |
| cam_io_dump(base, 0x900, (0x928 - 0x900) / 0x4); |
| } |
| |
| static void cam_lrme_cdm_write_reg_val_pair(uint32_t *buffer, |
| uint32_t *index, uint32_t reg_offset, uint32_t reg_value) |
| { |
| buffer[(*index)++] = reg_offset; |
| buffer[(*index)++] = reg_value; |
| } |
| |
| static void cam_lrme_hw_util_fill_fe_reg(struct cam_lrme_hw_io_buffer *io_buf, |
| uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd, |
| struct cam_lrme_hw_info *hw_info) |
| { |
| uint32_t reg_val; |
| |
| /* 1. config buffer size */ |
| reg_val = io_buf->io_cfg->planes[0].width; |
| reg_val |= (io_buf->io_cfg->planes[0].height << 16); |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_rd_reg.bus_client_reg[index].rd_buffer_size, |
| reg_val); |
| |
| CAM_DBG(CAM_LRME, |
| "width %d", io_buf->io_cfg->planes[0].width); |
| CAM_DBG(CAM_LRME, |
| "height %d", io_buf->io_cfg->planes[0].height); |
| |
| /* 2. config image address */ |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_rd_reg.bus_client_reg[index].addr_image, |
| io_buf->io_addr[0]); |
| |
| CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]); |
| |
| /* 3. config stride */ |
| reg_val = io_buf->io_cfg->planes[0].plane_stride; |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_rd_reg.bus_client_reg[index].rd_stride, |
| reg_val); |
| |
| CAM_DBG(CAM_LRME, "plane_stride %d", |
| io_buf->io_cfg->planes[0].plane_stride); |
| |
| /* 4. enable client */ |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_rd_reg.bus_client_reg[index].core_cfg, 0x1); |
| |
| /* 5. unpack_cfg */ |
| if (io_buf->io_cfg->format == CAM_FORMAT_PD10) |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, |
| 0x0); |
| else if (io_buf->io_cfg->format == CAM_FORMAT_Y_ONLY || |
| io_buf->io_cfg->format == CAM_FORMAT_PLAIN8) |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, |
| 0x1); |
| else if (io_buf->io_cfg->format == CAM_FORMAT_PLAIN16_10) |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, |
| 0x22); |
| else |
| CAM_ERR(CAM_LRME, "Unsupported format %d", |
| io_buf->io_cfg->format); |
| } |
| |
| static void cam_lrme_hw_util_fill_we_reg(struct cam_lrme_hw_io_buffer *io_buf, |
| uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd, |
| struct cam_lrme_hw_info *hw_info) |
| { |
| /* config client mode */ |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_wr_reg.bus_client_reg[index].cfg, |
| 0x1); |
| |
| /* image address */ |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_wr_reg.bus_client_reg[index].addr_image, |
| io_buf->io_addr[0]); |
| CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]); |
| |
| /* buffer width and height */ |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_wr_reg.bus_client_reg[index].buffer_width_cfg, |
| io_buf->io_cfg->planes[0].width); |
| CAM_DBG(CAM_LRME, "width %d", io_buf->io_cfg->planes[0].width); |
| |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_wr_reg.bus_client_reg[index].buffer_height_cfg, |
| io_buf->io_cfg->planes[0].height); |
| CAM_DBG(CAM_LRME, "height %d", io_buf->io_cfg->planes[0].height); |
| |
| /* packer cfg */ |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_wr_reg.bus_client_reg[index].packer_cfg, |
| (index == 0) ? 0x1 : 0x5); |
| |
| /* client stride */ |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, |
| hw_info->bus_wr_reg.bus_client_reg[index].wr_stride, |
| io_buf->io_cfg->planes[0].meta_stride); |
| CAM_DBG(CAM_LRME, "plane_stride %d", |
| io_buf->io_cfg->planes[0].plane_stride); |
| } |
| |
| |
| static int cam_lrme_hw_util_process_config_hw(struct cam_hw_info *lrme_hw, |
| struct cam_lrme_hw_cmd_config_args *config_args) |
| { |
| int i; |
| struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; |
| struct cam_lrme_cdm_info *hw_cdm_info; |
| uint32_t *cmd_buf_addr = config_args->cmd_buf_addr; |
| uint32_t reg_val_pair[CAM_LRME_MAX_REG_PAIR_NUM]; |
| struct cam_lrme_hw_io_buffer *io_buf; |
| struct cam_lrme_hw_info *hw_info = |
| ((struct cam_lrme_core *)lrme_hw->core_info)->hw_info; |
| uint32_t num_cmd = 0; |
| uint32_t size; |
| uint32_t mem_base, available_size = config_args->size; |
| uint32_t output_res_mask = 0, input_res_mask = 0; |
| |
| |
| if (!cmd_buf_addr) { |
| CAM_ERR(CAM_LRME, "Invalid input args"); |
| return -EINVAL; |
| } |
| |
| hw_cdm_info = |
| ((struct cam_lrme_core *)lrme_hw->core_info)->hw_cdm_info; |
| |
| for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) { |
| io_buf = &config_args->input_buf[i]; |
| |
| if (io_buf->valid == false) |
| break; |
| |
| if (io_buf->io_cfg->direction != CAM_BUF_INPUT) { |
| CAM_ERR(CAM_LRME, "Incorrect direction %d %d", |
| io_buf->io_cfg->direction, CAM_BUF_INPUT); |
| return -EINVAL; |
| } |
| CAM_DBG(CAM_LRME, |
| "resource_type %d", io_buf->io_cfg->resource_type); |
| |
| switch (io_buf->io_cfg->resource_type) { |
| case CAM_LRME_IO_TYPE_TAR: |
| cam_lrme_hw_util_fill_fe_reg(io_buf, 0, reg_val_pair, |
| &num_cmd, hw_info); |
| |
| input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_TAR; |
| break; |
| case CAM_LRME_IO_TYPE_REF: |
| cam_lrme_hw_util_fill_fe_reg(io_buf, 1, reg_val_pair, |
| &num_cmd, hw_info); |
| |
| input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_REF; |
| break; |
| default: |
| CAM_ERR(CAM_LRME, "wrong resource_type %d", |
| io_buf->io_cfg->resource_type); |
| return -EINVAL; |
| } |
| } |
| |
| for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++) |
| if (!((input_res_mask >> i) & 0x1)) |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd, |
| hw_info->bus_rd_reg.bus_client_reg[i].core_cfg, |
| 0x0); |
| |
| for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) { |
| io_buf = &config_args->output_buf[i]; |
| |
| if (io_buf->valid == false) |
| break; |
| |
| if (io_buf->io_cfg->direction != CAM_BUF_OUTPUT) { |
| CAM_ERR(CAM_LRME, "Incorrect direction %d %d", |
| io_buf->io_cfg->direction, CAM_BUF_INPUT); |
| return -EINVAL; |
| } |
| |
| CAM_DBG(CAM_LRME, "resource_type %d", |
| io_buf->io_cfg->resource_type); |
| switch (io_buf->io_cfg->resource_type) { |
| case CAM_LRME_IO_TYPE_DS2: |
| cam_lrme_hw_util_fill_we_reg(io_buf, 0, reg_val_pair, |
| &num_cmd, hw_info); |
| |
| output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_DS2; |
| break; |
| case CAM_LRME_IO_TYPE_RES: |
| cam_lrme_hw_util_fill_we_reg(io_buf, 1, reg_val_pair, |
| &num_cmd, hw_info); |
| |
| output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_RES; |
| break; |
| |
| default: |
| CAM_ERR(CAM_LRME, "wrong resource_type %d", |
| io_buf->io_cfg->resource_type); |
| return -EINVAL; |
| } |
| } |
| |
| for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++) |
| if (!((output_res_mask >> i) & 0x1)) |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd, |
| hw_info->bus_wr_reg.bus_client_reg[i].cfg, 0x0); |
| |
| if (output_res_mask) { |
| /* write composite mask */ |
| cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd, |
| hw_info->bus_wr_reg.common_reg.composite_mask_0, |
| output_res_mask); |
| } |
| |
| size = hw_cdm_info->cdm_ops->cdm_required_size_changebase(); |
| if ((size * 4) > available_size) { |
| CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d", |
| available_size, size); |
| return -EINVAL; |
| } |
| |
| mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info, CAM_LRME_BASE_IDX); |
| |
| hw_cdm_info->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base); |
| cmd_buf_addr += size; |
| available_size -= (size * 4); |
| |
| size = hw_cdm_info->cdm_ops->cdm_required_size_reg_random( |
| num_cmd / 2); |
| |
| if ((size * 4) > available_size) { |
| CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d", |
| available_size, size); |
| return -ENOMEM; |
| } |
| |
| hw_cdm_info->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmd / 2, |
| reg_val_pair); |
| cmd_buf_addr += size; |
| available_size -= (size * 4); |
| |
| config_args->config_buf_size = |
| config_args->size - available_size; |
| |
| return 0; |
| } |
| |
| static int cam_lrme_hw_util_submit_go(struct cam_hw_info *lrme_hw) |
| { |
| struct cam_lrme_core *lrme_core; |
| struct cam_hw_soc_info *soc_info; |
| struct cam_lrme_hw_info *hw_info; |
| |
| lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; |
| hw_info = lrme_core->hw_info; |
| soc_info = &lrme_hw->soc_info; |
| |
| cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + |
| hw_info->bus_rd_reg.common_reg.cmd); |
| |
| return 0; |
| } |
| |
| static int cam_lrme_hw_util_reset(struct cam_hw_info *lrme_hw, |
| uint32_t reset_type) |
| { |
| struct cam_lrme_core *lrme_core; |
| struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; |
| struct cam_lrme_hw_info *hw_info; |
| long time_left; |
| |
| lrme_core = lrme_hw->core_info; |
| hw_info = lrme_core->hw_info; |
| |
| switch (reset_type) { |
| case CAM_LRME_HW_RESET_TYPE_HW_RESET: |
| reinit_completion(&lrme_core->reset_complete); |
| cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + |
| hw_info->titan_reg.top_rst_cmd); |
| time_left = wait_for_completion_timeout( |
| &lrme_core->reset_complete, |
| msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT)); |
| if (time_left <= 0) { |
| CAM_ERR(CAM_LRME, |
| "HW reset wait failed time_left=%ld", |
| time_left); |
| return -ETIMEDOUT; |
| } |
| break; |
| case CAM_LRME_HW_RESET_TYPE_SW_RESET: |
| cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.sw_reset); |
| cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base + |
| hw_info->bus_rd_reg.common_reg.sw_reset); |
| reinit_completion(&lrme_core->reset_complete); |
| cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + |
| hw_info->titan_reg.top_rst_cmd); |
| time_left = wait_for_completion_timeout( |
| &lrme_core->reset_complete, |
| msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT)); |
| if (time_left <= 0) { |
| CAM_ERR(CAM_LRME, |
| "SW reset wait failed time_left=%ld", |
| time_left); |
| return -ETIMEDOUT; |
| } |
| break; |
| } |
| |
| return 0; |
| } |
| |
| int cam_lrme_hw_util_get_caps(struct cam_hw_info *lrme_hw, |
| struct cam_lrme_dev_cap *hw_caps) |
| { |
| struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; |
| struct cam_lrme_hw_info *hw_info = |
| ((struct cam_lrme_core *)lrme_hw->core_info)->hw_info; |
| uint32_t reg_value; |
| |
| if (!hw_info) { |
| CAM_ERR(CAM_LRME, "Invalid hw info data"); |
| return -EINVAL; |
| } |
| |
| reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + |
| hw_info->clc_reg.clc_hw_version); |
| hw_caps->clc_hw_version.gen = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); |
| hw_caps->clc_hw_version.rev = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); |
| hw_caps->clc_hw_version.step = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); |
| |
| reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + |
| hw_info->bus_rd_reg.common_reg.hw_version); |
| hw_caps->bus_rd_hw_version.gen = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); |
| hw_caps->bus_rd_hw_version.rev = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); |
| hw_caps->bus_rd_hw_version.step = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); |
| |
| reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.hw_version); |
| hw_caps->bus_wr_hw_version.gen = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); |
| hw_caps->bus_wr_hw_version.rev = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); |
| hw_caps->bus_wr_hw_version.step = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); |
| |
| reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + |
| hw_info->titan_reg.top_hw_version); |
| hw_caps->top_hw_version.gen = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); |
| hw_caps->top_hw_version.rev = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); |
| hw_caps->top_hw_version.step = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); |
| |
| reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + |
| hw_info->titan_reg.top_titan_version); |
| hw_caps->top_titan_version.gen = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); |
| hw_caps->top_titan_version.rev = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); |
| hw_caps->top_titan_version.step = |
| CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); |
| |
| return 0; |
| } |
| |
| static int cam_lrme_hw_util_submit_req(struct cam_lrme_core *lrme_core, |
| struct cam_lrme_frame_request *frame_req) |
| { |
| struct cam_lrme_cdm_info *hw_cdm_info = |
| lrme_core->hw_cdm_info; |
| struct cam_cdm_bl_request *cdm_cmd = hw_cdm_info->cdm_cmd; |
| struct cam_hw_update_entry *cmd; |
| int i, rc = 0; |
| |
| if (frame_req->num_hw_update_entries > 0) { |
| cdm_cmd->cmd_arrary_count = frame_req->num_hw_update_entries; |
| cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; |
| cdm_cmd->flag = false; |
| cdm_cmd->userdata = NULL; |
| cdm_cmd->cookie = 0; |
| |
| for (i = 0; i <= frame_req->num_hw_update_entries; i++) { |
| cmd = (frame_req->hw_update_entries + i); |
| cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle; |
| cdm_cmd->cmd[i].offset = cmd->offset; |
| cdm_cmd->cmd[i].len = cmd->len; |
| } |
| |
| rc = cam_cdm_submit_bls(hw_cdm_info->cdm_handle, cdm_cmd); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "Failed to submit cdm commands"); |
| return -EINVAL; |
| } |
| } else { |
| CAM_ERR(CAM_LRME, "No hw update entry"); |
| rc = -EINVAL; |
| } |
| |
| return rc; |
| } |
| |
| static int cam_lrme_hw_util_flush_ctx(struct cam_hw_info *lrme_hw, |
| void *ctxt_to_hw_map) |
| { |
| int rc = -ENODEV; |
| struct cam_lrme_core *lrme_core = lrme_hw->core_info; |
| struct cam_lrme_hw_cb_args cb_args; |
| struct cam_lrme_frame_request *req_proc, *req_submit; |
| struct cam_lrme_hw_submit_args submit_args; |
| |
| rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "reset failed"); |
| return rc; |
| } |
| |
| lrme_core->state = CAM_LRME_CORE_STATE_IDLE; |
| req_proc = lrme_core->req_proc; |
| req_submit = lrme_core->req_submit; |
| lrme_core->req_proc = NULL; |
| lrme_core->req_submit = NULL; |
| |
| if (req_submit && req_submit->ctxt_to_hw_map == ctxt_to_hw_map) { |
| cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; |
| cb_args.frame_req = req_submit; |
| if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) |
| lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( |
| lrme_core->hw_mgr_cb.data, &cb_args); |
| } else if (req_submit) { |
| submit_args.frame_req = req_submit; |
| submit_args.hw_update_entries = req_submit->hw_update_entries; |
| submit_args.num_hw_update_entries = |
| req_submit->num_hw_update_entries; |
| rc = cam_lrme_hw_util_submit_req(lrme_core, req_submit); |
| if (rc) |
| CAM_ERR(CAM_LRME, "Submit failed"); |
| lrme_core->req_submit = req_submit; |
| cam_lrme_hw_util_submit_go(lrme_hw); |
| lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; |
| } |
| |
| if (req_proc && req_proc->ctxt_to_hw_map == ctxt_to_hw_map) { |
| cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; |
| cb_args.frame_req = req_proc; |
| if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) |
| lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( |
| lrme_core->hw_mgr_cb.data, &cb_args); |
| } else if (req_proc) { |
| submit_args.frame_req = req_proc; |
| submit_args.hw_update_entries = req_proc->hw_update_entries; |
| submit_args.num_hw_update_entries = |
| req_proc->num_hw_update_entries; |
| rc = cam_lrme_hw_util_submit_req(lrme_core, req_proc); |
| if (rc) |
| CAM_ERR(CAM_LRME, "Submit failed"); |
| lrme_core->req_submit = req_proc; |
| cam_lrme_hw_util_submit_go(lrme_hw); |
| lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; |
| } |
| |
| return rc; |
| } |
| |
| static int cam_lrme_hw_util_flush_req(struct cam_hw_info *lrme_hw, |
| struct cam_lrme_frame_request *req_to_flush) |
| { |
| int rc = -ENODEV; |
| struct cam_lrme_core *lrme_core = lrme_hw->core_info; |
| struct cam_lrme_hw_cb_args cb_args; |
| struct cam_lrme_frame_request *req_proc, *req_submit; |
| struct cam_lrme_hw_submit_args submit_args; |
| |
| rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "reset failed"); |
| return rc; |
| } |
| |
| lrme_core->state = CAM_LRME_CORE_STATE_IDLE; |
| req_proc = lrme_core->req_proc; |
| req_submit = lrme_core->req_submit; |
| lrme_core->req_proc = NULL; |
| lrme_core->req_submit = NULL; |
| |
| if (req_submit && req_submit == req_to_flush) { |
| cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; |
| cb_args.frame_req = req_submit; |
| if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) |
| lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( |
| lrme_core->hw_mgr_cb.data, &cb_args); |
| } else if (req_submit) { |
| submit_args.frame_req = req_submit; |
| submit_args.hw_update_entries = req_submit->hw_update_entries; |
| submit_args.num_hw_update_entries = |
| req_submit->num_hw_update_entries; |
| rc = cam_lrme_hw_util_submit_req(lrme_core, req_submit); |
| if (rc) |
| CAM_ERR(CAM_LRME, "Submit failed"); |
| lrme_core->req_submit = req_submit; |
| cam_lrme_hw_util_submit_go(lrme_hw); |
| lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; |
| } |
| |
| if (req_proc && req_proc == req_to_flush) { |
| cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; |
| cb_args.frame_req = req_proc; |
| if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) |
| lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( |
| lrme_core->hw_mgr_cb.data, &cb_args); |
| } else if (req_proc) { |
| submit_args.frame_req = req_proc; |
| submit_args.hw_update_entries = req_proc->hw_update_entries; |
| submit_args.num_hw_update_entries = |
| req_proc->num_hw_update_entries; |
| rc = cam_lrme_hw_util_submit_req(lrme_core, req_proc); |
| if (rc) |
| CAM_ERR(CAM_LRME, "Submit failed"); |
| lrme_core->req_submit = req_proc; |
| cam_lrme_hw_util_submit_go(lrme_hw); |
| lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; |
| } |
| |
| return rc; |
| } |
| |
| |
| static int cam_lrme_hw_util_process_err(struct cam_hw_info *lrme_hw) |
| { |
| struct cam_lrme_core *lrme_core = lrme_hw->core_info; |
| struct cam_lrme_frame_request *req_proc, *req_submit; |
| struct cam_lrme_hw_cb_args cb_args; |
| int rc; |
| |
| req_proc = lrme_core->req_proc; |
| req_submit = lrme_core->req_submit; |
| cb_args.cb_type = CAM_LRME_CB_ERROR; |
| |
| if ((lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) && |
| (lrme_core->state != CAM_LRME_CORE_STATE_REQ_PENDING) && |
| (lrme_core->state != CAM_LRME_CORE_STATE_REQ_PROC_PEND)) { |
| CAM_ERR(CAM_LRME, "Get error irq in wrong state %d", |
| lrme_core->state); |
| } |
| |
| cam_lrme_dump_registers(lrme_hw->soc_info.reg_map[0].mem_base); |
| |
| CAM_ERR_RATE_LIMIT(CAM_LRME, "Start recovery"); |
| lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY; |
| rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); |
| if (rc) |
| CAM_ERR(CAM_LRME, "Failed to reset"); |
| |
| lrme_core->req_proc = NULL; |
| lrme_core->req_submit = NULL; |
| if (!rc) |
| lrme_core->state = CAM_LRME_CORE_STATE_IDLE; |
| |
| cb_args.frame_req = req_proc; |
| lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data, |
| &cb_args); |
| |
| cb_args.frame_req = req_submit; |
| lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data, |
| &cb_args); |
| |
| return rc; |
| } |
| |
| static int cam_lrme_hw_util_process_reg_update( |
| struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args) |
| { |
| struct cam_lrme_core *lrme_core = lrme_hw->core_info; |
| int rc = 0; |
| |
| cb_args->cb_type |= CAM_LRME_CB_COMP_REG_UPDATE; |
| if (lrme_core->state == CAM_LRME_CORE_STATE_REQ_PENDING) { |
| lrme_core->state = CAM_LRME_CORE_STATE_PROCESSING; |
| } else { |
| CAM_ERR(CAM_LRME, "Reg update in wrong state %d", |
| lrme_core->state); |
| rc = cam_lrme_hw_util_process_err(lrme_hw); |
| if (rc) |
| CAM_ERR(CAM_LRME, "Failed to reset"); |
| return -EINVAL; |
| } |
| |
| lrme_core->req_proc = lrme_core->req_submit; |
| lrme_core->req_submit = NULL; |
| |
| if (lrme_core->dump_flag) |
| cam_lrme_dump_registers(lrme_hw->soc_info.reg_map[0].mem_base); |
| |
| return 0; |
| } |
| |
| static int cam_lrme_hw_util_process_idle( |
| struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args) |
| { |
| struct cam_lrme_core *lrme_core = lrme_hw->core_info; |
| int rc = 0; |
| |
| cb_args->cb_type |= CAM_LRME_CB_BUF_DONE; |
| switch (lrme_core->state) { |
| case CAM_LRME_CORE_STATE_REQ_PROC_PEND: |
| cam_lrme_hw_util_submit_go(lrme_hw); |
| lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; |
| break; |
| |
| case CAM_LRME_CORE_STATE_PROCESSING: |
| lrme_core->state = CAM_LRME_CORE_STATE_IDLE; |
| break; |
| |
| default: |
| CAM_ERR(CAM_LRME, "Idle in wrong state %d", |
| lrme_core->state); |
| rc = cam_lrme_hw_util_process_err(lrme_hw); |
| return rc; |
| } |
| cb_args->frame_req = lrme_core->req_proc; |
| lrme_core->req_proc = NULL; |
| |
| return 0; |
| } |
| |
| void cam_lrme_set_irq(struct cam_hw_info *lrme_hw, |
| enum cam_lrme_irq_set set) |
| { |
| struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; |
| struct cam_lrme_core *lrme_core = lrme_hw->core_info; |
| struct cam_lrme_hw_info *hw_info = lrme_core->hw_info; |
| |
| switch (set) { |
| case CAM_LRME_IRQ_ENABLE: |
| cam_io_w_mb(0xFFFF, |
| soc_info->reg_map[0].mem_base + |
| hw_info->titan_reg.top_irq_mask); |
| cam_io_w_mb(0xFFFFF, |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.irq_mask_0); |
| cam_io_w_mb(0xFFFFF, |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.irq_mask_1); |
| cam_io_w_mb(0xFFFFF, |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_rd_reg.common_reg.irq_mask); |
| break; |
| |
| case CAM_LRME_IRQ_DISABLE: |
| cam_io_w_mb(0x0, |
| soc_info->reg_map[0].mem_base + |
| hw_info->titan_reg.top_irq_mask); |
| cam_io_w_mb(0x0, |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.irq_mask_0); |
| cam_io_w_mb(0x0, |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.irq_mask_1); |
| cam_io_w_mb(0x0, |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_rd_reg.common_reg.irq_mask); |
| break; |
| } |
| } |
| |
| |
| int cam_lrme_hw_process_irq(void *priv, void *data) |
| { |
| struct cam_lrme_hw_work_data *work_data; |
| struct cam_hw_info *lrme_hw; |
| struct cam_lrme_core *lrme_core; |
| int rc = 0; |
| uint32_t top_irq_status, fe_irq_status; |
| uint32_t *we_irq_status; |
| struct cam_lrme_hw_cb_args cb_args; |
| |
| if (!data || !priv) { |
| CAM_ERR(CAM_LRME, "Invalid data %pK %pK", data, priv); |
| return -EINVAL; |
| } |
| |
| memset(&cb_args, 0, sizeof(struct cam_lrme_hw_cb_args)); |
| lrme_hw = (struct cam_hw_info *)priv; |
| work_data = (struct cam_lrme_hw_work_data *)data; |
| lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; |
| top_irq_status = work_data->top_irq_status; |
| fe_irq_status = work_data->fe_irq_status; |
| we_irq_status = work_data->we_irq_status; |
| |
| CAM_DBG(CAM_LRME, |
| "top status %x, fe status %x, we status0 %x, we status1 %x", |
| top_irq_status, fe_irq_status, we_irq_status[0], |
| we_irq_status[1]); |
| CAM_DBG(CAM_LRME, "Current state %d", lrme_core->state); |
| |
| mutex_lock(&lrme_hw->hw_mutex); |
| |
| if (lrme_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { |
| CAM_DBG(CAM_LRME, "LRME HW is in off state"); |
| goto end; |
| } |
| |
| if (top_irq_status & (1 << 3)) { |
| CAM_DBG(CAM_LRME, "Error"); |
| rc = cam_lrme_hw_util_process_err(lrme_hw); |
| if (rc) |
| CAM_ERR(CAM_LRME, "Process error failed"); |
| goto end; |
| } |
| |
| if (we_irq_status[0] & (1 << 1)) { |
| CAM_DBG(CAM_LRME, "reg update"); |
| rc = cam_lrme_hw_util_process_reg_update(lrme_hw, &cb_args); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "Process reg_update failed"); |
| goto end; |
| } |
| } |
| |
| if (top_irq_status & (1 << 4)) { |
| CAM_DBG(CAM_LRME, "IDLE"); |
| if (!lrme_core->req_proc) { |
| CAM_DBG(CAM_LRME, "No frame request to process idle"); |
| goto end; |
| } |
| rc = cam_lrme_hw_util_process_idle(lrme_hw, &cb_args); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "Process idle failed"); |
| goto end; |
| } |
| } |
| |
| if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) { |
| lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( |
| lrme_core->hw_mgr_cb.data, &cb_args); |
| } else { |
| CAM_ERR(CAM_LRME, "No hw mgr cb"); |
| rc = -EINVAL; |
| } |
| |
| end: |
| mutex_unlock(&lrme_hw->hw_mutex); |
| return rc; |
| } |
| |
| int cam_lrme_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size) |
| { |
| struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; |
| int rc = 0; |
| struct cam_lrme_core *lrme_core; |
| |
| if (!lrme_hw) { |
| CAM_ERR(CAM_LRME, |
| "Invalid input params, lrme_hw %pK", |
| lrme_hw); |
| return -EINVAL; |
| } |
| |
| lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; |
| |
| mutex_lock(&lrme_hw->hw_mutex); |
| |
| if (lrme_hw->open_count > 0) { |
| lrme_hw->open_count++; |
| CAM_DBG(CAM_LRME, "This device is activated before"); |
| goto unlock; |
| } |
| |
| rc = cam_lrme_soc_enable_resources(lrme_hw); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "Failed to enable soc resources"); |
| goto unlock; |
| } |
| |
| rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "Failed to reset hw"); |
| goto disable_soc; |
| } |
| |
| if (lrme_core->hw_cdm_info) { |
| struct cam_lrme_cdm_info *hw_cdm_info = |
| lrme_core->hw_cdm_info; |
| |
| rc = cam_cdm_stream_on(hw_cdm_info->cdm_handle); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "Failed to stream on cdm"); |
| goto disable_soc; |
| } |
| } |
| |
| lrme_hw->hw_state = CAM_HW_STATE_POWER_UP; |
| lrme_hw->open_count++; |
| lrme_core->state = CAM_LRME_CORE_STATE_IDLE; |
| |
| CAM_DBG(CAM_LRME, "open count %d", lrme_hw->open_count); |
| mutex_unlock(&lrme_hw->hw_mutex); |
| return rc; |
| |
| disable_soc: |
| if (cam_lrme_soc_disable_resources(lrme_hw)) |
| CAM_ERR(CAM_LRME, "Error in disable soc resources"); |
| unlock: |
| CAM_DBG(CAM_LRME, "open count %d", lrme_hw->open_count); |
| mutex_unlock(&lrme_hw->hw_mutex); |
| return rc; |
| } |
| |
| int cam_lrme_hw_stop(void *hw_priv, void *hw_stop_args, uint32_t arg_size) |
| { |
| struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; |
| int rc = 0; |
| struct cam_lrme_core *lrme_core; |
| |
| if (!lrme_hw) { |
| CAM_ERR(CAM_LRME, "Invalid argument"); |
| return -EINVAL; |
| } |
| |
| lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; |
| |
| mutex_lock(&lrme_hw->hw_mutex); |
| |
| if (lrme_hw->open_count == 0) { |
| mutex_unlock(&lrme_hw->hw_mutex); |
| CAM_ERR(CAM_LRME, "Error Unbalanced stop"); |
| return -EINVAL; |
| } |
| lrme_hw->open_count--; |
| |
| CAM_DBG(CAM_LRME, "open count %d", lrme_hw->open_count); |
| |
| if (lrme_hw->open_count) |
| goto unlock; |
| |
| lrme_core->req_proc = NULL; |
| lrme_core->req_submit = NULL; |
| |
| if (lrme_core->hw_cdm_info) { |
| struct cam_lrme_cdm_info *hw_cdm_info = |
| lrme_core->hw_cdm_info; |
| |
| rc = cam_cdm_stream_off(hw_cdm_info->cdm_handle); |
| if (rc) { |
| CAM_ERR(CAM_LRME, |
| "Failed in CDM StreamOff, handle=0x%x, rc=%d", |
| hw_cdm_info->cdm_handle, rc); |
| goto unlock; |
| } |
| } |
| |
| rc = cam_lrme_soc_disable_resources(lrme_hw); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "Failed in Disable SOC, rc=%d", rc); |
| goto unlock; |
| } |
| |
| lrme_hw->hw_state = CAM_HW_STATE_POWER_DOWN; |
| if (lrme_core->state == CAM_LRME_CORE_STATE_IDLE) { |
| lrme_core->state = CAM_LRME_CORE_STATE_INIT; |
| } else { |
| CAM_ERR(CAM_LRME, "HW in wrong state %d", lrme_core->state); |
| return -EINVAL; |
| } |
| |
| unlock: |
| mutex_unlock(&lrme_hw->hw_mutex); |
| return rc; |
| } |
| |
| int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, |
| uint32_t arg_size) |
| { |
| struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; |
| struct cam_lrme_core *lrme_core; |
| struct cam_lrme_hw_submit_args *args = |
| (struct cam_lrme_hw_submit_args *)hw_submit_args; |
| int rc = 0; |
| struct cam_lrme_frame_request *frame_req; |
| |
| |
| if (!hw_priv || !hw_submit_args) { |
| CAM_ERR(CAM_LRME, "Invalid input"); |
| return -EINVAL; |
| } |
| |
| if (sizeof(struct cam_lrme_hw_submit_args) != arg_size) { |
| CAM_ERR(CAM_LRME, |
| "size of args %zu, arg_size %d", |
| sizeof(struct cam_lrme_hw_submit_args), arg_size); |
| return -EINVAL; |
| } |
| |
| frame_req = args->frame_req; |
| |
| mutex_lock(&lrme_hw->hw_mutex); |
| |
| if (lrme_hw->open_count == 0) { |
| CAM_ERR(CAM_LRME, "HW is not open"); |
| mutex_unlock(&lrme_hw->hw_mutex); |
| return -EINVAL; |
| } |
| |
| lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; |
| if (lrme_core->state != CAM_LRME_CORE_STATE_IDLE && |
| lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) { |
| mutex_unlock(&lrme_hw->hw_mutex); |
| CAM_DBG(CAM_LRME, "device busy, can not submit, state %d", |
| lrme_core->state); |
| return -EBUSY; |
| } |
| |
| if (lrme_core->req_submit != NULL) { |
| CAM_ERR(CAM_LRME, "req_submit is not NULL"); |
| return -EBUSY; |
| } |
| |
| rc = cam_lrme_hw_util_submit_req(lrme_core, frame_req); |
| if (rc) { |
| CAM_ERR(CAM_LRME, "Submit req failed"); |
| goto error; |
| } |
| |
| switch (lrme_core->state) { |
| case CAM_LRME_CORE_STATE_PROCESSING: |
| lrme_core->state = CAM_LRME_CORE_STATE_REQ_PROC_PEND; |
| break; |
| |
| case CAM_LRME_CORE_STATE_IDLE: |
| cam_lrme_hw_util_submit_go(lrme_hw); |
| lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; |
| break; |
| |
| default: |
| CAM_ERR(CAM_LRME, "Wrong hw state"); |
| rc = -EINVAL; |
| goto error; |
| } |
| |
| lrme_core->req_submit = frame_req; |
| |
| mutex_unlock(&lrme_hw->hw_mutex); |
| CAM_DBG(CAM_LRME, "Release lock, submit done for req %llu", |
| frame_req->req_id); |
| |
| return 0; |
| |
| error: |
| mutex_unlock(&lrme_hw->hw_mutex); |
| |
| return rc; |
| |
| } |
| |
| int cam_lrme_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) |
| { |
| struct cam_hw_info *lrme_hw = hw_priv; |
| struct cam_lrme_core *lrme_core; |
| struct cam_lrme_hw_reset_args *lrme_reset_args = reset_core_args; |
| int rc; |
| |
| if (!hw_priv) { |
| CAM_ERR(CAM_LRME, "Invalid input args"); |
| return -EINVAL; |
| } |
| |
| if (!reset_core_args || |
| sizeof(struct cam_lrme_hw_reset_args) != arg_size) { |
| CAM_ERR(CAM_LRME, "Invalid reset args"); |
| return -EINVAL; |
| } |
| |
| lrme_core = lrme_hw->core_info; |
| |
| mutex_lock(&lrme_hw->hw_mutex); |
| if (lrme_core->state == CAM_LRME_CORE_STATE_RECOVERY) { |
| mutex_unlock(&lrme_hw->hw_mutex); |
| CAM_ERR(CAM_LRME, "Reset not allowed in %d state", |
| lrme_core->state); |
| return -EINVAL; |
| } |
| |
| lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY; |
| |
| rc = cam_lrme_hw_util_reset(lrme_hw, lrme_reset_args->reset_type); |
| if (rc) { |
| mutex_unlock(&lrme_hw->hw_mutex); |
| CAM_ERR(CAM_FD, "Failed to reset"); |
| return rc; |
| } |
| |
| lrme_core->state = CAM_LRME_CORE_STATE_IDLE; |
| |
| mutex_unlock(&lrme_hw->hw_mutex); |
| |
| return 0; |
| } |
| |
| int cam_lrme_hw_flush(void *hw_priv, void *hw_flush_args, uint32_t arg_size) |
| { |
| struct cam_lrme_core *lrme_core = NULL; |
| struct cam_hw_info *lrme_hw = hw_priv; |
| struct cam_lrme_hw_flush_args *flush_args = |
| (struct cam_lrme_hw_flush_args *)hw_flush_args; |
| int rc = -ENODEV; |
| |
| if (!hw_priv) { |
| CAM_ERR(CAM_LRME, "Invalid arguments %pK", hw_priv); |
| return -EINVAL; |
| } |
| |
| lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; |
| |
| mutex_lock(&lrme_hw->hw_mutex); |
| |
| if (lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING && |
| lrme_core->state != CAM_LRME_CORE_STATE_REQ_PENDING && |
| lrme_core->state == CAM_LRME_CORE_STATE_REQ_PROC_PEND) { |
| mutex_unlock(&lrme_hw->hw_mutex); |
| CAM_DBG(CAM_LRME, "Stop not needed in %d state", |
| lrme_core->state); |
| return 0; |
| } |
| |
| if (!lrme_core->req_proc && !lrme_core->req_submit) { |
| mutex_unlock(&lrme_hw->hw_mutex); |
| CAM_DBG(CAM_LRME, "no req in device"); |
| return 0; |
| } |
| |
| switch (flush_args->flush_type) { |
| case CAM_FLUSH_TYPE_ALL: |
| if ((!lrme_core->req_submit || |
| lrme_core->req_submit->ctxt_to_hw_map != |
| flush_args->ctxt_to_hw_map) && |
| (!lrme_core->req_proc || |
| lrme_core->req_proc->ctxt_to_hw_map != |
| flush_args->ctxt_to_hw_map)) { |
| mutex_unlock(&lrme_hw->hw_mutex); |
| CAM_DBG(CAM_LRME, "hw running on different ctx"); |
| return 0; |
| } |
| rc = cam_lrme_hw_util_flush_ctx(lrme_hw, |
| flush_args->ctxt_to_hw_map); |
| if (rc) |
| CAM_ERR(CAM_LRME, "Flush all failed"); |
| break; |
| |
| case CAM_FLUSH_TYPE_REQ: |
| if ((!lrme_core->req_submit || |
| lrme_core->req_submit != flush_args->req_to_flush) && |
| (!lrme_core->req_proc || |
| lrme_core->req_proc != flush_args->req_to_flush)) { |
| mutex_unlock(&lrme_hw->hw_mutex); |
| CAM_DBG(CAM_LRME, "hw running on different ctx"); |
| return 0; |
| } |
| rc = cam_lrme_hw_util_flush_req(lrme_hw, |
| flush_args->req_to_flush); |
| if (rc) |
| CAM_ERR(CAM_LRME, "Flush req failed"); |
| break; |
| |
| default: |
| CAM_ERR(CAM_LRME, "Unsupported flush type"); |
| break; |
| } |
| |
| mutex_unlock(&lrme_hw->hw_mutex); |
| |
| return rc; |
| } |
| |
| int cam_lrme_hw_get_caps(void *hw_priv, void *get_hw_cap_args, |
| uint32_t arg_size) |
| { |
| struct cam_hw_info *lrme_hw; |
| struct cam_lrme_core *lrme_core; |
| struct cam_lrme_dev_cap *lrme_hw_caps = |
| (struct cam_lrme_dev_cap *)get_hw_cap_args; |
| |
| if (!hw_priv || !get_hw_cap_args) { |
| CAM_ERR(CAM_LRME, "Invalid input pointers %pK %pK", |
| hw_priv, get_hw_cap_args); |
| return -EINVAL; |
| } |
| |
| lrme_hw = (struct cam_hw_info *)hw_priv; |
| lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; |
| *lrme_hw_caps = lrme_core->hw_caps; |
| |
| return 0; |
| } |
| |
| irqreturn_t cam_lrme_hw_irq(int irq_num, void *data) |
| { |
| struct cam_hw_info *lrme_hw; |
| struct cam_lrme_core *lrme_core; |
| struct cam_hw_soc_info *soc_info; |
| struct cam_lrme_hw_info *hw_info; |
| struct crm_workq_task *task; |
| struct cam_lrme_hw_work_data *work_data; |
| uint32_t top_irq_status, fe_irq_status, we_irq_status0, we_irq_status1; |
| int rc; |
| |
| if (!data) { |
| CAM_ERR(CAM_LRME, "Invalid data in IRQ callback"); |
| return IRQ_NONE; |
| } |
| |
| lrme_hw = (struct cam_hw_info *)data; |
| lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; |
| soc_info = &lrme_hw->soc_info; |
| hw_info = lrme_core->hw_info; |
| |
| top_irq_status = cam_io_r_mb( |
| soc_info->reg_map[0].mem_base + |
| hw_info->titan_reg.top_irq_status); |
| CAM_DBG(CAM_LRME, "top_irq_status %x", top_irq_status); |
| cam_io_w_mb(top_irq_status, |
| soc_info->reg_map[0].mem_base + |
| hw_info->titan_reg.top_irq_clear); |
| top_irq_status &= CAM_LRME_TOP_IRQ_MASK; |
| |
| fe_irq_status = cam_io_r_mb( |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_rd_reg.common_reg.irq_status); |
| CAM_DBG(CAM_LRME, "fe_irq_status %x", fe_irq_status); |
| cam_io_w_mb(fe_irq_status, |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_rd_reg.common_reg.irq_clear); |
| fe_irq_status &= CAM_LRME_FE_IRQ_MASK; |
| |
| we_irq_status0 = cam_io_r_mb( |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.irq_status_0); |
| CAM_DBG(CAM_LRME, "we_irq_status[0] %x", we_irq_status0); |
| cam_io_w_mb(we_irq_status0, |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.irq_clear_0); |
| we_irq_status0 &= CAM_LRME_WE_IRQ_MASK_0; |
| |
| we_irq_status1 = cam_io_r_mb( |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.irq_status_1); |
| CAM_DBG(CAM_LRME, "we_irq_status[1] %x", we_irq_status1); |
| cam_io_w_mb(we_irq_status1, |
| soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.irq_clear_1); |
| we_irq_status1 &= CAM_LRME_WE_IRQ_MASK_1; |
| |
| cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + |
| hw_info->titan_reg.top_irq_cmd); |
| cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + |
| hw_info->bus_wr_reg.common_reg.irq_cmd); |
| cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + |
| hw_info->bus_rd_reg.common_reg.irq_cmd); |
| |
| if (top_irq_status & 0x1) { |
| complete(&lrme_core->reset_complete); |
| top_irq_status &= (~0x1); |
| } |
| |
| if (top_irq_status || fe_irq_status || |
| we_irq_status0 || we_irq_status1) { |
| task = cam_req_mgr_workq_get_task(lrme_core->work); |
| if (!task) { |
| CAM_ERR(CAM_LRME, "no empty task available"); |
| return IRQ_NONE; |
| } |
| work_data = (struct cam_lrme_hw_work_data *)task->payload; |
| work_data->top_irq_status = top_irq_status; |
| work_data->fe_irq_status = fe_irq_status; |
| work_data->we_irq_status[0] = we_irq_status0; |
| work_data->we_irq_status[1] = we_irq_status1; |
| task->process_cb = cam_lrme_hw_process_irq; |
| rc = cam_req_mgr_workq_enqueue_task(task, data, |
| CRM_TASK_PRIORITY_0); |
| if (rc) |
| CAM_ERR(CAM_LRME, |
| "Failed in enqueue work task, rc=%d", rc); |
| } |
| |
| return IRQ_HANDLED; |
| } |
| |
| int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type, |
| void *cmd_args, uint32_t arg_size) |
| { |
| struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; |
| int rc = 0; |
| |
| switch (cmd_type) { |
| case CAM_LRME_HW_CMD_PREPARE_HW_UPDATE: { |
| struct cam_lrme_hw_cmd_config_args *config_args; |
| |
| config_args = (struct cam_lrme_hw_cmd_config_args *)cmd_args; |
| rc = cam_lrme_hw_util_process_config_hw(lrme_hw, config_args); |
| break; |
| } |
| |
| case CAM_LRME_HW_CMD_REGISTER_CB: { |
| struct cam_lrme_hw_cmd_set_cb *cb_args; |
| struct cam_lrme_device *hw_device; |
| struct cam_lrme_core *lrme_core = |
| (struct cam_lrme_core *)lrme_hw->core_info; |
| cb_args = (struct cam_lrme_hw_cmd_set_cb *)cmd_args; |
| lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb = |
| cb_args->cam_lrme_hw_mgr_cb; |
| lrme_core->hw_mgr_cb.data = cb_args->data; |
| hw_device = cb_args->data; |
| rc = 0; |
| break; |
| } |
| |
| case CAM_LRME_HW_CMD_SUBMIT: { |
| struct cam_lrme_hw_submit_args *submit_args; |
| |
| submit_args = (struct cam_lrme_hw_submit_args *)cmd_args; |
| rc = cam_lrme_hw_submit_req(hw_priv, |
| submit_args, arg_size); |
| break; |
| } |
| |
| case CAM_LRME_HW_CMD_DUMP_REGISTER: { |
| struct cam_lrme_core *lrme_core = |
| (struct cam_lrme_core *)lrme_hw->core_info; |
| lrme_core->dump_flag = *(bool *)cmd_args; |
| CAM_DBG(CAM_LRME, "dump_flag %d", lrme_core->dump_flag); |
| break; |
| } |
| |
| default: |
| break; |
| } |
| |
| return rc; |
| } |