From cae1cb3896547622c844ade5793255ab5a2d4ec6 Mon Sep 17 00:00:00 2001 From: Abhilash Kumar Date: Fri, 25 Oct 2019 15:36:10 +0530 Subject: [PATCH 001/295] msm: camera: cdm: Add support for different CDM hardware Different CDM hardware have different capability and registers. With old register space, handling new features and operations would have been a complex task. This change takes care of old version of CDM and also changes the regspace to provide every register's access to CDM. This change further adds support for "arbitration" in case of multi-context CDMs. Exports reset functionality to clients, detection of CDM hang. Flushing the CDM requests and dumping the FIFO content for all contexts. It also adds submitting "debug_gen_irq" as BL_done IRQ is only an indication for availability of FIFO's. The AHB operations are completed can only be known if the added "debug_gen_irqs" gets executed and are received by the CDM. CRs-Fixed: 2535587 Change-Id: I9846b1c5320ba652c5d3b7d83d616d2dabc843e1 Signed-off-by: Abhilash Kumar --- drivers/cam_cdm/cam_cdm.h | 488 ++++-- drivers/cam_cdm/cam_cdm_core_common.c | 200 ++- drivers/cam_cdm/cam_cdm_core_common.h | 19 +- drivers/cam_cdm/cam_cdm_hw_core.c | 1374 +++++++++++++---- drivers/cam_cdm/cam_cdm_hw_reg_1_0.h | 149 ++ drivers/cam_cdm/cam_cdm_hw_reg_1_1.h | 160 ++ drivers/cam_cdm/cam_cdm_hw_reg_1_2.h | 180 +++ drivers/cam_cdm/cam_cdm_hw_reg_2_0.h | 251 +++ drivers/cam_cdm/cam_cdm_intf.c | 122 +- drivers/cam_cdm/cam_cdm_intf_api.h | 71 +- drivers/cam_cdm/cam_cdm_soc.c | 163 +- drivers/cam_cdm/cam_cdm_soc.h | 14 +- drivers/cam_cdm/cam_cdm_util.c | 170 +- drivers/cam_cdm/cam_cdm_util.h | 76 +- drivers/cam_cdm/cam_hw_cdm170_reg.h | 135 -- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c | 5 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 9 +- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 5 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c | 4 +- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 1 + drivers/cam_smmu/cam_smmu_api.c | 171 +- drivers/cam_utils/cam_soc_util.c | 4 + drivers/cam_utils/cam_soc_util.h | 2 + 23 files changed, 3037 insertions(+), 736 deletions(-) create mode 100644 drivers/cam_cdm/cam_cdm_hw_reg_1_0.h create mode 100644 drivers/cam_cdm/cam_cdm_hw_reg_1_1.h create mode 100644 drivers/cam_cdm/cam_cdm_hw_reg_1_2.h create mode 100644 drivers/cam_cdm/cam_cdm_hw_reg_2_0.h delete mode 100644 drivers/cam_cdm/cam_hw_cdm170_reg.h diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index ab12ab52f293..ade86fe5dd24 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -26,24 +26,341 @@ #define CAM_CDM_INFLIGHT_WORKS 5 #define CAM_CDM_HW_RESET_TIMEOUT 300 +/* + * Macros to get prepare and get information + * from client CDM handles. + */ + #define CAM_CDM_HW_ID_MASK 0xF -#define CAM_CDM_HW_ID_SHIFT 0x5 -#define CAM_CDM_CLIENTS_ID_MASK 0x1F +#define CAM_CDM_HW_ID_SHIFT 0x10 + +#define CAM_CDM_CLIENTS_ID_MASK 0xFF + +#define CAM_CDM_BL_FIFO_ID_MASK 0xF +#define CAM_CDM_BL_FIFO_ID_SHIFT 0x8 #define CAM_CDM_GET_HW_IDX(x) (((x) >> CAM_CDM_HW_ID_SHIFT) & \ CAM_CDM_HW_ID_MASK) -#define CAM_CDM_CREATE_CLIENT_HANDLE(hw_idx, client_idx) \ + +#define CAM_CDM_GET_BLFIFO_IDX(x) (((x) >> CAM_CDM_BL_FIFO_ID_SHIFT) & \ + CAM_CDM_BL_FIFO_ID_MASK) + +#define CAM_CDM_CREATE_CLIENT_HANDLE(hw_idx, priority, client_idx) \ ((((hw_idx) & CAM_CDM_HW_ID_MASK) << CAM_CDM_HW_ID_SHIFT) | \ + (((priority) & CAM_CDM_BL_FIFO_ID_MASK) << CAM_CDM_BL_FIFO_ID_SHIFT)| \ ((client_idx) & CAM_CDM_CLIENTS_ID_MASK)) #define CAM_CDM_GET_CLIENT_IDX(x) ((x) & CAM_CDM_CLIENTS_ID_MASK) #define CAM_PER_CDM_MAX_REGISTERED_CLIENTS (CAM_CDM_CLIENTS_ID_MASK + 1) #define CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM (CAM_CDM_HW_ID_MASK + 1) -/* enum cam_cdm_reg_attr - read, write, read and write permissions.*/ -enum cam_cdm_reg_attr { - CAM_REG_ATTR_READ, - CAM_REG_ATTR_WRITE, - CAM_REG_ATTR_READ_WRITE, +/* Number of FIFO supported on CDM */ +#define CAM_CDM_NUM_BL_FIFO 0x4 + +/* Max number of register set for different CDM */ +#define CAM_CDM_BL_FIFO_REG_NUM 0x4 +#define CAM_CDM_BL_FIFO_IRQ_REG_NUM 0x4 +#define CAM_CDM_BL_FIFO_PENDING_REQ_REG_NUM 0x2 +#define CAM_CDM_SCRATCH_REG_NUM 0xc +#define CAM_CDM_COMP_WAIT_STATUS_REG_NUM 0x2 +#define CAM_CDM_PERF_MON_REG_NUM 0x2 + +/* 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_REQ_SIZE_MAX 0x00 +#define CAM_CDM_BL_FIFO_REQ_SIZE_MAX_DIV2 0x01 +#define CAM_CDM_BL_FIFO_REQ_SIZE_MAX_DIV4 0x10 +#define CAM_CDM_BL_FIFO_REQ_SIZE_MAX_DIV8 0x11 + +/* CDM core status bitmap */ +#define CAM_CDM_HW_INIT_STATUS 0x0 +#define CAM_CDM_FIFO_0_BLDONE_STATUS 0x0 +#define CAM_CDM_FIFO_1_BLDONE_STATUS 0x1 +#define CAM_CDM_FIFO_2_BLDONE_STATUS 0x2 +#define CAM_CDM_FIFO_3_BLDONE_STATUS 0x3 +#define CAM_CDM_RESET_HW_STATUS 0x4 +#define CAM_CDM_ERROR_HW_STATUS 0x5 +#define CAM_CDM_FLUSH_HW_STATUS 0x6 + +/* Curent BL command masks and shifts */ +#define CAM_CDM_CURRENT_BL_LEN 0xFFFFF +#define CAM_CDM_CURRENT_BL_ARB 0x100000 +#define CAM_CDM_CURRENT_BL_FIFO 0xC00000 +#define CAM_CDM_CURRENT_BL_TAG 0xFF000000 + +#define CAM_CDM_CURRENT_BL_ARB_SHIFT 0x14 +#define CAM_CDM_CURRENT_BL_FIFO_SHIFT 0x16 +#define CAM_CDM_CURRENT_BL_TAG_SHIFT 0x18 + +/* IRQ bit-masks */ +#define CAM_CDM_IRQ_STATUS_RST_DONE_MASK 0x1 +#define CAM_CDM_IRQ_STATUS_INLINE_IRQ_MASK 0x2 +#define CAM_CDM_IRQ_STATUS_BL_DONE_MASK 0x4 +#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_ERRORS \ + (CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK | \ + CAM_CDM_IRQ_STATUS_ERROR_OVER_FLOW_MASK | \ + CAM_CDM_IRQ_STATUS_ERROR_AHB_BUS_MASK) + +/* Structure to store hw version info */ +struct cam_version_reg { + uint32_t hw_version; +}; + +/** + * struct cam_cdm_irq_regs - CDM IRQ registers + * + * @irq_mask: register offset for irq_mask + * @irq_clear: register offset for irq_clear + * @irq_clear_cmd: register offset to initiate irq clear + * @irq_set: register offset to set irq + * @irq_set_cmd: register offset to issue set_irq from irq_set + * @irq_status: register offset to look which irq is received + */ +struct cam_cdm_irq_regs { + uint32_t irq_mask; + uint32_t irq_clear; + uint32_t irq_clear_cmd; + uint32_t irq_set; + uint32_t irq_set_cmd; + uint32_t irq_status; +}; + +/** + * struct cam_cdm_bl_fifo_regs - BL_FIFO registers + * + * @bl_fifo_base: register offset to write bl_cmd base address + * @bl_fifo_len: register offset to write bl_cmd length + * @bl_fifo_store: register offset to commit the BL cmd + * @bl_fifo_cfg: register offset to config BL_FIFO depth, etc. + */ +struct cam_cdm_bl_fifo_regs { + uint32_t bl_fifo_base; + uint32_t bl_fifo_len; + uint32_t bl_fifo_store; + uint32_t bl_fifo_cfg; +}; + +/** + * struct cam_cdm_bl_pending_req_reg_params - BL_FIFO pending registers + * + * @rb_offset: register offset pending bl request in BL_FIFO + * @rb_mask: mask to get number of pending BLs in BL_FIFO + * @rb_num_fifo: number of BL_FIFO's information in the register + * @rb_next_fifo_shift: shift to get next fifo's pending BLs. + */ +struct cam_cdm_bl_pending_req_reg_params { + uint32_t rb_offset; + uint32_t rb_mask; + uint32_t rb_num_fifo; + uint32_t rb_next_fifo_shift; +}; + +/** + * struct cam_cdm_scratch_reg - scratch register + * + * @scratch_reg: offset of scratch register + */ +struct cam_cdm_scratch_reg { + uint32_t scratch_reg; +}; + +/* struct cam_cdm_perf_mon_regs - perf_mon registers */ +struct cam_cdm_perf_mon_regs { + uint32_t perf_mon_ctrl; + uint32_t perf_mon_0; + uint32_t perf_mon_1; + uint32_t perf_mon_2; +}; + +/** + * struct cam_cdm_perf_mon_regs - perf mon counter's registers + * + * @count_cfg_0: register offset to configure perf measures + * @always_count_val: register offset for always count value + * @busy_count_val: register offset to get busy count + * @stall_axi_count_val: register offset to get axi stall counts + * @count_status: register offset to know if count status finished + * for stall, busy and always. + */ +struct cam_cdm_perf_regs { + uint32_t count_cfg_0; + uint32_t always_count_val; + uint32_t busy_count_val; + uint32_t stall_axi_count_val; + uint32_t count_status; +}; + +/** + * struct cam_cdm_icl_data_regs - CDM icl data registers + * + * @icl_last_data_0: register offset to log last known good command + * @icl_last_data_1: register offset to log last known good command 1 + * @icl_last_data_2: register offset to log last known good command 2 + * @icl_inv_data: register offset to log CDM cmd that triggered + * invalid command. + */ +struct cam_cdm_icl_data_regs { + uint32_t icl_last_data_0; + uint32_t icl_last_data_1; + uint32_t icl_last_data_2; + uint32_t icl_inv_data; +}; + +/** + * struct cam_cdm_icl_misc_regs - CDM icl misc registers + * + * @icl_inv_bl_addr: register offset to give address of bl_cmd that + * gave invalid command + * @icl_status: register offset for context that gave good BL + * command and invalid command. + */ +struct cam_cdm_icl_misc_regs { + uint32_t icl_inv_bl_addr; + uint32_t icl_status; +}; + +/** + * struct cam_cdm_icl_regs - CDM icl registers + * + * @data_regs: structure with registers of all cdm good and invalid + * BL command information. + * @misc_regs: structure with registers for invalid command address + * and context + */ +struct cam_cdm_icl_regs { + struct cam_cdm_icl_data_regs *data_regs; + struct cam_cdm_icl_misc_regs *misc_regs; +}; + +/** + * struct cam_cdm_comp_wait_status - BL_FIFO comp_event status register + * + * @comp_wait_status: register offset to give information on whether the + * CDM is waiting for an event from another module + */ +struct cam_cdm_comp_wait_status { + uint32_t comp_wait_status; +}; + +/** + * struct cam_cdm_common_reg_data - structure for register data + * + * @num_bl_fifo: number of FIFO are there in CDM + * @num_bl_fifo_irq: number of FIFO irqs in CDM + * @num_bl_pending_req_reg: number of pending_requests register in CDM + * @num_scratch_reg: number of scratch registers in CDM + */ +struct cam_cdm_common_reg_data { + uint32_t num_bl_fifo; + uint32_t num_bl_fifo_irq; + uint32_t num_bl_pending_req_reg; + uint32_t num_scratch_reg; +}; + +/** + * struct cam_cdm_common_regs - common structure to get common registers + * of CDM + * + * @cdm_hw_version: offset to read cdm_hw_version + * @cam_version: offset to read the camera Titan architecture version + * @rst_cmd: offset to reset the CDM + * @cgc_cfg: offset to configure CDM CGC logic + * @core_cfg: offset to configure CDM core with ARB_SEL, implicit + * wait, etc. + * @core_en: offset to pause/enable CDM + * @fe_cfg: offset to configure CDM fetch engine + * @bl_fifo_rb: offset to set BL_FIFO read back + * @bl_fifo_base_rb: offset to read back base address on offset set by + * bl_fifo_rb + * @bl_fifo_len_rb: offset to read back base len and tag on offset set by + * bl_fifo_rb + * @usr_data: offset to read user data from GEN_IRQ commands + * @wait_status: offset to read status for last WAIT command + * @last_ahb_addr: offset to read back last AHB address generated by CDM + * @last_ahb_data: offset to read back last AHB data generated by CDM + * @core_debug: offset to configure CDM debug bus and debug features + * @last_ahb_err_addr: offset to read back last AHB Error address generated + * by CDM + * @last_ahb_err_data: offset to read back last AHB Error data generated + * by CDM + * @current_bl_base: offset to read back current command buffer BASE address + * value out of BL_FIFO + * @current_bl_len: offset to read back current command buffer len, TAG, + * context ID ARB value out of BL_FIFO + * @current_used_ahb_base: offset to read back current base address used by + * CDM to access camera register + * @debug_status: offset to read back current CDM status + * @bus_misr_cfg0: offset to enable bus MISR and configure sampling mode + * @bus_misr_cfg1: offset to select from one of the six MISR's for reading + * signature value + * @bus_misr_rd_val: offset to read MISR signature + * @pending_req: registers to read pending request in FIFO + * @comp_wait: registers to read comp_event CDM is waiting for + * @perf_mon: registers to read perf_mon information + * @scratch: registers to read scratch register value + * @perf_reg: registers to read performance counters value + * @icl_reg: registers to read information related to good + * and invalid commands in FIFO + * @spare: spare register + * + */ +struct cam_cdm_common_regs { + uint32_t cdm_hw_version; + const struct cam_version_reg *cam_version; + uint32_t rst_cmd; + uint32_t cgc_cfg; + uint32_t core_cfg; + uint32_t core_en; + uint32_t fe_cfg; + uint32_t bl_fifo_rb; + uint32_t bl_fifo_base_rb; + uint32_t bl_fifo_len_rb; + uint32_t usr_data; + uint32_t wait_status; + uint32_t last_ahb_addr; + uint32_t last_ahb_data; + uint32_t core_debug; + uint32_t last_ahb_err_addr; + uint32_t last_ahb_err_data; + uint32_t current_bl_base; + uint32_t current_bl_len; + uint32_t current_used_ahb_base; + uint32_t debug_status; + uint32_t bus_misr_cfg0; + uint32_t bus_misr_cfg1; + uint32_t bus_misr_rd_val; + const struct cam_cdm_bl_pending_req_reg_params + *pending_req[CAM_CDM_BL_FIFO_PENDING_REQ_REG_NUM]; + const struct cam_cdm_comp_wait_status + *comp_wait[CAM_CDM_COMP_WAIT_STATUS_REG_NUM]; + const struct cam_cdm_perf_mon_regs + *perf_mon[CAM_CDM_PERF_MON_REG_NUM]; + const struct cam_cdm_scratch_reg + *scratch[CAM_CDM_SCRATCH_REG_NUM]; + const struct cam_cdm_perf_regs *perf_reg; + const struct cam_cdm_icl_regs *icl_reg; + uint32_t spare; +}; + +/** + * struct cam_cdm_hw_reg_offset - BL_FIFO comp_event status register + * + * @cmn_reg: pointer to structure to get common registers of a CDM + * @bl_fifo_reg: pointer to structure to get BL_FIFO registers of a CDM + * @irq_reg: pointer to structure to get IRQ registers of a CDM + * @reg_data: pointer to structure to reg_data related to CDM + * registers + */ +struct cam_cdm_hw_reg_offset { + const struct cam_cdm_common_regs *cmn_reg; + const struct cam_cdm_bl_fifo_regs *bl_fifo_reg[CAM_CDM_BL_FIFO_REG_NUM]; + const struct cam_cdm_irq_regs *irq_reg[CAM_CDM_BL_FIFO_IRQ_REG_NUM]; + const struct cam_cdm_common_reg_data *reg_data; }; /* enum cam_cdm_hw_process_intf_cmd - interface commands.*/ @@ -52,83 +369,11 @@ enum cam_cdm_hw_process_intf_cmd { CAM_CDM_HW_INTF_CMD_RELEASE, CAM_CDM_HW_INTF_CMD_SUBMIT_BL, 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_INVALID, }; -/* enum cam_cdm_regs - CDM driver offset enums.*/ -enum cam_cdm_regs { - /*cfg_offsets 0*/ - CDM_CFG_HW_VERSION, - CDM_CFG_TITAN_VERSION, - CDM_CFG_RST_CMD, - CDM_CFG_CGC_CFG, - CDM_CFG_CORE_CFG, - CDM_CFG_CORE_EN, - CDM_CFG_FE_CFG, - /*irq_offsets 7*/ - CDM_IRQ_MASK, - CDM_IRQ_CLEAR, - CDM_IRQ_CLEAR_CMD, - CDM_IRQ_SET, - CDM_IRQ_SET_CMD, - CDM_IRQ_STATUS, - CDM_IRQ_USR_DATA, - /*BL FIFO Registers 14*/ - CDM_BL_FIFO_BASE_REG, - CDM_BL_FIFO_LEN_REG, - CDM_BL_FIFO_STORE_REG, - CDM_BL_FIFO_CFG, - CDM_BL_FIFO_RB, - CDM_BL_FIFO_BASE_RB, - CDM_BL_FIFO_LEN_RB, - CDM_BL_FIFO_PENDING_REQ_RB, - /*CDM System Debug Registers 22*/ - CDM_DBG_WAIT_STATUS, - CDM_DBG_SCRATCH_0_REG, - CDM_DBG_SCRATCH_1_REG, - CDM_DBG_SCRATCH_2_REG, - CDM_DBG_SCRATCH_3_REG, - CDM_DBG_SCRATCH_4_REG, - CDM_DBG_SCRATCH_5_REG, - CDM_DBG_SCRATCH_6_REG, - CDM_DBG_SCRATCH_7_REG, - CDM_DBG_LAST_AHB_ADDR, - CDM_DBG_LAST_AHB_DATA, - CDM_DBG_CORE_DBUG, - CDM_DBG_LAST_AHB_ERR_ADDR, - CDM_DBG_LAST_AHB_ERR_DATA, - CDM_DBG_CURRENT_BL_BASE, - CDM_DBG_CURRENT_BL_LEN, - CDM_DBG_CURRENT_USED_AHB_BASE, - CDM_DBG_DEBUG_STATUS, - /*FE Bus Miser Registers 40*/ - CDM_BUS_MISR_CFG_0, - CDM_BUS_MISR_CFG_1, - CDM_BUS_MISR_RD_VAL, - /*Performance Counter registers 43*/ - CDM_PERF_MON_CTRL, - CDM_PERF_MON_0, - CDM_PERF_MON_1, - CDM_PERF_MON_2, - /*Spare registers 47*/ - CDM_SPARE, -}; - -/* struct cam_cdm_reg_offset - struct for offset with attribute.*/ -struct cam_cdm_reg_offset { - uint32_t offset; - enum cam_cdm_reg_attr attribute; -}; - -/* struct cam_cdm_reg_offset_table - struct for whole offset table.*/ -struct cam_cdm_reg_offset_table { - uint32_t first_offset; - uint32_t last_offset; - uint32_t reg_count; - const struct cam_cdm_reg_offset *offsets; - uint32_t offset_max_size; -}; - /* enum cam_cdm_flags - Bit fields for CDM flags used */ enum cam_cdm_flags { CAM_CDM_FLAG_SHARED_CDM, @@ -147,6 +392,29 @@ enum cam_cdm_mem_base_index { CAM_HW_CDM_MAX_INDEX = CAM_SOC_MAX_BLOCK, }; +/* enum cam_cdm_bl_cb_type - Enum for possible CAM CDM cb request types */ +enum cam_cdm_bl_cb_type { + CAM_HW_CDM_BL_CB_CLIENT = 1, + CAM_HW_CDM_BL_CB_INTERNAL, +}; + +/* enum cam_cdm_arbitration - Enum type of arbitration */ +enum cam_cdm_arbitration { + CAM_CDM_ARBITRATION_NONE, + CAM_CDM_ARBITRATION_ROUND_ROBIN, + CAM_CDM_ARBITRATION_PRIORITY_BASED, + CAM_CDM_ARBITRATION_MAX, +}; + +enum cam_cdm_hw_version { + CAM_CDM_VERSION = 0, + CAM_CDM_VERSION_1_0 = 0x10000000, + CAM_CDM_VERSION_1_1 = 0x10010000, + CAM_CDM_VERSION_1_2 = 0x10020000, + CAM_CDM_VERSION_2_0 = 0x20000000, + CAM_CDM_VERSION_MAX, +}; + /* struct cam_cdm_client - struct for cdm clients data.*/ struct cam_cdm_client { struct cam_cdm_acquire_data data; @@ -162,15 +430,10 @@ struct cam_cdm_work_payload { struct cam_hw_info *hw; uint32_t irq_status; uint32_t irq_data; + int fifo_idx; struct work_struct work; }; -/* enum cam_cdm_bl_cb_type - Enum for possible CAM CDM cb request types */ -enum cam_cdm_bl_cb_type { - CAM_HW_CDM_BL_CB_CLIENT = 1, - CAM_HW_CDM_BL_CB_INTERNAL, -}; - /* struct cam_cdm_bl_cb_request_entry - callback entry for work to process.*/ struct cam_cdm_bl_cb_request_entry { uint8_t bl_tag; @@ -195,28 +458,63 @@ struct cam_cdm_hw_mem { size_t size; }; -/* struct cam_cdm - CDM hw device struct */ +/* struct cam_cdm_bl_fifo - CDM hw memory struct */ +struct cam_cdm_bl_fifo { + struct completion bl_complete; + struct workqueue_struct *work_queue; + struct list_head bl_request_list; + struct mutex fifo_lock; + uint8_t bl_tag; + uint32_t bl_depth; +}; + +/** + * struct cam_cdm - CDM hw device struct + * + * @index: index of CDM hardware + * @name: cdm_name + * @id: enum for possible CDM hardwares + * @flags: enum to tell if CDM is private of shared + * @reset_complete: completion event to make CDM wait for reset + * @work_queue: workqueue to schedule work for virtual CDM + * @bl_request_list: bl_request list for submitted commands in + * virtual CDM + * @version: CDM version with major, minor, incr and reserved + * @hw_version: CDM version as read from the cdm_version register + * @hw_family_version: version of hw family the CDM belongs to + * @iommu_hdl: CDM iommu handle + * @offsets: pointer to structure of CDM registers + * @ops: CDM ops for generating cdm commands + * @clients: CDM clients array currently active on CDM + * @bl_fifo: structure with per fifo related attributes + * @cdm_status: bitfield with bits assigned for different cdm status + * @bl_tag: slot value at which the next bl cmd will be written + * in case of virtual CDM + * @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 + */ struct cam_cdm { uint32_t index; char name[128]; enum cam_cdm_id id; enum cam_cdm_flags flags; struct completion reset_complete; - struct completion bl_complete; struct workqueue_struct *work_queue; struct list_head bl_request_list; struct cam_hw_version version; uint32_t hw_version; uint32_t hw_family_version; struct cam_iommu_handle iommu_hdl; - struct cam_cdm_reg_offset_table *offset_tbl; + struct cam_cdm_hw_reg_offset *offsets; struct cam_cdm_utils_ops *ops; struct cam_cdm_client *clients[CAM_PER_CDM_MAX_REGISTERED_CLIENTS]; + struct cam_cdm_bl_fifo bl_fifo[CAM_CDM_BL_FIFO_MAX]; + unsigned long cdm_status; uint8_t bl_tag; - atomic_t error; - atomic_t bl_done; - struct cam_cdm_hw_mem gen_irq; + struct cam_cdm_hw_mem gen_irq[CAM_CDM_BL_FIFO_MAX]; uint32_t cpas_handle; + enum cam_cdm_arbitration arbitration; }; /* struct cam_cdm_private_dt_data - CDM hw custom dt data */ @@ -224,6 +522,8 @@ struct cam_cdm_private_dt_data { bool dt_cdm_shared; uint32_t dt_num_supported_clients; const char *dt_cdm_client_name[CAM_PER_CDM_MAX_REGISTERED_CLIENTS]; + bool config_fifo; + uint32_t fifo_depth[CAM_CDM_BL_FIFO_MAX]; }; /* struct cam_cdm_intf_devices - CDM mgr interface devices */ diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index e903dc805ed0..095fc4d9f8ba 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -45,9 +45,10 @@ bool cam_cdm_set_cam_hw_version( uint32_t ver, struct cam_hw_version *cam_version) { switch (ver) { - case CAM_CDM170_VERSION: - case CAM_CDM175_VERSION: - case CAM_CDM480_VERSION: + case CAM_CDM100_VERSION: + case CAM_CDM110_VERSION: + case CAM_CDM120_VERSION: + case CAM_CDM200_VERSION: cam_version->major = (ver & 0xF0000000); cam_version->minor = (ver & 0xFFF0000); cam_version->incr = (ver & 0xFFFF); @@ -76,9 +77,10 @@ struct cam_cdm_utils_ops *cam_cdm_get_ops( { if (by_cam_version == false) { switch (ver) { - case CAM_CDM170_VERSION: - case CAM_CDM175_VERSION: - case CAM_CDM480_VERSION: + case CAM_CDM100_VERSION: + case CAM_CDM110_VERSION: + case CAM_CDM120_VERSION: + case CAM_CDM200_VERSION: return &CDM170_ops; default: CAM_ERR(CAM_CDM, "CDM Version=%x not supported in util", @@ -183,6 +185,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, return; } cam_cdm_get_client_refcount(client); + mutex_lock(&client->lock); if (client->data.cam_cdm_callback) { CAM_DBG(CAM_CDM, "Calling client=%s cb cookie=%d", client->data.identifier, node->cookie); @@ -195,6 +198,38 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, CAM_ERR(CAM_CDM, "No cb registered for client hdl=%x", node->client_hdl); } + mutex_unlock(&client->lock); + cam_cdm_put_client_refcount(client); + return; + } else if (status == CAM_CDM_CB_STATUS_HW_RESET_DONE || + status == CAM_CDM_CB_STATUS_HW_FLUSH || + status == CAM_CDM_CB_STATUS_HW_RESUBMIT || + status == CAM_CDM_CB_STATUS_HW_ERROR) { + int client_idx; + struct cam_cdm_bl_cb_request_entry *node = + (struct cam_cdm_bl_cb_request_entry *)data; + + client_idx = CAM_CDM_GET_CLIENT_IDX(node->client_hdl); + client = core->clients[client_idx]; + if ((!client) || (client->handle != node->client_hdl)) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, + node->client_hdl); + return; + } + cam_cdm_get_client_refcount(client); + mutex_lock(&client->lock); + if (client->data.cam_cdm_callback) { + client->data.cam_cdm_callback( + client->handle, + client->data.userdata, + status, + node->cookie); + } else { + CAM_ERR(CAM_CDM, + "No cb registered for client: name %s, hdl=%x", + client->data.identifier, client->handle); + } + mutex_unlock(&client->lock); cam_cdm_put_client_refcount(client); return; } @@ -202,6 +237,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) { if (core->clients[i] != NULL) { client = core->clients[i]; + cam_cdm_get_client_refcount(client); mutex_lock(&client->lock); CAM_DBG(CAM_CDM, "Found client slot %d", i); if (client->data.cam_cdm_callback) { @@ -221,6 +257,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, client->handle); } mutex_unlock(&client->lock); + cam_cdm_put_client_refcount(client); } } } @@ -479,6 +516,27 @@ int cam_cdm_process_cmd(void *hw_priv, data = (struct cam_cdm_acquire_data *)cmd_args; CAM_DBG(CAM_CDM, "Trying to acquire client=%s in hw idx=%d", data->identifier, core->index); + + if (data->priority >= CAM_CDM_BL_FIFO_MAX) { + mutex_unlock(&cdm_hw->hw_mutex); + CAM_ERR(CAM_CDM, + "Invalid priority requested %d", + data->priority); + rc = -EINVAL; + break; + } + + if (core->id != CAM_CDM_VIRTUAL && + core->bl_fifo[data->priority].bl_depth == 0) { + mutex_unlock(&cdm_hw->hw_mutex); + CAM_ERR(CAM_CDM, + "FIFO %d not supported for core %d", + data->priority, + core->id); + rc = -EINVAL; + break; + } + idx = cam_cdm_find_free_client_slot(core); if ((idx < 0) || (core->clients[idx])) { mutex_unlock(&cdm_hw->hw_mutex); @@ -527,6 +585,7 @@ int cam_cdm_process_cmd(void *hw_priv, sizeof(struct cam_cdm_acquire_data)); client->handle = CAM_CDM_CREATE_CLIENT_HANDLE( core->index, + data->priority, idx); client->stream_on = false; data->handle = client->handle; @@ -575,8 +634,133 @@ int cam_cdm_process_cmd(void *hw_priv, break; } case CAM_CDM_HW_INTF_CMD_RESET_HW: { - CAM_ERR(CAM_CDM, "CDM HW reset not supported for handle =%x", - *((uint32_t *)cmd_args)); + 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_reset_hw(cdm_hw, *handle); + if (rc) { + CAM_ERR(CAM_CDM, + "CDM HW reset failed for handle 0x%x rc = %d", + *handle, rc); + } else { + CAM_INFO_RATE_LIMIT(CAM_CDM, + "CDM HW reset done for handle 0x%x", + *handle); + } + mutex_unlock(&cdm_hw->hw_mutex); + break; + } + case CAM_CDM_HW_INTF_CMD_FLUSH_HW: { + 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_flush_hw(cdm_hw, *handle); + if (rc) { + CAM_ERR(CAM_CDM, + "CDM HW flush failed for handle 0x%x rc = %d", + *handle, rc); + } else { + CAM_INFO_RATE_LIMIT(CAM_CDM, + "CDM HW flush done for handle 0x%x", + *handle); + } + mutex_unlock(&cdm_hw->hw_mutex); + break; + } + case CAM_CDM_HW_INTF_CMD_HANDLE_ERROR: { + 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_handle_error(cdm_hw, *handle); + if (rc) { + CAM_ERR(CAM_CDM, + "CDM HW handle error failed for handle 0x%x rc = %d", + *handle, rc); + } else { + CAM_INFO_RATE_LIMIT(CAM_CDM, + "CDM HW handle error done for handle 0x%x", + *handle); + } + + mutex_unlock(&cdm_hw->hw_mutex); break; } default: diff --git a/drivers/cam_cdm/cam_cdm_core_common.h b/drivers/cam_cdm/cam_cdm_core_common.h index 8dcbe8ed1971..c7a55b58e0c6 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.h +++ b/drivers/cam_cdm/cam_cdm_core_common.h @@ -8,9 +8,19 @@ #include "cam_mem_mgr.h" -#define CAM_CDM170_VERSION 0x10000000 -#define CAM_CDM175_VERSION 0x10010000 -#define CAM_CDM480_VERSION 0x10020000 +#define CAM_CDM100_VERSION 0x10000000 +#define CAM_CDM110_VERSION 0x10010000 +#define CAM_CDM120_VERSION 0x10020000 +#define CAM_CDM200_VERSION 0x20000000 + +#define CAM_CDM_AHB_BURST_LEN_1 (BIT(1) - 1) +#define CAM_CDM_AHB_BURST_LEN_4 (BIT(2) - 1) +#define CAM_CDM_AHB_BURST_LEN_8 (BIT(3) - 1) +#define CAM_CDM_AHB_BURST_LEN_16 (BIT(4) - 1) +#define CAM_CDM_AHB_BURST_EN BIT(5) +#define CAM_CDM_AHB_STOP_ON_ERROR BIT(8) +#define CAM_CDM_ARB_SEL_RR BIT(16) +#define CAM_CDM_IMPLICIT_WAIT_EN BIT(17) extern struct cam_cdm_utils_ops CDM170_ops; @@ -37,6 +47,9 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, 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); +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); 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 f54f9d61b55f..dcb88c66b8a4 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -18,14 +18,13 @@ #include "cam_cdm_core_common.h" #include "cam_cdm_soc.h" #include "cam_io_util.h" -#include "cam_hw_cdm170_reg.h" - -#define CAM_HW_CDM_CPAS_0_NAME "qcom,cam170-cpas-cdm0" -#define CAM_HW_CDM_IPE_0_NAME "qcom,cam170-ipe0-cdm" -#define CAM_HW_CDM_IPE_1_NAME "qcom,cam170-ipe1-cdm" -#define CAM_HW_CDM_BPS_NAME "qcom,cam170-bps-cdm" +#include "cam_cdm_hw_reg_1_0.h" +#include "cam_cdm_hw_reg_1_1.h" +#include "cam_cdm_hw_reg_1_2.h" +#include "cam_cdm_hw_reg_2_0.h" #define CAM_CDM_BL_FIFO_WAIT_TIMEOUT 2000 +#define CAM_CDM_DBG_GEN_IRQ_USR_DATA 0xff static void cam_hw_cdm_work(struct work_struct *work); @@ -33,65 +32,96 @@ static void cam_hw_cdm_work(struct work_struct *work); static const struct of_device_id msm_cam_hw_cdm_dt_match[] = { { .compatible = CAM_HW_CDM_CPAS_0_NAME, - .data = &cam170_cpas_cdm_offset_table, + .data = &cam_cdm_1_0_reg_offset, + }, + { + .compatible = CAM_HW_CDM_CPAS_NAME_1_0, + .data = &cam_cdm_1_0_reg_offset, + }, + { + .compatible = CAM_HW_CDM_CPAS_NAME_1_1, + .data = &cam_cdm_1_1_reg_offset, + }, + { + .compatible = CAM_HW_CDM_CPAS_NAME_1_2, + .data = &cam_cdm_1_2_reg_offset, + }, + { + .compatible = CAM_HW_CDM_IFE_NAME_1_2, + .data = &cam_cdm_1_2_reg_offset, + }, + { + .compatible = CAM_HW_CDM_CPAS_NAME_2_0, + .data = &cam_cdm_2_0_reg_offset, + }, + { + .compatible = CAM_HW_CDM_OPE_NAME_2_0, + .data = &cam_cdm_2_0_reg_offset, }, - {} }; static enum cam_cdm_id cam_hw_cdm_get_id_by_name(char *name) { - if (!strcmp(CAM_HW_CDM_CPAS_0_NAME, name)) - return CAM_CDM_CPAS_0; + if (strnstr(name, CAM_HW_CDM_CPAS_0_NAME, + strlen(CAM_HW_CDM_CPAS_0_NAME))) + return CAM_CDM_CPAS; + if (strnstr(name, CAM_HW_CDM_CPAS_NAME_1_0, + strlen(CAM_HW_CDM_CPAS_NAME_1_0))) + return CAM_CDM_CPAS; + if (strnstr(name, CAM_HW_CDM_CPAS_NAME_1_1, + strlen(CAM_HW_CDM_CPAS_NAME_1_1))) + return CAM_CDM_CPAS; + if (strnstr(name, CAM_HW_CDM_CPAS_NAME_1_2, + strlen(CAM_HW_CDM_CPAS_NAME_1_2))) + return CAM_CDM_CPAS; + if (strnstr(name, CAM_HW_CDM_IFE_NAME_1_2, + strlen(CAM_HW_CDM_CPAS_NAME_1_2))) + return CAM_CDM_IFE; + if (strnstr(name, CAM_HW_CDM_CPAS_NAME_2_0, + strlen(CAM_HW_CDM_CPAS_NAME_2_0))) + return CAM_CDM_CPAS; + if (strnstr(name, CAM_HW_CDM_OPE_NAME_2_0, + strlen(CAM_HW_CDM_CPAS_NAME_2_0))) + return CAM_CDM_OPE; return CAM_CDM_MAX; } -int cam_hw_cdm_bl_fifo_pending_bl_rb(struct cam_hw_info *cdm_hw, - uint32_t *pending_bl) -{ - int rc = 0; - - if (cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_PENDING_REQ_RB, - pending_bl)) { - CAM_ERR(CAM_CDM, "Failed to read CDM pending BL's"); - rc = -EIO; - } - - return rc; -} - static int cam_hw_cdm_enable_bl_done_irq(struct cam_hw_info *cdm_hw, - bool enable) + bool enable, uint32_t fifo_idx) { int rc = -EIO; uint32_t irq_mask = 0; struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; - if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_MASK, - &irq_mask)) { + if (cam_cdm_read_hw_reg(cdm_hw, + core->offsets->irq_reg[fifo_idx]->irq_mask, + &irq_mask)) { CAM_ERR(CAM_CDM, "Failed to read CDM IRQ mask"); return rc; } if (enable == true) { - if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, - (irq_mask | 0x4))) { + if (cam_cdm_write_hw_reg(cdm_hw, + core->offsets->irq_reg[fifo_idx]->irq_mask, + (irq_mask | 0x4))) { CAM_ERR(CAM_CDM, "Write failed to enable BL done irq"); } else { - atomic_inc(&core->bl_done); + set_bit(fifo_idx, &core->cdm_status); rc = 0; CAM_DBG(CAM_CDM, "BL done irq enabled =%d", - atomic_read(&core->bl_done)); + test_bit(fifo_idx, &core->cdm_status)); } } else { - if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, - (irq_mask & 0x70003))) { + if (cam_cdm_write_hw_reg(cdm_hw, + core->offsets->irq_reg[fifo_idx]->irq_mask, + (irq_mask & 0x70003))) { CAM_ERR(CAM_CDM, "Write failed to disable BL done irq"); } else { - atomic_dec(&core->bl_done); + clear_bit(fifo_idx, &core->cdm_status); rc = 0; CAM_DBG(CAM_CDM, "BL done irq disable =%d", - atomic_read(&core->bl_done)); + test_bit(fifo_idx, &core->cdm_status)); } } return rc; @@ -100,14 +130,19 @@ static int cam_hw_cdm_enable_bl_done_irq(struct cam_hw_info *cdm_hw, static int cam_hw_cdm_enable_core(struct cam_hw_info *cdm_hw, bool enable) { int rc = 0; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; if (enable == true) { - if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CORE_EN, 0x01)) { + 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, CDM_CFG_CORE_EN, 0x02)) { + 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; } @@ -118,8 +153,11 @@ static int cam_hw_cdm_enable_core(struct cam_hw_info *cdm_hw, bool enable) int cam_hw_cdm_enable_core_dbg(struct cam_hw_info *cdm_hw) { int rc = 0; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; - if (cam_cdm_write_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, 0x10100)) { + if (cam_cdm_write_hw_reg(cdm_hw, + core->offsets->cmn_reg->core_debug, + 0x10100)) { CAM_ERR(CAM_CDM, "Failed to Write CDM HW core debug"); rc = -EIO; } @@ -130,8 +168,10 @@ int cam_hw_cdm_enable_core_dbg(struct cam_hw_info *cdm_hw) int cam_hw_cdm_disable_core_dbg(struct cam_hw_info *cdm_hw) { int rc = 0; + struct cam_cdm *cdm_core = (struct cam_cdm *)cdm_hw->core_info; - if (cam_cdm_write_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, 0)) { + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->cmn_reg->core_debug, 0)) { CAM_ERR(CAM_CDM, "Failed to Write CDM HW core debug"); rc = -EIO; } @@ -142,129 +182,362 @@ int cam_hw_cdm_disable_core_dbg(struct cam_hw_info *cdm_hw) void cam_hw_cdm_dump_scratch_registors(struct cam_hw_info *cdm_hw) { uint32_t dump_reg = 0; + int i; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; - cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_EN, &dump_reg); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->core_en, &dump_reg); CAM_ERR(CAM_CDM, "dump core en=%x", dump_reg); - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_0_REG, &dump_reg); - CAM_ERR(CAM_CDM, "dump scratch0=%x", dump_reg); + for (i = 0; i < core->offsets->reg_data->num_scratch_reg; i++) { + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->scratch[i]->scratch_reg, + &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch%d=%x", i, dump_reg); + } +} + +int cam_hw_cdm_bl_fifo_pending_bl_rb_in_fifo( + struct cam_hw_info *cdm_hw, + uint32_t fifo_idx, + uint32_t *pending_bl_req) +{ + int rc = 0; + uint32_t fifo_reg; + uint32_t fifo_id; + + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + + if (fifo_idx >= CAM_CDM_BL_FIFO_REG_NUM) { + CAM_ERR(CAM_CDM, + "BL_FIFO index is wrong. fifo_idx %d", + fifo_idx); + rc = -EINVAL; + goto end; + } + + fifo_reg = fifo_idx / 2; + fifo_id = fifo_idx % 2; + + if (core->offsets->cmn_reg->pending_req[fifo_reg]) { + if (cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->pending_req + [fifo_reg]->rb_offset, + pending_bl_req)) { + CAM_ERR(CAM_CDM, "Error reading CDM register"); + rc = -EIO; + goto end; + } + + *pending_bl_req = (*pending_bl_req >> ( + core->offsets->cmn_reg->pending_req + [fifo_reg]->rb_next_fifo_shift * + fifo_id)) & core->offsets->cmn_reg->pending_req + [fifo_reg]->rb_mask; + rc = 0; + } - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_1_REG, &dump_reg); - CAM_ERR(CAM_CDM, "dump scratch1=%x", dump_reg); + CAM_DBG(CAM_CDM, "pending_bl_req %d fifo_reg %d, fifo_id %d", + *pending_bl_req, fifo_reg, fifo_id); - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_2_REG, &dump_reg); - CAM_ERR(CAM_CDM, "dump scratch2=%x", dump_reg); +end: + return rc; +} - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_3_REG, &dump_reg); - CAM_ERR(CAM_CDM, "dump scratch3=%x", dump_reg); +int cam_hw_cdm_enable_core_dbg_per_fifo( + struct cam_hw_info *cdm_hw, + uint32_t fifo_idx) +{ + int rc = 0; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_4_REG, &dump_reg); - CAM_ERR(CAM_CDM, "dump scratch4=%x", dump_reg); + if (cam_cdm_write_hw_reg(cdm_hw, + core->offsets->cmn_reg->core_debug, + (0x10100 | fifo_idx << 20))) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core debug"); + rc = -EIO; + } - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_5_REG, &dump_reg); - CAM_ERR(CAM_CDM, "dump scratch5=%x", dump_reg); + return rc; +} - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_6_REG, &dump_reg); - CAM_ERR(CAM_CDM, "dump scratch6=%x", dump_reg); +void cam_hw_cdm_dump_bl_fifo_data(struct cam_hw_info *cdm_hw) +{ + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + int i, j; + uint32_t num_pending_req = 0, dump_reg; - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_7_REG, &dump_reg); - CAM_ERR(CAM_CDM, "dump scratch7=%x", dump_reg); + for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) { + cam_hw_cdm_bl_fifo_pending_bl_rb_in_fifo(cdm_hw, + i, &num_pending_req); + if (cam_hw_cdm_enable_core_dbg_per_fifo(cdm_hw, i)) { + CAM_ERR(CAM_CDM, + "Problem in selecting the fifo for readback"); + continue; + } + for (j = 0 ; j < num_pending_req ; j++) { + cam_cdm_write_hw_reg(cdm_hw, + core->offsets->cmn_reg->bl_fifo_rb, j); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->bl_fifo_base_rb, + &dump_reg); + CAM_INFO(CAM_CDM, "BL(%d) base addr =%x", j, dump_reg); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->bl_fifo_len_rb, + &dump_reg); + CAM_INFO(CAM_CDM, + "CDM HW current BL len=%d ARB %d tag=%d, ", + (dump_reg & CAM_CDM_CURRENT_BL_LEN), + (dump_reg & CAM_CDM_CURRENT_BL_ARB) >> + CAM_CDM_CURRENT_BL_ARB_SHIFT, + (dump_reg & CAM_CDM_CURRENT_BL_TAG) >> + CAM_CDM_CURRENT_BL_TAG_SHIFT); + } + } } void cam_hw_cdm_dump_core_debug_registers( struct cam_hw_info *cdm_hw) { - uint32_t dump_reg, core_dbg, loop_cnt; + uint32_t dump_reg, core_dbg; + int i; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; - mutex_lock(&cdm_hw->hw_mutex); - cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_EN, &dump_reg); + 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); + /* First pause CDM, If it fails still proceed to dump debug info */ cam_hw_cdm_enable_core(cdm_hw, false); - cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW current pending BL=%x", dump_reg); - loop_cnt = dump_reg; - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_DEBUG_STATUS, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW Debug status reg=%x", dump_reg); - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, &core_dbg); + + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->debug_status, + &dump_reg); + CAM_INFO(CAM_CDM, "CDM HW Debug status reg=%x", dump_reg); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->core_debug, + &core_dbg); if (core_dbg & 0x100) { - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_LAST_AHB_ADDR, &dump_reg); - CAM_ERR(CAM_CDM, "AHB dump reglastaddr=%x", dump_reg); - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_LAST_AHB_DATA, &dump_reg); - CAM_ERR(CAM_CDM, "AHB dump reglastdata=%x", dump_reg); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->last_ahb_addr, + &dump_reg); + CAM_INFO(CAM_CDM, "AHB dump reglastaddr=%x", dump_reg); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->last_ahb_data, + &dump_reg); + CAM_INFO(CAM_CDM, "AHB dump reglastdata=%x", dump_reg); } else { - CAM_ERR(CAM_CDM, "CDM HW AHB dump not enable"); + CAM_INFO(CAM_CDM, "CDM HW AHB dump not enable"); } - if (core_dbg & 0x10000) { - int i; + cam_hw_cdm_dump_bl_fifo_data(cdm_hw); - CAM_ERR(CAM_CDM, "CDM HW BL FIFO dump with loop count=%d", - loop_cnt); - for (i = 0 ; i < loop_cnt ; i++) { - cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_RB, i); - cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_BASE_RB, - &dump_reg); - CAM_ERR(CAM_CDM, "BL(%d) base addr =%x", i, dump_reg); - cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_LEN_RB, - &dump_reg); - CAM_ERR(CAM_CDM, "BL(%d) len=%d tag=%d", i, - (dump_reg & 0xFFFFF), (dump_reg & 0xFF000000)); - } - } else { - CAM_ERR(CAM_CDM, "CDM HW BL FIFO readback not enable"); + CAM_INFO(CAM_CDM, "CDM HW default dump"); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->core_cfg, &dump_reg); + CAM_INFO(CAM_CDM, "CDM HW core cfg=%x", dump_reg); + + for (i = 0; i < + core->offsets->reg_data->num_bl_fifo_irq; + i++) { + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->irq_reg[i]->irq_status, &dump_reg); + CAM_INFO(CAM_CDM, "CDM HW irq status%d=%x", i, dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->irq_reg[i]->irq_set, &dump_reg); + CAM_INFO(CAM_CDM, "CDM HW irq set%d=%x", i, dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->irq_reg[i]->irq_mask, &dump_reg); + CAM_INFO(CAM_CDM, "CDM HW irq mask%d=%x", i, dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->irq_reg[i]->irq_clear, &dump_reg); + CAM_INFO(CAM_CDM, "CDM HW irq clear%d=%x", i, dump_reg); } - CAM_ERR(CAM_CDM, "CDM HW default dump"); - cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_CFG, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW core cfg=%x", dump_reg); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->current_bl_base, &dump_reg); + CAM_INFO(CAM_CDM, "CDM HW current BL base=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->current_bl_len, &dump_reg); + CAM_INFO(CAM_CDM, + "CDM HW current BL len=%d ARB %d FIFO %d tag=%d, ", + (dump_reg & CAM_CDM_CURRENT_BL_LEN), + (dump_reg & CAM_CDM_CURRENT_BL_ARB) >> + CAM_CDM_CURRENT_BL_ARB_SHIFT, + (dump_reg & CAM_CDM_CURRENT_BL_FIFO) >> + CAM_CDM_CURRENT_BL_FIFO_SHIFT, + (dump_reg & CAM_CDM_CURRENT_BL_TAG) >> + CAM_CDM_CURRENT_BL_TAG_SHIFT); + + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->current_used_ahb_base, &dump_reg); + CAM_INFO(CAM_CDM, "CDM HW current AHB base=%x", dump_reg); - cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_STATUS, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW irq status=%x", dump_reg); + /* Enable CDM back */ + cam_hw_cdm_enable_core(cdm_hw, true); +} - cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_SET, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW irq set reg=%x", dump_reg); +enum cam_cdm_arbitration cam_cdm_get_arbitration_type( + uint32_t cdm_version, + enum cam_cdm_id id) +{ + enum cam_cdm_arbitration arbitration; - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CURRENT_BL_BASE, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW current BL base=%x", dump_reg); + if (cdm_version < CAM_CDM_VERSION_2_0) { + arbitration = CAM_CDM_ARBITRATION_NONE; + goto end; + } - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CURRENT_BL_LEN, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW current BL len=%d tag=%d", - (dump_reg & 0xFFFFF), (dump_reg & 0xFF000000)); + switch (id) { + case CAM_CDM_CPAS: + arbitration = CAM_CDM_ARBITRATION_ROUND_ROBIN; + break; + default: + arbitration = CAM_CDM_ARBITRATION_PRIORITY_BASED; + break; + } +end: + return arbitration; +} - cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CURRENT_USED_AHB_BASE, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW current AHB base=%x", dump_reg); +int cam_hw_cdm_set_cdm_blfifo_cfg(struct cam_hw_info *cdm_hw) +{ + uint32_t blfifo_cfg_mask = 0; + int rc = 0, i; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; - cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &dump_reg); - CAM_ERR(CAM_CDM, "CDM HW current pending BL=%x", dump_reg); + blfifo_cfg_mask = blfifo_cfg_mask | + CAM_CDM_BL_FIFO_REQ_SIZE_MAX; - /* Enable CDM back */ - cam_hw_cdm_enable_core(cdm_hw, true); - mutex_unlock(&cdm_hw->hw_mutex); + for (i = 0; i < core->offsets->reg_data->num_bl_fifo_irq; i++) { + rc = cam_cdm_write_hw_reg(cdm_hw, + core->offsets->irq_reg[i]->irq_mask, 0x70003); + if (rc) { + CAM_ERR(CAM_CDM, + "Unable to write to cdm irq mask register"); + rc = -EIO; + goto end; + } + } + if (core->hw_version >= CAM_CDM_VERSION_2_0) { + for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) { + blfifo_cfg_mask = blfifo_cfg_mask | + (core->bl_fifo[i].bl_depth + << CAM_CDM_BL_FIFO_LENGTH_CFG_SHIFT); + rc = cam_cdm_write_hw_reg(cdm_hw, + core->offsets->bl_fifo_reg[i]->bl_fifo_cfg, + blfifo_cfg_mask); + if (rc) { + CAM_ERR(CAM_CDM, + "Unable to write to cdm irq mask register"); + rc = -EIO; + goto end; + } + } + } else { + for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) { + rc = cam_cdm_write_hw_reg(cdm_hw, + core->offsets->bl_fifo_reg[i]->bl_fifo_cfg, + blfifo_cfg_mask); + if (rc) { + CAM_ERR(CAM_CDM, + "Unable to write to cdm irq mask register"); + rc = -EIO; + goto end; + } + } + } +end: + return rc; } -int cam_hw_cdm_wait_for_bl_fifo(struct cam_hw_info *cdm_hw, - uint32_t bl_count) +int cam_hw_cdm_set_cdm_core_cfg(struct cam_hw_info *cdm_hw) +{ + uint32_t cdm_version; + uint32_t cfg_mask = 0; + int rc; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + + cfg_mask = cfg_mask | + CAM_CDM_AHB_STOP_ON_ERROR| + CAM_CDM_AHB_BURST_EN| + CAM_CDM_AHB_BURST_LEN_16; + + /* use version from cdm_core structure. */ + if (cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->cdm_hw_version, + &cdm_version)) { + CAM_ERR(CAM_CDM, "Error reading CDM register"); + rc = -EIO; + goto end; + } + + if (cdm_version < CAM_CDM_VERSION_2_0) { + rc = cam_cdm_write_hw_reg(cdm_hw, + core->offsets->cmn_reg->core_cfg, cfg_mask); + if (rc) { + CAM_ERR(CAM_CDM, "Error writing cdm core cfg"); + rc = -EIO; + goto end; + } + } else { + if (core->id != CAM_CDM_CPAS) + cfg_mask = cfg_mask | CAM_CDM_IMPLICIT_WAIT_EN; + + if (core->arbitration == CAM_CDM_ARBITRATION_ROUND_ROBIN) + cfg_mask = cfg_mask | CAM_CDM_ARB_SEL_RR; + + rc = cam_cdm_write_hw_reg(cdm_hw, + core->offsets->cmn_reg->core_cfg, cfg_mask); + if (rc) { + CAM_ERR(CAM_CDM, "Error writing cdm core cfg"); + rc = -EIO; + goto end; + } + } + +end: + return rc; +} + +int cam_hw_cdm_wait_for_bl_fifo( + struct cam_hw_info *cdm_hw, + uint32_t bl_count, + uint32_t fifo_idx) { uint32_t pending_bl = 0; int32_t available_bl_slots = 0; int rc = -EIO; long time_left; struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + struct cam_cdm_bl_fifo *bl_fifo = NULL; + + if (fifo_idx >= CAM_CDM_BL_FIFO_MAX) { + rc = -EINVAL; + CAM_ERR(CAM_CDM, + "Invalid fifo index %d rc = %d", + fifo_idx, rc); + goto end; + } + + bl_fifo = &core->bl_fifo[fifo_idx]; do { - if (cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_PENDING_REQ_RB, - &pending_bl)) { + if (cam_hw_cdm_bl_fifo_pending_bl_rb_in_fifo( + cdm_hw, fifo_idx, &pending_bl)) { CAM_ERR(CAM_CDM, "Failed to read CDM pending BL's"); rc = -EIO; break; } - available_bl_slots = CAM_CDM_HWFIFO_SIZE - pending_bl; + available_bl_slots = bl_fifo->bl_depth - pending_bl; if (available_bl_slots < 0) { CAM_ERR(CAM_CDM, "Invalid available slots %d:%d:%d", - available_bl_slots, CAM_CDM_HWFIFO_SIZE, + available_bl_slots, bl_fifo->bl_depth, pending_bl); break; } @@ -275,25 +548,28 @@ int cam_hw_cdm_wait_for_bl_fifo(struct cam_hw_info *cdm_hw, rc = bl_count; break; } else if (0 == (available_bl_slots - 1)) { - rc = cam_hw_cdm_enable_bl_done_irq(cdm_hw, true); + rc = cam_hw_cdm_enable_bl_done_irq(cdm_hw, + true, fifo_idx); if (rc) { CAM_ERR(CAM_CDM, "Enable BL done irq failed"); break; } time_left = wait_for_completion_timeout( - &core->bl_complete, msecs_to_jiffies( + &core->bl_fifo[fifo_idx].bl_complete, + msecs_to_jiffies( CAM_CDM_BL_FIFO_WAIT_TIMEOUT)); if (time_left <= 0) { CAM_ERR(CAM_CDM, "CDM HW BL Wait timed out failed"); if (cam_hw_cdm_enable_bl_done_irq(cdm_hw, - false)) + false, fifo_idx)) CAM_ERR(CAM_CDM, "Disable BL done irq failed"); rc = -EIO; break; } - if (cam_hw_cdm_enable_bl_done_irq(cdm_hw, false)) + if (cam_hw_cdm_enable_bl_done_irq(cdm_hw, + false, fifo_idx)) CAM_ERR(CAM_CDM, "Disable BL done irq failed"); rc = 0; CAM_DBG(CAM_CDM, "CDM HW is ready for data"); @@ -303,78 +579,110 @@ int cam_hw_cdm_wait_for_bl_fifo(struct cam_hw_info *cdm_hw, } } while (1); +end: + return rc; } -bool cam_hw_cdm_bl_write(struct cam_hw_info *cdm_hw, uint32_t src, - uint32_t len, uint32_t tag) +bool cam_hw_cdm_bl_write( + struct cam_hw_info *cdm_hw, uint32_t src, + uint32_t len, uint32_t tag, bool set_arb, + uint32_t fifo_idx) { - if (cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_BASE_REG, src)) { + struct cam_cdm *cdm_core = (struct cam_cdm *)cdm_hw->core_info; + + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->bl_fifo_reg[fifo_idx]->bl_fifo_base, + src)) { CAM_ERR(CAM_CDM, "Failed to write CDM base to BL base"); return true; } - if (cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_LEN_REG, - ((len & 0xFFFFF) | ((tag & 0xFF) << 20)))) { + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->bl_fifo_reg[fifo_idx]->bl_fifo_len, + ((len & 0xFFFFF) | ((tag & 0xFF) << 24)) | + ((set_arb) ? (1 << 20) : (0)))) { CAM_ERR(CAM_CDM, "Failed to write CDM BL len"); return true; } return false; } -bool cam_hw_cdm_commit_bl_write(struct cam_hw_info *cdm_hw) +bool cam_hw_cdm_commit_bl_write(struct cam_hw_info *cdm_hw, uint32_t fifo_idx) { - if (cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_STORE_REG, 1)) { + struct cam_cdm *cdm_core = (struct cam_cdm *)cdm_hw->core_info; + + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->bl_fifo_reg[fifo_idx]->bl_fifo_store, + 1)) { CAM_ERR(CAM_CDM, "Failed to write CDM commit BL"); return true; } return false; } -int cam_hw_cdm_submit_gen_irq(struct cam_hw_info *cdm_hw, - struct cam_cdm_hw_intf_cmd_submit_bl *req) +int cam_hw_cdm_submit_gen_irq( + struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, + uint32_t fifo_idx, bool set_arb) { struct cam_cdm_bl_cb_request_entry *node; struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; uint32_t len; int rc; + bool bit_wr_enable = false; - if (core->bl_tag > 63) { - CAM_ERR(CAM_CDM, "bl_tag invalid =%d", core->bl_tag); + if (core->bl_fifo[fifo_idx].bl_tag > 63) { + CAM_ERR(CAM_CDM, + "bl_tag invalid =%d", + core->bl_fifo[fifo_idx].bl_tag); rc = -EINVAL; goto end; } CAM_DBG(CAM_CDM, "CDM write BL last cmd tag=%x total=%d cookie=%d", - core->bl_tag, req->data->cmd_arrary_count, req->data->cookie); + core->bl_fifo[fifo_idx].bl_tag, + req->data->cmd_arrary_count, + req->data->cookie); + node = kzalloc(sizeof(struct cam_cdm_bl_cb_request_entry), GFP_KERNEL); if (!node) { rc = -ENOMEM; goto end; } + + if (core->offsets->reg_data->num_bl_fifo > 1) + bit_wr_enable = true; + node->request_type = CAM_HW_CDM_BL_CB_CLIENT; node->client_hdl = req->handle; node->cookie = req->data->cookie; - node->bl_tag = core->bl_tag; + node->bl_tag = core->bl_fifo[fifo_idx].bl_tag; node->userdata = req->data->userdata; - list_add_tail(&node->entry, &core->bl_request_list); - len = core->ops->cdm_required_size_genirq() * core->bl_tag; - core->ops->cdm_write_genirq(((uint32_t *)core->gen_irq.kmdvaddr + len), - core->bl_tag); - rc = cam_hw_cdm_bl_write(cdm_hw, (core->gen_irq.vaddr + (4*len)), + list_add_tail(&node->entry, &core->bl_fifo[fifo_idx].bl_request_list); + len = core->ops->cdm_required_size_genirq() * + core->bl_fifo[fifo_idx].bl_tag; + core->ops->cdm_write_genirq( + ((uint32_t *)core->gen_irq[fifo_idx].kmdvaddr + len), + core->bl_fifo[fifo_idx].bl_tag, + bit_wr_enable, fifo_idx); + rc = cam_hw_cdm_bl_write(cdm_hw, + (core->gen_irq[fifo_idx].vaddr + (4*len)), ((4 * core->ops->cdm_required_size_genirq()) - 1), - core->bl_tag); + core->bl_fifo[fifo_idx].bl_tag, + set_arb, fifo_idx); if (rc) { CAM_ERR(CAM_CDM, "CDM hw bl write failed for gen irq bltag=%d", - core->bl_tag); + core->bl_fifo[fifo_idx].bl_tag); list_del_init(&node->entry); kfree(node); rc = -EIO; goto end; } - if (cam_hw_cdm_commit_bl_write(cdm_hw)) { - CAM_ERR(CAM_CDM, "Cannot commit the genirq BL with tag tag=%d", - core->bl_tag); + if (cam_hw_cdm_commit_bl_write(cdm_hw, fifo_idx)) { + CAM_ERR(CAM_CDM, + "Cannot commit the genirq BL with tag tag=%d", + core->bl_fifo[fifo_idx].bl_tag); list_del_init(&node->entry); kfree(node); rc = -EIO; @@ -384,6 +692,52 @@ int cam_hw_cdm_submit_gen_irq(struct cam_hw_info *cdm_hw, return rc; } +int cam_hw_cdm_submit_debug_gen_irq( + struct cam_hw_info *cdm_hw, + uint32_t fifo_idx) +{ + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + uint32_t len; + int rc; + bool bit_wr_enable = false; + + CAM_DBG(CAM_CDM, + "CDM write BL last cmd tag=0x%x", + core->bl_fifo[fifo_idx].bl_tag); + + if (core->offsets->reg_data->num_bl_fifo > 1) + bit_wr_enable = true; + + len = core->ops->cdm_required_size_genirq() * + core->bl_fifo[fifo_idx].bl_tag; + core->ops->cdm_write_genirq( + ((uint32_t *)core->gen_irq[fifo_idx].kmdvaddr + len), + CAM_CDM_DBG_GEN_IRQ_USR_DATA, bit_wr_enable, fifo_idx); + rc = cam_hw_cdm_bl_write(cdm_hw, + (core->gen_irq[fifo_idx].vaddr + (4*len)), + ((4 * core->ops->cdm_required_size_genirq()) - 1), + core->bl_fifo[fifo_idx].bl_tag, + false, fifo_idx); + if (rc) { + CAM_ERR(CAM_CDM, + "CDM hw bl write failed for dbggenirq USRdata=%d tag 0x%x", + CAM_CDM_DBG_GEN_IRQ_USR_DATA, + core->bl_fifo[fifo_idx].bl_tag); + rc = -EIO; + goto end; + } + if (cam_hw_cdm_commit_bl_write(cdm_hw, fifo_idx)) { + CAM_ERR(CAM_CDM, + "Cannot commit the dbggenirq BL with tag tag=0x%x", + core->bl_fifo[fifo_idx].bl_tag); + rc = -EIO; + goto end; + } + +end: + return rc; +} + 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) @@ -391,24 +745,42 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, int i, rc; struct cam_cdm_bl_request *cdm_cmd = req->data; struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; - uint32_t pending_bl = 0; + struct cam_cdm_bl_fifo *bl_fifo = NULL; + uint32_t pending_bl = 0, fifo_idx = 0; int write_count = 0; - if (req->data->cmd_arrary_count > CAM_CDM_HWFIFO_SIZE) { - pr_info("requested BL more than max size, cnt=%d max=%d", - req->data->cmd_arrary_count, CAM_CDM_HWFIFO_SIZE); + fifo_idx = CAM_CDM_GET_BLFIFO_IDX(client->handle); + + if (fifo_idx >= CAM_CDM_BL_FIFO_MAX) { + rc = -EINVAL; + CAM_ERR(CAM_CDM, "Invalid handle 0x%x, rc = %d", + client->handle, rc); + goto end; } - if (atomic_read(&core->error)) - return -EIO; + bl_fifo = &core->bl_fifo[fifo_idx]; - mutex_lock(&cdm_hw->hw_mutex); + if (req->data->cmd_arrary_count > bl_fifo->bl_depth) { + CAM_INFO(CAM_CDM, + "requested BL more than max size, cnt=%d max=%d", + req->data->cmd_arrary_count, + 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); - rc = cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &pending_bl); + + rc = cam_hw_cdm_bl_fifo_pending_bl_rb_in_fifo(cdm_hw, + fifo_idx, &pending_bl); + if (rc) { CAM_ERR(CAM_CDM, "Cannot read the current BL depth"); mutex_unlock(&client->lock); - mutex_unlock(&cdm_hw->hw_mutex); + mutex_unlock(&core->bl_fifo[fifo_idx].fifo_lock); return rc; } @@ -425,16 +797,19 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, rc = -EINVAL; break; } - if (atomic_read(&core->error)) { + if (test_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status) || + test_bit(CAM_CDM_RESET_HW_STATUS, + &core->cdm_status)) { CAM_ERR_RATE_LIMIT(CAM_CDM, - "In error state cnt=%d total cnt=%d\n", - i, req->data->cmd_arrary_count); - rc = -EIO; + "In error/reset state cnt=%d total cnt=%d cdm_status 0x%x", + i, req->data->cmd_arrary_count, + core->cdm_status); + rc = -EAGAIN; break; } if (write_count == 0) { write_count = cam_hw_cdm_wait_for_bl_fifo(cdm_hw, - (req->data->cmd_arrary_count - i)); + (req->data->cmd_arrary_count - i), fifo_idx); if (write_count < 0) { CAM_ERR(CAM_CDM, "wait for bl fifo failed %d:%d", @@ -485,13 +860,16 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, } CAM_DBG(CAM_CDM, "Got the HW VA"); - if (core->bl_tag >= - (CAM_CDM_HWFIFO_SIZE - 1)) - core->bl_tag = 0; + 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_tag); + (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); @@ -512,40 +890,92 @@ 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", - i, core->bl_tag, req->data->cmd_arrary_count); + 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)) { + if (cam_hw_cdm_commit_bl_write(cdm_hw, fifo_idx)) { CAM_ERR(CAM_CDM, "Cannot commit the BL %d tag=%d", - i, core->bl_tag); + 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_tag); - core->bl_tag++; + core->bl_fifo[fifo_idx].bl_tag); + core->bl_fifo[fifo_idx].bl_tag++; + + if (cdm_cmd->cmd[i].enable_debug_gen_irq) { + rc = cam_hw_cdm_submit_debug_gen_irq(cdm_hw, + fifo_idx); + if (rc == 0) + core->bl_fifo[fifo_idx].bl_tag++; + if (core->bl_fifo[fifo_idx].bl_tag >= + (bl_fifo->bl_depth - + 1)) + core->bl_fifo[fifo_idx].bl_tag = 0; + } + if ((req->data->flag == true) && (i == (req->data->cmd_arrary_count - 1))) { rc = cam_hw_cdm_submit_gen_irq( - cdm_hw, req); + cdm_hw, req, fifo_idx, + cdm_cmd->gen_irq_arb); if (rc == 0) - core->bl_tag++; + core->bl_fifo[fifo_idx].bl_tag++; } } } mutex_unlock(&client->lock); - mutex_unlock(&cdm_hw->hw_mutex); + mutex_unlock(&core->bl_fifo[fifo_idx].fifo_lock); + +end: return rc; } +static void cam_hw_cdm_reset_cleanup( + struct cam_hw_info *cdm_hw, + uint32_t handle) +{ + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + int i; + struct cam_cdm_bl_cb_request_entry *node, *tnode; + bool flush_hw = false; + + if (test_bit(CAM_CDM_FLUSH_HW_STATUS, &core->cdm_status)) + flush_hw = true; + + for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) { + list_for_each_entry_safe(node, tnode, + &core->bl_fifo[i].bl_request_list, entry) { + if (node->request_type == + CAM_HW_CDM_BL_CB_CLIENT) { + if (flush_hw) + cam_cdm_notify_clients(cdm_hw, + (node->client_hdl == handle) ? + CAM_CDM_CB_STATUS_HW_FLUSH : + CAM_CDM_CB_STATUS_HW_RESUBMIT, + (void *)node); + else + cam_cdm_notify_clients(cdm_hw, + CAM_CDM_CB_STATUS_HW_RESET_DONE, + (void *)node); + } + list_del_init(&node->entry); + kfree(node); + } + core->bl_fifo[i].bl_tag = 0; + } +} + static void cam_hw_cdm_work(struct work_struct *work) { struct cam_cdm_work_payload *payload; struct cam_hw_info *cdm_hw; struct cam_cdm *core; + int i; payload = container_of(work, struct cam_cdm_work_payload, work); if (payload) { @@ -554,14 +984,24 @@ static void cam_hw_cdm_work(struct work_struct *work) CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); if (payload->irq_status & - CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { + 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); - mutex_lock(&cdm_hw->hw_mutex); + + if (payload->irq_data == 0xff) { + CAM_INFO(CAM_CDM, "Debug genirq received"); + kfree(payload); + return; + } + + mutex_lock(&core->bl_fifo[payload->fifo_idx] + .fifo_lock); list_for_each_entry_safe(node, tnode, - &core->bl_request_list, entry) { + &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, @@ -580,41 +1020,42 @@ static void cam_hw_cdm_work(struct work_struct *work) } kfree(node); } - mutex_unlock(&cdm_hw->hw_mutex); + mutex_unlock(&core->bl_fifo[payload->fifo_idx] + .fifo_lock); } if (payload->irq_status & - CAM_CDM_IRQ_STATUS_INFO_RST_DONE_MASK) { + 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_INFO_BL_DONE_MASK) { - if (atomic_read(&core->bl_done)) { + CAM_CDM_IRQ_STATUS_BL_DONE_MASK) { + if (test_bit(payload->fifo_idx, &core->cdm_status)) { CAM_DBG(CAM_CDM, "CDM HW BL done IRQ"); - complete(&core->bl_complete); + complete(&core->bl_fifo[payload->fifo_idx] + .bl_complete); } } if (payload->irq_status & - CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK) { + CAM_CDM_IRQ_STATUS_ERRORS) { CAM_ERR_RATE_LIMIT(CAM_CDM, - "Invalid command IRQ, Need HW reset\n"); - atomic_inc(&core->error); - cam_hw_cdm_dump_core_debug_registers(cdm_hw); - } - if (payload->irq_status & - CAM_CDM_IRQ_STATUS_ERROR_AHB_BUS_MASK) { - CAM_ERR_RATE_LIMIT(CAM_CDM, "AHB Error IRQ\n"); - atomic_inc(&core->error); - cam_hw_cdm_dump_core_debug_registers(cdm_hw); - atomic_dec(&core->error); - } - if (payload->irq_status & - CAM_CDM_IRQ_STATUS_ERROR_OVER_FLOW_MASK) { - CAM_ERR_RATE_LIMIT(CAM_CDM, "Overflow Error IRQ\n"); - atomic_inc(&core->error); + "CDM Error IRQ status %d\n", + payload->irq_status); + set_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status); + 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); - atomic_dec(&core->error); + 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); + if (!(payload->irq_status & + CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK)) + clear_bit(CAM_CDM_ERROR_HW_STATUS, + &core->cdm_status); } kfree(payload); } else { @@ -629,17 +1070,24 @@ static void cam_hw_cdm_iommu_fault_handler(struct iommu_domain *domain, { struct cam_hw_info *cdm_hw = NULL; struct cam_cdm *core = NULL; + int i; if (token) { cdm_hw = (struct cam_hw_info *)token; core = (struct cam_cdm *)cdm_hw->core_info; - atomic_inc(&core->error); + set_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status); + 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); + 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); CAM_ERR_RATE_LIMIT(CAM_CDM, "Page fault iova addr %pK\n", (void *)iova); cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_PAGEFAULT, (void *)iova); - atomic_dec(&core->error); + clear_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status); } else { CAM_ERR(CAM_CDM, "Invalid token"); } @@ -650,46 +1098,88 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) { struct cam_hw_info *cdm_hw = data; struct cam_cdm *cdm_core = cdm_hw->core_info; - struct cam_cdm_work_payload *payload; + struct cam_cdm_work_payload *payload[CAM_CDM_BL_FIFO_MAX] = {0}; + uint32_t user_data = 0; + uint32_t irq_status[CAM_CDM_BL_FIFO_MAX] = {0}; bool work_status; + int i; CAM_DBG(CAM_CDM, "Got irq"); - payload = kzalloc(sizeof(struct cam_cdm_work_payload), GFP_ATOMIC); - if (payload) { - if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_STATUS, - &payload->irq_status)) { + + 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, + &irq_status[i])) { CAM_ERR(CAM_CDM, "Failed to read CDM HW IRQ status"); } - if (!payload->irq_status) { - CAM_ERR_RATE_LIMIT(CAM_CDM, "Invalid irq received\n"); - kfree(payload); - return IRQ_HANDLED; + } + + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo_irq; i++) { + if (!irq_status[i]) { + cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->irq_reg[i]->irq_clear, + irq_status[i]); + continue; } - if (payload->irq_status & - CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { - if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_USR_DATA, - &payload->irq_data)) { + + payload[i] = kzalloc(sizeof(struct cam_cdm_work_payload), + GFP_ATOMIC); + + if (!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); + + if (payload[i]->irq_data == + CAM_CDM_DBG_GEN_IRQ_USR_DATA) + CAM_INFO(CAM_CDM, + "Debug gen_irq received"); } - CAM_DBG(CAM_CDM, "Got payload=%d", payload->irq_status); - payload->hw = cdm_hw; - INIT_WORK((struct work_struct *)&payload->work, + + payload[i]->fifo_idx = i; + payload[i]->irq_status = irq_status[i]; + payload[i]->hw = cdm_hw; + + INIT_WORK((struct work_struct *)&payload[i]->work, cam_hw_cdm_work); - if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR, - payload->irq_status)) - CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ Clear"); - if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR_CMD, 0x01)) - CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ cmd"); - work_status = queue_work(cdm_core->work_queue, &payload->work); + + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->irq_reg[i]->irq_clear, + payload[i]->irq_status)) { + CAM_ERR(CAM_CDM, + "Failed to Write CDM HW IRQ Clear"); + kfree(payload[i]); + return IRQ_HANDLED; + } + + 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->irq_status); - kfree(payload); + CAM_ERR(CAM_CDM, + "Failed to queue work for irq=0x%x", + payload[i]->irq_status); + kfree(payload[i]); } } + 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"); + return IRQ_HANDLED; } @@ -699,27 +1189,32 @@ int cam_hw_cdm_alloc_genirq_mem(void *hw_priv) struct cam_mem_mgr_request_desc genirq_alloc_cmd; struct cam_mem_mgr_memory_desc genirq_alloc_out; struct cam_cdm *cdm_core = NULL; - int rc = -EINVAL; + int rc = -EINVAL, i; if (!hw_priv) return rc; cdm_core = (struct cam_cdm *)cdm_hw->core_info; genirq_alloc_cmd.align = 0; - genirq_alloc_cmd.size = (8 * CAM_CDM_HWFIFO_SIZE); genirq_alloc_cmd.smmu_hdl = cdm_core->iommu_hdl.non_secure; genirq_alloc_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE; - rc = cam_mem_mgr_request_mem(&genirq_alloc_cmd, - &genirq_alloc_out); - if (rc) { - CAM_ERR(CAM_CDM, "Failed to get genirq cmd space rc=%d", rc); - goto end; + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { + genirq_alloc_cmd.size = (8 * + cdm_core->bl_fifo[i].bl_depth); + rc = cam_mem_mgr_request_mem(&genirq_alloc_cmd, + &genirq_alloc_out); + if (rc) { + CAM_ERR(CAM_CDM, + "Failed to get genirq cmd space rc=%d", + rc); + goto end; + } + cdm_core->gen_irq[i].handle = genirq_alloc_out.mem_handle; + cdm_core->gen_irq[i].vaddr = (genirq_alloc_out.iova & + 0xFFFFFFFF); + cdm_core->gen_irq[i].kmdvaddr = genirq_alloc_out.kva; + cdm_core->gen_irq[i].size = genirq_alloc_out.len; } - cdm_core->gen_irq.handle = genirq_alloc_out.mem_handle; - cdm_core->gen_irq.vaddr = (genirq_alloc_out.iova & 0xFFFFFFFF); - cdm_core->gen_irq.kmdvaddr = genirq_alloc_out.kva; - cdm_core->gen_irq.size = genirq_alloc_out.len; - end: return rc; } @@ -729,28 +1224,292 @@ int cam_hw_cdm_release_genirq_mem(void *hw_priv) struct cam_hw_info *cdm_hw = hw_priv; struct cam_cdm *cdm_core = NULL; struct cam_mem_mgr_memory_desc genirq_release_cmd; - int rc = -EINVAL; + int rc = -EINVAL, i; if (!hw_priv) return rc; cdm_core = (struct cam_cdm *)cdm_hw->core_info; - genirq_release_cmd.mem_handle = cdm_core->gen_irq.handle; - rc = cam_mem_mgr_release_mem(&genirq_release_cmd); - if (rc) - CAM_ERR(CAM_CDM, "Failed to put genirq cmd space for hw"); + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { + genirq_release_cmd.mem_handle = cdm_core->gen_irq[i].handle; + rc = cam_mem_mgr_release_mem(&genirq_release_cmd); + if (rc) + CAM_ERR(CAM_CDM, + "Failed to put genirq cmd space for hw rc %d", + rc); + } + + return rc; +} + +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; + + 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); + + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { + 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"); + goto end; + } + } + + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->cmn_reg->rst_cmd, 0x9)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW reset"); + goto end; + } + + 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); + goto end; + } + + rc = cam_hw_cdm_set_cdm_core_cfg(cdm_hw); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to configure CDM rc=%d", rc); + goto end; + } + + rc = cam_hw_cdm_set_cdm_blfifo_cfg(cdm_hw); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to configure CDM fifo rc=%d", rc); + goto end; + } + + cam_hw_cdm_reset_cleanup(cdm_hw, handle); +end: + 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); + + return rc; +} + +int cam_hw_cdm_handle_error_info( + struct cam_hw_info *cdm_hw, + uint32_t handle) +{ + struct cam_cdm *cdm_core = NULL; + struct cam_cdm_bl_cb_request_entry *node = NULL; + long time_left; + int i, rc = -EIO, reset_hw_hdl = 0x0; + uint32_t current_bl_data = 0, current_fifo = 0, current_tag = 0; + + 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); + + rc = cam_cdm_read_hw_reg(cdm_hw, + cdm_core->offsets->cmn_reg->current_bl_len, + ¤t_bl_data); + + current_fifo = ((CAM_CDM_CURRENT_BL_FIFO & current_bl_data) + >> CAM_CDM_CURRENT_BL_FIFO_SHIFT); + current_tag = ((CAM_CDM_CURRENT_BL_TAG & current_bl_data) + >> CAM_CDM_CURRENT_BL_TAG_SHIFT); + + if (current_fifo >= CAM_CDM_BL_FIFO_MAX) { + rc = -EFAULT; + goto end; + } + + CAM_ERR(CAM_CDM, "Hang detected for fifo %d with tag 0x%x", + current_fifo, current_tag); + + /* dump cdm registers for further debug */ + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + + for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { + 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"); + goto end; + } + } + + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->cmn_reg->rst_cmd, 0x9)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW reset"); + goto end; + } + + CAM_DBG(CAM_CDM, "Waiting for CDM HW resetdone"); + 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); + goto end; + } + + rc = cam_hw_cdm_set_cdm_core_cfg(cdm_hw); + + if (rc) { + CAM_ERR(CAM_CDM, "Failed to configure CDM rc=%d", rc); + goto end; + } + + rc = cam_hw_cdm_set_cdm_blfifo_cfg(cdm_hw); + + if (rc) { + CAM_ERR(CAM_CDM, "Failed to configure CDM fifo rc=%d", rc); + goto end; + } + + node = list_first_entry_or_null( + &cdm_core->bl_fifo[current_fifo].bl_request_list, + struct cam_cdm_bl_cb_request_entry, entry); + + if (node != NULL) { + if (node->request_type == CAM_HW_CDM_BL_CB_CLIENT) { + cam_cdm_notify_clients(cdm_hw, + CAM_CDM_CB_STATUS_HW_ERROR, + (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); + } + list_del_init(&node->entry); + kfree(node); + } + + cam_hw_cdm_reset_cleanup(cdm_hw, reset_hw_hdl); +end: + clear_bit(CAM_CDM_FLUSH_HW_STATUS, &cdm_core->cdm_status); + 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); + + return rc; +} + +int cam_hw_cdm_flush_hw(struct cam_hw_info *cdm_hw, uint32_t handle) +{ + struct cam_cdm *cdm_core = NULL; + int rc = 0; + + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + + set_bit(CAM_CDM_FLUSH_HW_STATUS, &cdm_core->cdm_status); + rc = cam_hw_cdm_reset_hw(cdm_hw, handle); + clear_bit(CAM_CDM_FLUSH_HW_STATUS, &cdm_core->cdm_status); + + return rc; +} + +int cam_hw_cdm_handle_error( + struct cam_hw_info *cdm_hw, + uint32_t handle) +{ + struct cam_cdm *cdm_core = NULL; + int rc = 0; + + 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_get_cdm_config(struct cam_hw_info *cdm_hw) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_cdm *core = NULL; + int rc = 0; + + core = (struct cam_cdm *)cdm_hw->core_info; + soc_info = &cdm_hw->soc_info; + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) { + CAM_ERR(CAM_CDM, "Enable platform failed for dev %s", + soc_info->dev_name); + goto end; + } else { + CAM_DBG(CAM_CDM, "CDM init success"); + cdm_hw->hw_state = CAM_HW_STATE_POWER_UP; + } + + if (cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->cdm_hw_version, + &core->hw_version)) { + CAM_ERR(CAM_CDM, "Failed to read CDM HW Version"); + rc = -EIO; + goto disable_platform_resource; + } + + if (core->offsets->cmn_reg->cam_version) { + if (cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->cam_version->hw_version, + &core->hw_family_version)) { + CAM_ERR(CAM_CDM, "Failed to read CDM family Version"); + rc = -EIO; + goto disable_platform_resource; + } + } + + CAM_DBG(CAM_CDM, + "CDM Hw version read success family =%x hw =%x", + core->hw_family_version, core->hw_version); + + core->ops = cam_cdm_get_ops(core->hw_version, NULL, + false); + + if (!core->ops) { + CAM_ERR(CAM_CDM, "Failed to util ops for cdm hw name %s", + core->name); + rc = -EINVAL; + goto disable_platform_resource; + } + +disable_platform_resource: + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + + if (rc) { + CAM_ERR(CAM_CDM, "disable platform failed for dev %s", + soc_info->dev_name); + } else { + CAM_DBG(CAM_CDM, "CDM Deinit success"); + cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + } +end: + return rc; +} + int cam_hw_cdm_init(void *hw_priv, void *init_hw_args, uint32_t arg_size) { struct cam_hw_info *cdm_hw = hw_priv; struct cam_hw_soc_info *soc_info = NULL; struct cam_cdm *cdm_core = NULL; - int rc; - long time_left; + int rc, i, reset_hw_hdl = 0x0; if (!hw_priv) return -EINVAL; @@ -768,31 +1527,25 @@ int cam_hw_cdm_init(void *hw_priv, CAM_DBG(CAM_CDM, "Enable soc done"); /* Before triggering the reset to HW, clear the reset complete */ - atomic_set(&cdm_core->error, 0); - atomic_set(&cdm_core->bl_done, 0); - reinit_completion(&cdm_core->reset_complete); - reinit_completion(&cdm_core->bl_complete); + clear_bit(CAM_CDM_ERROR_HW_STATUS, &cdm_core->cdm_status); - if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, 0x70003)) { - CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ mask"); - goto disable_return; - } - if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_RST_CMD, 0x9)) { - CAM_ERR(CAM_CDM, "Failed to Write CDM HW reset"); - goto disable_return; + for (i = 0; i < CAM_CDM_BL_FIFO_MAX; i++) { + clear_bit(i, &cdm_core->cdm_status); + reinit_completion(&cdm_core->bl_fifo[i].bl_complete); } - CAM_DBG(CAM_CDM, "Waiting for CDM HW resetdone"); - time_left = wait_for_completion_timeout(&cdm_core->reset_complete, - msecs_to_jiffies(CAM_CDM_HW_RESET_TIMEOUT)); + rc = cam_hw_cdm_reset_hw(cdm_hw, reset_hw_hdl); - if (time_left <= 0) { + if (rc) { CAM_ERR(CAM_CDM, "CDM HW reset Wait failed rc=%d", rc); goto disable_return; } else { CAM_DBG(CAM_CDM, "CDM Init success"); cdm_hw->hw_state = CAM_HW_STATE_POWER_UP; - cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, 0x70003); + 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, + 0x70003); rc = 0; goto end; } @@ -830,7 +1583,7 @@ int cam_hw_cdm_deinit(void *hw_priv, int cam_hw_cdm_probe(struct platform_device *pdev) { - int rc; + int rc, len = 0, i, j; struct cam_hw_info *cdm_hw = NULL; struct cam_hw_intf *cdm_hw_intf = NULL; struct cam_cdm *cdm_core = NULL; @@ -838,6 +1591,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) struct cam_cpas_register_params cpas_parms; struct cam_ahb_vote ahb_vote; struct cam_axi_vote axi_vote = {0}; + char cdm_name[128], work_q_name[128]; cdm_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); if (!cdm_hw_intf) @@ -880,16 +1634,17 @@ int cam_hw_cdm_probe(struct platform_device *pdev) else cdm_core->flags = CAM_CDM_FLAG_PRIVATE_CDM; - cdm_core->bl_tag = 0; cdm_core->id = cam_hw_cdm_get_id_by_name(cdm_core->name); + + CAM_DBG(CAM_CDM, "cdm_name %s", cdm_core->name); + if (cdm_core->id >= CAM_CDM_MAX) { CAM_ERR(CAM_CDM, "Failed to get CDM HW name for %s", cdm_core->name); goto release_private_mem; } - INIT_LIST_HEAD(&cdm_core->bl_request_list); + init_completion(&cdm_core->reset_complete); - init_completion(&cdm_core->bl_complete); cdm_hw_intf->hw_priv = cdm_hw; cdm_hw_intf->hw_ops.get_hw_caps = cam_cdm_get_caps; cdm_hw_intf->hw_ops.init = cam_hw_cdm_init; @@ -906,19 +1661,47 @@ int cam_hw_cdm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, cdm_hw_intf); - rc = cam_smmu_get_handle("cpas-cdm0", &cdm_core->iommu_hdl.non_secure); + snprintf(cdm_name, sizeof(cdm_name), "%s%d", + cdm_hw->soc_info.label_name, cdm_hw->soc_info.index); + + rc = cam_smmu_get_handle(cdm_name, &cdm_core->iommu_hdl.non_secure); if (rc < 0) { - CAM_ERR(CAM_CDM, "cpas-cdm get iommu handle failed"); - goto unlock_release_mem; + if (rc != -EALREADY) { + CAM_ERR(CAM_CDM, + "%s get iommu handle failed, rc = %d", + cdm_name, rc); + goto unlock_release_mem; + } + rc = 0; } + cam_smmu_set_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, cam_hw_cdm_iommu_fault_handler, cdm_hw); cdm_core->iommu_hdl.secure = -1; - cdm_core->work_queue = alloc_workqueue(cdm_core->name, - WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, - CAM_CDM_INFLIGHT_WORKS); + for (i = 0; i < CAM_CDM_BL_FIFO_MAX; i++) { + INIT_LIST_HEAD(&cdm_core->bl_fifo[i].bl_request_list); + + mutex_init(&cdm_core->bl_fifo[i].fifo_lock); + + init_completion(&cdm_core->bl_fifo[i].bl_complete); + + len = strlcpy(work_q_name, cdm_core->name, + sizeof(cdm_core->name)); + snprintf(work_q_name + len, sizeof(work_q_name) - len, "%d", i); + cdm_core->bl_fifo[i].work_queue = alloc_workqueue(work_q_name, + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, + CAM_CDM_INFLIGHT_WORKS); + if (!cdm_core->bl_fifo[i].work_queue) { + CAM_ERR(CAM_CDM, + "Workqueue allocation failed for FIFO %d, cdm %s", + i, cdm_core->name); + goto failed_workq_create; + } + + CAM_DBG(CAM_CDM, "wq %s", work_q_name); + } rc = cam_soc_util_request_platform_resource(&cdm_hw->soc_info, cam_hw_cdm_irq, cdm_hw); @@ -926,12 +1709,12 @@ int cam_hw_cdm_probe(struct platform_device *pdev) CAM_ERR(CAM_CDM, "Failed to request platform resource"); goto destroy_non_secure_hdl; } - cpas_parms.cam_cpas_client_cb = cam_cdm_cpas_cb; cpas_parms.cell_index = cdm_hw->soc_info.index; cpas_parms.dev = &pdev->dev; cpas_parms.userdata = cdm_hw_intf; - strlcpy(cpas_parms.identifier, "cpas-cdm", CAM_HW_IDENTIFIER_LENGTH); + strlcpy(cpas_parms.identifier, cdm_hw->soc_info.label_name, + CAM_HW_IDENTIFIER_LENGTH); rc = cam_cpas_register_client(&cpas_parms); if (rc) { CAM_ERR(CAM_CDM, "Virtual CDM CPAS registration failed"); @@ -956,37 +1739,44 @@ int cam_hw_cdm_probe(struct platform_device *pdev) goto cpas_unregister; } - rc = cam_hw_cdm_init(cdm_hw, NULL, 0); + rc = cam_hw_cdm_get_cdm_config(cdm_hw); if (rc) { - CAM_ERR(CAM_CDM, "Failed to Init CDM HW"); + CAM_ERR(CAM_CDM, "Failed to get cdm configuration rc = %d", rc); goto cpas_stop; } - cdm_hw->open_count++; - if (cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_HW_VERSION, - &cdm_core->hw_version)) { - CAM_ERR(CAM_CDM, "Failed to read CDM HW Version"); - goto deinit; + if (cdm_core->hw_version < CAM_CDM_VERSION_2_0) { + for (i = 0; i < CAM_CDM_BL_FIFO_MAX; i++) { + cdm_core->bl_fifo[i].bl_depth = + CAM_CDM_BL_FIFO_LENGTH_MAX_DEFAULT; + CAM_DBG(CAM_CDM, "Setting FIFO%d length to %d", + i, cdm_core->bl_fifo[i].bl_depth); + } + } else { + for (i = 0; i < CAM_CDM_BL_FIFO_MAX; i++) { + cdm_core->bl_fifo[i].bl_depth = + soc_private->fifo_depth[i]; + CAM_DBG(CAM_CDM, "Setting FIFO%d length to %d", + i, cdm_core->bl_fifo[i].bl_depth); + } } - if (cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_TITAN_VERSION, - &cdm_core->hw_family_version)) { - CAM_ERR(CAM_CDM, "Failed to read CDM family Version"); - goto deinit; - } + cdm_core->arbitration = cam_cdm_get_arbitration_type( + cdm_core->hw_version, cdm_core->id); - CAM_DBG(CAM_CDM, "CDM Hw version read success family =%x hw =%x", - cdm_core->hw_family_version, cdm_core->hw_version); - cdm_core->ops = cam_cdm_get_ops(cdm_core->hw_version, NULL, - false); - if (!cdm_core->ops) { - CAM_ERR(CAM_CDM, "Failed to util ops for hw"); - goto deinit; + cdm_core->cdm_status = CAM_CDM_HW_INIT_STATUS; + + rc = cam_hw_cdm_init(cdm_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to Init CDM HW"); + goto cpas_stop; } + cdm_hw->open_count++; if (!cam_cdm_set_cam_hw_version(cdm_core->hw_version, &cdm_core->version)) { - CAM_ERR(CAM_CDM, "Failed to set cam he version for hw"); + CAM_ERR(CAM_CDM, "Failed to set cam hw version for hw"); + rc = -EINVAL; goto deinit; } @@ -1014,7 +1804,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) cdm_hw->open_count--; mutex_unlock(&cdm_hw->hw_mutex); - CAM_DBG(CAM_CDM, "CDM%d probe successful", cdm_hw_intf->hw_idx); + CAM_DBG(CAM_CDM, "%s probe successful", cdm_core->name); return rc; @@ -1031,9 +1821,11 @@ int cam_hw_cdm_probe(struct platform_device *pdev) release_platform_resource: if (cam_soc_util_release_platform_resource(&cdm_hw->soc_info)) CAM_ERR(CAM_CDM, "Release platform resource failed"); - - flush_workqueue(cdm_core->work_queue); - destroy_workqueue(cdm_core->work_queue); +failed_workq_create: + for (j = 0; j < i; j++) { + flush_workqueue(cdm_core->bl_fifo[j].work_queue); + destroy_workqueue(cdm_core->bl_fifo[j].work_queue); + } destroy_non_secure_hdl: cam_smmu_set_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, NULL, cdm_hw); @@ -1053,7 +1845,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) int cam_hw_cdm_remove(struct platform_device *pdev) { - int rc = -EBUSY; + int rc = -EBUSY, i; struct cam_hw_info *cdm_hw = NULL; struct cam_hw_intf *cdm_hw_intf = NULL; struct cam_cdm *cdm_core = NULL; @@ -1102,8 +1894,10 @@ int cam_hw_cdm_remove(struct platform_device *pdev) if (cam_soc_util_release_platform_resource(&cdm_hw->soc_info)) CAM_ERR(CAM_CDM, "Release platform resource failed"); - flush_workqueue(cdm_core->work_queue); - destroy_workqueue(cdm_core->work_queue); + for (i = 0; i < CAM_CDM_BL_FIFO_MAX; i++) { + flush_workqueue(cdm_core->bl_fifo[i].work_queue); + destroy_workqueue(cdm_core->bl_fifo[i].work_queue); + } if (cam_smmu_destroy_handle(cdm_core->iommu_hdl.non_secure)) CAM_ERR(CAM_CDM, "Release iommu secure hdl failed"); diff --git a/drivers/cam_cdm/cam_cdm_hw_reg_1_0.h b/drivers/cam_cdm/cam_cdm_hw_reg_1_0.h new file mode 100644 index 000000000000..ad0e9d62731d --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_hw_reg_1_0.h @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_cdm.h" + +static struct cam_version_reg cdm_hw_1_0_titan_version = { + .hw_version = 0x4, +}; + +struct cam_cdm_bl_pending_req_reg_params cdm_hw_1_0_bl_pending_req0 = { + .rb_offset = 0x6c, + .rb_mask = 0x7F, + .rb_num_fifo = 0x1, + .rb_next_fifo_shift = 0x0, +}; + +static struct cam_cdm_irq_regs cdm_hw_1_0_irq0 = { + .irq_mask = 0x30, + .irq_clear = 0x34, + .irq_clear_cmd = 0x38, + .irq_set = 0x3c, + .irq_set_cmd = 0x40, + .irq_status = 0x44, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_1_0_bl_fifo0 = { + .bl_fifo_base = 0x50, + .bl_fifo_len = 0x54, + .bl_fifo_store = 0x58, + .bl_fifo_cfg = 0x5c, +}; + +static struct cam_cdm_scratch_reg cdm_1_0_scratch_reg0 = { + .scratch_reg = 0x90, +}; + +static struct cam_cdm_scratch_reg cdm_1_0_scratch_reg1 = { + .scratch_reg = 0x94, +}; + +static struct cam_cdm_scratch_reg cdm_1_0_scratch_reg2 = { + .scratch_reg = 0x98, +}; + +static struct cam_cdm_scratch_reg cdm_1_0_scratch_reg3 = { + .scratch_reg = 0x9c, +}; + +static struct cam_cdm_scratch_reg cdm_1_0_scratch_reg4 = { + .scratch_reg = 0xa0, +}; + +static struct cam_cdm_scratch_reg cdm_1_0_scratch_reg5 = { + .scratch_reg = 0xa4, +}; + +static struct cam_cdm_scratch_reg cdm_1_0_scratch_reg6 = { + .scratch_reg = 0xa8, +}; + +static struct cam_cdm_scratch_reg cdm_1_0_scratch_reg7 = { + .scratch_reg = 0xac, +}; + +static struct cam_cdm_perf_mon_regs cdm_1_0_perf_mon0 = { + .perf_mon_ctrl = 0x110, + .perf_mon_0 = 0x114, + .perf_mon_1 = 0x118, + .perf_mon_2 = 0x11c, +}; + +static struct cam_cdm_common_regs cdm_hw_1_0_cmn_reg_offset = { + .cdm_hw_version = 0x0, + .cam_version = &cdm_hw_1_0_titan_version, + .rst_cmd = 0x10, + .cgc_cfg = 0x14, + .core_cfg = 0x18, + .core_en = 0x1c, + .fe_cfg = 0x20, + .bl_fifo_rb = 0x60, + .bl_fifo_base_rb = 0x64, + .bl_fifo_len_rb = 0x68, + .usr_data = 0x80, + .wait_status = 0x84, + .last_ahb_addr = 0xd0, + .last_ahb_data = 0xd4, + .core_debug = 0xd8, + .last_ahb_err_addr = 0xe0, + .last_ahb_err_data = 0xe4, + .current_bl_base = 0xe8, + .current_bl_len = 0xec, + .current_used_ahb_base = 0xf0, + .debug_status = 0xf4, + .bus_misr_cfg0 = 0x100, + .bus_misr_cfg1 = 0x104, + .bus_misr_rd_val = 0x108, + .pending_req = { + &cdm_hw_1_0_bl_pending_req0, + NULL, + }, + .comp_wait = { NULL, NULL }, + .perf_mon = { + &cdm_1_0_perf_mon0, + NULL, + }, + .scratch = { + &cdm_1_0_scratch_reg0, + &cdm_1_0_scratch_reg1, + &cdm_1_0_scratch_reg2, + &cdm_1_0_scratch_reg3, + &cdm_1_0_scratch_reg4, + &cdm_1_0_scratch_reg5, + &cdm_1_0_scratch_reg6, + &cdm_1_0_scratch_reg7, + NULL, + NULL, + NULL, + NULL, + }, + .perf_reg = NULL, + .icl_reg = NULL, + .spare = 0x200, +}; + +static struct cam_cdm_common_reg_data cdm_hw_1_0_cmn_reg_data = { + .num_bl_fifo = 0x1, + .num_bl_fifo_irq = 0x1, + .num_bl_pending_req_reg = 0x1, + .num_scratch_reg = 0x8, +}; + +static struct cam_cdm_hw_reg_offset cam_cdm_1_0_reg_offset = { + .cmn_reg = &cdm_hw_1_0_cmn_reg_offset, + .bl_fifo_reg = { + &cdm_hw_1_0_bl_fifo0, + NULL, + NULL, + NULL, + }, + .irq_reg = { + &cdm_hw_1_0_irq0, + NULL, + NULL, + NULL, + }, + .reg_data = &cdm_hw_1_0_cmn_reg_data, +}; diff --git a/drivers/cam_cdm/cam_cdm_hw_reg_1_1.h b/drivers/cam_cdm/cam_cdm_hw_reg_1_1.h new file mode 100644 index 000000000000..c2345df725bc --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_hw_reg_1_1.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_cdm.h" + +static struct cam_version_reg cdm_hw_1_1_titan_version = { + .hw_version = 0x4, +}; + +struct cam_cdm_bl_pending_req_reg_params cdm_hw_1_1_bl_pending_req0 = { + .rb_offset = 0x6c, + .rb_mask = 0x7f, + .rb_num_fifo = 0x1, + .rb_next_fifo_shift = 0x0, +}; + +static struct cam_cdm_irq_regs cdm_hw_1_1_irq0 = { + .irq_mask = 0x30, + .irq_clear = 0x34, + .irq_clear_cmd = 0x38, + .irq_set = 0x3c, + .irq_set_cmd = 0x40, + .irq_status = 0x44, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_1_1_bl_fifo0 = { + .bl_fifo_base = 0x50, + .bl_fifo_len = 0x54, + .bl_fifo_store = 0x58, + .bl_fifo_cfg = 0x5c, +}; + +static struct cam_cdm_scratch_reg cdm_1_1_scratch_reg0 = { + .scratch_reg = 0x90, +}; + +static struct cam_cdm_scratch_reg cdm_1_1_scratch_reg1 = { + .scratch_reg = 0x94, +}; + +static struct cam_cdm_scratch_reg cdm_1_1_scratch_reg2 = { + .scratch_reg = 0x98, +}; + +static struct cam_cdm_scratch_reg cdm_1_1_scratch_reg3 = { + .scratch_reg = 0x9c, +}; + +static struct cam_cdm_scratch_reg cdm_1_1_scratch_reg4 = { + .scratch_reg = 0xa0, +}; + +static struct cam_cdm_scratch_reg cdm_1_1_scratch_reg5 = { + .scratch_reg = 0xa4, +}; + +static struct cam_cdm_scratch_reg cdm_1_1_scratch_reg6 = { + .scratch_reg = 0xa8, +}; + +static struct cam_cdm_scratch_reg cdm_1_1_scratch_reg7 = { + .scratch_reg = 0xac, +}; + +static struct cam_cdm_perf_mon_regs cdm_1_1_perf_mon0 = { + .perf_mon_ctrl = 0x110, + .perf_mon_0 = 0x114, + .perf_mon_1 = 0x118, + .perf_mon_2 = 0x11c, +}; + +static struct cam_cdm_comp_wait_status cdm_1_1_comp_wait_status0 = { + .comp_wait_status = 0x88, +}; + +static struct cam_cdm_comp_wait_status cdm_1_1_comp_wait_status1 = { + .comp_wait_status = 0x8c, +}; + +static struct cam_cdm_common_regs cdm_hw_1_1_cmn_reg_offset = { + .cdm_hw_version = 0x0, + .cam_version = &cdm_hw_1_1_titan_version, + .rst_cmd = 0x10, + .cgc_cfg = 0x14, + .core_cfg = 0x18, + .core_en = 0x1c, + .fe_cfg = 0x20, + .bl_fifo_rb = 0x60, + .bl_fifo_base_rb = 0x64, + .bl_fifo_len_rb = 0x68, + .usr_data = 0x80, + .wait_status = 0x84, + .last_ahb_addr = 0xd0, + .last_ahb_data = 0xd4, + .core_debug = 0xd8, + .last_ahb_err_addr = 0xe0, + .last_ahb_err_data = 0xe4, + .current_bl_base = 0xe8, + .current_bl_len = 0xec, + .current_used_ahb_base = 0xf0, + .debug_status = 0xf4, + .bus_misr_cfg0 = 0x100, + .bus_misr_cfg1 = 0x104, + .bus_misr_rd_val = 0x108, + .pending_req = { + &cdm_hw_1_1_bl_pending_req0, + NULL, + }, + .comp_wait = { + &cdm_1_1_comp_wait_status0, + &cdm_1_1_comp_wait_status1, + }, + .perf_mon = { + &cdm_1_1_perf_mon0, + NULL, + }, + .scratch = { + &cdm_1_1_scratch_reg0, + &cdm_1_1_scratch_reg1, + &cdm_1_1_scratch_reg2, + &cdm_1_1_scratch_reg3, + &cdm_1_1_scratch_reg4, + &cdm_1_1_scratch_reg5, + &cdm_1_1_scratch_reg6, + &cdm_1_1_scratch_reg7, + NULL, + NULL, + NULL, + NULL, + }, + .perf_reg = NULL, + .icl_reg = NULL, + .spare = 0x1fc, +}; + +static struct cam_cdm_common_reg_data cdm_hw_1_1_cmn_reg_data = { + .num_bl_fifo = 0x1, + .num_bl_fifo_irq = 0x1, + .num_bl_pending_req_reg = 0x1, + .num_scratch_reg = 0x8, +}; + +struct cam_cdm_hw_reg_offset cam_cdm_1_1_reg_offset = { + .cmn_reg = &cdm_hw_1_1_cmn_reg_offset, + .bl_fifo_reg = { + &cdm_hw_1_1_bl_fifo0, + NULL, + NULL, + NULL, + }, + .irq_reg = { + &cdm_hw_1_1_irq0, + NULL, + NULL, + NULL, + }, + .reg_data = &cdm_hw_1_1_cmn_reg_data, +}; diff --git a/drivers/cam_cdm/cam_cdm_hw_reg_1_2.h b/drivers/cam_cdm/cam_cdm_hw_reg_1_2.h new file mode 100644 index 000000000000..63d1410eaff2 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_hw_reg_1_2.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_cdm.h" + +static struct cam_version_reg cdm_hw_1_2_titan_version = { + .hw_version = 0x4, +}; + +struct cam_cdm_bl_pending_req_reg_params cdm_hw_1_2_bl_pending_req0 = { + .rb_offset = 0x6c, + .rb_mask = 0x7f, + .rb_num_fifo = 0x1, + .rb_next_fifo_shift = 0x0, +}; + +static struct cam_cdm_irq_regs cdm_hw_1_2_irq0 = { + .irq_mask = 0x30, + .irq_clear = 0x34, + .irq_clear_cmd = 0x38, + .irq_set = 0x3c, + .irq_set_cmd = 0x40, + .irq_status = 0x44, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_1_2_bl_fifo0 = { + .bl_fifo_base = 0x50, + .bl_fifo_len = 0x54, + .bl_fifo_store = 0x58, + .bl_fifo_cfg = 0x5c, +}; + +static struct cam_cdm_scratch_reg cdm_1_2_scratch_reg0 = { + .scratch_reg = 0x90, +}; + +static struct cam_cdm_scratch_reg cdm_1_2_scratch_reg1 = { + .scratch_reg = 0x94, +}; + +static struct cam_cdm_scratch_reg cdm_1_2_scratch_reg2 = { + .scratch_reg = 0x98, +}; + +static struct cam_cdm_scratch_reg cdm_1_2_scratch_reg3 = { + .scratch_reg = 0x9c, +}; + +static struct cam_cdm_scratch_reg cdm_1_2_scratch_reg4 = { + .scratch_reg = 0xa0, +}; + +static struct cam_cdm_scratch_reg cdm_1_2_scratch_reg5 = { + .scratch_reg = 0xa4, +}; + +static struct cam_cdm_scratch_reg cdm_1_2_scratch_reg6 = { + .scratch_reg = 0xa8, +}; + +static struct cam_cdm_scratch_reg cdm_1_2_scratch_reg7 = { + .scratch_reg = 0xac, +}; + +static struct cam_cdm_perf_mon_regs cdm_1_2_perf_mon0 = { + .perf_mon_ctrl = 0x110, + .perf_mon_0 = 0x114, + .perf_mon_1 = 0x118, + .perf_mon_2 = 0x11c, +}; + +static struct cam_cdm_comp_wait_status cdm_1_2_comp_wait_status0 = { + .comp_wait_status = 0x88, +}; + +static struct cam_cdm_comp_wait_status cdm_1_2_comp_wait_status1 = { + .comp_wait_status = 0x8c, +}; + +static struct cam_cdm_perf_regs cdm_1_2_perf = { + .count_cfg_0 = 0x180, + .always_count_val = 0x184, + .busy_count_val = 0x188, + .stall_axi_count_val = 0x18c, + .count_status = 0x190, +}; + +static struct cam_cdm_icl_data_regs cdm_1_2_icl_data = { + .icl_last_data_0 = 0x1c0, + .icl_last_data_1 = 0x1c4, + .icl_last_data_2 = 0x1c8, + .icl_inv_data = 0x1cc, +}; + +static struct cam_cdm_icl_regs cdm_1_2_icl = { + .data_regs = &cdm_1_2_icl_data, + .misc_regs = NULL, +}; + +static struct cam_cdm_common_regs cdm_hw_1_2_cmn_reg_offset = { + .cdm_hw_version = 0x0, + .cam_version = &cdm_hw_1_2_titan_version, + .rst_cmd = 0x10, + .cgc_cfg = 0x14, + .core_cfg = 0x18, + .core_en = 0x1c, + .fe_cfg = 0x20, + .bl_fifo_rb = 0x60, + .bl_fifo_base_rb = 0x64, + .bl_fifo_len_rb = 0x68, + .usr_data = 0x80, + .wait_status = 0x84, + .last_ahb_addr = 0xd0, + .last_ahb_data = 0xd4, + .core_debug = 0xd8, + .last_ahb_err_addr = 0xe0, + .last_ahb_err_data = 0xe4, + .current_bl_base = 0xe8, + .current_bl_len = 0xec, + .current_used_ahb_base = 0xf0, + .debug_status = 0xf4, + .bus_misr_cfg0 = 0x100, + .bus_misr_cfg1 = 0x104, + .bus_misr_rd_val = 0x108, + .pending_req = { + &cdm_hw_1_2_bl_pending_req0, + NULL, + }, + .comp_wait = { + &cdm_1_2_comp_wait_status0, + &cdm_1_2_comp_wait_status1, + }, + .perf_mon = { + &cdm_1_2_perf_mon0, + NULL, + }, + .scratch = { + &cdm_1_2_scratch_reg0, + &cdm_1_2_scratch_reg1, + &cdm_1_2_scratch_reg2, + &cdm_1_2_scratch_reg3, + &cdm_1_2_scratch_reg4, + &cdm_1_2_scratch_reg5, + &cdm_1_2_scratch_reg6, + &cdm_1_2_scratch_reg7, + NULL, + NULL, + NULL, + NULL, + }, + .perf_reg = &cdm_1_2_perf, + .icl_reg = &cdm_1_2_icl, + .spare = 0x1fc, +}; + +static struct cam_cdm_common_reg_data cdm_hw_1_2_cmn_reg_data = { + .num_bl_fifo = 0x1, + .num_bl_fifo_irq = 0x1, + .num_bl_pending_req_reg = 0x1, + .num_scratch_reg = 0x8, +}; + +struct cam_cdm_hw_reg_offset cam_cdm_1_2_reg_offset = { + .cmn_reg = &cdm_hw_1_2_cmn_reg_offset, + .bl_fifo_reg = { + &cdm_hw_1_2_bl_fifo0, + NULL, + NULL, + NULL, + }, + .irq_reg = { + &cdm_hw_1_2_irq0, + NULL, + NULL, + NULL, + }, + .reg_data = &cdm_hw_1_2_cmn_reg_data, +}; diff --git a/drivers/cam_cdm/cam_cdm_hw_reg_2_0.h b/drivers/cam_cdm/cam_cdm_hw_reg_2_0.h new file mode 100644 index 000000000000..bd5a7963e1ba --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_hw_reg_2_0.h @@ -0,0 +1,251 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_cdm.h" + +struct cam_cdm_bl_pending_req_reg_params cdm_hw_2_0_bl_pending_req0 = { + .rb_offset = 0x6c, + .rb_mask = 0x1ff, + .rb_num_fifo = 0x2, + .rb_next_fifo_shift = 0x10, +}; + +struct cam_cdm_bl_pending_req_reg_params cdm_hw_2_0_bl_pending_req1 = { + .rb_offset = 0x70, + .rb_mask = 0x1ff, + .rb_num_fifo = 0x2, + .rb_next_fifo_shift = 0x10, +}; + +static struct cam_cdm_irq_regs cdm_hw_2_0_irq0 = { + .irq_mask = 0x30, + .irq_clear = 0x34, + .irq_clear_cmd = 0x38, + .irq_set = 0x3c, + .irq_set_cmd = 0x40, + .irq_status = 0x44, +}; + +static struct cam_cdm_irq_regs cdm_hw_2_0_irq1 = { + .irq_mask = 0x130, + .irq_clear = 0x134, + .irq_clear_cmd = 0x138, + .irq_set = 0x13c, + .irq_set_cmd = 0x140, + .irq_status = 0x144, +}; + +static struct cam_cdm_irq_regs cdm_hw_2_0_irq2 = { + .irq_mask = 0x230, + .irq_clear = 0x234, + .irq_clear_cmd = 0x238, + .irq_set = 0x23c, + .irq_set_cmd = 0x240, + .irq_status = 0x244, +}; + +static struct cam_cdm_irq_regs cdm_hw_2_0_irq3 = { + .irq_mask = 0x330, + .irq_clear = 0x334, + .irq_clear_cmd = 0x338, + .irq_set = 0x33c, + .irq_set_cmd = 0x340, + .irq_status = 0x344, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_2_0_bl_fifo0 = { + .bl_fifo_base = 0x50, + .bl_fifo_len = 0x54, + .bl_fifo_store = 0x58, + .bl_fifo_cfg = 0x5c, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_2_0_bl_fifo1 = { + .bl_fifo_base = 0x150, + .bl_fifo_len = 0x154, + .bl_fifo_store = 0x158, + .bl_fifo_cfg = 0x15c, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_2_0_bl_fifo2 = { + .bl_fifo_base = 0x250, + .bl_fifo_len = 0x254, + .bl_fifo_store = 0x258, + .bl_fifo_cfg = 0x25c, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_2_0_bl_fifo3 = { + .bl_fifo_base = 0x350, + .bl_fifo_len = 0x354, + .bl_fifo_store = 0x358, + .bl_fifo_cfg = 0x35c, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg0 = { + .scratch_reg = 0x90, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg1 = { + .scratch_reg = 0x94, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg2 = { + .scratch_reg = 0x98, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg3 = { + .scratch_reg = 0x9c, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg4 = { + .scratch_reg = 0xa0, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg5 = { + .scratch_reg = 0xa4, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg6 = { + .scratch_reg = 0xa8, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg7 = { + .scratch_reg = 0xac, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg8 = { + .scratch_reg = 0xb0, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg9 = { + .scratch_reg = 0xb4, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg10 = { + .scratch_reg = 0xb8, +}; + +static struct cam_cdm_scratch_reg cdm_2_0_scratch_reg11 = { + .scratch_reg = 0xbc, +}; + +static struct cam_cdm_perf_mon_regs cdm_2_0_perf_mon0 = { + .perf_mon_ctrl = 0x110, + .perf_mon_0 = 0x114, + .perf_mon_1 = 0x118, + .perf_mon_2 = 0x11c, +}; + +static struct cam_cdm_perf_mon_regs cdm_2_0_perf_mon1 = { + .perf_mon_ctrl = 0x120, + .perf_mon_0 = 0x124, + .perf_mon_1 = 0x128, + .perf_mon_2 = 0x12c, +}; + +static struct cam_cdm_comp_wait_status cdm_2_0_comp_wait_status0 = { + .comp_wait_status = 0x88, +}; + +static struct cam_cdm_comp_wait_status cdm_2_0_comp_wait_status1 = { + .comp_wait_status = 0x8c, +}; + +static struct cam_cdm_icl_data_regs cdm_2_0_icl_data = { + .icl_last_data_0 = 0x1c0, + .icl_last_data_1 = 0x1c4, + .icl_last_data_2 = 0x1c8, + .icl_inv_data = 0x1cc, +}; + +static struct cam_cdm_icl_misc_regs cdm_2_0_icl_misc = { + .icl_inv_bl_addr = 0x1d0, + .icl_status = 0x1d4, +}; + +static struct cam_cdm_icl_regs cdm_2_0_icl = { + .data_regs = &cdm_2_0_icl_data, + .misc_regs = &cdm_2_0_icl_misc, +}; + +static struct cam_cdm_common_regs cdm_hw_2_0_cmn_reg_offset = { + .cdm_hw_version = 0x0, + .cam_version = NULL, + .rst_cmd = 0x10, + .cgc_cfg = 0x14, + .core_cfg = 0x18, + .core_en = 0x1c, + .fe_cfg = 0x20, + .bl_fifo_rb = 0x60, + .bl_fifo_base_rb = 0x64, + .bl_fifo_len_rb = 0x68, + .usr_data = 0x80, + .wait_status = 0x84, + .last_ahb_addr = 0xd0, + .last_ahb_data = 0xd4, + .core_debug = 0xd8, + .last_ahb_err_addr = 0xe0, + .last_ahb_err_data = 0xe4, + .current_bl_base = 0xe8, + .current_bl_len = 0xec, + .current_used_ahb_base = 0xf0, + .debug_status = 0xf4, + .bus_misr_cfg0 = 0x100, + .bus_misr_cfg1 = 0x104, + .bus_misr_rd_val = 0x108, + .pending_req = { + &cdm_hw_2_0_bl_pending_req0, + &cdm_hw_2_0_bl_pending_req1, + }, + .comp_wait = { + &cdm_2_0_comp_wait_status0, + &cdm_2_0_comp_wait_status1, + }, + .perf_mon = { + &cdm_2_0_perf_mon0, + &cdm_2_0_perf_mon1, + }, + .scratch = { + &cdm_2_0_scratch_reg0, + &cdm_2_0_scratch_reg1, + &cdm_2_0_scratch_reg2, + &cdm_2_0_scratch_reg3, + &cdm_2_0_scratch_reg4, + &cdm_2_0_scratch_reg5, + &cdm_2_0_scratch_reg6, + &cdm_2_0_scratch_reg7, + &cdm_2_0_scratch_reg8, + &cdm_2_0_scratch_reg9, + &cdm_2_0_scratch_reg10, + &cdm_2_0_scratch_reg11, + }, + .perf_reg = NULL, + .icl_reg = &cdm_2_0_icl, + .spare = 0x1fc, +}; + +static struct cam_cdm_common_reg_data cdm_hw_2_0_cmn_reg_data = { + .num_bl_fifo = 0x4, + .num_bl_fifo_irq = 0x4, + .num_bl_pending_req_reg = 0x2, + .num_scratch_reg = 0xc, +}; + +struct cam_cdm_hw_reg_offset cam_cdm_2_0_reg_offset = { + .cmn_reg = &cdm_hw_2_0_cmn_reg_offset, + .bl_fifo_reg = { + &cdm_hw_2_0_bl_fifo0, + &cdm_hw_2_0_bl_fifo1, + &cdm_hw_2_0_bl_fifo2, + &cdm_hw_2_0_bl_fifo3, + }, + .irq_reg = { + &cdm_hw_2_0_irq0, + &cdm_hw_2_0_irq1, + &cdm_hw_2_0_irq2, + &cdm_hw_2_0_irq3, + }, + .reg_data = &cdm_hw_2_0_cmn_reg_data, +}; diff --git a/drivers/cam_cdm/cam_cdm_intf.c b/drivers/cam_cdm/cam_cdm_intf.c index 94e2f36d0544..7796eb7f9a40 100644 --- a/drivers/cam_cdm/cam_cdm_intf.c +++ b/drivers/cam_cdm/cam_cdm_intf.c @@ -15,6 +15,7 @@ #include "cam_cdm_virtual.h" #include "cam_soc_util.h" #include "cam_cdm_soc.h" +#include "cam_cdm_core_common.h" static struct cam_cdm_intf_mgr cdm_mgr; static DEFINE_MUTEX(cam_cdm_mgr_lock); @@ -77,13 +78,15 @@ static int get_cdm_index_by_id(char *identifier, uint32_t cell_index, uint32_t *hw_index) { int rc = -EPERM, i, j; - char client_name[128]; + char client_name[128], name_index[160]; - CAM_DBG(CAM_CDM, "Looking for HW id of =%s and index=%d", - identifier, cell_index); snprintf(client_name, sizeof(client_name), "%s", identifier); - CAM_DBG(CAM_CDM, "Looking for HW id of %s count:%d", client_name, - cdm_mgr.cdm_count); + snprintf(name_index, sizeof(name_index), "%s%d", + identifier, cell_index); + + CAM_DBG(CAM_CDM, + "Looking for HW id of =%s or %s and index=%d cdm_count %d", + identifier, name_index, cell_index, cdm_mgr.cdm_count); mutex_lock(&cam_cdm_mgr_lock); for (i = 0; i < cdm_mgr.cdm_count; i++) { mutex_lock(&cdm_mgr.nodes[i].lock); @@ -92,11 +95,14 @@ static int get_cdm_index_by_id(char *identifier, for (j = 0; j < cdm_mgr.nodes[i].data->dt_num_supported_clients; j++) { - CAM_DBG(CAM_CDM, "client name:%s", - cdm_mgr.nodes[i].data->dt_cdm_client_name[j]); + CAM_DBG(CAM_CDM, "client name:%s dev Index: %d", + cdm_mgr.nodes[i].data->dt_cdm_client_name[j], + i); if (!strcmp( cdm_mgr.nodes[i].data->dt_cdm_client_name[j], - client_name)) { + client_name) || !strcmp( + cdm_mgr.nodes[i].data->dt_cdm_client_name[j], + name_index)) { rc = 0; *hw_index = i; break; @@ -131,9 +137,14 @@ int cam_cdm_get_iommu_handle(char *identifier, mutex_unlock(&cdm_mgr.nodes[i].lock); continue; } + CAM_DBG(CAM_CDM, "dt_num_supported_clients=%d", + cdm_mgr.nodes[i].data->dt_num_supported_clients); for (j = 0; j < cdm_mgr.nodes[i].data->dt_num_supported_clients; j++) { + CAM_DBG(CAM_CDM, "client name:%s dev Index: %d", + cdm_mgr.nodes[i].data->dt_cdm_client_name[j], + i); if (!strcmp( cdm_mgr.nodes[i].data->dt_cdm_client_name[j], identifier)) { @@ -155,6 +166,8 @@ int cam_cdm_acquire(struct cam_cdm_acquire_data *data) { int rc = -EPERM; struct cam_hw_intf *hw; + struct cam_hw_info *cdm_hw; + struct cam_cdm *core = NULL; uint32_t hw_index = 0; if ((!data) || (!data->base_array_cnt)) @@ -177,12 +190,17 @@ int cam_cdm_acquire(struct cam_cdm_acquire_data *data) CAM_ERR(CAM_CDM, "Failed to identify associated hw id"); goto end; } else { - CAM_DBG(CAM_CDM, "hw_index:%d", hw_index); hw = cdm_mgr.nodes[hw_index].device; if (hw && hw->hw_ops.process_cmd) { + cdm_hw = hw->hw_priv; + core = (struct cam_cdm *)cdm_hw->core_info; + data->id = core->id; + CAM_DBG(CAM_CDM, + "Device = %s, hw_index = %d, CDM id = %d", + data->identifier, hw_index, data->id); rc = hw->hw_ops.process_cmd(hw->hw_priv, - CAM_CDM_HW_INTF_CMD_ACQUIRE, data, - sizeof(struct cam_cdm_acquire_data)); + CAM_CDM_HW_INTF_CMD_ACQUIRE, data, + sizeof(struct cam_cdm_acquire_data)); if (rc < 0) { CAM_ERR(CAM_CDM, "CDM hw acquire failed"); goto end; @@ -203,6 +221,19 @@ int cam_cdm_acquire(struct cam_cdm_acquire_data *data) } EXPORT_SYMBOL(cam_cdm_acquire); +struct cam_cdm_utils_ops *cam_cdm_publish_ops(void) +{ + struct cam_hw_version cdm_version; + + cdm_version.major = 1; + cdm_version.minor = 0; + cdm_version.incr = 0; + cdm_version.reserved = 0; + + return cam_cdm_get_ops(0, &cdm_version, true); +} +EXPORT_SYMBOL(cam_cdm_publish_ops); + int cam_cdm_release(uint32_t handle) { uint32_t hw_index; @@ -379,6 +410,75 @@ int cam_cdm_reset_hw(uint32_t handle) } EXPORT_SYMBOL(cam_cdm_reset_hw); +int cam_cdm_flush_hw(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_FLUSH_HW, &handle, + sizeof(handle)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "CDM hw release failed for handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_flush_hw); + +int cam_cdm_handle_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_HANDLE_ERROR, + &handle, + sizeof(handle)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "CDM hw release failed for handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_handle_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 3e89b22b1b18..756f7f4bea4e 100644 --- a/drivers/cam_cdm/cam_cdm_intf_api.h +++ b/drivers/cam_cdm/cam_cdm_intf_api.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_API_H_ @@ -14,7 +14,10 @@ enum cam_cdm_id { CAM_CDM_VIRTUAL, CAM_CDM_HW_ANY, - CAM_CDM_CPAS_0, + CAM_CDM_CPAS, + CAM_CDM_IFE, + CAM_CDM_TFE, + CAM_CDM_OPE, CAM_CDM_IPE0, CAM_CDM_IPE1, CAM_CDM_BPS, @@ -29,6 +32,9 @@ enum cam_cdm_cb_status { CAM_CDM_CB_STATUS_PAGEFAULT, CAM_CDM_CB_STATUS_HW_RESET_ONGOING, CAM_CDM_CB_STATUS_HW_RESET_DONE, + CAM_CDM_CB_STATUS_HW_FLUSH, + CAM_CDM_CB_STATUS_HW_RESUBMIT, + CAM_CDM_CB_STATUS_HW_ERROR, CAM_CDM_CB_STATUS_UNKNOWN_ERROR, }; @@ -39,17 +45,26 @@ enum cam_cdm_bl_cmd_addr_type { CAM_CDM_BL_CMD_TYPE_KERNEL_IOVA, }; +/* enum cam_cdm_bl_fifo - interface commands.*/ +enum cam_cdm_bl_fifo_queue { + CAM_CDM_BL_FIFO_0, + CAM_CDM_BL_FIFO_1, + CAM_CDM_BL_FIFO_2, + CAM_CDM_BL_FIFO_3, + CAM_CDM_BL_FIFO_MAX, +}; + /** * struct cam_cdm_acquire_data - Cam CDM acquire data structure * * @identifier : Input identifier string which is the device label from dt - * like vfe, ife, jpeg etc + * like vfe, ife, jpeg etc * @cell_index : Input integer identifier pointing to the cell index from dt * of the device. This can be used to form a unique string * with @identifier like vfe0, ife1, jpeg0 etc * @id : ID of a specific or any CDM HW which needs to be acquired. * @userdata : Input private data which will be returned as part - * of callback. + * of callback. * @cam_cdm_callback : Input callback pointer for triggering the * callbacks from CDM driver * @handle : CDM Client handle @@ -57,12 +72,14 @@ enum cam_cdm_bl_cmd_addr_type { * @status : Callback status * @cookie : Cookie if the callback is gen irq status * @base_array_cnt : Input number of ioremapped address pair pointing - * in base_array, needed only if selected cdm is a virtual. + * in base_array, needed only if selected cdm is a virtual. * @base_array : Input pointer to ioremapped address pair arrary - * needed only if selected cdm is a virtual. + * needed only if selected cdm is a virtual. + * @priority : Priority of the client. * @cdm_version : CDM version is output while acquiring HW cdm and - * it is Input while acquiring virtual cdm, Currently fixing it - * to one version below acquire API. + * it is Input while acquiring virtual cdm. + * Currently fixing it to one version below + * acquire API. * @ops : Output pointer updated by cdm driver to the CDM * util ops for this HW version of CDM acquired. * @handle : Output Unique handle generated for this acquire @@ -77,6 +94,7 @@ struct cam_cdm_acquire_data { enum cam_cdm_cb_status status, uint64_t cookie); uint32_t base_array_cnt; struct cam_soc_reg_map *base_array[CAM_SOC_MAX_BLOCK]; + enum cam_cdm_bl_fifo_queue priority; struct cam_hw_version cdm_version; struct cam_cdm_utils_ops *ops; uint32_t handle; @@ -92,7 +110,8 @@ struct cam_cdm_acquire_data { * @len : Input length of the BL command, Cannot be more than 1MB and * this is will be validated with offset+size of the memory pointed * by mem_handle - * + * @enable_debug_gen_irq : bool flag to submit extra gen_irq afteR bl_command + * @arbitrate : bool flag to arbitrate on submitted BL boundary */ struct cam_cdm_bl_cmd { union { @@ -102,6 +121,8 @@ struct cam_cdm_bl_cmd { } bl_addr; uint32_t offset; uint32_t len; + bool enable_debug_gen_irq; + bool arbitrate; }; /** @@ -114,6 +135,7 @@ struct cam_cdm_bl_cmd { * @cookie : Cookie if the callback is gen irq status * @type : type of the submitted bl cmd address. * @cmd_arrary_count : Input number of BL commands to be submitted to CDM + * @gen_irq_arb : enum for setting arbitration in gen_irq * @bl_cmd_array : Input payload holding the BL cmd's arrary * to be sumbitted. * @@ -124,6 +146,7 @@ struct cam_cdm_bl_request { uint64_t cookie; enum cam_cdm_bl_cmd_addr_type type; uint32_t cmd_arrary_count; + bool gen_irq_arb; struct cam_cdm_bl_cmd cmd[1]; }; @@ -191,7 +214,7 @@ int cam_cdm_stream_off(uint32_t handle); /** * @brief : API to reset previously acquired CDM, - * this can be only performed only the CDM is private. + * this should be only performed only if the CDM is private. * * @handle : Input handle of the CDM to reset * @@ -199,4 +222,32 @@ int cam_cdm_stream_off(uint32_t handle); */ int cam_cdm_reset_hw(uint32_t handle); +/** + * @brief : API to flush previously acquired CDM, + * this should be only performed only if the CDM is private. + * + * @handle : Input handle of the CDM to reset + * + * @return 0 on success + */ +int cam_cdm_flush_hw(uint32_t handle); + +/** + * @brief : API to detect culprit bl_tag in previously acquired CDM, + * this should be only performed only if the CDM is private. + * + * @handle : Input handle of the CDM to reset + * + * @return 0 on success + */ +int cam_cdm_handle_error(uint32_t handle); + +/** + * @brief : API get CDM ops + * + * @return : CDM operations + * + */ +struct cam_cdm_utils_ops *cam_cdm_publish_ops(void); + #endif /* _CAM_CDM_API_H_ */ diff --git a/drivers/cam_cdm/cam_cdm_soc.c b/drivers/cam_cdm/cam_cdm_soc.c index 2fb5d5fe97b9..11d2d0b10e59 100644 --- a/drivers/cam_cdm/cam_cdm_soc.c +++ b/drivers/cam_cdm/cam_cdm_soc.c @@ -15,45 +15,35 @@ #include "cam_cdm.h" #include "cam_soc_util.h" #include "cam_io_util.h" +#include "cam_cdm_soc.h" #define CAM_CDM_OFFSET_FROM_REG(x, y) ((x)->offsets[y].offset) #define CAM_CDM_ATTR_FROM_REG(x, y) ((x)->offsets[y].attribute) bool cam_cdm_read_hw_reg(struct cam_hw_info *cdm_hw, - enum cam_cdm_regs reg, uint32_t *value) + uint32_t reg, uint32_t *value) { void __iomem *reg_addr; - struct cam_cdm *cdm = (struct cam_cdm *)cdm_hw->core_info; void __iomem *base = cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].mem_base; resource_size_t mem_len = cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].size; - CAM_DBG(CAM_CDM, "E: b=%pK blen=%d reg=%x off=%x", (void __iomem *)base, - (int)mem_len, reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, - reg))); - CAM_DBG(CAM_CDM, "E: b=%pK reg=%x off=%x", (void __iomem *)base, - reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg))); + CAM_DBG(CAM_CDM, "E: b=%pK blen=%d off=%x", (void __iomem *)base, + (int)mem_len, reg); - if ((reg > cdm->offset_tbl->offset_max_size) || - (reg > cdm->offset_tbl->last_offset)) { - CAM_ERR_RATE_LIMIT(CAM_CDM, "Invalid reg=%d\n", reg); + reg_addr = (base + reg); + if (reg_addr > (base + mem_len)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "Invalid mapped region %d", reg); goto permission_error; - } else { - reg_addr = (base + (CAM_CDM_OFFSET_FROM_REG( - cdm->offset_tbl, reg))); - if (reg_addr > (base + mem_len)) { - CAM_ERR_RATE_LIMIT(CAM_CDM, - "Invalid mapped region %d", reg); - goto permission_error; - } - *value = cam_io_r_mb(reg_addr); - CAM_DBG(CAM_CDM, "X b=%pK reg=%x off=%x val=%x", - (void __iomem *)base, reg, - (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg)), - *value); - return false; } + *value = cam_io_r_mb(reg_addr); + CAM_DBG(CAM_CDM, "X b=%pK off=%x val=%x", + (void __iomem *)base, reg, + *value); + return false; + permission_error: *value = 0; return true; @@ -61,36 +51,27 @@ bool cam_cdm_read_hw_reg(struct cam_hw_info *cdm_hw, } bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw, - enum cam_cdm_regs reg, uint32_t value) + uint32_t reg, uint32_t value) { void __iomem *reg_addr; - struct cam_cdm *cdm = (struct cam_cdm *)cdm_hw->core_info; void __iomem *base = cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].mem_base; resource_size_t mem_len = cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].size; - CAM_DBG(CAM_CDM, "E: b=%pK reg=%x off=%x val=%x", (void __iomem *)base, - reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg)), value); + CAM_DBG(CAM_CDM, "E: b=%pK off=%x val=%x", (void __iomem *)base, + reg, value); - if ((reg > cdm->offset_tbl->offset_max_size) || - (reg > cdm->offset_tbl->last_offset)) { - CAM_ERR_RATE_LIMIT(CAM_CDM, "CDM accessing invalid reg=%d\n", + reg_addr = (base + reg); + if (reg_addr > (base + mem_len)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "Accessing invalid region:%d\n", reg); goto permission_error; - } else { - reg_addr = (base + CAM_CDM_OFFSET_FROM_REG( - cdm->offset_tbl, reg)); - if (reg_addr > (base + mem_len)) { - CAM_ERR_RATE_LIMIT(CAM_CDM, - "Accessing invalid region %d:%d\n", - reg, (CAM_CDM_OFFSET_FROM_REG( - cdm->offset_tbl, reg))); - goto permission_error; - } - cam_io_w_mb(value, reg_addr); - return false; } + cam_io_w_mb(value, reg_addr); + return false; + permission_error: return true; @@ -99,7 +80,7 @@ bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw, int cam_cdm_soc_load_dt_private(struct platform_device *pdev, struct cam_cdm_private_dt_data *ptr) { - int i, rc = -EINVAL; + int i, rc = -EINVAL, num_fifo_entries = 0; ptr->dt_num_supported_clients = of_property_count_strings( pdev->dev.of_node, @@ -111,7 +92,7 @@ int cam_cdm_soc_load_dt_private(struct platform_device *pdev, CAM_ERR(CAM_CDM, "Invalid count of client names count=%d", ptr->dt_num_supported_clients); rc = -EINVAL; - return rc; + goto end; } if (ptr->dt_num_supported_clients < 0) { CAM_DBG(CAM_CDM, "No cdm client names found"); @@ -127,10 +108,43 @@ int cam_cdm_soc_load_dt_private(struct platform_device *pdev, ptr->dt_cdm_client_name[i]); if (rc < 0) { CAM_ERR(CAM_CDM, "Reading cdm-client-names failed"); - break; + goto end; } } + ptr->config_fifo = of_property_read_bool(pdev->dev.of_node, + "config-fifo"); + if (ptr->config_fifo) { + num_fifo_entries = of_property_count_u32_elems( + pdev->dev.of_node, + "fifo-depths"); + if (num_fifo_entries != CAM_CDM_NUM_BL_FIFO) { + CAM_ERR(CAM_CDM, + "Wrong number of configurable FIFOs %d", + num_fifo_entries); + rc = -EINVAL; + goto end; + } + for (i = 0; i < num_fifo_entries; i++) { + rc = of_property_read_u32_index(pdev->dev.of_node, + "fifo-depths", i, &ptr->fifo_depth[i]); + if (rc < 0) { + CAM_ERR(CAM_CDM, + "Unable to read fifo-depth rc %d", + rc); + goto end; + } + CAM_DBG(CAM_CDM, "FIFO%d depth is %d", + i, ptr->fifo_depth[i]); + } + } else { + for (i = 0; i < CAM_CDM_BL_FIFO_MAX; i++) { + ptr->fifo_depth[i] = CAM_CDM_BL_FIFO_LENGTH_MAX_DEFAULT; + CAM_DBG(CAM_CDM, "FIFO%d depth is %d", + i, ptr->fifo_depth[i]); + } + } +end: return rc; } @@ -140,6 +154,7 @@ int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw, int rc; struct cam_hw_soc_info *soc_ptr; const struct of_device_id *id; + struct cam_cdm *cdm_core = cdm_hw->core_info; if (!cdm_hw || (cdm_hw->soc_info.soc_private) || !(cdm_hw->soc_info.pdev)) @@ -150,38 +165,44 @@ int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw, rc = cam_soc_util_get_dt_properties(soc_ptr); if (rc != 0) { CAM_ERR(CAM_CDM, "Failed to retrieve the CDM dt properties"); - } else { - soc_ptr->soc_private = kzalloc( - sizeof(struct cam_cdm_private_dt_data), - GFP_KERNEL); - if (!soc_ptr->soc_private) - return -ENOMEM; - - rc = cam_cdm_soc_load_dt_private(soc_ptr->pdev, - soc_ptr->soc_private); - if (rc != 0) { - CAM_ERR(CAM_CDM, "Failed to load CDM dt private data"); - goto error; - } - id = of_match_node(table, soc_ptr->pdev->dev.of_node); - if ((!id) || !(id->data)) { - CAM_ERR(CAM_CDM, "Failed to retrieve the CDM id table"); - goto error; - } - CAM_DBG(CAM_CDM, "CDM Hw Id compatible =%s", id->compatible); - ((struct cam_cdm *)cdm_hw->core_info)->offset_tbl = - (struct cam_cdm_reg_offset_table *)id->data; - strlcpy(((struct cam_cdm *)cdm_hw->core_info)->name, - id->compatible, - sizeof(((struct cam_cdm *)cdm_hw->core_info)->name)); + goto end; } - return rc; + soc_ptr->soc_private = kzalloc( + sizeof(struct cam_cdm_private_dt_data), + GFP_KERNEL); + if (!soc_ptr->soc_private) + return -ENOMEM; + + rc = cam_cdm_soc_load_dt_private(soc_ptr->pdev, + soc_ptr->soc_private); + if (rc != 0) { + CAM_ERR(CAM_CDM, "Failed to load CDM dt private data"); + goto error; + } + + id = of_match_node(table, soc_ptr->pdev->dev.of_node); + if ((!id) || !(id->data)) { + CAM_ERR(CAM_CDM, "Failed to retrieve the CDM id table"); + goto error; + } + cdm_core->offsets = + (struct cam_cdm_hw_reg_offset *)id->data; + + CAM_DBG(CAM_CDM, "name %s", cdm_core->name); + + snprintf(cdm_core->name, sizeof(cdm_core->name) + 1, "%s%d", + id->compatible, soc_ptr->index); + + CAM_DBG(CAM_CDM, "name %s", cdm_core->name); + + goto end; error: rc = -EINVAL; kfree(soc_ptr->soc_private); soc_ptr->soc_private = NULL; +end: return rc; } diff --git a/drivers/cam_cdm/cam_cdm_soc.h b/drivers/cam_cdm/cam_cdm_soc.h index b422b34f244b..137922e1bd35 100644 --- a/drivers/cam_cdm/cam_cdm_soc.h +++ b/drivers/cam_cdm/cam_cdm_soc.h @@ -1,17 +1,25 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_SOC_H_ #define _CAM_CDM_SOC_H_ +#define CAM_HW_CDM_CPAS_0_NAME "qcom,cam170-cpas-cdm0" +#define CAM_HW_CDM_CPAS_NAME_1_0 "qcom,cam-cpas-cdm1_0" +#define CAM_HW_CDM_CPAS_NAME_1_1 "qcom,cam-cpas-cdm1_1" +#define CAM_HW_CDM_CPAS_NAME_1_2 "qcom,cam-cpas-cdm1_2" +#define CAM_HW_CDM_IFE_NAME_1_2 "qcom,cam-ife-cdm1_2" +#define CAM_HW_CDM_CPAS_NAME_2_0 "qcom,cam-cpas-cdm2_0" +#define CAM_HW_CDM_OPE_NAME_2_0 "qcom,cam-ope-cdm2_0" + int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw, const struct of_device_id *table); bool cam_cdm_read_hw_reg(struct cam_hw_info *cdm_hw, - enum cam_cdm_regs reg, uint32_t *value); + uint32_t reg, uint32_t *value); bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw, - enum cam_cdm_regs reg, uint32_t value); + uint32_t reg, uint32_t value); int cam_cdm_intf_mgr_soc_get_dt_properties( struct platform_device *pdev, struct cam_cdm_intf_mgr *mgr); diff --git a/drivers/cam_cdm/cam_cdm_util.c b/drivers/cam_cdm/cam_cdm_util.c index 278dadb18db4..3f606ab45635 100644 --- a/drivers/cam_cdm/cam_cdm_util.c +++ b/drivers/cam_cdm/cam_cdm_util.c @@ -38,6 +38,9 @@ static unsigned int CDMCmdHeaderSizes[ 1, /* PERF_CONTROL*/ 3, /* DMI32*/ 3, /* DMI64*/ + 3, /* WaitCompEvent*/ + 3, /* ClearCompEvent*/ + 3, /* WaitPrefetchDisable*/ }; /** @@ -156,11 +159,34 @@ struct cdm_perf_ctrl_cmd { unsigned int cmd : 8; } __attribute__((__packed__)); +struct cdm_wait_comp_event_cmd { + unsigned int reserved : 8; + unsigned int id : 8; + unsigned int id_reserved: 8; + unsigned int cmd : 8; + unsigned int mask1; + unsigned int mask2; +} __attribute__((__packed__)); + +struct cdm_prefetch_disable_event_cmd { + unsigned int reserved : 8; + unsigned int id : 8; + unsigned int id_reserved: 8; + unsigned int cmd : 8; + unsigned int mask1; + unsigned int mask2; +} __attribute__((__packed__)); + uint32_t cdm_get_cmd_header_size(unsigned int command) { return CDMCmdHeaderSizes[command]; } +uint32_t cdm_required_size_dmi(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); +} + uint32_t cdm_required_size_reg_continuous(uint32_t numVals) { return cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT) + numVals; @@ -172,9 +198,9 @@ uint32_t cdm_required_size_reg_random(uint32_t numRegVals) (2 * numRegVals); } -uint32_t cdm_required_size_dmi(void) +uint32_t cdm_required_size_indirect(void) { - return cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); + return cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT); } uint32_t cdm_required_size_genirq(void) @@ -182,9 +208,9 @@ uint32_t cdm_required_size_genirq(void) return cdm_get_cmd_header_size(CAM_CDM_CMD_GEN_IRQ); } -uint32_t cdm_required_size_indirect(void) +uint32_t cdm_required_size_wait_event(void) { - return cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT); + return cdm_get_cmd_header_size(CAM_CDM_CMD_WAIT_EVENT); } uint32_t cdm_required_size_changebase(void) @@ -192,6 +218,16 @@ uint32_t cdm_required_size_changebase(void) return cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE); } +uint32_t cdm_required_size_comp_wait(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_COMP_WAIT); +} + +uint32_t cdm_required_size_prefetch_disable(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_WAIT_PREFETCH_DISABLE); +} + uint32_t cdm_offsetof_dmi_addr(void) { return offsetof(struct cdm_dmi_cmd, addr); @@ -202,6 +238,23 @@ uint32_t cdm_offsetof_indirect_addr(void) return offsetof(struct cdm_indirect_cmd, addr); } +uint32_t *cdm_write_dmi(uint32_t *pCmdBuffer, uint8_t dmiCmd, + uint32_t DMIAddr, uint8_t DMISel, uint32_t dmiBufferAddr, + uint32_t length) +{ + struct cdm_dmi_cmd *pHeader = (struct cdm_dmi_cmd *)pCmdBuffer; + + pHeader->cmd = CAM_CDM_CMD_DMI; + pHeader->addr = dmiBufferAddr; + pHeader->length = length; + pHeader->DMIAddr = DMIAddr; + pHeader->DMISel = DMISel; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); + + return pCmdBuffer; +} + uint32_t *cdm_write_regcontinuous(uint32_t *pCmdBuffer, uint32_t reg, uint32_t numVals, uint32_t *pVals) { @@ -248,23 +301,6 @@ uint32_t *cdm_write_regrandom(uint32_t *pCmdBuffer, uint32_t numRegVals, return dst; } -uint32_t *cdm_write_dmi(uint32_t *pCmdBuffer, uint8_t dmiCmd, - uint32_t DMIAddr, uint8_t DMISel, uint32_t dmiBufferAddr, - uint32_t length) -{ - struct cdm_dmi_cmd *pHeader = (struct cdm_dmi_cmd *)pCmdBuffer; - - pHeader->cmd = dmiCmd; - pHeader->addr = dmiBufferAddr; - pHeader->length = length - 1; - pHeader->DMIAddr = DMIAddr; - pHeader->DMISel = DMISel; - - pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); - - return pCmdBuffer; -} - uint32_t *cdm_write_indirect(uint32_t *pCmdBuffer, uint32_t indirectBufAddr, uint32_t length) { @@ -280,11 +316,50 @@ uint32_t *cdm_write_indirect(uint32_t *pCmdBuffer, uint32_t indirectBufAddr, return pCmdBuffer; } +void cdm_write_genirq(uint32_t *pCmdBuffer, uint32_t userdata, + bool bit_wr_enable, uint32_t fifo_idx) +{ + struct cdm_genirq_cmd *pHeader = (struct cdm_genirq_cmd *)pCmdBuffer; + + CAM_DBG(CAM_CDM, "userdata 0x%x, fifo_idx %d", + userdata, fifo_idx); + + if (bit_wr_enable) + pHeader->reserved = (unsigned int)((fifo_idx << 1) + | (unsigned int)(bit_wr_enable)); + + pHeader->cmd = CAM_CDM_CMD_GEN_IRQ; + pHeader->userdata = (userdata << (8 * fifo_idx)); +} + +uint32_t *cdm_write_wait_event(uint32_t *pcmdbuffer, uint32_t iw, + uint32_t id, uint32_t mask, + uint32_t offset, uint32_t data) +{ + struct cdm_wait_event_cmd *pheader = + (struct cdm_wait_event_cmd *)pcmdbuffer; + + pheader->cmd = CAM_CDM_CMD_WAIT_EVENT; + pheader->mask = mask; + pheader->data = data; + pheader->id = id; + pheader->iw = iw; + pheader->offset = offset; + pheader->iw_reserved = 0; + pheader->offset_reserved = 0; + + pcmdbuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_WAIT_EVENT); + + return pcmdbuffer; +} + uint32_t *cdm_write_changebase(uint32_t *pCmdBuffer, uint32_t base) { struct cdm_changebase_cmd *pHeader = (struct cdm_changebase_cmd *)pCmdBuffer; + CAM_DBG(CAM_CDM, "Change to base 0x%x", base); + pHeader->cmd = CAM_CDM_CMD_CHANGE_BASE; pHeader->base = base; pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE); @@ -292,30 +367,63 @@ uint32_t *cdm_write_changebase(uint32_t *pCmdBuffer, uint32_t base) return pCmdBuffer; } -void cdm_write_genirq(uint32_t *pCmdBuffer, uint32_t userdata) +uint32_t *cdm_write_wait_comp_event( + uint32_t *pCmdBuffer, uint32_t mask1, uint32_t mask2) { - struct cdm_genirq_cmd *pHeader = (struct cdm_genirq_cmd *)pCmdBuffer; + struct cdm_wait_comp_event_cmd *pHeader = + (struct cdm_wait_comp_event_cmd *)pCmdBuffer; - pHeader->cmd = CAM_CDM_CMD_GEN_IRQ; - pHeader->userdata = userdata; + pHeader->cmd = CAM_CDM_COMP_WAIT; + pHeader->mask1 = mask1; + pHeader->mask2 = mask2; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_COMP_WAIT); + + return pCmdBuffer; } +uint32_t *cdm_write_wait_prefetch_disable( + uint32_t *pCmdBuffer, + uint32_t id, + uint32_t mask1, + uint32_t mask2) +{ + struct cdm_prefetch_disable_event_cmd *pHeader = + (struct cdm_prefetch_disable_event_cmd *)pCmdBuffer; + + pHeader->cmd = CAM_CDM_WAIT_PREFETCH_DISABLE; + pHeader->id = id; + pHeader->mask1 = mask1; + pHeader->mask2 = mask2; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_WAIT_PREFETCH_DISABLE); + + return pCmdBuffer; +} + + struct cam_cdm_utils_ops CDM170_ops = { cdm_get_cmd_header_size, + cdm_required_size_dmi, cdm_required_size_reg_continuous, cdm_required_size_reg_random, - cdm_required_size_dmi, - cdm_required_size_genirq, cdm_required_size_indirect, + cdm_required_size_genirq, + cdm_required_size_wait_event, cdm_required_size_changebase, + cdm_required_size_comp_wait, + cdm_required_size_prefetch_disable, cdm_offsetof_dmi_addr, cdm_offsetof_indirect_addr, + cdm_write_dmi, cdm_write_regcontinuous, cdm_write_regrandom, - cdm_write_dmi, cdm_write_indirect, - cdm_write_changebase, cdm_write_genirq, + cdm_write_wait_event, + cdm_write_changebase, + cdm_write_wait_comp_event, + cdm_write_wait_prefetch_disable, }; int cam_cdm_get_ioremap_from_base(uint32_t hw_base, @@ -672,7 +780,7 @@ void cam_cdm_util_dump_cmd_buf( uint32_t cmd = 0; if (!cmd_buf_start || !cmd_buf_end) { - CAM_INFO(CAM_CDM, "Invalid args"); + CAM_ERR(CAM_CDM, "Invalid args"); return; } @@ -708,7 +816,7 @@ void cam_cdm_util_dump_cmd_buf( buf_now += cam_cdm_util_dump_perf_ctrl_cmd(buf_now); break; default: - CAM_INFO(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x", + CAM_ERR(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x", cmd, *buf_now); buf_now++; break; diff --git a/drivers/cam_cdm/cam_cdm_util.h b/drivers/cam_cdm/cam_cdm_util.h index 663eca92a5fe..1eed75459e71 100644 --- a/drivers/cam_cdm/cam_cdm_util.h +++ b/drivers/cam_cdm/cam_cdm_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_UTIL_H_ @@ -19,10 +19,13 @@ enum cam_cdm_command { CAM_CDM_CMD_PERF_CTRL = 0x9, CAM_CDM_CMD_DMI_32 = 0xa, CAM_CDM_CMD_DMI_64 = 0xb, - CAM_CDM_CMD_PRIVATE_BASE = 0xc, + CAM_CDM_COMP_WAIT = 0xc, + CAM_CDM_CLEAR_COMP_WAIT = 0xd, + CAM_CDM_WAIT_PREFETCH_DISABLE = 0xe, + CAM_CDM_CMD_PRIVATE_BASE = 0xf, CAM_CDM_CMD_SWD_DMI_32 = (CAM_CDM_CMD_PRIVATE_BASE + 0x64), CAM_CDM_CMD_SWD_DMI_64 = (CAM_CDM_CMD_PRIVATE_BASE + 0x65), - CAM_CDM_CMD_PRIVATE_BASE_MAX = 0x7F + CAM_CDM_CMD_PRIVATE_BASE_MAX = 0x7F, }; /** @@ -53,6 +56,10 @@ enum cam_cdm_command { * in dwords. * @return Size in dwords * + * @cdm_required_size_comp_wait: Calculates the size of a comp-wait command + * in dwords. + * @return Size in dwords + * * @cdm_required_size_changebase: Calculates the size of a change-base command * in dwords. * @return Size in dwords @@ -102,46 +109,73 @@ enum cam_cdm_command { * @base: New base (device) address * @return Pointer in command buffer pointing past the written commands * - * @cdm_write_genirq: Writes a gen irq command into the command buffer. + * @cdm_write_genirq: Writes a gen irq command into the command buffer. * @pCmdBuffer: Pointer to command buffer * @userdata: userdata or cookie return by hardware during irq. + * + * @cdm_write_wait_comp_event: Writes a wait comp event cmd into the + * command buffer. + * @pCmdBuffer: Pointer to command buffer + * @mask1: This value decides which comp events to wait (0 - 31). + * @mask2: This value decides which comp events to wait (32 - 65). */ struct cam_cdm_utils_ops { uint32_t (*cdm_get_cmd_header_size)(unsigned int command); +uint32_t (*cdm_required_size_dmi)(void); uint32_t (*cdm_required_size_reg_continuous)(uint32_t numVals); uint32_t (*cdm_required_size_reg_random)(uint32_t numRegVals); -uint32_t (*cdm_required_size_dmi)(void); -uint32_t (*cdm_required_size_genirq)(void); uint32_t (*cdm_required_size_indirect)(void); +uint32_t (*cdm_required_size_genirq)(void); +uint32_t (*cdm_required_size_wait_event)(void); uint32_t (*cdm_required_size_changebase)(void); +uint32_t (*cdm_required_size_comp_wait)(void); +uint32_t (*cdm_required_size_prefetch_disable)(void); uint32_t (*cdm_offsetof_dmi_addr)(void); uint32_t (*cdm_offsetof_indirect_addr)(void); +uint32_t *(*cdm_write_dmi)( + uint32_t *pCmdBuffer, + uint8_t dmiCmd, + uint32_t DMIAddr, + uint8_t DMISel, + uint32_t dmiBufferAddr, + uint32_t length); uint32_t* (*cdm_write_regcontinuous)( uint32_t *pCmdBuffer, - uint32_t reg, - uint32_t numVals, + uint32_t reg, + uint32_t numVals, uint32_t *pVals); uint32_t *(*cdm_write_regrandom)( uint32_t *pCmdBuffer, - uint32_t numRegVals, + uint32_t numRegVals, uint32_t *pRegVals); -uint32_t *(*cdm_write_dmi)( - uint32_t *pCmdBuffer, - uint8_t dmiCmd, - uint32_t DMIAddr, - uint8_t DMISel, - uint32_t dmiBufferAddr, - uint32_t length); uint32_t *(*cdm_write_indirect)( uint32_t *pCmdBuffer, - uint32_t indirectBufferAddr, - uint32_t length); + uint32_t indirectBufferAddr, + uint32_t length); +void (*cdm_write_genirq)( + uint32_t *pCmdBuffer, + uint32_t userdata, + bool bit_wr_enable, + uint32_t fifo_idx); +uint32_t *(*cdm_write_wait_event)( + uint32_t *pCmdBuffer, + uint32_t iw, + uint32_t id, + uint32_t mask, + uint32_t offset, + uint32_t data); uint32_t *(*cdm_write_changebase)( uint32_t *pCmdBuffer, - uint32_t base); -void (*cdm_write_genirq)( + uint32_t base); +uint32_t *(*cdm_write_wait_comp_event)( + uint32_t *pCmdBuffer, + uint32_t mask1, + uint32_t mask2); +uint32_t *(*cdm_write_wait_prefetch_disable)( uint32_t *pCmdBuffer, - uint32_t userdata); + uint32_t id, + uint32_t mask1, + uint32_t mask2); }; /** diff --git a/drivers/cam_cdm/cam_hw_cdm170_reg.h b/drivers/cam_cdm/cam_hw_cdm170_reg.h deleted file mode 100644 index 4a0fbda825c5..000000000000 --- a/drivers/cam_cdm/cam_hw_cdm170_reg.h +++ /dev/null @@ -1,135 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - */ - -#ifndef _CAM_HW_CDM170_REG_H_ -#define _CAM_HW_CDM170_REG_H_ - -#define CAM_CDM_REG_OFFSET_FIRST 0x0 -#define CAM_CDM_REG_OFFSET_LAST 0x200 -#define CAM_CDM_REGS_COUNT 0x30 -#define CAM_CDM_HWFIFO_SIZE 0x40 - -#define CAM_CDM_OFFSET_HW_VERSION 0x0 -#define CAM_CDM_OFFSET_TITAN_VERSION 0x4 -#define CAM_CDM_OFFSET_RST_CMD 0x10 -#define CAM_CDM_OFFSET_CGC_CFG 0x14 -#define CAM_CDM_OFFSET_CORE_CFG 0x18 -#define CAM_CDM_OFFSET_CORE_EN 0x1c -#define CAM_CDM_OFFSET_FE_CFG 0x20 -#define CAM_CDM_OFFSET_IRQ_MASK 0x30 -#define CAM_CDM_OFFSET_IRQ_CLEAR 0x34 -#define CAM_CDM_OFFSET_IRQ_CLEAR_CMD 0x38 -#define CAM_CDM_OFFSET_IRQ_SET 0x3c -#define CAM_CDM_OFFSET_IRQ_SET_CMD 0x40 - -#define CAM_CDM_OFFSET_IRQ_STATUS 0x44 -#define CAM_CDM_IRQ_STATUS_INFO_RST_DONE_MASK 0x1 -#define CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK 0x2 -#define CAM_CDM_IRQ_STATUS_INFO_BL_DONE_MASK 0x4 -#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_OFFSET_BL_FIFO_BASE_REG 0x50 -#define CAM_CDM_OFFSET_BL_FIFO_LEN_REG 0x54 -#define CAM_CDM_OFFSET_BL_FIFO_STORE_REG 0x58 -#define CAM_CDM_OFFSET_BL_FIFO_CFG 0x5c -#define CAM_CDM_OFFSET_BL_FIFO_RB 0x60 -#define CAM_CDM_OFFSET_BL_FIFO_BASE_RB 0x64 -#define CAM_CDM_OFFSET_BL_FIFO_LEN_RB 0x68 -#define CAM_CDM_OFFSET_BL_FIFO_PENDING_REQ_RB 0x6c -#define CAM_CDM_OFFSET_IRQ_USR_DATA 0x80 -#define CAM_CDM_OFFSET_WAIT_STATUS 0x84 -#define CAM_CDM_OFFSET_SCRATCH_0_REG 0x90 -#define CAM_CDM_OFFSET_SCRATCH_1_REG 0x94 -#define CAM_CDM_OFFSET_SCRATCH_2_REG 0x98 -#define CAM_CDM_OFFSET_SCRATCH_3_REG 0x9c -#define CAM_CDM_OFFSET_SCRATCH_4_REG 0xa0 -#define CAM_CDM_OFFSET_SCRATCH_5_REG 0xa4 -#define CAM_CDM_OFFSET_SCRATCH_6_REG 0xa8 -#define CAM_CDM_OFFSET_SCRATCH_7_REG 0xac -#define CAM_CDM_OFFSET_LAST_AHB_ADDR 0xd0 -#define CAM_CDM_OFFSET_LAST_AHB_DATA 0xd4 -#define CAM_CDM_OFFSET_CORE_DBUG 0xd8 -#define CAM_CDM_OFFSET_LAST_AHB_ERR_ADDR 0xe0 -#define CAM_CDM_OFFSET_LAST_AHB_ERR_DATA 0xe4 -#define CAM_CDM_OFFSET_CURRENT_BL_BASE 0xe8 -#define CAM_CDM_OFFSET_CURRENT_BL_LEN 0xec -#define CAM_CDM_OFFSET_CURRENT_USED_AHB_BASE 0xf0 -#define CAM_CDM_OFFSET_DEBUG_STATUS 0xf4 -#define CAM_CDM_OFFSET_BUS_MISR_CFG_0 0x100 -#define CAM_CDM_OFFSET_BUS_MISR_CFG_1 0x104 -#define CAM_CDM_OFFSET_BUS_MISR_RD_VAL 0x108 -#define CAM_CDM_OFFSET_PERF_MON_CTRL 0x110 -#define CAM_CDM_OFFSET_PERF_MON_0 0x114 -#define CAM_CDM_OFFSET_PERF_MON_1 0x118 -#define CAM_CDM_OFFSET_PERF_MON_2 0x11c -#define CAM_CDM_OFFSET_SPARE 0x200 - -/* - * Always make sure below register offsets are aligned with - * enum cam_cdm_regs offsets - */ -struct cam_cdm_reg_offset cam170_cpas_cdm_register_offsets[] = { - { CAM_CDM_OFFSET_HW_VERSION, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_TITAN_VERSION, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_RST_CMD, CAM_REG_ATTR_WRITE }, - { CAM_CDM_OFFSET_CGC_CFG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_CORE_CFG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_CORE_EN, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_FE_CFG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_IRQ_MASK, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_IRQ_CLEAR, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_IRQ_CLEAR_CMD, CAM_REG_ATTR_WRITE }, - { CAM_CDM_OFFSET_IRQ_SET, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_IRQ_SET_CMD, CAM_REG_ATTR_WRITE }, - { CAM_CDM_OFFSET_IRQ_STATUS, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_IRQ_USR_DATA, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_BL_FIFO_BASE_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_BL_FIFO_LEN_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_BL_FIFO_STORE_REG, CAM_REG_ATTR_WRITE }, - { CAM_CDM_OFFSET_BL_FIFO_CFG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_BL_FIFO_RB, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_BL_FIFO_BASE_RB, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_BL_FIFO_LEN_RB, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_BL_FIFO_PENDING_REQ_RB, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_WAIT_STATUS, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_SCRATCH_0_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_SCRATCH_1_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_SCRATCH_2_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_SCRATCH_3_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_SCRATCH_4_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_SCRATCH_5_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_SCRATCH_6_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_SCRATCH_7_REG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_LAST_AHB_ADDR, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_LAST_AHB_DATA, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_CORE_DBUG, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_LAST_AHB_ERR_ADDR, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_LAST_AHB_ERR_DATA, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_CURRENT_BL_BASE, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_CURRENT_BL_LEN, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_CURRENT_USED_AHB_BASE, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_DEBUG_STATUS, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_BUS_MISR_CFG_0, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_BUS_MISR_CFG_1, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_BUS_MISR_RD_VAL, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_PERF_MON_CTRL, CAM_REG_ATTR_READ_WRITE }, - { CAM_CDM_OFFSET_PERF_MON_0, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_PERF_MON_1, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_PERF_MON_2, CAM_REG_ATTR_READ }, - { CAM_CDM_OFFSET_SPARE, CAM_REG_ATTR_READ_WRITE } -}; - -struct cam_cdm_reg_offset_table cam170_cpas_cdm_offset_table = { - .first_offset = 0x0, - .last_offset = 0x200, - .reg_count = 0x30, - .offsets = cam170_cpas_cdm_register_offsets, - .offset_max_size = (sizeof(cam170_cpas_cdm_register_offsets)/ - sizeof(struct cam_cdm_reg_offset)), -}; - -#endif /* _CAM_HW_CDM170_REG_H_ */ diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index c28fcdf3efc6..93a7976bfebe 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #include "cam_fd_hw_core.h" @@ -903,12 +903,14 @@ int cam_fd_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size) cdm_cmd->flag = false; cdm_cmd->userdata = NULL; cdm_cmd->cookie = 0; + cdm_cmd->gen_irq_arb = false; for (i = 0 ; i <= start_args->num_hw_update_entries; i++) { cmd = (start_args->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; + cdm_cmd->cmd[i].arbitrate = false; } rc = cam_cdm_submit_bls(ctx_hw_private->cdm_handle, cdm_cmd); @@ -1032,6 +1034,7 @@ int cam_fd_hw_reserve(void *hw_priv, void *hw_reserve_args, uint32_t arg_size) cdm_acquire.cam_cdm_callback = cam_fd_hw_util_cdm_callback; cdm_acquire.id = CAM_CDM_VIRTUAL; cdm_acquire.base_array_cnt = fd_hw->soc_info.num_reg_map; + cdm_acquire.priority = CAM_CDM_BL_FIFO_0; for (i = 0; i < fd_hw->soc_info.num_reg_map; i++) cdm_acquire.base_array[i] = &fd_hw->soc_info.reg_map[i]; 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 05b41a7d8def..c43cb21c44e5 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 @@ -2719,8 +2719,9 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) cdm_acquire.base_array[j++] = ife_hw_mgr->cdm_reg_map[i]; } - cdm_acquire.base_array_cnt = j; + cdm_acquire.base_array_cnt = j; + cdm_acquire.priority = CAM_CDM_BL_FIFO_0; cdm_acquire.id = CAM_CDM_VIRTUAL; cdm_acquire.cam_cdm_callback = cam_ife_cam_cdm_callback; rc = cam_cdm_acquire(&cdm_acquire); @@ -2907,9 +2908,9 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) cdm_acquire.base_array[j++] = ife_hw_mgr->cdm_reg_map[i]; } - cdm_acquire.base_array_cnt = j; - + cdm_acquire.base_array_cnt = j; + cdm_acquire.priority = CAM_CDM_BL_FIFO_0; cdm_acquire.id = CAM_CDM_VIRTUAL; cdm_acquire.cam_cdm_callback = cam_ife_cam_cdm_callback; rc = cam_cdm_acquire(&cdm_acquire); @@ -3426,6 +3427,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, cdm_cmd->flag = true; cdm_cmd->userdata = hw_update_data; cdm_cmd->cookie = cfg->request_id; + cdm_cmd->gen_irq_arb = false; for (i = 0 ; i < cfg->num_hw_update_entries; i++) { cmd = (cfg->hw_update_entries + i); @@ -3444,6 +3446,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, cdm_cmd->cmd[i - skip].bl_addr.mem_handle = cmd->handle; cdm_cmd->cmd[i - skip].offset = cmd->offset; cdm_cmd->cmd[i - skip].len = cmd->len; + cdm_cmd->cmd[i - skip].arbitrate = false; } cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries - skip; diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 27a12377d16e..e5cbc66e066d 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -303,6 +303,7 @@ static int cam_jpeg_insert_cdm_change_base( config_args->hw_update_entries[CAM_JPEG_CHBASE].offset; cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].len = size * sizeof(uint32_t); cdm_cmd->cmd_arrary_count++; + cdm_cmd->gen_irq_arb = false; ch_base_iova_addr += size; *ch_base_iova_addr = 0; @@ -439,6 +440,7 @@ static int cam_jpeg_mgr_process_cmd(void *priv, void *data) cdm_cmd->userdata = NULL; cdm_cmd->cookie = 0; cdm_cmd->cmd_arrary_count = 0; + cdm_cmd->gen_irq_arb = false; rc = cam_jpeg_insert_cdm_change_base(config_args, ctx_data, hw_mgr); @@ -457,6 +459,8 @@ static int cam_jpeg_mgr_process_cmd(void *priv, void *data) cmd->offset; cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].len = cmd->len; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].arbitrate = + false; CAM_DBG(CAM_JPEG, "i %d entry h %d o %d l %d", i, cmd->handle, cmd->offset, cmd->len); cdm_cmd->cmd_arrary_count++; @@ -1186,6 +1190,7 @@ static int cam_jpeg_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) cdm_acquire.base_array_cnt = 1; cdm_acquire.id = CAM_CDM_VIRTUAL; cdm_acquire.cam_cdm_callback = NULL; + cdm_acquire.priority = CAM_CDM_BL_FIFO_0; rc = cam_cdm_acquire(&cdm_acquire); if (rc) { diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c index b736708fa99d..1d92554c76ea 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #include "cam_lrme_hw_core.h" @@ -416,12 +416,14 @@ static int cam_lrme_hw_util_submit_req(struct cam_lrme_core *lrme_core, cdm_cmd->flag = false; cdm_cmd->userdata = NULL; cdm_cmd->cookie = 0; + cdm_cmd->gen_irq_arb = false; 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; + cdm_cmd->cmd[i].arbitrate = false; } rc = cam_cdm_submit_bls(hw_cdm_info->cdm_handle, cdm_cmd); diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index 4e2609648b30..5276f74c31f9 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -53,6 +53,7 @@ static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core, cdm_acquire.cam_cdm_callback = NULL; cdm_acquire.id = CAM_CDM_VIRTUAL; cdm_acquire.base_array_cnt = lrme_hw->soc_info.num_reg_map; + cdm_acquire.priority = CAM_CDM_BL_FIFO_0; for (i = 0; i < lrme_hw->soc_info.num_reg_map; i++) cdm_acquire.base_array[i] = &lrme_hw->soc_info.reg_map[i]; diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 784ea62e0925..fb32768d7f6b 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -28,7 +28,8 @@ #define COOKIE_SIZE (BYTE_SIZE*COOKIE_NUM_BYTE) #define COOKIE_MASK ((1<> COOKIE_SIZE) & COOKIE_MASK) @@ -96,7 +97,7 @@ struct cam_context_bank_info { struct iommu_domain *domain; dma_addr_t va_start; size_t va_len; - const char *name; + const char *name[CAM_SMMU_SHARED_HDL_MAX]; bool is_secure; uint8_t scratch_buf_support; uint8_t firmware_support; @@ -131,9 +132,11 @@ struct cam_context_bank_info { int cb_count; int secure_count; int pf_count; - size_t io_mapping_size; size_t shared_mapping_size; + bool is_mul_client; + int device_count; + int num_shared_hdl; }; struct cam_iommu_cb_set { @@ -371,12 +374,16 @@ static void cam_smmu_print_kernel_list(int idx) static void cam_smmu_print_table(void) { - int i; + int i, j; for (i = 0; i < iommu_cb_set.cb_num; i++) { - CAM_ERR(CAM_SMMU, "i= %d, handle= %d, name_addr=%pK", i, - (int)iommu_cb_set.cb_info[i].handle, - (void *)iommu_cb_set.cb_info[i].name); + for (j = 0; j < iommu_cb_set.cb_info[i].num_shared_hdl; j++) { + CAM_ERR(CAM_SMMU, + "i= %d, handle= %d, name_addr=%pK name %s", + i, (int)iommu_cb_set.cb_info[i].handle, + (void *)iommu_cb_set.cb_info[i].name[j], + iommu_cb_set.cb_info[i].name[j]); + } CAM_ERR(CAM_SMMU, "dev = %pK", iommu_cb_set.cb_info[i].dev); } } @@ -401,7 +408,7 @@ static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr) "Found va 0x%lx in:0x%lx-0x%lx, fd %d cb:%s", current_addr, start_addr, end_addr, mapping->ion_fd, - iommu_cb_set.cb_info[idx].name); + iommu_cb_set.cb_info[idx].name[0]); goto end; } else { if (start_addr > current_addr) @@ -431,9 +438,9 @@ static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr) closest_mapping->buf, buf_handle); } else - CAM_INFO(CAM_SMMU, + CAM_ERR(CAM_SMMU, "Cannot find vaddr:%lx in SMMU %s virt address", - current_addr, iommu_cb_set.cb_info[idx].name); + current_addr, iommu_cb_set.cb_info[idx].name[0]); return buf_handle; } @@ -469,7 +476,7 @@ void cam_smmu_set_client_page_fault_handler(int handle, if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) { CAM_ERR(CAM_SMMU, "%s Should not regiester more handlers", - iommu_cb_set.cb_info[idx].name); + iommu_cb_set.cb_info[idx].name[0]); mutex_unlock(&iommu_cb_set.cb_info[idx].lock); return; } @@ -497,7 +504,7 @@ void cam_smmu_set_client_page_fault_handler(int handle, if (i == CAM_SMMU_CB_MAX) CAM_ERR(CAM_SMMU, "Error: hdl %x no matching tokens: %s", - handle, iommu_cb_set.cb_info[idx].name); + handle, iommu_cb_set.cb_info[idx].name[0]); } mutex_unlock(&iommu_cb_set.cb_info[idx].lock); } @@ -539,7 +546,7 @@ void cam_smmu_unset_client_page_fault_handler(int handle, void *token) } if (i == CAM_SMMU_CB_MAX) CAM_ERR(CAM_SMMU, "Error: hdl %x no matching tokens: %s", - handle, iommu_cb_set.cb_info[idx].name); + handle, iommu_cb_set.cb_info[idx].name[0]); mutex_unlock(&iommu_cb_set.cb_info[idx].lock); } @@ -562,7 +569,7 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, cb_name = (char *)token; /* Check whether it is in the table */ for (idx = 0; idx < iommu_cb_set.cb_num; idx++) { - if (!strcmp(iommu_cb_set.cb_info[idx].name, cb_name)) + if (!strcmp(iommu_cb_set.cb_info[idx].name[0], cb_name)) break; } @@ -716,45 +723,69 @@ static int cam_smmu_attach_device(int idx) static int cam_smmu_create_add_handle_in_table(char *name, int *hdl) { - int i; + int i, j; int handle; + bool valid = false; /* create handle and add in the iommu hardware table */ for (i = 0; i < iommu_cb_set.cb_num; i++) { - if (!strcmp(iommu_cb_set.cb_info[i].name, name)) { - mutex_lock(&iommu_cb_set.cb_info[i].lock); - if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT) { - if (iommu_cb_set.cb_info[i].is_secure) - iommu_cb_set.cb_info[i].secure_count++; + for (j = 0; j < iommu_cb_set.cb_info[i].num_shared_hdl; j++) { + if (!strcmp(iommu_cb_set.cb_info[i].name[j], name)) + valid = true; - mutex_unlock(&iommu_cb_set.cb_info[i].lock); + if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT && + valid) { + mutex_lock(&iommu_cb_set.cb_info[i].lock); if (iommu_cb_set.cb_info[i].is_secure) { + iommu_cb_set.cb_info[i].secure_count++; *hdl = iommu_cb_set.cb_info[i].handle; + mutex_unlock( + &iommu_cb_set.cb_info[i].lock); + return 0; + } + + if (iommu_cb_set.cb_info[i].is_mul_client) { + iommu_cb_set.cb_info[i].device_count++; + *hdl = iommu_cb_set.cb_info[i].handle; + mutex_unlock( + &iommu_cb_set.cb_info[i].lock); + CAM_INFO(CAM_SMMU, + "%s already got handle 0x%x", + name, + iommu_cb_set.cb_info[i].handle); return 0; } CAM_ERR(CAM_SMMU, "Error: %s already got handle 0x%x", name, iommu_cb_set.cb_info[i].handle); - - return -EINVAL; + mutex_unlock(&iommu_cb_set.cb_info[i].lock); + return -EALREADY; } - /* make sure handle is unique */ - do { - handle = cam_smmu_create_iommu_handle(i); - } while (cam_smmu_check_handle_unique(handle)); - - /* put handle in the table */ - iommu_cb_set.cb_info[i].handle = handle; - iommu_cb_set.cb_info[i].cb_count = 0; - if (iommu_cb_set.cb_info[i].is_secure) - iommu_cb_set.cb_info[i].secure_count++; - *hdl = handle; - CAM_DBG(CAM_SMMU, "%s creates handle 0x%x", - name, handle); - mutex_unlock(&iommu_cb_set.cb_info[i].lock); - return 0; + if (iommu_cb_set.cb_info[i].handle == HANDLE_INIT && + valid) { + /* make sure handle is unique */ + do { + handle = + cam_smmu_create_iommu_handle(i); + } while (cam_smmu_check_handle_unique(handle)); + + /* put handle in the table */ + iommu_cb_set.cb_info[i].handle = handle; + iommu_cb_set.cb_info[i].cb_count = 0; + if (iommu_cb_set.cb_info[i].is_secure) + iommu_cb_set.cb_info[i].secure_count++; + + if (iommu_cb_set.cb_info[i].is_mul_client) + iommu_cb_set.cb_info[i].device_count++; + + *hdl = handle; + CAM_DBG(CAM_SMMU, "%s creates handle 0x%x", + name, handle); + mutex_unlock(&iommu_cb_set.cb_info[i].lock); + return 0; + } } } @@ -2045,7 +2076,7 @@ static enum cam_smmu_buf_state cam_smmu_validate_secure_fd_in_list(int idx, int cam_smmu_get_handle(char *identifier, int *handle_ptr) { - int ret = 0; + int rc = 0; if (!identifier) { CAM_ERR(CAM_SMMU, "Error: iommu hardware name is NULL"); @@ -2058,11 +2089,12 @@ int cam_smmu_get_handle(char *identifier, int *handle_ptr) } /* create and put handle in the table */ - ret = cam_smmu_create_add_handle_in_table(identifier, handle_ptr); - if (ret < 0) - CAM_ERR(CAM_SMMU, "Error: %s get handle fail", identifier); + rc = cam_smmu_create_add_handle_in_table(identifier, handle_ptr); + if (rc < 0) + CAM_ERR(CAM_SMMU, "Error: %s get handle fail, rc %d", + identifier, rc); - return ret; + return rc; } EXPORT_SYMBOL(cam_smmu_get_handle); @@ -2335,7 +2367,7 @@ int cam_smmu_get_scratch_iova(int handle, if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { CAM_ERR(CAM_SMMU, "Err:Dev %s should call SMMU attach before map buffer", - iommu_cb_set.cb_info[idx].name); + iommu_cb_set.cb_info[idx].name[0]); rc = -EINVAL; goto error; } @@ -2743,7 +2775,7 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { CAM_ERR(CAM_SMMU, "Err:Dev %s should call SMMU attach before map buffer", - iommu_cb_set.cb_info[idx].name); + iommu_cb_set.cb_info[idx].name[0]); rc = -EINVAL; goto get_addr_end; } @@ -2807,7 +2839,7 @@ int cam_smmu_map_kernel_iova(int handle, struct dma_buf *buf, if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { CAM_ERR(CAM_SMMU, "Err:Dev %s should call SMMU attach before map buffer", - iommu_cb_set.cb_info[idx].name); + iommu_cb_set.cb_info[idx].name[0]); rc = -EINVAL; goto get_addr_end; } @@ -3146,7 +3178,7 @@ int cam_smmu_destroy_handle(int handle) if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) { CAM_ERR(CAM_SMMU, "UMD %s buffer list is not clean", - iommu_cb_set.cb_info[idx].name); + iommu_cb_set.cb_info[idx].name[0]); cam_smmu_print_user_list(idx); cam_smmu_clean_user_buffer_list(idx); } @@ -3154,7 +3186,7 @@ int cam_smmu_destroy_handle(int handle) if (!list_empty_careful( &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list)) { CAM_ERR(CAM_SMMU, "KMD %s buffer list is not clean", - iommu_cb_set.cb_info[idx].name); + iommu_cb_set.cb_info[idx].name[0]); cam_smmu_print_kernel_list(idx); cam_smmu_clean_kernel_buffer_list(idx); } @@ -3175,6 +3207,19 @@ int cam_smmu_destroy_handle(int handle) return 0; } + if (iommu_cb_set.cb_info[idx].is_mul_client && + iommu_cb_set.cb_info[idx].device_count) { + iommu_cb_set.cb_info[idx].device_count--; + + if (!iommu_cb_set.cb_info[idx].device_count) { + iommu_cb_set.cb_info[idx].cb_count = 0; + iommu_cb_set.cb_info[idx].handle = HANDLE_INIT; + } + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return 0; + } + + iommu_cb_set.cb_info[idx].device_count = 0; iommu_cb_set.cb_info[idx].cb_count = 0; iommu_cb_set.cb_info[idx].handle = HANDLE_INIT; mutex_unlock(&iommu_cb_set.cb_info[idx].lock); @@ -3453,7 +3498,7 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, region_id); } - CAM_DBG(CAM_SMMU, "Found label -> %s", cb->name); + CAM_DBG(CAM_SMMU, "Found label -> %s", cb->name[0]); CAM_DBG(CAM_SMMU, "Found region -> %s", region_name); CAM_DBG(CAM_SMMU, "region_start -> %X", region_start); CAM_DBG(CAM_SMMU, "region_len -> %X", region_len); @@ -3476,6 +3521,7 @@ static int cam_populate_smmu_context_banks(struct device *dev, int rc = 0; struct cam_context_bank_info *cb; struct device *ctx = NULL; + int i = 0; if (!dev) { CAM_ERR(CAM_SMMU, "Error: Invalid device"); @@ -3492,8 +3538,24 @@ static int cam_populate_smmu_context_banks(struct device *dev, /* read the context bank from cb set */ cb = &iommu_cb_set.cb_info[iommu_cb_set.cb_init_count]; + cb->is_mul_client = + of_property_read_bool(dev->of_node, "multiple-client-devices"); + + cb->num_shared_hdl = of_property_count_strings(dev->of_node, + "label"); + + if (cb->num_shared_hdl > + CAM_SMMU_SHARED_HDL_MAX) { + CAM_ERR(CAM_CDM, "Invalid count of client names count=%d", + cb->num_shared_hdl); + rc = -EINVAL; + return rc; + } + /* set the name of the context bank */ - rc = of_property_read_string(dev->of_node, "label", &cb->name); + for (i = 0; i < cb->num_shared_hdl; i++) + rc = of_property_read_string_index(dev->of_node, + "label", i, &cb->name[i]); if (rc < 0) { CAM_ERR(CAM_SMMU, "Error: failed to read label from sub device"); @@ -3517,22 +3579,23 @@ static int cam_populate_smmu_context_banks(struct device *dev, /* set up the iommu mapping for the context bank */ if (type == CAM_QSMMU) { CAM_ERR(CAM_SMMU, "Error: QSMMU ctx not supported for : %s", - cb->name); + cb->name[0]); return -ENODEV; } ctx = dev; - CAM_DBG(CAM_SMMU, "getting Arm SMMU ctx : %s", cb->name); + CAM_DBG(CAM_SMMU, "getting Arm SMMU ctx : %s", cb->name[0]); rc = cam_smmu_setup_cb(cb, ctx); if (rc < 0) { - CAM_ERR(CAM_SMMU, "Error: failed to setup cb : %s", cb->name); + CAM_ERR(CAM_SMMU, "Error: failed to setup cb : %s", + cb->name[0]); goto cb_init_fail; } if (cb->io_support && cb->domain) iommu_set_fault_handler(cb->domain, cam_smmu_iommu_fault_handler, - (void *)cb->name); + (void *)cb->name[0]); if (!dev->dma_parms) dev->dma_parms = devm_kzalloc(dev, diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 04f2f80b82ba..8c89c5d07936 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -1292,6 +1292,10 @@ int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info) } } + rc = of_property_read_string(of_node, "label", &soc_info->label_name); + if (rc) + CAM_DBG(CAM_UTIL, "Label is not available in the node: %d", rc); + if (soc_info->num_mem_block > 0) { rc = of_property_read_u32_array(of_node, "reg-cam-base", soc_info->mem_block_cam_base, soc_info->num_mem_block); diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index ad2382b835ef..19cb0ae2a81c 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -123,6 +123,7 @@ struct cam_soc_gpio_data { * @index: Instance id for the camera device * @dev_name: Device Name * @irq_name: Name of the irq associated with the device + * @label_name: label name * @irq_line: Irq resource * @irq_data: Private data that is passed when IRQ is requested * @compatible: Compatible string associated with the device @@ -171,6 +172,7 @@ struct cam_hw_soc_info { uint32_t index; const char *dev_name; const char *irq_name; + const char *label_name; struct resource *irq_line; void *irq_data; const char *compatible; -- GitLab From 08900a71c262952515fce96e073b2b0f711e4a2e Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Thu, 25 Jul 2019 10:43:29 +0530 Subject: [PATCH 002/295] msm: camera: ope: Add support to OPE driver OPE is camera offline engine, support is added to enable camera OPE hardware. CRs-Fixed: 2520602 Change-Id: I8b08ecb34323ee927f2be88707ad65ad2444447d Signed-off-by: Suresh Vankadara Signed-off-by: Ravikishore Pampana --- drivers/Makefile | 1 + drivers/cam_ope/Makefile | 15 + drivers/cam_ope/cam_ope_context.c | 273 ++ drivers/cam_ope/cam_ope_context.h | 44 + drivers/cam_ope/cam_ope_subdev.c | 278 ++ drivers/cam_ope/ope_hw_mgr/Makefile | 18 + drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 2248 +++++++++++++++++ drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 399 +++ .../cam_ope/ope_hw_mgr/cam_ope_hw_mgr_intf.h | 16 + drivers/cam_ope/ope_hw_mgr/ope_hw/Makefile | 19 + .../cam_ope/ope_hw_mgr/ope_hw/bus_rd/Makefile | 15 + .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 693 +++++ .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.h | 139 + .../cam_ope/ope_hw_mgr/ope_hw/bus_wr/Makefile | 15 + .../ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c | 785 ++++++ .../ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.h | 137 + drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 1781 +++++++++++++ drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.h | 99 + drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c | 255 ++ .../cam_ope/ope_hw_mgr/ope_hw/ope_dev_intf.h | 168 ++ drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h | 399 +++ .../cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h | 532 ++++ drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c | 136 + drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.h | 33 + .../cam_ope/ope_hw_mgr/ope_hw/top/Makefile | 15 + .../cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c | 246 ++ .../cam_ope/ope_hw_mgr/ope_hw/top/ope_top.h | 41 + drivers/cam_utils/cam_debug_util.c | 5 + drivers/cam_utils/cam_debug_util.h | 2 + include/uapi/media/cam_defs.h | 14 +- include/uapi/media/cam_ope.h | 333 +++ include/uapi/media/cam_req_mgr.h | 1 + 32 files changed, 9154 insertions(+), 1 deletion(-) create mode 100644 drivers/cam_ope/Makefile create mode 100644 drivers/cam_ope/cam_ope_context.c create mode 100644 drivers/cam_ope/cam_ope_context.h create mode 100644 drivers/cam_ope/cam_ope_subdev.c create mode 100644 drivers/cam_ope/ope_hw_mgr/Makefile create mode 100644 drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c create mode 100644 drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h create mode 100644 drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr_intf.h create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/Makefile create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/Makefile create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.h create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/Makefile create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.h create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.h create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev_intf.h create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.h create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/top/Makefile create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c create mode 100644 drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.h create mode 100644 include/uapi/media/cam_ope.h diff --git a/drivers/Makefile b/drivers/Makefile index 13edfb587419..2da1af6c15cb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_cust/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ope/ diff --git a/drivers/cam_ope/Makefile b/drivers/cam_ope/Makefile new file mode 100644 index 000000000000..1f5182836677 --- /dev/null +++ b/drivers/cam_ope/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += ope_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ope_subdev.o cam_ope_context.o + diff --git a/drivers/cam_ope/cam_ope_context.c b/drivers/cam_ope/cam_ope_context.c new file mode 100644 index 000000000000..ba35176b0d45 --- /dev/null +++ b/drivers/cam_ope/cam_ope_context.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cam_sync_api.h" +#include "cam_node.h" +#include "cam_context.h" +#include "cam_context_utils.h" +#include "cam_ope_context.h" +#include "cam_req_mgr_util.h" +#include "cam_mem_mgr.h" +#include "cam_trace.h" +#include "cam_debug_util.h" +#include "cam_packet_util.h" + +static const char ope_dev_name[] = "cam-ope"; + +static int cam_ope_context_dump_active_request(void *data, unsigned long iova, + uint32_t buf_info) +{ + struct cam_context *ctx = (struct cam_context *)data; + struct cam_ctx_request *req = NULL; + struct cam_ctx_request *req_temp = NULL; + struct cam_hw_mgr_dump_pf_data *pf_dbg_entry = NULL; + int rc = 0; + bool b_mem_found = false; + + if (!ctx) { + CAM_ERR(CAM_OPE, "Invalid ctx"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) { + CAM_ERR(CAM_ICP, "Invalid state icp ctx %d state %d", + ctx->ctx_id, ctx->state); + goto end; + } + + CAM_INFO(CAM_OPE, "iommu fault for ope ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + pf_dbg_entry = &(req->pf_data); + CAM_INFO(CAM_OPE, "req_id : %lld", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &b_mem_found); + if (rc) + CAM_ERR(CAM_OPE, "Failed to dump pf info"); + + if (b_mem_found) + CAM_ERR(CAM_OPE, "Found page fault in req %lld %d", + req->request_id, rc); + } + +end: + mutex_unlock(&ctx->ctx_mutex); + return rc; +} + +static int __cam_ope_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (!rc) { + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("OPE", ctx); + } + + return rc; +} + +static int __cam_ope_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_OPE, "Unable to release device"); + + ctx->state = CAM_CTX_AVAILABLE; + trace_cam_context_state("OPE", ctx); + return rc; +} + +static int __cam_ope_start_dev_in_acquired(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_start_dev_to_hw(ctx, cmd); + if (!rc) { + ctx->state = CAM_CTX_READY; + trace_cam_context_state("OPE", ctx); + } + + return rc; +} + +static int __cam_ope_flush_dev_in_ready(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_flush_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_OPE, "Failed to flush device"); + + return rc; +} + +static int __cam_ope_config_dev_in_ready(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc; + size_t len; + uintptr_t packet_addr; + + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc) { + CAM_ERR(CAM_OPE, "[%s][%d] Can not get packet address", + ctx->dev_name, ctx->ctx_id); + rc = -EINVAL; + return rc; + } + + rc = cam_context_prepare_dev_to_hw(ctx, cmd); + + if (rc) + CAM_ERR(CAM_OPE, "Failed to prepare device"); + + return rc; +} + +static int __cam_ope_stop_dev_in_ready(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_stop_dev_to_hw(ctx); + if (rc) + CAM_ERR(CAM_OPE, "Failed to stop device"); + + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("OPE", ctx); + return rc; +} + +static int __cam_ope_release_dev_in_ready(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = __cam_ope_stop_dev_in_ready(ctx, NULL); + if (rc) + CAM_ERR(CAM_OPE, "Failed to stop device"); + + rc = __cam_ope_release_dev_in_acquired(ctx, cmd); + if (rc) + CAM_ERR(CAM_OPE, "Failed to release device"); + + return rc; +} + +static int __cam_ope_handle_buf_done_in_ready(void *ctx, + uint32_t evt_id, void *done) +{ + return cam_context_buf_done_from_hw(ctx, done, evt_id); +} + +static struct cam_ctx_ops + cam_ope_ctx_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_ope_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .release_dev = __cam_ope_release_dev_in_acquired, + .start_dev = __cam_ope_start_dev_in_acquired, + .config_dev = __cam_ope_config_dev_in_ready, + .flush_dev = __cam_ope_flush_dev_in_ready, + }, + .crm_ops = {}, + .irq_ops = __cam_ope_handle_buf_done_in_ready, + .pagefault_ops = cam_ope_context_dump_active_request, + }, + /* Ready */ + { + .ioctl_ops = { + .stop_dev = __cam_ope_stop_dev_in_ready, + .release_dev = __cam_ope_release_dev_in_ready, + .config_dev = __cam_ope_config_dev_in_ready, + .flush_dev = __cam_ope_flush_dev_in_ready, + }, + .crm_ops = {}, + .irq_ops = __cam_ope_handle_buf_done_in_ready, + .pagefault_ops = cam_ope_context_dump_active_request, + }, + /* Activated */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + .pagefault_ops = cam_ope_context_dump_active_request, + }, +}; + +int cam_ope_context_init(struct cam_ope_context *ctx, + struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id) +{ + int rc; + + if ((!ctx) || (!ctx->base) || (!hw_intf)) { + CAM_ERR(CAM_OPE, "Invalid params: %pK %pK", ctx, hw_intf); + rc = -EINVAL; + goto err; + } + + rc = cam_context_init(ctx->base, ope_dev_name, CAM_OPE, ctx_id, + NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_OPE, "Camera Context Base init failed"); + goto err; + } + + ctx->base->state_machine = cam_ope_ctx_state_machine; + ctx->base->ctx_priv = ctx; + ctx->ctxt_to_hw_map = NULL; + +err: + return rc; +} + +int cam_ope_context_deinit(struct cam_ope_context *ctx) +{ + if ((!ctx) || (!ctx->base)) { + CAM_ERR(CAM_OPE, "Invalid params: %pK", ctx); + return -EINVAL; + } + + cam_context_deinit(ctx->base); + memset(ctx, 0, sizeof(*ctx)); + + return 0; +} + + diff --git a/drivers/cam_ope/cam_ope_context.h b/drivers/cam_ope/cam_ope_context.h new file mode 100644 index 000000000000..59b2c2748e80 --- /dev/null +++ b/drivers/cam_ope/cam_ope_context.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_OPE_CONTEXT_H_ +#define _CAM_OPE_CONTEXT_H_ + +#include "cam_context.h" + +#define OPE_CTX_MAX 32 + +/** + * struct cam_ope_context - ope context + * @base: ope context object + * @state_machine: state machine for OPE context + * @req_base: common request structure + * @state: ope context state + * @ctxt_to_hw_map: context to FW handle mapping + */ +struct cam_ope_context { + struct cam_context *base; + struct cam_ctx_ops *state_machine; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + uint32_t state; + void *ctxt_to_hw_map; +}; + +/** + * cam_ope_context_init() - OPE context init + * @ctx: Pointer to context + * @hw_intf: Pointer to OPE hardware interface + * @ctx_id: ID for this context + */ +int cam_ope_context_init(struct cam_ope_context *ctx, + struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id); + +/** + * cam_ope_context_deinit() - OPE context deinit + * @ctx: Pointer to context + */ +int cam_ope_context_deinit(struct cam_ope_context *ctx); + +#endif /* _CAM_OPE_CONTEXT_H_ */ diff --git a/drivers/cam_ope/cam_ope_subdev.c b/drivers/cam_ope/cam_ope_subdev.c new file mode 100644 index 000000000000..22175ec1b9bc --- /dev/null +++ b/drivers/cam_ope/cam_ope_subdev.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_req_mgr_dev.h" +#include "cam_subdev.h" +#include "cam_node.h" +#include "cam_context.h" +#include "cam_ope_context.h" +#include "cam_ope_hw_mgr_intf.h" +#include "cam_hw_mgr_intf.h" +#include "cam_debug_util.h" +#include "cam_smmu_api.h" + +#define OPE_DEV_NAME "cam-ope" + +struct cam_ope_subdev { + struct cam_subdev sd; + struct cam_node *node; + struct cam_context ctx[OPE_CTX_MAX]; + struct cam_ope_context ctx_ope[OPE_CTX_MAX]; + struct mutex ope_lock; + int32_t open_cnt; + int32_t reserved; +}; + +static struct cam_ope_subdev g_ope_dev; + +static void cam_ope_dev_iommu_fault_handler( + struct iommu_domain *domain, struct device *dev, unsigned long iova, + int flags, void *token, uint32_t buf_info) +{ + int i = 0; + struct cam_node *node = NULL; + + if (!token) { + CAM_ERR(CAM_OPE, "invalid token in page handler cb"); + return; + } + + node = (struct cam_node *)token; + + for (i = 0; i < node->ctx_size; i++) + cam_context_dump_pf_info(&(node->ctx_list[i]), iova, + buf_info); +} + +static int cam_ope_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_hw_mgr_intf *hw_mgr_intf = NULL; + struct cam_node *node = v4l2_get_subdevdata(sd); + int rc = 0; + + mutex_lock(&g_ope_dev.ope_lock); + if (g_ope_dev.open_cnt >= 1) { + CAM_ERR(CAM_OPE, "OPE subdev is already opened"); + rc = -EALREADY; + goto end; + } + + if (!node) { + CAM_ERR(CAM_OPE, "Invalid args"); + rc = -EINVAL; + goto end; + } + + hw_mgr_intf = &node->hw_mgr_intf; + rc = hw_mgr_intf->hw_open(hw_mgr_intf->hw_mgr_priv, NULL); + if (rc < 0) { + CAM_ERR(CAM_OPE, "OPE HW open failed: %d", rc); + goto end; + } + g_ope_dev.open_cnt++; + CAM_DBG(CAM_OPE, "OPE HW open success: %d", rc); +end: + mutex_unlock(&g_ope_dev.ope_lock); + return rc; +} + +static int cam_ope_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_hw_mgr_intf *hw_mgr_intf = NULL; + struct cam_node *node = v4l2_get_subdevdata(sd); + + mutex_lock(&g_ope_dev.ope_lock); + if (g_ope_dev.open_cnt <= 0) { + CAM_DBG(CAM_OPE, "OPE subdev is already closed"); + rc = -EINVAL; + goto end; + } + g_ope_dev.open_cnt--; + if (!node) { + CAM_ERR(CAM_OPE, "Invalid args"); + rc = -EINVAL; + goto end; + } + + hw_mgr_intf = &node->hw_mgr_intf; + if (!hw_mgr_intf) { + CAM_ERR(CAM_OPE, "hw_mgr_intf is not initialized"); + rc = -EINVAL; + goto end; + } + + rc = cam_node_shutdown(node); + if (rc < 0) { + CAM_ERR(CAM_OPE, "HW close failed"); + goto end; + } + CAM_DBG(CAM_OPE, "OPE HW close success: %d", rc); + +end: + mutex_unlock(&g_ope_dev.ope_lock); + return rc; +} + +const struct v4l2_subdev_internal_ops cam_ope_subdev_internal_ops = { + .open = cam_ope_subdev_open, + .close = cam_ope_subdev_close, +}; + +static int cam_ope_subdev_probe(struct platform_device *pdev) +{ + int rc = 0, i = 0; + struct cam_node *node; + struct cam_hw_mgr_intf *hw_mgr_intf; + int iommu_hdl = -1; + + CAM_DBG(CAM_OPE, "OPE subdev probe start"); + if (!pdev) { + CAM_ERR(CAM_OPE, "pdev is NULL"); + return -EINVAL; + } + + g_ope_dev.sd.pdev = pdev; + g_ope_dev.sd.internal_ops = &cam_ope_subdev_internal_ops; + rc = cam_subdev_probe(&g_ope_dev.sd, pdev, OPE_DEV_NAME, + CAM_OPE_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_OPE, "OPE cam_subdev_probe failed:%d", rc); + return rc; + } + + node = (struct cam_node *) g_ope_dev.sd.token; + + hw_mgr_intf = kzalloc(sizeof(*hw_mgr_intf), GFP_KERNEL); + if (!hw_mgr_intf) { + rc = -EINVAL; + goto hw_alloc_fail; + } + + rc = cam_ope_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf, + &iommu_hdl); + if (rc) { + CAM_ERR(CAM_OPE, "OPE HW manager init failed: %d", rc); + goto hw_init_fail; + } + + for (i = 0; i < OPE_CTX_MAX; i++) { + g_ope_dev.ctx_ope[i].base = &g_ope_dev.ctx[i]; + rc = cam_ope_context_init(&g_ope_dev.ctx_ope[i], + hw_mgr_intf, i); + if (rc) { + CAM_ERR(CAM_OPE, "OPE context init failed"); + goto ctx_fail; + } + } + + rc = cam_node_init(node, hw_mgr_intf, g_ope_dev.ctx, + OPE_CTX_MAX, OPE_DEV_NAME); + if (rc) { + CAM_ERR(CAM_OPE, "OPE node init failed"); + goto ctx_fail; + } + + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_ope_dev_iommu_fault_handler, node); + + g_ope_dev.open_cnt = 0; + mutex_init(&g_ope_dev.ope_lock); + + CAM_DBG(CAM_OPE, "OPE subdev probe complete"); + + return rc; + +ctx_fail: + for (--i; i >= 0; i--) + cam_ope_context_deinit(&g_ope_dev.ctx_ope[i]); +hw_init_fail: + kfree(hw_mgr_intf); +hw_alloc_fail: + cam_subdev_remove(&g_ope_dev.sd); + return rc; +} + +static int cam_ope_subdev_remove(struct platform_device *pdev) +{ + int i; + struct v4l2_subdev *sd; + struct cam_subdev *subdev; + + if (!pdev) { + CAM_ERR(CAM_OPE, "pdev is NULL"); + return -ENODEV; + } + + sd = platform_get_drvdata(pdev); + if (!sd) { + CAM_ERR(CAM_OPE, "V4l2 subdev is NULL"); + return -ENODEV; + } + + subdev = v4l2_get_subdevdata(sd); + if (!subdev) { + CAM_ERR(CAM_OPE, "cam subdev is NULL"); + return -ENODEV; + } + + for (i = 0; i < OPE_CTX_MAX; i++) + cam_ope_context_deinit(&g_ope_dev.ctx_ope[i]); + cam_node_deinit(g_ope_dev.node); + cam_subdev_remove(&g_ope_dev.sd); + mutex_destroy(&g_ope_dev.ope_lock); + + return 0; +} + +static const struct of_device_id cam_ope_dt_match[] = { + {.compatible = "qcom,cam-ope"}, + {} +}; + + +static struct platform_driver cam_ope_driver = { + .probe = cam_ope_subdev_probe, + .remove = cam_ope_subdev_remove, + .driver = { + .name = "cam_ope", + .of_match_table = cam_ope_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_ope_init_module(void) +{ + return platform_driver_register(&cam_ope_driver); +} + +static void __exit cam_ope_exit_module(void) +{ + platform_driver_unregister(&cam_ope_driver); +} +module_init(cam_ope_init_module); +module_exit(cam_ope_exit_module); +MODULE_DESCRIPTION("MSM OPE driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/cam_ope/ope_hw_mgr/Makefile b/drivers/cam_ope/ope_hw_mgr/Makefile new file mode 100644 index 000000000000..bec1684d42ee --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += ope_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ope_hw_mgr.o + + 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 new file mode 100644 index 000000000000..659279992d04 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c @@ -0,0 +1,2248 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cam_sync_api.h" +#include "cam_packet_util.h" +#include "cam_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_ope_hw_mgr_intf.h" +#include "cam_ope_hw_mgr.h" +#include "ope_hw.h" +#include "cam_smmu_api.h" +#include "cam_mem_mgr.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" +#include "cam_debug_util.h" +#include "cam_soc_util.h" +#include "cam_trace.h" +#include "cam_cpas_api.h" +#include "cam_common_util.h" +#include "cam_cdm_intf_api.h" +#include "cam_cdm_util.h" +#include "cam_cdm.h" +#include "ope_dev_intf.h" + +static struct cam_ope_hw_mgr *ope_hw_mgr; + +static int cam_ope_mgr_get_rsc_idx(struct cam_ope_ctx *ctx_data, + struct ope_io_buf_info *in_io_buf) +{ + int k = 0; + int rsc_idx = -EINVAL; + + if (in_io_buf->direction == CAM_BUF_INPUT) { + for (k = 0; k < OPE_IN_RES_MAX; k++) { + if (ctx_data->ope_acquire.in_res[k].res_id == + in_io_buf->resource_type) + break; + } + if (k == OPE_IN_RES_MAX) { + CAM_ERR(CAM_OPE, "Invalid res_id %d", + in_io_buf->resource_type); + goto end; + } + rsc_idx = k; + } else if (in_io_buf->direction == CAM_BUF_OUTPUT) { + for (k = 0; k < OPE_OUT_RES_MAX; k++) { + if (ctx_data->ope_acquire.out_res[k].res_id == + in_io_buf->resource_type) + break; + } + if (k == OPE_OUT_RES_MAX) { + CAM_ERR(CAM_OPE, "Invalid res_id %d", + in_io_buf->resource_type); + goto end; + } + rsc_idx = k; + } + +end: + return rsc_idx; +} + +static int cam_ope_mgr_process_cmd(void *priv, void *data) +{ + int rc; + struct ope_cmd_work_data *task_data = NULL; + struct cam_ope_ctx *ctx_data; + struct cam_cdm_bl_request *cdm_cmd; + + if (!data || !priv) { + CAM_ERR(CAM_OPE, "Invalid params%pK %pK", data, priv); + return -EINVAL; + } + + ctx_data = priv; + 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); + rc = cam_cdm_submit_bls(ctx_data->ope_cdm.cdm_handle, cdm_cmd); + + if (!rc) + ctx_data->req_cnt++; + else + CAM_ERR(CAM_OPE, "submit failed for %lld", cdm_cmd->cookie); + + return rc; +} + +static int cam_ope_mgr_reset_hw(void) +{ + struct cam_ope_hw_mgr *hw_mgr = ope_hw_mgr; + int i, rc = 0; + + for (i = 0; i < ope_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 Reset failed: %d", rc); + return rc; + } + } + + return rc; +} + +static int cam_ope_req_timer_modify(struct cam_ope_ctx *ctx_data, + int32_t expires) +{ + if (ctx_data->req_watch_dog) { + CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + crm_timer_modify(ctx_data->req_watch_dog, expires); + } + return 0; +} + +static int cam_ope_req_timer_stop(struct cam_ope_ctx *ctx_data) +{ + if (ctx_data->req_watch_dog) { + CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + crm_timer_exit(&ctx_data->req_watch_dog); + ctx_data->req_watch_dog = NULL; + } + return 0; +} + +static int cam_ope_req_timer_reset(struct cam_ope_ctx *ctx_data) +{ + if (ctx_data && ctx_data->req_watch_dog) + crm_timer_reset(ctx_data->req_watch_dog); + + return 0; +} + + +static int cam_ope_mgr_reapply_config(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, + struct cam_ope_request *ope_req) +{ + int rc = 0; + uint64_t request_id = 0; + struct crm_workq_task *task; + struct ope_cmd_work_data *task_data; + + request_id = ope_req->request_id; + CAM_DBG(CAM_OPE, "reapply req_id = %lld", request_id); + + task = cam_req_mgr_workq_get_task(ope_hw_mgr->cmd_work); + if (!task) { + CAM_ERR(CAM_OPE, "no empty task"); + return -ENOMEM; + } + + task_data = (struct ope_cmd_work_data *)task->payload; + task_data->data = (void *)ope_req->cdm_cmd; + task_data->req_id = request_id; + task_data->type = OPE_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_ope_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, ctx_data, + CRM_TASK_PRIORITY_0); + + return rc; +} + +static bool cam_ope_is_pending_request(struct cam_ope_ctx *ctx_data) +{ + return !bitmap_empty(ctx_data->bitmap, CAM_CTX_REQ_MAX); +} + +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; + + 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); + cam_ope_req_timer_reset(ctx_data); + } else { + cam_ope_req_timer_modify(ctx_data, ~0); + } + return 0; +} + +static void cam_ope_req_timer_cb(struct timer_list *timer_data) +{ + unsigned long flags; + struct crm_workq_task *task; + struct ope_clk_work_data *task_data; + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + + spin_lock_irqsave(&ope_hw_mgr->hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task(ope_hw_mgr->timer_work); + if (!task) { + CAM_ERR(CAM_OPE, "no empty task"); + spin_unlock_irqrestore(&ope_hw_mgr->hw_mgr_lock, flags); + return; + } + + task_data = (struct ope_clk_work_data *)task->payload; + task_data->data = timer->parent; + task_data->type = OPE_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_ope_process_request_timer; + cam_req_mgr_workq_enqueue_task(task, ope_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&ope_hw_mgr->hw_mgr_lock, flags); +} + +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); + if (rc) + CAM_ERR(CAM_ICP, "Failed to start timer"); + + 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 void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, + enum cam_cdm_cb_status status, uint64_t cookie) +{ + int rc = 0; + struct cam_ope_ctx *ctx; + struct cam_ope_request *ope_req; + struct cam_hw_done_event_data buf_data; + bool flag = false; + + if (!userdata) { + CAM_ERR(CAM_OPE, "Invalid ctx from CDM callback"); + return; + } + + CAM_DBG(CAM_FD, "CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", + handle, userdata, status, cookie); + + ctx = userdata; + ope_req = ctx->req_list[cookie]; + + mutex_lock(&ctx->ctx_mutex); + if (ctx->ctx_state != OPE_CTX_STATE_ACQUIRED) { + CAM_DBG(CAM_OPE, "ctx %u is in %d state", + ctx->ctx_id, ctx->ctx_state); + mutex_unlock(&ctx->ctx_mutex); + return; + } + + if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { + CAM_DBG(CAM_OPE, + "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_ope_req_timer_reset(ctx); + } else if (status == CAM_CDM_CB_STATUS_HW_RESUBMIT) { + CAM_INFO(CAM_OPE, "After reset of CDM and OPE, reapply req"); + rc = cam_ope_mgr_reapply_config(ope_hw_mgr, ctx, ope_req); + if (!rc) + 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); + CAM_ERR(CAM_OPE, "Rst of CDM and OPE for error reqid = %lld", + ope_req->request_id); + rc = cam_ope_mgr_reset_hw(); + flag = true; + } + + ctx->req_cnt--; + + buf_data.request_id = ope_req->request_id; + ope_req->request_id = 0; + kzfree(ctx->req_list[cookie]->cdm_cmd); + ctx->req_list[cookie]->cdm_cmd = NULL; + kzfree(ctx->req_list[cookie]); + ctx->req_list[cookie] = NULL; + clear_bit(cookie, ctx->bitmap); + ctx->ctxt_event_cb(ctx->context_priv, flag, &buf_data); + +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; + unsigned long flags; + struct cam_ope_hw_mgr *hw_mgr = data; + struct crm_workq_task *task; + struct ope_msg_work_data *task_data; + + if (!data) { + CAM_ERR(CAM_OPE, "irq cb data is NULL"); + return rc; + } + + spin_lock_irqsave(&hw_mgr->hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task(ope_hw_mgr->msg_work); + if (!task) { + CAM_ERR(CAM_OPE, "no empty task"); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + return -ENOMEM; + } + + task_data = (struct ope_msg_work_data *)task->payload; + task_data->data = hw_mgr; + task_data->irq_status = irq_status; + task_data->type = OPE_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_ope_mgr_process_msg; + rc = cam_req_mgr_workq_enqueue_task(task, ope_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + + return rc; +} + +static int cam_ope_mgr_create_kmd_buf(struct cam_ope_hw_mgr *hw_mgr, + struct cam_packet *packet, + struct cam_hw_prepare_update_args *prepare_args, + struct cam_ope_ctx *ctx_data, uint32_t req_idx, + uintptr_t ope_cmd_buf_addr) +{ + int i, rc = 0; + struct cam_ope_dev_prepare_req prepare_req; + + prepare_req.ctx_data = ctx_data; + prepare_req.hw_mgr = hw_mgr; + prepare_req.packet = packet; + prepare_req.prepare_args = prepare_args; + prepare_req.req_idx = req_idx; + prepare_req.kmd_buf_offset = 0; + prepare_req.frame_process = + (struct ope_frame_process *)ope_cmd_buf_addr; + + for (i = 0; i < ope_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_PREPARE, &prepare_req, sizeof(prepare_req)); + if (rc) { + CAM_ERR(CAM_OPE, "OPE Dev prepare failed: %d", rc); + goto end; + } + +end: + return rc; +} + +static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, + struct cam_packet *packet, + struct cam_hw_prepare_update_args *prep_args, + struct cam_ope_ctx *ctx_data, uint32_t req_idx) +{ + + int i, j = 0, k = 0, l, rc = 0; + struct ope_io_buf *io_buf; + int32_t sync_in_obj[CAM_MAX_IN_RES]; + int32_t merged_sync_in_obj; + struct cam_ope_request *ope_request; + + ope_request = ctx_data->req_list[req_idx]; + prep_args->num_out_map_entries = 0; + prep_args->num_in_map_entries = 0; + + ope_request = ctx_data->req_list[req_idx]; + CAM_DBG(CAM_OPE, "E: req_idx = %u %x", req_idx, packet); + + 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]; + if (io_buf->direction == CAM_BUF_INPUT) { + if (io_buf->fence != -1) { + sync_in_obj[j++] = io_buf->fence; + prep_args->num_in_map_entries++; + } else { + CAM_ERR(CAM_OPE, "Invalid fence %d %d", + io_buf->resource_type, + ope_request->request_id); + } + } else { + if (io_buf->fence != -1) { + prep_args->out_map_entries[k].sync_id = + io_buf->fence; + k++; + prep_args->num_out_map_entries++; + } else { + CAM_ERR(CAM_OPE, "Invalid fence %d %d", + io_buf->resource_type, + ope_request->request_id); + } + } + CAM_DBG(CAM_REQ, + "ctx_id: %u req_id: %llu dir[%d] %u, fence: %d", + ctx_data->ctx_id, packet->header.request_id, i, + io_buf->direction, io_buf->fence); + CAM_DBG(CAM_REQ, "rsc_type = %u fmt = %d", + io_buf->resource_type, + io_buf->format); + } + } + + if (prep_args->num_in_map_entries > 1) + 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) { + rc = cam_sync_merge(&sync_in_obj[0], + prep_args->num_in_map_entries, &merged_sync_in_obj); + if (rc) { + prep_args->num_out_map_entries = 0; + prep_args->num_in_map_entries = 0; + return rc; + } + + ope_request->in_resource = merged_sync_in_obj; + + prep_args->in_map_entries[0].sync_id = merged_sync_in_obj; + prep_args->num_in_map_entries = 1; + CAM_DBG(CAM_REQ, "ctx_id: %u req_id: %llu Merged Sync obj: %d", + ctx_data->ctx_id, packet->header.request_id, + merged_sync_in_obj); + } else if (prep_args->num_in_map_entries == 1) { + prep_args->in_map_entries[0].sync_id = sync_in_obj[0]; + prep_args->num_in_map_entries = 1; + ope_request->in_resource = 0; + CAM_DBG(CAM_OPE, "fence = %d", sync_in_obj[0]); + } else { + CAM_DBG(CAM_OPE, "No input fences"); + prep_args->num_in_map_entries = 0; + ope_request->in_resource = 0; + rc = -EINVAL; + } + return rc; +} + +static void cam_ope_mgr_print_stripe_info(uint32_t batch, + uint32_t io_buf, uint32_t plane, uint32_t stripe, + struct ope_stripe_io *stripe_info, uint64_t iova_addr) +{ + CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d: E", + batch, io_buf, plane, stripe); + CAM_DBG(CAM_OPE, "width: %d s_w: %u s_h: %u s_s: %u", + stripe_info->width, stripe_info->width, + stripe_info->height, stripe_info->stride); + CAM_DBG(CAM_OPE, "s_xinit = %u iova = %x s_loc = %u", + stripe_info->s_location, stripe_info->x_init, + iova_addr); + CAM_DBG(CAM_OPE, "s_off = %u s_format = %u s_len = %u", + stripe_info->offset, stripe_info->format, + stripe_info->len); + CAM_DBG(CAM_OPE, "s_align = %u s_pack = %u s_unpack = %u", + stripe_info->alignment, stripe_info->pack_format, + stripe_info->unpack_format); + CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d: E", + batch, io_buf, plane, stripe); +} + +static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, + struct cam_packet *packet, struct cam_ope_ctx *ctx_data, + uintptr_t frame_process_addr, size_t length, uint32_t req_idx) +{ + int rc = 0; + int i, j, k, l; + uint64_t iova_addr; + size_t len; + struct ope_frame_process *in_frame_process; + struct ope_frame_set *in_frame_set; + struct ope_io_buf_info *in_io_buf; + struct ope_stripe_info *in_stripe_info; + struct cam_ope_request *ope_request; + struct ope_io_buf *io_buf; + struct ope_stripe_io *stripe_info; + uint32_t alignment; + uint32_t rsc_idx; + uint32_t pack_format; + uint32_t unpack_format; + struct ope_in_res_info *in_res; + struct ope_out_res_info *out_res; + + in_frame_process = (struct ope_frame_process *)frame_process_addr; + + ope_request = ctx_data->req_list[req_idx]; + ope_request->num_batch = in_frame_process->batch_size; + + for (i = 0; i < in_frame_process->batch_size; i++) { + in_frame_set = &in_frame_process->frame_set[i]; + for (j = 0; j < in_frame_set->num_io_bufs; j++) { + in_io_buf = &in_frame_set->io_buf[j]; + CAM_DBG(CAM_OPE, "i:%d j:%d dir: %x rsc: %u plane: %d", + i, j, in_io_buf->direction, + in_io_buf->resource_type, + in_io_buf->num_planes); + for (k = 0; k < in_io_buf->num_planes; k++) { + CAM_DBG(CAM_OPE, "i:%d j:%d k:%d numstripe: %d", + i, j, k, in_io_buf->num_stripes[k]); + CAM_DBG(CAM_OPE, "m_hdl: %d len: %d", + in_io_buf->mem_handle[k], + in_io_buf->length[k]); + for (l = 0; l < in_io_buf->num_stripes[k]; + l++) { + in_stripe_info = + &in_io_buf->stripe_info[k][l]; + CAM_DBG(CAM_OPE, "i:%d j:%d k:%d l:%d", + i, j, k, l); + CAM_DBG(CAM_OPE, "%d s_loc:%d w:%d", + in_stripe_info->x_init, + in_stripe_info->stripe_location, + in_stripe_info->width); + CAM_DBG(CAM_OPE, "s_off: %d d_bus: %d", + in_stripe_info->offset, + in_stripe_info->disable_bus); + } + } + } + } + + for (i = 0; i < ope_request->num_batch; i++) { + in_frame_set = &in_frame_process->frame_set[i]; + ope_request->num_io_bufs[i] = in_frame_set->num_io_bufs; + if (in_frame_set->num_io_bufs > OPE_MAX_IO_BUFS) { + CAM_ERR(CAM_OPE, "Wrong number of io buffers: %d", + in_frame_set->num_io_bufs); + return -EINVAL; + } + + 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]; + if (in_io_buf->num_planes > OPE_MAX_PLANES) { + CAM_ERR(CAM_OPE, "wrong number of planes: %u", + in_io_buf->num_planes); + return -EINVAL; + } + + io_buf->num_planes = in_io_buf->num_planes; + io_buf->resource_type = in_io_buf->resource_type; + io_buf->direction = in_io_buf->direction; + io_buf->fence = in_io_buf->fence; + io_buf->format = in_io_buf->format; + + rc = cam_ope_mgr_get_rsc_idx(ctx_data, in_io_buf); + if (rc < 0) { + CAM_ERR(CAM_OPE, "Invalid rsc idx = %d", rc); + return rc; + } + rsc_idx = rc; + if (in_io_buf->direction == CAM_BUF_INPUT) { + in_res = + &ctx_data->ope_acquire.in_res[rsc_idx]; + alignment = in_res->alignment; + unpack_format = in_res->unpacker_format; + pack_format = 0; + } else if (in_io_buf->direction == CAM_BUF_OUTPUT) { + out_res = + &ctx_data->ope_acquire.out_res[rsc_idx]; + alignment = out_res->alignment; + pack_format = out_res->packer_format; + unpack_format = 0; + } + + CAM_DBG(CAM_OPE, "i:%d j:%d dir:%d rsc type:%d fmt:%d", + i, j, io_buf->direction, io_buf->resource_type, + io_buf->format); + for (k = 0; k < in_io_buf->num_planes; k++) { + io_buf->num_stripes[k] = + in_io_buf->num_stripes[k]; + rc = cam_mem_get_io_buf( + in_io_buf->mem_handle[k], + hw_mgr->iommu_hdl, &iova_addr, &len); + if (rc) { + CAM_ERR(CAM_OPE, "get buf failed: %d", + rc); + return -EINVAL; + } + if (len < in_io_buf->length[k]) { + CAM_ERR(CAM_OPE, "Invalid length"); + return -EINVAL; + } + iova_addr += in_io_buf->plane_offset[k]; + for (l = 0; l < in_io_buf->num_stripes[k]; + l++) { + in_stripe_info = + &in_io_buf->stripe_info[k][l]; + stripe_info = &io_buf->s_io[k][l]; + stripe_info->offset = + in_stripe_info->offset; + stripe_info->format = in_io_buf->format; + stripe_info->s_location = + in_stripe_info->stripe_location; + stripe_info->iova_addr = + iova_addr + stripe_info->offset; + stripe_info->width = + in_stripe_info->width; + stripe_info->height = + in_io_buf->height[k]; + stripe_info->stride = + in_io_buf->plane_stride[k]; + stripe_info->x_init = + in_stripe_info->x_init; + stripe_info->len = len; + stripe_info->alignment = alignment; + stripe_info->pack_format = pack_format; + stripe_info->unpack_format = + unpack_format; + cam_ope_mgr_print_stripe_info(i, j, + k, l, stripe_info, iova_addr); + } + } + } + } + + return rc; +} + +static int cam_ope_mgr_process_cmd_buf_req(struct cam_ope_hw_mgr *hw_mgr, + struct cam_packet *packet, struct cam_ope_ctx *ctx_data, + uintptr_t frame_process_addr, size_t length, uint32_t req_idx) +{ + int rc = 0; + int i, j; + uint64_t iova_addr; + uint64_t iova_cdm_addr; + uintptr_t cpu_addr; + size_t len; + struct ope_frame_process *frame_process; + struct ope_cmd_buf_info *cmd_buf; + struct cam_ope_request *ope_request; + bool is_kmd_buf_valid = false; + + frame_process = (struct ope_frame_process *)frame_process_addr; + + if (frame_process->batch_size > OPE_MAX_BATCH_SIZE) { + CAM_ERR(CAM_OPE, "Invalid batch: %d", + frame_process->batch_size); + return -EINVAL; + } + + for (i = 0; i < frame_process->batch_size; i++) { + if (frame_process->num_cmd_bufs[i] > OPE_MAX_CMD_BUFS) { + CAM_ERR(CAM_OPE, "Invalid cmd bufs for batch %d %d", + i, frame_process->num_cmd_bufs[i]); + return -EINVAL; + } + } + + CAM_DBG(CAM_OPE, "cmd buf for req id = %lld b_size = %d", + packet->header.request_id, frame_process->batch_size); + + for (i = 0; i < frame_process->batch_size; i++) { + CAM_DBG(CAM_OPE, "batch: %d count %d", i, + frame_process->num_cmd_bufs[i]); + for (j = 0; j < frame_process->num_cmd_bufs[i]; j++) { + CAM_DBG(CAM_OPE, "batch: %d cmd_buf_idx :%d mem_hdl:%x", + i, j, frame_process->cmd_buf[i][j].mem_handle); + CAM_DBG(CAM_OPE, "size = %u scope = %d buf_type = %d", + frame_process->cmd_buf[i][j].size, + frame_process->cmd_buf[i][j].cmd_buf_scope, + frame_process->cmd_buf[i][j].type); + CAM_DBG(CAM_OPE, "usage = %d buffered = %d s_idx = %d", + frame_process->cmd_buf[i][j].cmd_buf_usage, + frame_process->cmd_buf[i][j].cmd_buf_buffered, + frame_process->cmd_buf[i][j].stripe_idx); + } + } + + ope_request = ctx_data->req_list[req_idx]; + ope_request->num_batch = frame_process->batch_size; + + 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]; + + switch (cmd_buf->cmd_buf_scope) { + case OPE_CMD_BUF_SCOPE_FRAME: { + rc = cam_mem_get_io_buf(cmd_buf->mem_handle, + hw_mgr->iommu_hdl, &iova_addr, &len); + if (rc) { + CAM_ERR(CAM_OPE, "get cmd buffailed %x", + hw_mgr->iommu_hdl); + goto end; + } + iova_addr = iova_addr + cmd_buf->offset; + + rc = cam_mem_get_io_buf(cmd_buf->mem_handle, + hw_mgr->iommu_cdm_hdl, + &iova_cdm_addr, &len); + if (rc) { + CAM_ERR(CAM_OPE, "get cmd buffailed %x", + hw_mgr->iommu_hdl); + goto end; + } + iova_cdm_addr = iova_cdm_addr + cmd_buf->offset; + + rc = cam_mem_get_cpu_buf(cmd_buf->mem_handle, + &cpu_addr, &len); + if (rc || !cpu_addr) { + CAM_ERR(CAM_OPE, "get cmd buffailed %x", + hw_mgr->iommu_hdl); + goto end; + } + cpu_addr = cpu_addr + + frame_process->cmd_buf[i][j].offset; + CAM_DBG(CAM_OPE, "Hdl %x size %d len %d off %d", + cmd_buf->mem_handle, cmd_buf->size, + cmd_buf->length, + cmd_buf->offset); + if (cmd_buf->cmd_buf_usage == OPE_CMD_BUF_KMD) { + ope_request->ope_kmd_buf.mem_handle = + cmd_buf->mem_handle; + ope_request->ope_kmd_buf.cpu_addr = + cpu_addr; + ope_request->ope_kmd_buf.iova_addr = + iova_addr; + ope_request->ope_kmd_buf.iova_cdm_addr = + iova_cdm_addr; + ope_request->ope_kmd_buf.len = len; + ope_request->ope_kmd_buf.size = + cmd_buf->size; + is_kmd_buf_valid = true; + CAM_DBG(CAM_OPE, "kbuf:%x io:%x cdm:%x", + ope_request->ope_kmd_buf.cpu_addr, + ope_request->ope_kmd_buf.iova_addr, + ope_request->ope_kmd_buf.iova_cdm_addr); + break; + } else if (cmd_buf->cmd_buf_usage == + OPE_CMD_BUF_DEBUG) { + ope_request->ope_debug_buf.cpu_addr = + cpu_addr; + ope_request->ope_debug_buf.iova_addr = + iova_addr; + ope_request->ope_debug_buf.len = + len; + ope_request->ope_debug_buf.size = + cmd_buf->size; + CAM_DBG(CAM_OPE, "dbg buf = %x", + ope_request->ope_debug_buf.cpu_addr); + break; + } + break; + } + case OPE_CMD_BUF_SCOPE_STRIPE: { + uint32_t num_cmd_bufs = 0; + uint32_t s_idx = 0; + + s_idx = cmd_buf->stripe_idx; + num_cmd_bufs = + ope_request->num_stripe_cmd_bufs[i][s_idx]; + + if (!num_cmd_bufs) + ope_request->num_stripes[i]++; + + ope_request->num_stripe_cmd_bufs[i][s_idx]++; + break; + } + + default: + break; + } + } + } + + + for (i = 0; i < frame_process->batch_size; i++) { + CAM_DBG(CAM_OPE, "num of stripes for batch %d is %d", + i, ope_request->num_stripes[i]); + for (j = 0; j < ope_request->num_stripes[i]; j++) { + CAM_DBG(CAM_OPE, "cmd buffers for stripe: %d:%d is %d", + i, j, ope_request->num_stripe_cmd_bufs[i][j]); + } + } + + if (!is_kmd_buf_valid) { + CAM_DBG(CAM_OPE, "Invalid kmd buffer"); + rc = -EINVAL; + } +end: + return rc; +} + +static int cam_ope_mgr_process_cmd_desc(struct cam_ope_hw_mgr *hw_mgr, + struct cam_packet *packet, struct cam_ope_ctx *ctx_data, + uintptr_t *ope_cmd_buf_addr, uint32_t req_idx) +{ + int rc = 0; + int i; + int num_cmd_buf = 0; + size_t len; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t cpu_addr = 0; + struct cam_ope_request *ope_request; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + + *ope_cmd_buf_addr = 0; + for (i = 0; i < packet->num_cmd_buf; i++, num_cmd_buf++) { + 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", + hw_mgr->iommu_hdl); + num_cmd_buf = (num_cmd_buf > 0) ? + num_cmd_buf-- : 0; + goto end; + } + if ((len <= cmd_desc[i].offset) || + (cmd_desc[i].size < cmd_desc[i].length) || + ((len - cmd_desc[i].offset) < + cmd_desc[i].length)) { + CAM_ERR(CAM_OPE, "Invalid offset or length"); + goto end; + } + cpu_addr = cpu_addr + cmd_desc[i].offset; + *ope_cmd_buf_addr = cpu_addr; + } + + if (!cpu_addr) { + CAM_ERR(CAM_OPE, "invalid number of cmd buf"); + *ope_cmd_buf_addr = 0; + return -EINVAL; + } + + ope_request = ctx_data->req_list[req_idx]; + ope_request->request_id = packet->header.request_id; + ope_request->req_idx = req_idx; + + rc = cam_ope_mgr_process_cmd_buf_req(hw_mgr, packet, ctx_data, + cpu_addr, len, req_idx); + if (rc) { + CAM_ERR(CAM_OPE, "Process OPE cmd request is failed: %d", rc); + goto end; + } + + rc = cam_ope_mgr_process_cmd_io_buf_req(hw_mgr, packet, ctx_data, + cpu_addr, len, req_idx); + if (rc) { + CAM_ERR(CAM_OPE, "Process OPE cmd io request is failed: %d", + rc); + goto end; + } + + return rc; + +end: + *ope_cmd_buf_addr = 0; + return rc; +} + +static bool cam_ope_mgr_is_valid_inconfig(struct cam_packet *packet) +{ + int i, num_in_map_entries = 0; + bool in_config_valid = false; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + + io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload + + packet->io_configs_offset/4); + + for (i = 0 ; i < packet->num_io_configs; i++) + if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) + num_in_map_entries++; + + if (num_in_map_entries <= OPE_IN_RES_MAX) { + in_config_valid = true; + } else { + CAM_ERR(CAM_OPE, "In config entries(%u) more than allowed(%u)", + num_in_map_entries, OPE_IN_RES_MAX); + } + + CAM_DBG(CAM_OPE, "number of in_config info: %u %u %u %u", + packet->num_io_configs, OPE_MAX_IO_BUFS, + num_in_map_entries, OPE_IN_RES_MAX); + + return in_config_valid; +} + +static bool cam_ope_mgr_is_valid_outconfig(struct cam_packet *packet) +{ + int i, num_out_map_entries = 0; + bool out_config_valid = false; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + + io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload + + packet->io_configs_offset/4); + + for (i = 0 ; i < packet->num_io_configs; i++) + if (io_cfg_ptr[i].direction == CAM_BUF_OUTPUT) + num_out_map_entries++; + + if (num_out_map_entries <= OPE_OUT_RES_MAX) { + out_config_valid = true; + } else { + CAM_ERR(CAM_OPE, "Out config entries(%u) more than allowed(%u)", + num_out_map_entries, OPE_OUT_RES_MAX); + } + + CAM_DBG(CAM_OPE, "number of out_config info: %u %u %u %u", + packet->num_io_configs, OPE_MAX_IO_BUFS, + num_out_map_entries, OPE_OUT_RES_MAX); + + return out_config_valid; +} + +static int cam_ope_mgr_pkt_validation(struct cam_packet *packet) +{ + if ((packet->header.op_code & 0xff) != + OPE_OPCODE_CONFIG) { + CAM_ERR(CAM_OPE, "Invalid Opcode in pkt: %d", + packet->header.op_code & 0xff); + return -EINVAL; + } + + if (packet->num_io_configs > OPE_MAX_IO_BUFS) { + CAM_ERR(CAM_OPE, "Invalid number of io configs: %d %d", + OPE_MAX_IO_BUFS, packet->num_io_configs); + return -EINVAL; + } + + if (packet->num_cmd_buf > OPE_PACKET_MAX_CMD_BUFS) { + CAM_ERR(CAM_OPE, "Invalid number of cmd buffers: %d %d", + OPE_PACKET_MAX_CMD_BUFS, packet->num_cmd_buf); + return -EINVAL; + } + + if (!cam_ope_mgr_is_valid_inconfig(packet) || + !cam_ope_mgr_is_valid_outconfig(packet)) { + return -EINVAL; + } + + CAM_DBG(CAM_OPE, "number of cmd/patch info: %u %u %u %u", + packet->num_cmd_buf, + packet->num_io_configs, OPE_MAX_IO_BUFS, + packet->num_patches); + return 0; +} + +static int cam_ope_get_acquire_info(struct cam_ope_hw_mgr *hw_mgr, + struct cam_hw_acquire_args *args, + struct cam_ope_ctx *ctx) +{ + int i = 0; + + if (args->num_acq > 1) { + CAM_ERR(CAM_OPE, "Invalid number of resources: %d", + args->num_acq); + return -EINVAL; + } + + if (args->acquire_info_size < + sizeof(struct ope_acquire_dev_info)) { + CAM_ERR(CAM_OPE, "Invalid acquire size = %d", + args->acquire_info_size); + return -EINVAL; + } + + if (copy_from_user(&ctx->ope_acquire, + (void __user *)args->acquire_info, + sizeof(struct ope_acquire_dev_info))) { + CAM_ERR(CAM_OPE, "Failed in acquire"); + return -EFAULT; + } + + if (ctx->ope_acquire.secure_mode > CAM_SECURE_MODE_SECURE) { + CAM_ERR(CAM_OPE, "Invalid mode:%d", + ctx->ope_acquire.secure_mode); + return -EINVAL; + } + + if (ctx->ope_acquire.num_out_res > OPE_OUT_RES_MAX) { + CAM_ERR(CAM_OPE, "num of out resources exceeding : %u", + ctx->ope_acquire.num_out_res); + return -EINVAL; + } + + if (ctx->ope_acquire.num_in_res > OPE_IN_RES_MAX) { + CAM_ERR(CAM_OPE, "num of in resources exceeding : %u", + ctx->ope_acquire.num_in_res); + return -EINVAL; + } + + if (ctx->ope_acquire.dev_type >= OPE_DEV_TYPE_MAX) { + CAM_ERR(CAM_OPE, "Invalid device type: %d", + ctx->ope_acquire.dev_type); + return -EFAULT; + } + + if (ctx->ope_acquire.hw_type >= OPE_HW_TYPE_MAX) { + CAM_ERR(CAM_OPE, "Invalid HW type: %d", + ctx->ope_acquire.hw_type); + return -EFAULT; + } + + CAM_DBG(CAM_OPE, "top: %u %u %s %u %u %u %u %u", + ctx->ope_acquire.hw_type, ctx->ope_acquire.dev_type, + ctx->ope_acquire.dev_name, + ctx->ope_acquire.nrt_stripes_for_arb, + ctx->ope_acquire.secure_mode, ctx->ope_acquire.batch_size, + ctx->ope_acquire.num_in_res, ctx->ope_acquire.num_out_res); + + for (i = 0; i < ctx->ope_acquire.num_in_res; i++) { + CAM_DBG(CAM_OPE, "IN: %u %u %u %u %u %u %u %u", + ctx->ope_acquire.in_res[i].res_id, + ctx->ope_acquire.in_res[i].format, + ctx->ope_acquire.in_res[i].width, + ctx->ope_acquire.in_res[i].height, + ctx->ope_acquire.in_res[i].alignment, + ctx->ope_acquire.in_res[i].unpacker_format, + ctx->ope_acquire.in_res[i].max_stripe_size, + ctx->ope_acquire.in_res[i].fps); + } + + for (i = 0; i < ctx->ope_acquire.num_out_res; i++) { + CAM_DBG(CAM_OPE, "OUT: %u %u %u %u %u %u %u %u", + ctx->ope_acquire.out_res[i].res_id, + ctx->ope_acquire.out_res[i].format, + ctx->ope_acquire.out_res[i].width, + ctx->ope_acquire.out_res[i].height, + ctx->ope_acquire.out_res[i].alignment, + ctx->ope_acquire.out_res[i].packer_format, + ctx->ope_acquire.out_res[i].subsample_period, + ctx->ope_acquire.out_res[i].subsample_pattern); + } + + return 0; +} + +static int cam_ope_get_free_ctx(struct cam_ope_hw_mgr *hw_mgr) +{ + int i; + + i = find_first_zero_bit(hw_mgr->ctx_bitmap, hw_mgr->ctx_bits); + if (i >= OPE_CTX_MAX || i < 0) { + CAM_ERR(CAM_OPE, "Invalid ctx id = %d", i); + return -EINVAL; + } + + mutex_lock(&hw_mgr->ctx[i].ctx_mutex); + if (hw_mgr->ctx[i].ctx_state != OPE_CTX_STATE_FREE) { + CAM_ERR(CAM_OPE, "Invalid ctx %d state %d", + i, hw_mgr->ctx[i].ctx_state); + mutex_unlock(&hw_mgr->ctx[i].ctx_mutex); + return -EINVAL; + } + set_bit(i, hw_mgr->ctx_bitmap); + mutex_unlock(&hw_mgr->ctx[i].ctx_mutex); + + return i; +} + + +static int cam_ope_put_free_ctx(struct cam_ope_hw_mgr *hw_mgr, uint32_t ctx_id) +{ + if (ctx_id >= OPE_CTX_MAX) { + CAM_ERR(CAM_OPE, "Invalid ctx_id: %d", ctx_id); + return 0; + } + + hw_mgr->ctx[ctx_id].ctx_state = OPE_CTX_STATE_FREE; + clear_bit(ctx_id, hw_mgr->ctx_bitmap); + + return 0; +} + +static int cam_ope_mgr_get_hw_caps(void *hw_priv, void *hw_caps_args) +{ + struct cam_ope_hw_mgr *hw_mgr; + struct cam_query_cap_cmd *query_cap = hw_caps_args; + struct ope_hw_ver hw_ver; + int rc = 0, i; + + if (!hw_priv || !hw_caps_args) { + CAM_ERR(CAM_OPE, "Invalid args: %x %x", hw_priv, hw_caps_args); + return -EINVAL; + } + + hw_mgr = hw_priv; + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (copy_from_user(&hw_mgr->ope_caps, + u64_to_user_ptr(query_cap->caps_handle), + sizeof(struct ope_query_cap_cmd))) { + CAM_ERR(CAM_OPE, "copy_from_user failed: size = %d", + sizeof(struct ope_query_cap_cmd)); + rc = -EFAULT; + goto end; + } + + for (i = 0; i < hw_mgr->num_ope; i++) { + rc = hw_mgr->ope_dev_intf[i]->hw_ops.get_hw_caps( + hw_mgr->ope_dev_intf[i]->hw_priv, + &hw_ver, sizeof(hw_ver)); + if (rc) + goto end; + + hw_mgr->ope_caps.hw_ver[i] = hw_ver; + } + + hw_mgr->ope_caps.dev_iommu_handle.non_secure = hw_mgr->iommu_hdl; + hw_mgr->ope_caps.dev_iommu_handle.secure = hw_mgr->iommu_sec_hdl; + hw_mgr->ope_caps.cdm_iommu_handle.non_secure = hw_mgr->iommu_cdm_hdl; + hw_mgr->ope_caps.cdm_iommu_handle.secure = hw_mgr->iommu_sec_cdm_hdl; + hw_mgr->ope_caps.num_ope = hw_mgr->num_ope; + + CAM_DBG(CAM_OPE, "iommu sec %d iommu ns %d cdm s %d cdm ns %d", + hw_mgr->ope_caps.dev_iommu_handle.secure, + hw_mgr->ope_caps.dev_iommu_handle.non_secure, + hw_mgr->ope_caps.cdm_iommu_handle.secure, + hw_mgr->ope_caps.cdm_iommu_handle.non_secure); + + if (copy_to_user(u64_to_user_ptr(query_cap->caps_handle), + &hw_mgr->ope_caps, sizeof(struct ope_query_cap_cmd))) { + CAM_ERR(CAM_OPE, "copy_to_user failed: size = %d", + sizeof(struct ope_query_cap_cmd)); + rc = -EFAULT; + } + +end: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) +{ + int rc = 0, i; + int ctx_id; + struct cam_ope_hw_mgr *hw_mgr = hw_priv; + struct cam_ope_ctx *ctx; + 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_ope_dev_init init; + struct cam_ope_dev_clk_update clk_update; + struct cam_ope_dev_bw_update bw_update; + struct cam_ope_set_irq_cb irq_cb; + + if ((!hw_priv) || (!hw_acquire_args)) { + CAM_ERR(CAM_OPE, "Invalid args: %x %x", + hw_priv, hw_acquire_args); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + ctx_id = cam_ope_get_free_ctx(hw_mgr); + if (ctx_id < 0) { + CAM_ERR(CAM_OPE, "No free ctx"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return ctx_id; + } + + ctx = &hw_mgr->ctx[ctx_id]; + ctx->ctx_id = ctx_id; + mutex_lock(&ctx->ctx_mutex); + rc = cam_ope_get_acquire_info(hw_mgr, args, ctx); + if (rc < 0) { + CAM_ERR(CAM_OPE, "get_acquire info failed: %d", rc); + goto end; + } + + + if (!hw_mgr->ope_ctx_cnt) { + 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.init( + hw_mgr->ope_dev_intf[i]->hw_priv, &init, + sizeof(init)); + if (rc) { + CAM_ERR(CAM_OPE, "OPE Dev init failed: %d", rc); + goto end; + } + } + + /* Install IRQ CB */ + irq_cb.ope_hw_mgr_cb = cam_ope_hw_mgr_cb; + 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( + hw_mgr->ope_dev_intf[i]->hw_priv, + OPE_HW_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) { + CAM_ERR(CAM_OPE, "OPE Dev init failed: %d", rc); + goto ope_irq_set_failed; + } + } + } + + ope_dev_acquire.ctx_id = ctx_id; + ope_dev_acquire.ope_acquire = &ctx->ope_acquire; + + for (i = 0; i < ope_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_ACQUIRE, + &ope_dev_acquire, sizeof(ope_dev_acquire)); + if (rc) { + CAM_ERR(CAM_OPE, "OPE Dev acquire failed: %d", rc); + goto ope_dev_acquire_failed; + } + } + + 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( + hw_mgr->ope_dev_intf[i]->hw_priv, OPE_HW_CLK_UPDATE, + &clk_update, sizeof(clk_update)); + if (rc) { + CAM_ERR(CAM_OPE, "OPE Dev clk update failed: %d", rc); + goto ope_clk_update_failed; + } + } + + 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 = + CAM_AXI_TRANSACTION_WRITE; + 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)); + if (rc) { + CAM_ERR(CAM_OPE, "OPE Dev clk update failed: %d", rc); + goto ope_bw_update_failed; + } + } + + cam_ope_start_req_timer(ctx); + hw_mgr->ope_ctx_cnt++; + ctx->context_priv = args->context_data; + args->ctxt_to_hw_map = ctx; + ctx->ctxt_event_cb = args->event_cb; + ctx->ctx_state = OPE_CTX_STATE_ACQUIRED; + + mutex_unlock(&ctx->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; + +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( + 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_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( + 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"); + } + } +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); + } + } +end: + 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_release_ctx(struct cam_ope_hw_mgr *hw_mgr, int ctx_id) +{ + int i = 0, rc = 0; + struct cam_ope_dev_release ope_dev_release; + + if (ctx_id >= OPE_CTX_MAX) { + CAM_ERR(CAM_OPE, "ctx_id is wrong: %d", ctx_id); + return -EINVAL; + } + + mutex_lock(&hw_mgr->ctx[ctx_id].ctx_mutex); + if (hw_mgr->ctx[ctx_id].ctx_state != + OPE_CTX_STATE_ACQUIRED) { + mutex_unlock(&hw_mgr->ctx[ctx_id].ctx_mutex); + CAM_DBG(CAM_OPE, "ctx id: %d not in right state: %d", + ctx_id, hw_mgr->ctx[ctx_id].ctx_state); + return 0; + } + + hw_mgr->ctx[ctx_id].ctx_state = OPE_CTX_STATE_RELEASE; + + for (i = 0; i < ope_hw_mgr->num_ope; i++) { + ope_dev_release.ctx_id = ctx_id; + rc = 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); + } + + rc = cam_cdm_stream_off(hw_mgr->ctx[ctx_id].ope_cdm.cdm_handle); + if (rc) + CAM_ERR(CAM_OPE, "OPE CDM streamoff failed: %d", rc); + + rc = cam_cdm_release(hw_mgr->ctx[ctx_id].ope_cdm.cdm_handle); + if (rc) + CAM_ERR(CAM_OPE, "OPE CDM relase failed: %d", rc); + + + for (i = 0; i < CAM_CTX_REQ_MAX; i++) { + if (!hw_mgr->ctx[ctx_id].req_list[i]) + continue; + + if (hw_mgr->ctx[ctx_id].req_list[i]->cdm_cmd) { + kzfree(hw_mgr->ctx[ctx_id].req_list[i]->cdm_cmd); + hw_mgr->ctx[ctx_id].req_list[i]->cdm_cmd = NULL; + } + 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); + } + + 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; + cam_ope_put_free_ctx(hw_mgr, ctx_id); + hw_mgr->ope_ctx_cnt--; + mutex_unlock(&hw_mgr->ctx[ctx_id].ctx_mutex); + CAM_DBG(CAM_OPE, "X: ctx_id = %d", ctx_id); + + return 0; +} + +static int cam_ope_mgr_release_hw(void *hw_priv, void *hw_release_args) +{ + int i, rc = 0; + int ctx_id = 0; + struct cam_hw_release_args *release_hw = hw_release_args; + struct cam_ope_hw_mgr *hw_mgr = hw_priv; + struct cam_ope_ctx *ctx_data = NULL; + struct cam_ope_set_irq_cb irq_cb; + struct cam_hw_intf *dev_intf; + + if (!release_hw || !hw_mgr) { + CAM_ERR(CAM_OPE, "Invalid args: %pK %pK", release_hw, hw_mgr); + return -EINVAL; + } + + ctx_data = release_hw->ctxt_to_hw_map; + if (!ctx_data) { + CAM_ERR(CAM_OPE, "NULL ctx data"); + return -EINVAL; + } + + ctx_id = ctx_data->ctx_id; + if (ctx_id < 0 || ctx_id >= OPE_CTX_MAX) { + CAM_ERR(CAM_OPE, "Invalid ctx id: %d", ctx_id); + return -EINVAL; + } + + mutex_lock(&hw_mgr->ctx[ctx_id].ctx_mutex); + if (hw_mgr->ctx[ctx_id].ctx_state != OPE_CTX_STATE_ACQUIRED) { + CAM_DBG(CAM_OPE, "ctx is not in use: %d", ctx_id); + mutex_unlock(&hw_mgr->ctx[ctx_id].ctx_mutex); + return -EINVAL; + } + mutex_unlock(&hw_mgr->ctx[ctx_id].ctx_mutex); + + mutex_lock(&hw_mgr->hw_mgr_mutex); + rc = cam_ope_mgr_release_ctx(hw_mgr, ctx_id); + if (!hw_mgr->ope_ctx_cnt) { + CAM_DBG(CAM_OPE, "Last Release"); + if (!hw_mgr->ope_ctx_cnt) { + for (i = 0; i < ope_hw_mgr->num_ope; i++) { + dev_intf = hw_mgr->ope_dev_intf[i]; + irq_cb.ope_hw_mgr_cb = NULL; + irq_cb.data = NULL; + rc = dev_intf->hw_ops.process_cmd( + hw_mgr->ope_dev_intf[i]->hw_priv, + OPE_HW_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + CAM_ERR(CAM_OPE, "IRQ dereg failed: %d", + rc); + } + for (i = 0; i < ope_hw_mgr->num_ope; i++) { + dev_intf = hw_mgr->ope_dev_intf[i]; + rc = dev_intf->hw_ops.deinit( + hw_mgr->ope_dev_intf[i]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_OPE, "deinit failed: %d", + rc); + } + } + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + CAM_DBG(CAM_OPE, "Release done for ctx_id %d", ctx_id); + return rc; +} + +static int cam_ope_mgr_prepare_hw_update(void *hw_priv, + void *hw_prepare_update_args) +{ + int rc = 0; + struct cam_packet *packet = NULL; + struct cam_ope_hw_mgr *hw_mgr = hw_priv; + struct cam_hw_prepare_update_args *prepare_args = + hw_prepare_update_args; + struct cam_ope_ctx *ctx_data = NULL; + uintptr_t ope_cmd_buf_addr; + uint32_t request_idx = 0; + struct cam_ope_request *ope_req; + + if ((!prepare_args) || (!hw_mgr) || (!prepare_args->packet)) { + CAM_ERR(CAM_OPE, "Invalid args: %x %x", + prepare_args, hw_mgr); + return -EINVAL; + } + + ctx_data = prepare_args->ctxt_to_hw_map; + if (!ctx_data) { + CAM_ERR(CAM_OPE, "Invalid Context"); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + if (ctx_data->ctx_state != OPE_CTX_STATE_ACQUIRED) { + mutex_unlock(&ctx_data->ctx_mutex); + CAM_ERR(CAM_OPE, "ctx id %u is not acquired state: %d", + ctx_data->ctx_id, ctx_data->ctx_state); + return -EINVAL; + } + + packet = prepare_args->packet; + 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); + 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"); + return -EINVAL; + } + + rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_cdm_hdl, + hw_mgr->iommu_sec_cdm_hdl); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + CAM_ERR(CAM_OPE, "Patching is failed: %d", rc); + return -EINVAL; + } + + request_idx = find_first_zero_bit(ctx_data->bitmap, ctx_data->bits); + if (request_idx >= CAM_CTX_REQ_MAX || request_idx < 0) { + mutex_unlock(&ctx_data->ctx_mutex); + CAM_ERR(CAM_OPE, "Invalid ctx req slot = %d", request_idx); + return -EINVAL; + } + set_bit(request_idx, ctx_data->bitmap); + + ctx_data->req_list[request_idx] = + kzalloc(sizeof(struct cam_ope_request), GFP_KERNEL); + if (!ctx_data->req_list[request_idx]) { + rc = -ENOMEM; + mutex_unlock(&ctx_data->ctx_mutex); + goto req_mem_alloc_failed; + } + + ope_req = ctx_data->req_list[request_idx]; + ope_req->cdm_cmd = + kzalloc(((sizeof(struct cam_cdm_bl_request)) + + ((OPE_MAX_CDM_BLS - 1) * + sizeof(struct cam_cdm_bl_cmd))), + GFP_KERNEL); + if (!ope_req->cdm_cmd) { + rc = -ENOMEM; + mutex_unlock(&ctx_data->ctx_mutex); + goto req_cdm_mem_alloc_failed; + } + + rc = cam_ope_mgr_process_cmd_desc(hw_mgr, packet, + 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); + goto end; + } + + rc = cam_ope_mgr_process_io_cfg(hw_mgr, packet, prepare_args, + ctx_data, request_idx); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + CAM_ERR(CAM_OPE, "IO cfg processing failed: %d", rc); + goto end; + } + + rc = cam_ope_mgr_create_kmd_buf(hw_mgr, packet, prepare_args, + 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); + 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]; + + mutex_unlock(&ctx_data->ctx_mutex); + + return rc; + +end: + kzfree(ctx_data->req_list[request_idx]->cdm_cmd); + ctx_data->req_list[request_idx]->cdm_cmd = NULL; +req_cdm_mem_alloc_failed: + kzfree(ctx_data->req_list[request_idx]); + ctx_data->req_list[request_idx] = NULL; +req_mem_alloc_failed: + clear_bit(request_idx, ctx_data->bitmap); + return rc; +} + +static int cam_ope_mgr_handle_config_err( + struct cam_hw_config_args *config_args, + struct cam_ope_ctx *ctx_data) +{ + struct cam_hw_done_event_data buf_data; + struct cam_ope_request *ope_req; + uint32_t req_idx; + + ope_req = config_args->priv; + + buf_data.request_id = ope_req->request_id; + ctx_data->ctxt_event_cb(ctx_data->context_priv, false, &buf_data); + + req_idx = ope_req->req_idx; + ope_req->request_id = 0; + kzfree(ctx_data->req_list[req_idx]->cdm_cmd); + ctx_data->req_list[req_idx]->cdm_cmd = NULL; + kzfree(ctx_data->req_list[req_idx]); + ctx_data->req_list[req_idx] = NULL; + clear_bit(req_idx, ctx_data->bitmap); + + return 0; +} + +static int cam_ope_mgr_enqueue_config(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, + struct cam_hw_config_args *config_args) +{ + int rc = 0; + uint64_t request_id = 0; + struct crm_workq_task *task; + struct ope_cmd_work_data *task_data; + struct cam_hw_update_entry *hw_update_entries; + struct cam_ope_request *ope_req = NULL; + + ope_req = config_args->priv; + request_id = ope_req->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); + if (!task) { + CAM_ERR(CAM_OPE, "no empty task"); + return -ENOMEM; + } + + task_data = (struct ope_cmd_work_data *)task->payload; + task_data->data = (void *)hw_update_entries->addr; + task_data->req_id = request_id; + task_data->type = OPE_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_ope_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, ctx_data, + CRM_TASK_PRIORITY_0); + + return rc; +} + +static int cam_ope_mgr_config_hw(void *hw_priv, void *hw_config_args) +{ + int rc = 0; + struct cam_ope_hw_mgr *hw_mgr = hw_priv; + struct cam_hw_config_args *config_args = hw_config_args; + struct cam_ope_ctx *ctx_data = NULL; + struct cam_ope_request *ope_req = NULL; + struct cam_cdm_bl_request *cdm_cmd; + + CAM_DBG(CAM_OPE, "E"); + if (!hw_mgr || !config_args) { + CAM_ERR(CAM_OPE, "Invalid arguments %pK %pK", + hw_mgr, config_args); + return -EINVAL; + } + + if (!config_args->num_hw_update_entries) { + CAM_ERR(CAM_OPE, "No hw update enteries are available"); + return -EINVAL; + } + + ctx_data = config_args->ctxt_to_hw_map; + mutex_lock(&hw_mgr->hw_mgr_mutex); + mutex_lock(&ctx_data->ctx_mutex); + if (ctx_data->ctx_state != OPE_CTX_STATE_ACQUIRED) { + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_OPE, "ctx id :%u is not in use", + ctx_data->ctx_id); + return -EINVAL; + } + + ope_req = config_args->priv; + cdm_cmd = (struct cam_cdm_bl_request *) + config_args->hw_update_entries->addr; + cdm_cmd->cookie = ope_req->req_idx; + + 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_ope_req_timer_modify(ctx_data, 200); + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +config_err: + cam_ope_mgr_handle_config_err(config_args, ctx_data); + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_ope_mgr_hw_open_u(void *hw_priv, void *fw_download_args) +{ + struct cam_ope_hw_mgr *hw_mgr; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_OPE, "Invalid args: %pK", hw_priv); + return -EINVAL; + } + + hw_mgr = hw_priv; + if (!hw_mgr->open_cnt) { + hw_mgr->open_cnt++; + } else { + rc = -EBUSY; + CAM_ERR(CAM_OPE, "Multiple opens are not supported"); + } + + return rc; +} + +static cam_ope_mgr_hw_close_u(void *hw_priv, void *hw_close_args) +{ + struct cam_ope_hw_mgr *hw_mgr; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_OPE, "Invalid args: %pK", hw_priv); + return -EINVAL; + } + + hw_mgr = hw_priv; + if (!hw_mgr->open_cnt) { + rc = -EINVAL; + CAM_ERR(CAM_OPE, "device is already closed"); + } else { + hw_mgr->open_cnt--; + } + + return rc; +} + +static int cam_ope_mgr_flush_req(struct cam_ope_ctx *ctx_data, + struct cam_hw_flush_args *flush_args) +{ + int idx; + int64_t request_id; + + request_id = *(int64_t *)flush_args->flush_req_pending[0]; + for (idx = 0; idx < CAM_CTX_REQ_MAX; idx++) { + if (!ctx_data->req_list[idx]) + continue; + + if (ctx_data->req_list[idx]->request_id != request_id) + continue; + + ctx_data->req_list[idx]->request_id = 0; + kzfree(ctx_data->req_list[idx]->cdm_cmd); + ctx_data->req_list[idx]->cdm_cmd = NULL; + kzfree(ctx_data->req_list[idx]); + ctx_data->req_list[idx] = NULL; + clear_bit(idx, ctx_data->bitmap); + } + + return 0; +} + +static int cam_ope_mgr_flush_all(struct cam_ope_ctx *ctx_data, + struct cam_hw_flush_args *flush_args) +{ + int i, rc; + struct cam_ope_hw_mgr *hw_mgr = ope_hw_mgr; + + rc = cam_cdm_flush_hw(ctx_data->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 reset failed: %d", rc); + } + + for (i = 0; i < CAM_CTX_REQ_MAX; i++) { + if (!ctx_data->req_list[i]) + continue; + + ctx_data->req_list[i]->request_id = 0; + kzfree(ctx_data->req_list[i]->cdm_cmd); + ctx_data->req_list[i]->cdm_cmd = NULL; + kzfree(ctx_data->req_list[i]); + ctx_data->req_list[i] = NULL; + clear_bit(i, ctx_data->bitmap); + } + + return rc; +} + +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; + + if ((!hw_priv) || (!hw_flush_args)) { + CAM_ERR(CAM_OPE, "Input params are Null"); + return -EINVAL; + } + + ctx_data = flush_args->ctxt_to_hw_map; + if (!ctx_data) { + CAM_ERR(CAM_OPE, "Ctx data is NULL"); + return -EINVAL; + } + + if ((flush_args->flush_type >= CAM_FLUSH_TYPE_MAX) || + (flush_args->flush_type < CAM_FLUSH_TYPE_REQ)) { + CAM_ERR(CAM_OPE, "Invalid flush type: %d", + flush_args->flush_type); + 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(&ctx_data->ctx_mutex); + cam_ope_mgr_flush_all(ctx_data, flush_args); + mutex_unlock(&ctx_data->ctx_mutex); + break; + case CAM_FLUSH_TYPE_REQ: + mutex_lock(&ctx_data->ctx_mutex); + if (flush_args->num_req_active) { + CAM_ERR(CAM_OPE, "Flush request is not supported"); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + if (flush_args->num_req_pending) + cam_ope_mgr_flush_req(ctx_data, flush_args); + mutex_unlock(&ctx_data->ctx_mutex); + break; + default: + CAM_ERR(CAM_OPE, "Invalid flush type: %d", + flush_args->flush_type); + return -EINVAL; + } + + return 0; +} + +static int cam_ope_mgr_alloc_devs(struct device_node *of_node) +{ + int rc; + uint32_t num_dev; + + rc = of_property_read_u32(of_node, "num-ope", &num_dev); + if (rc) { + CAM_ERR(CAM_OPE, "getting num of ope failed: %d", rc); + return -EINVAL; + } + + ope_hw_mgr->devices[OPE_DEV_OPE] = kzalloc( + sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL); + if (!ope_hw_mgr->devices[OPE_DEV_OPE]) + return -ENOMEM; + + return 0; +} + +static int cam_ope_mgr_init_devs(struct device_node *of_node) +{ + int rc = 0; + int count, i; + const char *name = NULL; + struct device_node *child_node = NULL; + struct platform_device *child_pdev = NULL; + struct cam_hw_intf *child_dev_intf = NULL; + struct cam_hw_info *ope_dev; + struct cam_hw_soc_info *soc_info = NULL; + + rc = cam_ope_mgr_alloc_devs(of_node); + if (rc) + return rc; + + count = of_property_count_strings(of_node, "compat-hw-name"); + if (!count) { + CAM_ERR(CAM_OPE, "no compat hw found in dev tree, cnt = %d", + count); + rc = -EINVAL; + goto compat_hw_name_failed; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "compat-hw-name", + i, &name); + if (rc) { + CAM_ERR(CAM_OPE, "getting dev object name failed"); + goto compat_hw_name_failed; + } + + child_node = of_find_node_by_name(NULL, name); + if (!child_node) { + CAM_ERR(CAM_OPE, "Cannot find node in dtsi %s", name); + rc = -ENODEV; + goto compat_hw_name_failed; + } + + child_pdev = of_find_device_by_node(child_node); + if (!child_pdev) { + CAM_ERR(CAM_OPE, "failed to find device on bus %s", + child_node->name); + rc = -ENODEV; + of_node_put(child_node); + goto compat_hw_name_failed; + } + + child_dev_intf = (struct cam_hw_intf *)platform_get_drvdata( + child_pdev); + if (!child_dev_intf) { + CAM_ERR(CAM_OPE, "no child device"); + of_node_put(child_node); + goto compat_hw_name_failed; + } + ope_hw_mgr->devices[child_dev_intf->hw_type] + [child_dev_intf->hw_idx] = child_dev_intf; + + if (!child_dev_intf->hw_ops.process_cmd) + goto compat_hw_name_failed; + + of_node_put(child_node); + } + + ope_hw_mgr->num_ope = count; + for (i = 0; i < count; i++) { + ope_hw_mgr->ope_dev_intf[i] = + ope_hw_mgr->devices[OPE_DEV_OPE][i]; + ope_dev = ope_hw_mgr->ope_dev_intf[i]->hw_priv; + soc_info = &ope_dev->soc_info; + ope_hw_mgr->cdm_reg_map[i][0] = + soc_info->reg_map[0].mem_base; + } + + ope_hw_mgr->hfi_en = of_property_read_bool(of_node, "hfi_en"); + + return 0; +compat_hw_name_failed: + kfree(ope_hw_mgr->devices[OPE_DEV_OPE]); + ope_hw_mgr->devices[OPE_DEV_OPE] = NULL; + return rc; +} + +static int cam_ope_mgr_create_wq(void) +{ + + int rc; + int i; + + rc = cam_req_mgr_workq_create("ope_command_queue", OPE_WORKQ_NUM_TASK, + &ope_hw_mgr->cmd_work, CRM_WORKQ_USAGE_NON_IRQ, + 0); + if (rc) { + CAM_ERR(CAM_OPE, "unable to create a command worker"); + goto cmd_work_failed; + } + + rc = cam_req_mgr_workq_create("ope_message_queue", OPE_WORKQ_NUM_TASK, + &ope_hw_mgr->msg_work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_OPE, "unable to create a message worker"); + goto msg_work_failed; + } + + rc = cam_req_mgr_workq_create("ope_timer_queue", OPE_WORKQ_NUM_TASK, + &ope_hw_mgr->timer_work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_OPE, "unable to create a timer worker"); + goto timer_work_failed; + } + + ope_hw_mgr->cmd_work_data = + kzalloc(sizeof(struct ope_cmd_work_data) * OPE_WORKQ_NUM_TASK, + GFP_KERNEL); + if (!ope_hw_mgr->cmd_work_data) { + rc = -ENOMEM; + goto cmd_work_data_failed; + } + + ope_hw_mgr->msg_work_data = + kzalloc(sizeof(struct ope_msg_work_data) * OPE_WORKQ_NUM_TASK, + GFP_KERNEL); + if (!ope_hw_mgr->msg_work_data) { + rc = -ENOMEM; + goto msg_work_data_failed; + } + + ope_hw_mgr->timer_work_data = + kzalloc(sizeof(struct ope_clk_work_data) * OPE_WORKQ_NUM_TASK, + GFP_KERNEL); + if (!ope_hw_mgr->timer_work_data) { + rc = -ENOMEM; + goto timer_work_data_failed; + } + + for (i = 0; i < OPE_WORKQ_NUM_TASK; i++) + ope_hw_mgr->msg_work->task.pool[i].payload = + &ope_hw_mgr->msg_work_data[i]; + + for (i = 0; i < OPE_WORKQ_NUM_TASK; i++) + ope_hw_mgr->cmd_work->task.pool[i].payload = + &ope_hw_mgr->cmd_work_data[i]; + + for (i = 0; i < OPE_WORKQ_NUM_TASK; i++) + ope_hw_mgr->timer_work->task.pool[i].payload = + &ope_hw_mgr->timer_work_data[i]; + return 0; + + +timer_work_data_failed: + kfree(ope_hw_mgr->msg_work_data); +msg_work_data_failed: + kfree(ope_hw_mgr->cmd_work_data); +cmd_work_data_failed: + cam_req_mgr_workq_destroy(&ope_hw_mgr->timer_work); +timer_work_failed: + cam_req_mgr_workq_destroy(&ope_hw_mgr->msg_work); +msg_work_failed: + cam_req_mgr_workq_destroy(&ope_hw_mgr->cmd_work); +cmd_work_failed: + return rc; +} + + +int cam_ope_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, + int *iommu_hdl) +{ + int i, rc = 0, j; + struct cam_hw_mgr_intf *hw_mgr_intf; + struct cam_iommu_handle cdm_handles; + + if (!of_node || !hw_mgr_hdl) { + CAM_ERR(CAM_OPE, "Invalid args of_node %pK hw_mgr %pK", + of_node, hw_mgr_hdl); + return -EINVAL; + } + hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl; + + ope_hw_mgr = kzalloc(sizeof(struct cam_ope_hw_mgr), GFP_KERNEL); + if (!ope_hw_mgr) { + CAM_ERR(CAM_OPE, "Unable to allocate mem for: size = %d", + sizeof(struct cam_ope_hw_mgr)); + return -ENOMEM; + } + + hw_mgr_intf->hw_mgr_priv = ope_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_ope_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_ope_mgr_acquire_hw; + hw_mgr_intf->hw_release = cam_ope_mgr_release_hw; + hw_mgr_intf->hw_start = NULL; + hw_mgr_intf->hw_stop = NULL; + hw_mgr_intf->hw_prepare_update = cam_ope_mgr_prepare_hw_update; + hw_mgr_intf->hw_config_stream_settings = NULL; + hw_mgr_intf->hw_config = cam_ope_mgr_config_hw; + hw_mgr_intf->hw_read = NULL; + hw_mgr_intf->hw_write = NULL; + hw_mgr_intf->hw_cmd = NULL; + hw_mgr_intf->hw_open = cam_ope_mgr_hw_open_u; + hw_mgr_intf->hw_close = cam_ope_mgr_hw_close_u; + hw_mgr_intf->hw_flush = cam_ope_mgr_hw_flush; + + ope_hw_mgr->secure_mode = false; + mutex_init(&ope_hw_mgr->hw_mgr_mutex); + spin_lock_init(&ope_hw_mgr->hw_mgr_lock); + + for (i = 0; i < OPE_CTX_MAX; i++) { + ope_hw_mgr->ctx[i].bitmap_size = + BITS_TO_LONGS(CAM_CTX_REQ_MAX) * + sizeof(long); + ope_hw_mgr->ctx[i].bitmap = kzalloc( + ope_hw_mgr->ctx[i].bitmap_size, GFP_KERNEL); + if (!ope_hw_mgr->ctx[i].bitmap) { + CAM_ERR(CAM_OPE, "bitmap allocation failed: size = %d", + ope_hw_mgr->ctx[i].bitmap_size); + rc = -ENOMEM; + goto ope_ctx_bitmap_failed; + } + ope_hw_mgr->ctx[i].bits = ope_hw_mgr->ctx[i].bitmap_size * + BITS_PER_BYTE; + mutex_init(&ope_hw_mgr->ctx[i].ctx_mutex); + } + + rc = cam_ope_mgr_init_devs(of_node); + if (rc) + goto dev_init_failed; + + ope_hw_mgr->ctx_bitmap_size = + BITS_TO_LONGS(OPE_CTX_MAX) * sizeof(long); + ope_hw_mgr->ctx_bitmap = kzalloc(ope_hw_mgr->ctx_bitmap_size, + GFP_KERNEL); + if (!ope_hw_mgr->ctx_bitmap) { + rc = -ENOMEM; + goto ctx_bitmap_alloc_failed; + } + + ope_hw_mgr->ctx_bits = ope_hw_mgr->ctx_bitmap_size * + BITS_PER_BYTE; + + rc = cam_smmu_get_handle("ope", &ope_hw_mgr->iommu_hdl); + if (rc) { + CAM_ERR(CAM_OPE, "get mmu handle failed: %d", rc); + goto ope_get_hdl_failed; + } + + rc = cam_smmu_get_handle("cam-secure", &ope_hw_mgr->iommu_sec_hdl); + if (rc) { + CAM_ERR(CAM_OPE, "get secure mmu handle failed: %d", rc); + goto secure_hdl_failed; + } + + rc = cam_cdm_get_iommu_handle("ope", &cdm_handles); + if (rc) { + CAM_ERR(CAM_OPE, "ope cdm handle get is failed: %d", rc); + goto ope_cdm_hdl_failed; + } + + ope_hw_mgr->iommu_cdm_hdl = cdm_handles.non_secure; + ope_hw_mgr->iommu_sec_cdm_hdl = cdm_handles.secure; + CAM_DBG(CAM_OPE, "iommu hdls %x %x cdm %x %x", + ope_hw_mgr->iommu_hdl, ope_hw_mgr->iommu_sec_hdl, + ope_hw_mgr->iommu_cdm_hdl, + ope_hw_mgr->iommu_sec_cdm_hdl); + + rc = cam_ope_mgr_create_wq(); + if (rc) + goto ope_wq_create_failed; + + if (iommu_hdl) + *iommu_hdl = ope_hw_mgr->iommu_hdl; + + return rc; + +ope_wq_create_failed: + ope_hw_mgr->iommu_cdm_hdl = -1; + ope_hw_mgr->iommu_sec_cdm_hdl = -1; +ope_cdm_hdl_failed: + cam_smmu_destroy_handle(ope_hw_mgr->iommu_sec_hdl); + ope_hw_mgr->iommu_sec_hdl = -1; +secure_hdl_failed: + cam_smmu_destroy_handle(ope_hw_mgr->iommu_hdl); + ope_hw_mgr->iommu_hdl = -1; +ope_get_hdl_failed: + kzfree(ope_hw_mgr->ctx_bitmap); + ope_hw_mgr->ctx_bitmap = NULL; + ope_hw_mgr->ctx_bitmap_size = 0; + ope_hw_mgr->ctx_bits = 0; +ctx_bitmap_alloc_failed: + kzfree(ope_hw_mgr->devices[OPE_DEV_OPE]); + ope_hw_mgr->devices[OPE_DEV_OPE] = NULL; +dev_init_failed: +ope_ctx_bitmap_failed: + mutex_destroy(&ope_hw_mgr->hw_mgr_mutex); + for (j = i - 1; j >= 0; j--) { + mutex_destroy(&ope_hw_mgr->ctx[j].ctx_mutex); + kzfree(ope_hw_mgr->ctx[j].bitmap); + ope_hw_mgr->ctx[j].bitmap = NULL; + ope_hw_mgr->ctx[j].bitmap_size = 0; + ope_hw_mgr->ctx[j].bits = 0; + } + kzfree(ope_hw_mgr); + ope_hw_mgr = NULL; + + return rc; +} + 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 new file mode 100644 index 000000000000..5544573c7ec7 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h @@ -0,0 +1,399 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_OPE_HW_MGR_H +#define CAM_OPE_HW_MGR_H + +#include +#include +#include +#include "ope_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" +#include "cam_smmu_api.h" +#include "cam_soc_util.h" +#include "cam_req_mgr_timer.h" +#include "cam_context.h" +#include "ope_hw.h" +#include "cam_cdm_intf_api.h" +#include "cam_req_mgr_timer.h" + +#define OPE_CTX_MAX 32 +#define CAM_FRAME_CMD_MAX 20 + + +#define OPE_WORKQ_NUM_TASK 100 +#define OPE_WORKQ_TASK_CMD_TYPE 1 +#define OPE_WORKQ_TASK_MSG_TYPE 2 + +#define OPE_PACKET_SIZE 0 +#define OPE_PACKET_TYPE 1 +#define OPE_PACKET_OPCODE 2 + +#define OPE_PACKET_MAX_CMD_BUFS 4 + +#define OPE_MAX_OUTPUT_SUPPORTED 8 +#define OPE_MAX_INPUT_SUPPORTED 3 + +#define OPE_FRAME_PROCESS_SUCCESS 0 +#define OPE_FRAME_PROCESS_FAILURE 1 + +#define OPE_CTX_STATE_FREE 0 +#define OPE_CTX_STATE_IN_USE 1 +#define OPE_CTX_STATE_ACQUIRED 2 +#define OPE_CTX_STATE_RELEASE 3 + +#define OPE_CMDS OPE_MAX_CMD_BUFS +#define CAM_MAX_IN_RES 8 + +#define OPE_MAX_CDM_BLS 16 + +/** + * struct ope_cmd_work_data + * + * @type: Type of work data + * @data: Private data + * @req_id: Request Id + */ +struct ope_cmd_work_data { + uint32_t type; + void *data; + int64_t req_id; +}; + +/** + * struct ope_msg_work_data + * + * @type: Type of work data + * @data: Private data + * @irq_status: IRQ status + */ +struct ope_msg_work_data { + uint32_t type; + void *data; + uint32_t irq_status; +}; + +/** + * struct ope_clk_work_data + * + * @type: Type of work data + * @data: Private data + */ +struct ope_clk_work_data { + uint32_t type; + void *data; +}; + +/** + * struct cdm_dmi_cmd + * + * @length: Number of bytes in LUT + * @reserved: reserved bits + * @cmd: Command ID (CDMCmd) + * @addr: Address of the LUT in memory + * @DMIAddr: Address of the target DMI config register + * @DMISel: DMI identifier + */ +struct cdm_dmi_cmd { + unsigned int length : 16; + unsigned int reserved : 8; + unsigned int cmd : 8; + unsigned int addr; + unsigned int DMIAddr : 24; + unsigned int DMISel : 8; +} __attribute__((__packed__)); + +/** + * struct ope_debug_buffer + * + * @cpu_addr: CPU address + * @iova_addr: IOVA address + * @len: Buffer length + * @size: Buffer Size + */ +struct ope_debug_buffer { + uintptr_t cpu_addr; + dma_addr_t iova_addr; + size_t len; + uint32_t size; +}; + +/** + * struct ope_kmd_buffer + * + * @mem_handle: Memory handle + * @cpu_addr: CPU address + * @iova_addr: IOVA address + * @iova_cdm_addr: CDM IOVA address + * @len: Buffer length + * @size: Buffer Size + */ +struct ope_kmd_buffer { + uint32_t mem_handle; + uintptr_t cpu_addr; + dma_addr_t iova_addr; + dma_addr_t iova_cdm_addr; + size_t len; + uint32_t size; +}; + +struct ope_stripe_settings { + uintptr_t cpu_addr; + dma_addr_t iova_addr; + size_t len; + uint32_t size; + uint32_t buf_type; + uint32_t type_buffered; +}; + +/** + * struct ope_pass_settings + * + * @cpu_addr: CPU address + * @iova_addr: IOVA address + * @len: Buffer length + * @size: Buffer Size + * @idx: Pass Index + * @buf_type: Direct/Indirect type + * @type_buffered: SB/DB types + */ +struct ope_pass_settings { + uintptr_t cpu_addr; + dma_addr_t iova_addr; + size_t len; + uint32_t size; + uint32_t idx; + uint32_t buf_type; + uint32_t type_buffered; +}; + +/** + * struct ope_frame_settings + * + * @cpu_addr: CPU address + * @iova_addr: IOVA address + * @offset: offset + * @len: Buffer length + * @size: Buffer Size + * @buf_type: Direct/Indirect type + * @type_buffered: SB/DB types + * @prefecth_disable: Disable prefetch + */ +struct ope_frame_settings { + uintptr_t cpu_addr; + dma_addr_t iova_addr; + uint32_t offset; + size_t len; + uint32_t size; + uint32_t buf_type; + uint32_t type_buffered; + uint32_t prefecth_disable; +}; + +/** + * struct ope_stripe_io + * + * @format: Stripe format + * @s_location: Stripe location + * @cpu_addr: Stripe CPU address + * @iova_addr: Stripe IOVA address + * @width: Stripe width + * @height: Stripe height + * @stride: Stripe stride + * @unpack_format: Unpack format + * @pack_format: Packing format + * @alignment: Stripe alignment + * @offset: Stripe offset + * @x_init: X_init + * @subsample_period: Subsample period + * @subsample_pattern: Subsample pattern + * @len: Stripe buffer length + * @disable_bus: disable bus for the stripe + */ +struct ope_stripe_io { + uint32_t format; + uint32_t s_location; + uintptr_t cpu_addr; + dma_addr_t iova_addr; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t unpack_format; + uint32_t pack_format; + uint32_t alignment; + uint32_t offset; + uint32_t x_init; + uint32_t subsample_period; + uint32_t subsample_pattern; + size_t len; + uint32_t disable_bus; +}; + +/** + * struct ope_io_buf + * + * @direction: Direction of a buffer + * @resource_type: Resource type of IO Buffer + * @format: Format + * @fence: Fence + * @num_planes: Number of planes + * @num_stripes: Number of stripes + * @s_io: Stripe info + */ +struct ope_io_buf { + uint32_t direction; + uint32_t resource_type; + uint32_t format; + uint32_t fence; + uint32_t num_planes; + uint32_t num_stripes[OPE_MAX_PLANES]; + struct ope_stripe_io s_io[OPE_MAX_PLANES][OPE_MAX_STRIPES]; +}; + +/** + * struct cam_ope_request + * + * @request_id: Request Id + * @req_idx: Index in request list + * @state: Request state + * @num_batch: Number of batches + * @num_cmd_bufs: Number of command buffers + * @num_frame_bufs: Number of frame buffers + * @num_pass_bufs: Number of pass Buffers + * @num_stripes: Number of Stripes + * @num_io_bufs: Number of IO Buffers + * @in_resource: Input resource + * @num_stripe_cmd_bufs: Command buffers per stripe + * @ope_kmd_buf: KMD buffer for OPE programming + * @ope_debug_buf: Debug buffer + * @io_buf: IO config info of a request + * @cdm_cmd: CDM command for OPE CDM + */ +struct cam_ope_request { + uint64_t request_id; + uint32_t req_idx; + uint32_t state; + uint32_t num_batch; + uint32_t num_cmd_bufs; + uint32_t num_frame_bufs; + uint32_t num_pass_bufs; + uint32_t num_stripes[OPE_MAX_BATCH_SIZE]; + uint32_t num_io_bufs[OPE_MAX_BATCH_SIZE]; + uint32_t in_resource; + 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 cam_cdm_bl_request *cdm_cmd; +}; + +/** + * struct cam_ope_cdm + * + * @cdm_handle: OPE CDM Handle + * @cdm_ops: OPE CDM Operations + */ +struct cam_ope_cdm { + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; +}; + +/** + * struct cam_ope_ctx + * + * @context_priv: Private data of context + * @bitmap: Context bit map + * @bitmap_size: Context bit map size + * @bits: Context bit map bits + * @ctx_id: Context ID + * @ctx_state: State of a context + * @req_cnt: Requests count + * @ctx_mutex: Mutex for context + * @acquire_dev_cmd: Cam acquire command + * @ope_acquire: OPE acquire command + * @ctxt_event_cb: Callback of a context + * @req_list: Request List + * @ope_cdm: OPE CDM info + * @req_watch_dog: Watchdog for requests + */ +struct cam_ope_ctx { + void *context_priv; + size_t bitmap_size; + void *bitmap; + size_t bits; + uint32_t ctx_id; + uint32_t ctx_state; + uint32_t req_cnt; + struct mutex ctx_mutex; + struct cam_acquire_dev_cmd acquire_dev_cmd; + struct ope_acquire_dev_info ope_acquire; + cam_hw_event_cb_func ctxt_event_cb; + struct cam_ope_request *req_list[CAM_CTX_REQ_MAX]; + struct cam_ope_cdm ope_cdm; + struct cam_req_mgr_timer *req_watch_dog; +}; + +/** + * struct cam_ope_hw_mgr + * + * @open_cnt: OPE device open count + * @ope_ctx_cnt: Open context count + * @hw_mgr_mutex: Mutex for HW manager + * @hw_mgr_lock: Spinlock for HW manager + * @hfi_en: Flag for HFI + * @iommu_hdl: OPE Handle + * @iommu_sec_hdl: OPE Handle for secure + * @iommu_cdm_hdl: CDM Handle + * @iommu_sec_cdm_hdl: CDM Handle for secure + * @num_ope: Number of OPE + * @secure_mode: Mode of OPE operation + * @ctx_bitmap: Context bit map + * @ctx_bitmap_size: Context bit map size + * @ctx_bits: Context bit map bits + * @ctx: OPE context + * @devices: OPE devices + * @ope_caps: OPE capabilities + * @cmd_work: Command work + * @msg_work: Message work + * @timer_work: Timer work + * @cmd_work_data: Command work data + * @msg_work_data: Message work data + * @timer_work_data: Timer work data + * @ope_dev_intf: OPE device interface + * @cdm_reg_map: OPE CDM register map + */ +struct cam_ope_hw_mgr { + int32_t open_cnt; + uint32_t ope_ctx_cnt; + struct mutex hw_mgr_mutex; + spinlock_t hw_mgr_lock; + bool hfi_en; + int32_t iommu_hdl; + int32_t iommu_sec_hdl; + int32_t iommu_cdm_hdl; + int32_t iommu_sec_cdm_hdl; + uint32_t num_ope; + bool secure_mode; + void *ctx_bitmap; + size_t ctx_bitmap_size; + size_t ctx_bits; + struct cam_ope_ctx ctx[OPE_CTX_MAX]; + struct cam_hw_intf **devices[OPE_DEV_MAX]; + struct ope_query_cap_cmd ope_caps; + + struct cam_req_mgr_core_workq *cmd_work; + struct cam_req_mgr_core_workq *msg_work; + struct cam_req_mgr_core_workq *timer_work; + struct ope_cmd_work_data *cmd_work_data; + struct ope_msg_work_data *msg_work_data; + struct ope_clk_work_data *timer_work_data; + struct cam_hw_intf *ope_dev_intf[OPE_DEV_MAX]; + struct cam_soc_reg_map *cdm_reg_map[OPE_DEV_MAX][OPE_BASE_MAX]; +}; + +#endif /* CAM_OPE_HW_MGR_H */ diff --git a/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr_intf.h b/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr_intf.h new file mode 100644 index 000000000000..9ab06daac0c7 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr_intf.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_OPE_HW_MGR_INTF_H +#define CAM_OPE_HW_MGR_INTF_H + +#include +#include +#include + +int cam_ope_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, + int *iommu_hdl); + +#endif /* CAM_OPE_HW_MGR_INTF_H */ diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/Makefile b/drivers/cam_ope/ope_hw_mgr/ope_hw/Makefile new file mode 100644 index 000000000000..4cc9398173c3 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw/top +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/fw_inc +ccflags-y += -I$(srctree)/techpack/camera/drivers +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += ope_dev.o ope_soc.o ope_core.o top/ bus_rd/ bus_wr/ diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/Makefile b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/Makefile new file mode 100644 index 000000000000..cdfb8bdaa055 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd +ccflags-y += -I$(srctree)/techpack/camera/drivers +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += ope_bus_rd.o 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 new file mode 100644 index 000000000000..6053401d208c --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c @@ -0,0 +1,693 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "ope_core.h" +#include "ope_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "ope_hw.h" +#include "ope_dev_intf.h" +#include "ope_bus_rd.h" + +static struct ope_bus_rd *bus_rd; + +static int cam_ope_bus_rd_in_port_idx(uint32_t input_port_id) +{ + int i; + + for (i = 0; i < OPE_IN_RES_MAX; i++) + if (bus_rd->in_port_to_rm[i].input_port_id == + input_port_id) + return i; + + return -EINVAL; +} + +static int cam_ope_bus_rd_combo_idx(uint32_t format) +{ + int rc = -EINVAL; + + switch (format) { + case CAM_FORMAT_YUV422: + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + rc = BUS_RD_YUV; + break; + 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_MIPI_RAW_20: + case CAM_FORMAT_QTI_RAW_8: + case CAM_FORMAT_QTI_RAW_10: + case CAM_FORMAT_QTI_RAW_12: + case CAM_FORMAT_QTI_RAW_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN32_20: + case CAM_FORMAT_PLAIN64: + case CAM_FORMAT_PLAIN128: + rc = BUS_RD_BAYER; + break; + default: + break; + } + + CAM_DBG(CAM_OPE, "Input format = %u rc = %d", + format, rc); + return rc; +} + +static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, + int32_t ctx_id, uint32_t *kmd_buf, int batch_idx, + int io_idx, struct cam_ope_dev_prepare_req *prepare) +{ + int k, l, m; + uint32_t idx; + int32_t combo_idx; + uint32_t req_idx, count = 0, temp; + uint32_t temp_reg[128] = {0}; + uint32_t rm_id, header_size; + uint32_t rsc_type; + struct cam_hw_prepare_update_args *prepare_args; + struct cam_ope_ctx *ctx_data; + struct cam_ope_request *ope_request; + struct ope_io_buf *io_buf; + struct ope_stripe_io *stripe_io; + struct ope_bus_rd_ctx *bus_rd_ctx; + struct cam_ope_bus_rd_reg *rd_reg; + struct cam_ope_bus_rd_client_reg *rd_reg_client; + struct cam_ope_bus_rd_reg_val *rd_reg_val; + struct cam_ope_bus_rd_client_reg_val *rd_res_val_client; + struct ope_bus_in_port_to_rm *in_port_to_rm; + struct ope_bus_rd_io_port_cdm_info *io_port_cdm; + struct cam_cdm_utils_ops *cdm_ops; + struct ope_bus_rd_io_port_info *io_port_info; + + + if (ctx_id < 0 || !prepare) { + CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, prepare); + return NULL; + } + + if (batch_idx >= OPE_MAX_BATCH_SIZE) { + CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx); + return NULL; + } + + if (io_idx >= OPE_MAX_IO_BUFS) { + CAM_ERR(CAM_OPE, "Invalid IO idx: %d", io_idx); + return NULL; + } + + prepare_args = prepare->prepare_args; + ctx_data = prepare->ctx_data; + req_idx = prepare->req_idx; + cdm_ops = ctx_data->ope_cdm.cdm_ops; + + ope_request = ctx_data->req_list[req_idx]; + CAM_DBG(CAM_OPE, "req_idx = %d req_id = %lld KMDbuf %x offset %d", + req_idx, ope_request->request_id, + kmd_buf, prepare->kmd_buf_offset); + bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; + io_port_info = &bus_rd_ctx->io_port_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]; + + CAM_DBG(CAM_OPE, "batch:%d iobuf:%d direction:%d", + batch_idx, io_idx, io_buf->direction); + io_port_cdm = + &bus_rd_ctx->io_port_cdm_batch.io_port_cdm[batch_idx]; + 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 NULL; + } + + for (k = 0; k < io_buf->num_planes; k++) { + for (l = 0; l < io_buf->num_stripes[k]; l++) { + stripe_io = &io_buf->s_io[k][l]; + rsc_type = io_buf->resource_type - 1; + /* frame level info */ + /* stripe level info */ + rm_id = in_port_to_rm->rm_port_id[combo_idx][k]; + rd_reg_client = &rd_reg->rd_clients[rm_id]; + rd_res_val_client = &rd_reg_val->rd_clients[rm_id]; + + /* security cfg */ + temp_reg[count++] = rd_reg->offset + + rd_reg->security_cfg; + temp_reg[count++] = + ctx_data->ope_acquire.secure_mode; + + /* enable client */ + temp_reg[count++] = rd_reg->offset + + rd_reg_client->core_cfg; + temp_reg[count++] = 1; + + /* ccif meta data */ + temp_reg[count++] = rd_reg->offset + + rd_reg_client->ccif_meta_data; + temp = 0; + temp |= stripe_io->s_location & + rd_res_val_client->stripe_location_mask; + temp |= (io_port_info->pixel_pattern[rsc_type] & + rd_res_val_client->pix_pattern_mask) << + rd_res_val_client->pix_pattern_shift; + temp_reg[count++] = temp; + + /* Address of the Image */ + temp_reg[count++] = rd_reg->offset + + rd_reg_client->img_addr; + temp_reg[count++] = stripe_io->iova_addr; + + /* Buffer size */ + temp_reg[count++] = rd_reg->offset + + rd_reg_client->img_cfg; + temp = 0; + temp = stripe_io->height; + temp |= + (stripe_io->width & + rd_res_val_client->img_width_mask) << + rd_res_val_client->img_width_shift; + temp_reg[count++] = temp; + + /* stride */ + temp_reg[count++] = rd_reg->offset + + rd_reg_client->stride; + temp_reg[count++] = stripe_io->stride; + + /* Unpack cfg : Mode and alignment */ + temp_reg[count++] = rd_reg->offset + + rd_reg_client->unpack_cfg; + temp = 0; + temp |= (stripe_io->unpack_format & + rd_res_val_client->mode_mask) << + rd_res_val_client->mode_shift; + temp |= (stripe_io->alignment & + rd_res_val_client->alignment_mask) << + rd_res_val_client->alignment_shift; + temp_reg[count++] = temp; + + /* latency buffer allocation */ + temp_reg[count++] = rd_reg->offset + + rd_reg_client->latency_buf_allocation; + temp_reg[count++] = io_port_info->latency_buf_size; + + header_size = cdm_ops->cdm_get_cmd_header_size( + CAM_CDM_CMD_REG_RANDOM); + idx = io_port_cdm->num_s_cmd_bufs[l]; + io_port_cdm->s_cdm_info[l][idx].len = sizeof(temp) * + (count + header_size); + io_port_cdm->s_cdm_info[l][idx].offset = + prepare->kmd_buf_offset; + io_port_cdm->s_cdm_info[l][idx].addr = kmd_buf; + io_port_cdm->num_s_cmd_bufs[l]++; + + kmd_buf = cdm_ops->cdm_write_regrandom( + kmd_buf, count/2, temp_reg); + prepare->kmd_buf_offset += ((count + header_size) * + sizeof(temp)); + CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", + batch_idx, io_idx, k, l); + for (m = 0; m < count; m++) + CAM_DBG(CAM_OPE, "%d:temp:%x", + m, temp_reg[m]); + CAM_DBG(CAM_OPE, "kmd_buf:%x offset:%d", + kmd_buf, prepare->kmd_buf_offset); + CAM_DBG(CAM_OPE, "%x count: %d size:%d", + temp_reg, count, header_size); + CAM_DBG(CAM_OPE, "RD cmdbufs:%d off:%d", + io_port_cdm->num_s_cmd_bufs[l], + io_port_cdm->s_cdm_info[l][idx].offset); + CAM_DBG(CAM_OPE, "len:%d", + io_port_cdm->s_cdm_info[l][idx].len); + CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", + batch_idx, io_idx, k, l); + count = 0; + } + } + + return kmd_buf; +} + +static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0; + int i, j; + int32_t combo_idx; + uint32_t req_idx, count = 0, temp; + uint32_t temp_reg[32] = {0}; + uint32_t header_size; + uint32_t *kmd_buf; + struct cam_ope_dev_prepare_req *prepare; + struct cam_ope_ctx *ctx_data; + struct cam_ope_request *ope_request; + struct ope_io_buf *io_buf; + struct ope_bus_rd_ctx *bus_rd_ctx; + 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 cam_cdm_utils_ops *cdm_ops; + + if (ctx_id < 0 || !data) { + CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data); + return -EINVAL; + } + prepare = data; + + ctx_data = prepare->ctx_data; + req_idx = prepare->req_idx; + cdm_ops = ctx_data->ope_cdm.cdm_ops; + + ope_request = ctx_data->req_list[req_idx]; + kmd_buf = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr + + prepare->kmd_buf_offset; + CAM_DBG(CAM_OPE, "req_idx = %d req_id = %lld", + req_idx, ope_request->request_id); + CAM_DBG(CAM_OPE, "KMD buf and offset = %x %d", + kmd_buf, prepare->kmd_buf_offset); + bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; + io_port_cdm_batch = + &bus_rd_ctx->io_port_cdm_batch; + memset(io_port_cdm_batch, 0, + sizeof(struct ope_bus_rd_io_port_cdm_batch)); + rd_reg = ope_hw_info->bus_rd_reg; + rd_reg_val = ope_hw_info->bus_rd_reg_val; + + 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]; + if (io_buf->direction != CAM_BUF_INPUT) + continue; + + CAM_DBG(CAM_OPE, "batch:%d iobuf:%d direction:%d", + i, j, io_buf->direction); + io_port_cdm = + &bus_rd_ctx->io_port_cdm_batch.io_port_cdm[i]; + + combo_idx = cam_ope_bus_rd_combo_idx(io_buf->format); + if (combo_idx < 0) { + CAM_ERR(CAM_OPE, "Invalid combo_idx"); + return combo_idx; + } + + kmd_buf = cam_ope_bus_rd_update(ope_hw_info, + ctx_id, kmd_buf, i, j, prepare); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + } + } + + if (!io_port_cdm) { + rc = -EINVAL; + goto end; + } + + /* Go command */ + count = 0; + temp_reg[count++] = rd_reg->offset + + rd_reg->input_if_cmd; + temp = 0; + temp |= rd_reg_val->go_cmd; + temp_reg[count++] = temp; + + header_size = + cdm_ops->cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); + io_port_cdm->go_cmd_addr = kmd_buf; + io_port_cdm->go_cmd_len = + sizeof(temp) * (count + header_size); + io_port_cdm->go_cmd_offset = + prepare->kmd_buf_offset; + kmd_buf = cdm_ops->cdm_write_regrandom( + kmd_buf, count/2, temp_reg); + prepare->kmd_buf_offset += + ((count + header_size) * sizeof(temp)); + CAM_DBG(CAM_OPE, "kmd_buf:%x,offset:%d", + kmd_buf, prepare->kmd_buf_offset); + CAM_DBG(CAM_OPE, "t_reg:%xcount: %d size:%d", + temp_reg, count, header_size); + prepare->rd_cdm_batch = &bus_rd_ctx->io_port_cdm_batch; + +end: + return rc; +} + +static int cam_ope_bus_rd_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_rd_ctx *bus_rd_ctx; + + if (ctx_id < 0) { + CAM_ERR(CAM_OPE, "Invalid data: %d", ctx_id); + return -EINVAL; + } + + in_acquire = bus_rd->bus_rd_ctx[ctx_id].ope_acquire; + bus_rd->bus_rd_ctx[ctx_id].ope_acquire = NULL; + bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; + bus_rd_ctx->num_in_ports = 0; + + for (i = 0; i < bus_rd_ctx->num_in_ports; i++) { + bus_rd_ctx->io_port_info.input_port_id[i] = 0; + bus_rd_ctx->io_port_info.input_format_type[i - 1] = 0; + bus_rd_ctx->io_port_info.pixel_pattern[i - 1] = 0; + } + + return rc; +} + +static int cam_ope_bus_rd_acquire(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_rd_ctx *bus_rd_ctx; + struct ope_bus_in_port_to_rm *in_port_to_rm; + struct cam_ope_bus_rd_reg_val *bus_rd_reg_val; + int combo_idx; + int in_port_idx; + + + if (ctx_id < 0 || !data || !ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid data: %d %x %x", + ctx_id, data, ope_hw_info); + return -EINVAL; + } + + bus_rd->bus_rd_ctx[ctx_id].ope_acquire = data; + in_acquire = data; + bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; + bus_rd_ctx->num_in_ports = in_acquire->num_in_res; + bus_rd_ctx->security_flag = in_acquire->secure_mode; + bus_rd_reg_val = ope_hw_info->bus_rd_reg_val; + + for (i = 0; i < in_acquire->num_in_res; i++) { + if (!in_acquire->in_res[i].width) + continue; + + CAM_DBG(CAM_OPE, "i = %d format = %u width = %x height = %x", + i, in_acquire->in_res[i].format, + in_acquire->in_res[i].width, + in_acquire->in_res[i].height); + CAM_DBG(CAM_OPE, "pix_pattern:%u alignment:%u unpack_format:%u", + in_acquire->in_res[i].pixel_pattern, + in_acquire->in_res[i].alignment, + in_acquire->in_res[i].unpacker_format); + CAM_DBG(CAM_OPE, "max_stripe = %u fps = %u", + in_acquire->in_res[i].max_stripe_size, + in_acquire->in_res[i].fps); + + in_port_idx = cam_ope_bus_rd_in_port_idx(i + 1); + if (in_port_idx < 0) { + CAM_ERR(CAM_OPE, "Invalid in_port_idx: %d", i + 1); + rc = -EINVAL; + goto end; + } + + in_port_to_rm = &bus_rd->in_port_to_rm[in_port_idx]; + combo_idx = cam_ope_bus_rd_combo_idx( + in_acquire->in_res[i].format); + if (combo_idx < 0) { + CAM_ERR(CAM_OPE, "Invalid format: %d", + in_acquire->in_res[i].format); + rc = -EINVAL; + goto end; + } + + if (!in_port_to_rm->num_rm[combo_idx]) { + CAM_ERR(CAM_OPE, "Invalid format for Input port"); + rc = -EINVAL; + goto end; + } + + bus_rd_ctx->io_port_info.input_port_id[i] = + in_acquire->in_res[i].res_id; + bus_rd_ctx->io_port_info.input_format_type[i] = + in_acquire->in_res[i].format; + if (in_acquire->in_res[i].pixel_pattern > + PIXEL_PATTERN_CRYCBY) { + CAM_ERR(CAM_OPE, "Invalid pix pattern = %u", + in_acquire->in_res[i].pixel_pattern); + rc = -EINVAL; + goto end; + } + + bus_rd_ctx->io_port_info.pixel_pattern[i] = + in_acquire->in_res[i].pixel_pattern; + bus_rd_ctx->io_port_info.latency_buf_size = + bus_rd_reg_val->latency_buf_size; + + CAM_DBG(CAM_OPE, "i:%d port_id = %u format %u pix_pattern = %u", + i, bus_rd_ctx->io_port_info.input_port_id[i], + bus_rd_ctx->io_port_info.input_format_type[i], + bus_rd_ctx->io_port_info.pixel_pattern[i]); + CAM_DBG(CAM_OPE, "latency_buf_size = %u", + bus_rd_ctx->io_port_info.latency_buf_size); + } + +end: + return rc; +} + +static int cam_ope_bus_rd_init(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0; + struct cam_ope_bus_rd_reg_val *bus_rd_reg_val; + struct cam_ope_bus_rd_reg *bus_rd_reg; + struct cam_ope_dev_init *dev_init = data; + + if (!ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + + bus_rd_reg_val = ope_hw_info->bus_rd_reg_val; + bus_rd_reg = ope_hw_info->bus_rd_reg; + bus_rd_reg->base = dev_init->core_info->ope_hw_info->ope_bus_rd_base; + + /* OPE SW RESET */ + init_completion(&bus_rd->reset_complete); + + /* enable interrupt mask */ + cam_io_w_mb(bus_rd_reg_val->irq_mask, + ope_hw_info->bus_rd_reg->base + bus_rd_reg->irq_mask); + + cam_io_w_mb(bus_rd_reg_val->sw_reset, + ope_hw_info->bus_rd_reg->base + bus_rd_reg->sw_reset); + + rc = wait_for_completion_timeout( + &bus_rd->reset_complete, msecs_to_jiffies(30000)); + + if (!rc || rc < 0) { + CAM_ERR(CAM_OPE, "reset error result = %d", rc); + if (!rc) + rc = -ETIMEDOUT; + } else { + rc = 0; + } + + cam_io_w_mb(bus_rd_reg_val->irq_mask, + ope_hw_info->bus_rd_reg->base + bus_rd_reg->irq_mask); + + return rc; +} + +static int cam_ope_bus_rd_probe(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0, i, j, combo_idx, k; + struct cam_ope_bus_rd_reg_val *bus_rd_reg_val; + struct cam_ope_bus_rd_reg *bus_rd_reg; + struct ope_bus_in_port_to_rm *in_port_to_rm; + uint32_t input_port_idx; + uint32_t rm_idx; + + if (!ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + bus_rd = kzalloc(sizeof(struct ope_bus_rd), GFP_KERNEL); + if (!bus_rd) { + CAM_ERR(CAM_OPE, "Out of memory"); + return -ENOMEM; + } + bus_rd->ope_hw_info = ope_hw_info; + bus_rd_reg_val = ope_hw_info->bus_rd_reg_val; + bus_rd_reg = ope_hw_info->bus_rd_reg; + + for (i = 0; i < bus_rd_reg_val->num_clients; i++) { + input_port_idx = + bus_rd_reg_val->rd_clients[i].input_port_id - 1; + in_port_to_rm = &bus_rd->in_port_to_rm[input_port_idx]; + if (bus_rd_reg_val->rd_clients[i].format_type & + BUS_RD_COMBO_BAYER_MASK) { + combo_idx = BUS_RD_BAYER; + rm_idx = in_port_to_rm->num_rm[combo_idx]; + in_port_to_rm->input_port_id = + bus_rd_reg_val->rd_clients[i].input_port_id; + in_port_to_rm->rm_port_id[combo_idx][rm_idx] = + bus_rd_reg_val->rd_clients[i].rm_port_id; + if (!in_port_to_rm->num_rm[combo_idx]) + in_port_to_rm->num_combos++; + in_port_to_rm->num_rm[combo_idx]++; + } + if (bus_rd_reg_val->rd_clients[i].format_type & + BUS_RD_COMBO_YUV_MASK) { + combo_idx = BUS_RD_YUV; + rm_idx = in_port_to_rm->num_rm[combo_idx]; + in_port_to_rm->input_port_id = + bus_rd_reg_val->rd_clients[i].input_port_id; + in_port_to_rm->rm_port_id[combo_idx][rm_idx] = + bus_rd_reg_val->rd_clients[i].rm_port_id; + if (!in_port_to_rm->num_rm[combo_idx]) + in_port_to_rm->num_combos++; + in_port_to_rm->num_rm[combo_idx]++; + } + } + + for (i = 0; i < OPE_IN_RES_MAX; i++) { + in_port_to_rm = &bus_rd->in_port_to_rm[i]; + CAM_DBG(CAM_OPE, "input port id = %d num_combos = %d", + in_port_to_rm->input_port_id, + in_port_to_rm->num_combos); + for (j = 0; j < in_port_to_rm->num_combos; j++) { + CAM_DBG(CAM_OPE, "combo idx = %d num_rms = %d", + j, in_port_to_rm->num_rm[j]); + for (k = 0; k < in_port_to_rm->num_rm[j]; k++) { + CAM_DBG(CAM_OPE, "rm port id = %d", + in_port_to_rm->rm_port_id[j][k]); + } + } + } + + return rc; +} + +static int cam_ope_bus_rd_isr(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0; + uint32_t irq_status; + struct cam_ope_bus_rd_reg *bus_rd_reg; + struct cam_ope_bus_rd_reg_val *bus_rd_reg_val; + struct cam_ope_irq_data *irq_data = data; + + if (!ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + + bus_rd_reg = ope_hw_info->bus_rd_reg; + bus_rd_reg_val = ope_hw_info->bus_rd_reg_val; + + /* Read and Clear Top Interrupt status */ + irq_status = cam_io_r_mb(bus_rd_reg->base + bus_rd_reg->irq_status); + cam_io_w_mb(irq_status, + bus_rd_reg->base + bus_rd_reg->irq_clear); + + cam_io_w_mb(bus_rd_reg_val->irq_set_clear, + bus_rd_reg->base + bus_rd_reg->irq_cmd); + + if (irq_status & bus_rd_reg_val->rst_done) { + complete(&bus_rd->reset_complete); + CAM_ERR(CAM_OPE, "ope bus rd reset done"); + } + + if ((irq_status & bus_rd_reg_val->violation) == + bus_rd_reg_val->violation) { + irq_data->error = 1; + CAM_ERR(CAM_OPE, "ope bus rd CCIF vioalation"); + } + + return rc; +} + +int cam_ope_bus_rd_process(struct ope_hw *ope_hw_info, + int32_t ctx_id, uint32_t cmd_id, void *data) +{ + int rc = -EINVAL; + + switch (cmd_id) { + case OPE_HW_PROBE: + CAM_DBG(CAM_OPE, "OPE_HW_PROBE: E"); + rc = cam_ope_bus_rd_probe(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_PROBE: X"); + break; + case OPE_HW_INIT: + CAM_DBG(CAM_OPE, "OPE_HW_INIT: E"); + rc = cam_ope_bus_rd_init(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_INIT: X"); + break; + case OPE_HW_ACQUIRE: + CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: E"); + rc = cam_ope_bus_rd_acquire(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: X"); + break; + case OPE_HW_RELEASE: + CAM_DBG(CAM_OPE, "OPE_HW_RELEASE: E"); + rc = cam_ope_bus_rd_release(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_RELEASE: X"); + break; + case OPE_HW_PREPARE: + CAM_DBG(CAM_OPE, "OPE_HW_PREPARE: E"); + rc = cam_ope_bus_rd_prepare(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_PREPARE: X"); + break; + case OPE_HW_ISR: + rc = cam_ope_bus_rd_isr(ope_hw_info, 0, data); + break; + case OPE_HW_DEINIT: + case OPE_HW_START: + case OPE_HW_STOP: + case OPE_HW_FLUSH: + case OPE_HW_CLK_UPDATE: + case OPE_HW_BW_UPDATE: + case OPE_HW_RESET: + case OPE_HW_SET_IRQ_CB: + rc = 0; + CAM_DBG(CAM_OPE, "Unhandled cmds: %d", cmd_id); + break; + default: + CAM_ERR(CAM_OPE, "Unsupported cmd: %d", cmd_id); + break; + } + + return rc; +} + diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.h b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.h new file mode 100644 index 000000000000..da91d75fcbd5 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.h @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef OPE_BUS_RD_H +#define OPE_BUS_RD_H + +#include +#include +#include +#include "ope_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" +#include "cam_soc_util.h" +#include "cam_context.h" +#include "cam_ope_context.h" +#include "cam_ope_hw_mgr.h" + + +/** + * struct ope_bus_rd_cdm_info + * + * @offset: Offset + * @addr: Address + * @len: Length + */ +struct ope_bus_rd_cdm_info { + uint32_t offset; + uint32_t *addr; + uint32_t len; +}; + +/** + * struct ope_bus_rd_io_port_cdm_info + * + * @num_frames_cmds: Number of frame commands + * @f_cdm_info: Frame cdm info + * @num_stripes: Number of stripes + * @num_s_cmd_bufs: Number of stripe commands + * @s_cdm_info: Stripe cdm info + * @go_cmd_addr: GO command address + * @go_cmd_len: GO command length + */ +struct ope_bus_rd_io_port_cdm_info { + uint32_t num_frames_cmds; + struct ope_bus_rd_cdm_info f_cdm_info[MAX_RD_CLIENTS]; + uint32_t num_stripes; + uint32_t num_s_cmd_bufs[OPE_MAX_STRIPES]; + struct ope_bus_rd_cdm_info s_cdm_info[OPE_MAX_STRIPES][MAX_RD_CLIENTS]; + uint32_t go_cmd_offset; + uint32_t *go_cmd_addr; + uint32_t go_cmd_len; +}; + +/** + * struct ope_bus_rd_io_port_cdm_batch + * + * num_batch: Number of batches + * io_port_cdm: CDM IO Port Info + */ +struct ope_bus_rd_io_port_cdm_batch { + uint32_t num_batch; + struct ope_bus_rd_io_port_cdm_info io_port_cdm[OPE_MAX_BATCH_SIZE]; +}; + +/** + * struct ope_bus_rd_rm + * + * @rm_port_id: RM port ID + * @format_type: Format type + */ +struct ope_bus_rd_rm { + uint32_t rm_port_id; + uint32_t format_type; +}; + +/** + * struct ope_bus_in_port_to_rm + * + * @input_port_id: Intput port ID + * @num_combos: Number of combos + * @num_rm: Number of RMs + * @rm_port_id: RM port Id + */ +struct ope_bus_in_port_to_rm { + uint32_t input_port_id; + uint32_t num_combos; + uint32_t num_rm[BUS_RD_COMBO_MAX]; + uint32_t rm_port_id[BUS_RD_COMBO_MAX][MAX_RD_CLIENTS]; +}; + +/** + * struct ope_bus_rd_io_port_info + * + * @pixel_pattern: Pixel pattern + * @input_port_id: Port Id + * @input_format_type: Format type + * @latency_buf_size: Latency buffer size + */ +struct ope_bus_rd_io_port_info { + uint32_t pixel_pattern[OPE_IN_RES_MAX]; + uint32_t input_port_id[OPE_IN_RES_MAX]; + uint32_t input_format_type[OPE_IN_RES_MAX]; + uint32_t latency_buf_size; +}; + +/** + * struct ope_bus_rd_ctx + * + * @ope_acquire: OPE acquire structure + * @security_flag: security flag + * @num_in_ports: Number of in ports + * @io_port_info: IO port info + * @io_port_cdm_batch: IO port cdm info + */ +struct ope_bus_rd_ctx { + struct ope_acquire_dev_info *ope_acquire; + bool security_flag; + uint32_t num_in_ports; + struct ope_bus_rd_io_port_info io_port_info; + struct ope_bus_rd_io_port_cdm_batch io_port_cdm_batch; +}; + +/** + * struct ope_bus_rd + * + * @ope_hw_info: OPE hardware info + * @in_port_to_rm: IO port to RM mapping + * @bus_rd_ctx: RM context + */ +struct ope_bus_rd { + struct ope_hw *ope_hw_info; + struct ope_bus_in_port_to_rm in_port_to_rm[OPE_IN_RES_MAX]; + struct ope_bus_rd_ctx bus_rd_ctx[OPE_CTX_MAX]; + struct completion reset_complete; +}; +#endif /* OPE_BUS_RD_H */ + diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/Makefile b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/Makefile new file mode 100644 index 000000000000..0bce408bcdd6 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr +ccflags-y += -I$(srctree)/techpack/camera/drivers +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += ope_bus_wr.o 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 new file mode 100644 index 000000000000..77a6c8d0af17 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c @@ -0,0 +1,785 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "ope_core.h" +#include "ope_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "ope_hw.h" +#include "ope_dev_intf.h" +#include "ope_bus_wr.h" +#include "cam_cdm_util.h" + +static struct ope_bus_wr *wr_info; + +static int cam_ope_bus_en_port_idx( + struct cam_ope_request *ope_request, + uint32_t batch_idx, + uint32_t output_port_id) +{ + int i; + struct ope_io_buf *io_buf; + + if (batch_idx >= OPE_MAX_BATCH_SIZE) { + CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx); + return -EINVAL; + } + + for (i = 0; i < ope_request->num_io_bufs[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) + return i; + } + + return -EINVAL; +} +static int cam_ope_bus_wr_out_port_idx(uint32_t output_port_id) +{ + int i; + + for (i = 0; i < OPE_OUT_RES_MAX; i++) + if (wr_info->out_port_to_wm[i].output_port_id == output_port_id) + return i; + + return -EINVAL; +} + + +static int cam_ope_bus_wr_subsample( + struct cam_ope_ctx *ctx_data, + struct ope_hw *ope_hw_info, + struct cam_ope_bus_wr_client_reg *wr_reg_client, + struct ope_io_buf *io_buf, + uint32_t *temp_reg, uint32_t count, + int plane_idx, int stripe_idx) +{ + int k, l; + struct cam_ope_bus_wr_reg *wr_reg; + struct cam_ope_bus_wr_reg_val *wr_reg_val; + + wr_reg = ope_hw_info->bus_wr_reg; + wr_reg_val = ope_hw_info->bus_wr_reg_val; + + if (plane_idx >= OPE_MAX_PLANES) { + CAM_ERR(CAM_OPE, "Invalid plane idx: %d", plane_idx); + return count; + } + k = plane_idx; + l = stripe_idx; + + /* subsample period and pattern */ + if ((ctx_data->ope_acquire.dev_type == + OPE_DEV_TYPE_OPE_RT) && l == 0) { + temp_reg[count++] = wr_reg->offset + + wr_reg_client->subsample_period; + temp_reg[count++] = io_buf->num_stripes[k]; + + temp_reg[count++] = wr_reg->offset + + wr_reg_client->subsample_pattern; + temp_reg[count++] = 1 << + (io_buf->num_stripes[k] - 1); + } else if ((ctx_data->ope_acquire.dev_type == + OPE_DEV_TYPE_OPE_NRT) && + ((l % + ctx_data->ope_acquire.nrt_stripes_for_arb) == + 0)) { + if (io_buf->num_stripes[k] >= + (l + + ctx_data->ope_acquire.nrt_stripes_for_arb)){ + temp_reg[count++] = wr_reg->offset + + wr_reg_client->subsample_period; + temp_reg[count++] = + ctx_data->ope_acquire.nrt_stripes_for_arb; + + temp_reg[count++] = wr_reg->offset + + wr_reg_client->subsample_pattern; + temp_reg[count++] = 1 << + (ctx_data->ope_acquire.nrt_stripes_for_arb - + 1); + } else { + temp_reg[count++] = wr_reg->offset + + wr_reg_client->subsample_period; + temp_reg[count++] = io_buf->num_stripes[k] - l; + + /* subsample pattern */ + temp_reg[count++] = wr_reg->offset + + wr_reg_client->subsample_pattern; + temp_reg[count++] = 1 << (io_buf->num_stripes[k] - + l - 1); + } + } + return count; +} + +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; + + if (ctx_id < 0) { + 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; + } + + return rc; +} + +static uint32_t *cam_ope_bus_wr_update(struct ope_hw *ope_hw_info, + int32_t ctx_id, struct cam_ope_dev_prepare_req *prepare, + int batch_idx, int io_idx, + uint32_t *kmd_buf, uint32_t *num_stripes) +{ + int k, l, out_port_idx; + uint32_t idx; + uint32_t num_wm_ports; + uint32_t comb_idx; + uint32_t req_idx; + uint32_t temp_reg[128]; + uint32_t count = 0; + uint32_t temp = 0; + uint32_t wm_port_id; + uint32_t header_size; + struct cam_hw_prepare_update_args *prepare_args; + struct cam_ope_ctx *ctx_data; + struct cam_ope_request *ope_request; + struct ope_io_buf *io_buf; + struct ope_stripe_io *stripe_io; + struct ope_bus_wr_ctx *bus_wr_ctx; + struct cam_ope_bus_wr_reg *wr_reg; + struct cam_ope_bus_wr_client_reg *wr_reg_client; + struct cam_ope_bus_wr_reg_val *wr_reg_val; + struct cam_ope_bus_wr_client_reg_val *wr_res_val_client; + struct ope_bus_out_port_to_wm *out_port_to_wm; + struct ope_bus_wr_io_port_cdm_batch *io_port_cdm_batch; + struct ope_bus_wr_io_port_cdm_info *io_port_cdm; + struct cam_cdm_utils_ops *cdm_ops; + + + if (ctx_id < 0 || !prepare) { + CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, prepare); + return NULL; + } + + if (batch_idx >= OPE_MAX_BATCH_SIZE) { + CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx); + return NULL; + } + + if (io_idx >= OPE_MAX_IO_BUFS) { + CAM_ERR(CAM_OPE, "Invalid IO idx: %d", io_idx); + return NULL; + } + + prepare_args = prepare->prepare_args; + ctx_data = prepare->ctx_data; + req_idx = prepare->req_idx; + 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]; + 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; + + CAM_DBG(CAM_OPE, "kmd_buf = %x req_idx = %d req_id = %lld offset = %d", + kmd_buf, req_idx, ope_request->request_id, + prepare->kmd_buf_offset); + + 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); + + io_port_cdm = + &bus_wr_ctx->io_port_cdm_batch.io_port_cdm[batch_idx]; + out_port_idx = + cam_ope_bus_wr_out_port_idx(io_buf->resource_type); + if (out_port_idx < 0) { + CAM_ERR(CAM_OPE, "Invalid idx for rsc type: %d", + io_buf->resource_type); + return NULL; + } + out_port_to_wm = &wr_info->out_port_to_wm[out_port_idx]; + comb_idx = BUS_WR_YUV; + num_wm_ports = out_port_to_wm->num_wm[comb_idx]; + + for (k = 0; k < io_buf->num_planes; k++) { + *num_stripes = io_buf->num_stripes[k]; + for (l = 0; l < io_buf->num_stripes[k]; l++) { + stripe_io = &io_buf->s_io[k][l]; + CAM_DBG(CAM_OPE, "comb_idx = %d p_idx = %d s_idx = %d", + comb_idx, k, l); + /* frame level info */ + /* stripe level info */ + wm_port_id = out_port_to_wm->wm_port_id[comb_idx][k]; + wr_reg_client = &wr_reg->wr_clients[wm_port_id]; + wr_res_val_client = &wr_reg_val->wr_clients[wm_port_id]; + + /* Core cfg: enable, Mode */ + temp_reg[count++] = wr_reg->offset + + wr_reg_client->core_cfg; + temp = 0; + if (!stripe_io->disable_bus) + temp = wr_res_val_client->core_cfg_en; + temp |= ((wr_res_val_client->mode & + wr_res_val_client->mode_mask) << + wr_res_val_client->mode_shift); + temp_reg[count++] = temp; + + /* Address of the Image */ + temp_reg[count++] = wr_reg->offset + + wr_reg_client->img_addr; + temp_reg[count++] = stripe_io->iova_addr; + + /* Buffer size */ + temp_reg[count++] = wr_reg->offset + + wr_reg_client->img_cfg; + temp = 0; + temp = stripe_io->width; + temp |= (stripe_io->height & + wr_res_val_client->height_mask) << + wr_res_val_client->height_shift; + temp_reg[count++] = temp; + + /* x_init */ + temp_reg[count++] = wr_reg->offset + + wr_reg_client->x_init; + temp_reg[count++] = stripe_io->x_init; + + /* stride */ + temp_reg[count++] = wr_reg->offset + + wr_reg_client->stride; + temp_reg[count++] = stripe_io->stride; + + /* pack cfg : Format and alignment */ + temp_reg[count++] = wr_reg->offset + + wr_reg_client->pack_cfg; + temp = 0; + temp |= ((stripe_io->pack_format & + wr_res_val_client->format_mask) << + wr_res_val_client->format_shift); + temp |= ((stripe_io->alignment & + wr_res_val_client->alignment_mask) << + wr_res_val_client->alignment_shift); + temp_reg[count++] = temp; + + /* subsample period and pattern */ + count = cam_ope_bus_wr_subsample( + ctx_data, ope_hw_info, + wr_reg_client, io_buf, + temp_reg, count, k, l); + + header_size = cdm_ops->cdm_get_cmd_header_size( + CAM_CDM_CMD_REG_RANDOM); + idx = io_port_cdm->num_s_cmd_bufs[l]; + io_port_cdm->s_cdm_info[l][idx].len = + sizeof(temp) * (count + header_size); + io_port_cdm->s_cdm_info[l][idx].offset = + prepare->kmd_buf_offset; + io_port_cdm->s_cdm_info[l][idx].addr = kmd_buf; + io_port_cdm->num_s_cmd_bufs[l]++; + + kmd_buf = cdm_ops->cdm_write_regrandom( + kmd_buf, count/2, temp_reg); + prepare->kmd_buf_offset += ((count + header_size) * + sizeof(temp)); + + CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", + batch_idx, io_idx, k, l); + CAM_DBG(CAM_OPE, "kmdbuf:%x, offset:%d", + kmd_buf, prepare->kmd_buf_offset); + CAM_DBG(CAM_OPE, "count:%d temp_reg:%x", + count, temp_reg, header_size); + CAM_DBG(CAM_OPE, "header_size:%d", header_size); + + CAM_DBG(CAM_OPE, "WR cmd bufs = %d", + io_port_cdm->num_s_cmd_bufs[l]); + CAM_DBG(CAM_OPE, "off:%d len:%d", + io_port_cdm->s_cdm_info[l][idx].offset, + io_port_cdm->s_cdm_info[l][idx].len); + CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", + batch_idx, io_idx, k, l); + count = 0; + } + } + + return kmd_buf; +} + +static uint32_t *cam_ope_bus_wm_disable(struct ope_hw *ope_hw_info, + int32_t ctx_id, struct cam_ope_dev_prepare_req *prepare, + int batch_idx, int io_idx, + uint32_t *kmd_buf, uint32_t num_stripes) +{ + int k, l; + uint32_t idx; + uint32_t num_wm_ports; + uint32_t comb_idx; + uint32_t req_idx; + uint32_t temp_reg[128]; + uint32_t count = 0; + uint32_t temp = 0; + uint32_t wm_port_id; + uint32_t header_size; + struct cam_ope_ctx *ctx_data; + struct ope_bus_wr_ctx *bus_wr_ctx; + struct cam_ope_bus_wr_reg *wr_reg; + struct cam_ope_bus_wr_client_reg *wr_reg_client; + struct ope_bus_out_port_to_wm *out_port_to_wm; + struct ope_bus_wr_io_port_cdm_batch *io_port_cdm_batch; + struct ope_bus_wr_io_port_cdm_info *io_port_cdm; + struct cam_cdm_utils_ops *cdm_ops; + + + if (ctx_id < 0 || !prepare) { + CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, prepare); + return NULL; + } + + if (batch_idx >= OPE_MAX_BATCH_SIZE) { + CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx); + return NULL; + } + + ctx_data = prepare->ctx_data; + req_idx = prepare->req_idx; + cdm_ops = ctx_data->ope_cdm.cdm_ops; + + 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; + + CAM_DBG(CAM_OPE, "kmd_buf = %x req_idx = %d offset = %d", + kmd_buf, req_idx, prepare->kmd_buf_offset); + + io_port_cdm = + &bus_wr_ctx->io_port_cdm_batch.io_port_cdm[batch_idx]; + out_port_to_wm = &wr_info->out_port_to_wm[io_idx]; + comb_idx = BUS_WR_YUV; + num_wm_ports = out_port_to_wm->num_wm[comb_idx]; + + for (k = 0; k < num_wm_ports; k++) { + for (l = 0; l < num_stripes; l++) { + CAM_DBG(CAM_OPE, "comb_idx = %d p_idx = %d s_idx = %d", + comb_idx, k, l); + /* frame level info */ + /* stripe level info */ + wm_port_id = out_port_to_wm->wm_port_id[comb_idx][k]; + wr_reg_client = &wr_reg->wr_clients[wm_port_id]; + + /* Core cfg: enable, Mode */ + temp_reg[count++] = wr_reg->offset + + wr_reg_client->core_cfg; + temp_reg[count++] = 0; + + header_size = cdm_ops->cdm_get_cmd_header_size( + CAM_CDM_CMD_REG_RANDOM); + idx = io_port_cdm->num_s_cmd_bufs[l]; + io_port_cdm->s_cdm_info[l][idx].len = + sizeof(temp) * (count + header_size); + io_port_cdm->s_cdm_info[l][idx].offset = + prepare->kmd_buf_offset; + io_port_cdm->s_cdm_info[l][idx].addr = kmd_buf; + io_port_cdm->num_s_cmd_bufs[l]++; + + kmd_buf = cdm_ops->cdm_write_regrandom( + kmd_buf, count/2, temp_reg); + prepare->kmd_buf_offset += ((count + header_size) * + sizeof(temp)); + + CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", + batch_idx, io_idx, k, l); + CAM_DBG(CAM_OPE, "kmdbuf:%x, offset:%d", + kmd_buf, prepare->kmd_buf_offset); + CAM_DBG(CAM_OPE, "count:%d temp_reg:%x", + count, temp_reg, header_size); + CAM_DBG(CAM_OPE, "header_size:%d", header_size); + + CAM_DBG(CAM_OPE, "WR cmd bufs = %d", + io_port_cdm->num_s_cmd_bufs[l]); + CAM_DBG(CAM_OPE, "off:%d len:%d", + io_port_cdm->s_cdm_info[l][idx].offset, + io_port_cdm->s_cdm_info[l][idx].len); + CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", + batch_idx, io_idx, k, l); + count = 0; + } + } + + prepare->wr_cdm_batch = &bus_wr_ctx->io_port_cdm_batch; + + return kmd_buf; +} + +static int cam_ope_bus_wr_prepare(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0; + int i, j = 0; + uint32_t req_idx; + uint32_t *kmd_buf; + struct cam_ope_dev_prepare_req *prepare; + struct cam_ope_ctx *ctx_data; + struct cam_ope_request *ope_request; + struct ope_io_buf *io_buf; + uint32_t temp; + int io_buf_idx; + uint32_t num_stripes = 0; + struct ope_bus_wr_io_port_cdm_batch *io_port_cdm_batch; + struct ope_bus_wr_ctx *bus_wr_ctx; + + if (ctx_id < 0 || !data) { + CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data); + return -EINVAL; + } + prepare = data; + ctx_data = prepare->ctx_data; + req_idx = prepare->req_idx; + 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 + + (prepare->kmd_buf_offset / sizeof(temp)); + + + CAM_DBG(CAM_OPE, "kmd_buf = %x req_idx = %d req_id = %lld offset = %d", + 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; + 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]; + CAM_DBG(CAM_OPE, "batch = %d io buf num = %d dir = %d", + i, j, io_buf->direction); + if (io_buf->direction != CAM_BUF_OUTPUT) + continue; + + kmd_buf = cam_ope_bus_wr_update(ope_hw_info, + ctx_id, prepare, i, j, + kmd_buf, &num_stripes); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + } + } + + /* Disable WMs which are not enabled */ + for (i = 0; i < ope_request->num_batch; i++) { + for (j = OPE_OUT_RES_VIDEO; j <= OPE_OUT_RES_MAX; j++) { + io_buf_idx = cam_ope_bus_en_port_idx(ope_request, i, j); + if (io_buf_idx >= 0) + continue; + + io_buf_idx = cam_ope_bus_wr_out_port_idx(j); + if (io_buf_idx < 0) { + CAM_ERR(CAM_OPE, "Invalid idx for rsc type:%d", + j); + return io_buf_idx; + } + kmd_buf = cam_ope_bus_wm_disable(ope_hw_info, + ctx_id, prepare, i, io_buf_idx, + kmd_buf, num_stripes); + } + } + prepare->wr_cdm_batch = &bus_wr_ctx->io_port_cdm_batch; + +end: + return rc; +} + +static int cam_ope_bus_wr_acquire(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; + struct ope_bus_out_port_to_wm *out_port_to_wr; + int combo_idx; + int out_port_idx; + + if (ctx_id < 0 || !data) { + CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data); + return -EINVAL; + } + + 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->num_out_ports = in_acquire->num_out_res; + bus_wr_ctx->security_flag = in_acquire->secure_mode; + + for (i = 0; i < in_acquire->num_out_res; i++) { + if (!in_acquire->out_res[i].width) + continue; + + CAM_DBG(CAM_OPE, "i = %d format = %u width = %x height = %x", + i, in_acquire->out_res[i].format, + in_acquire->out_res[i].width, + in_acquire->out_res[i].height); + CAM_DBG(CAM_OPE, "pix_pattern:%u alignment:%u packer_format:%u", + in_acquire->out_res[i].pixel_pattern, + in_acquire->out_res[i].alignment, + in_acquire->out_res[i].packer_format); + CAM_DBG(CAM_OPE, "subsample_period = %u subsample_pattern = %u", + in_acquire->out_res[i].subsample_period, + in_acquire->out_res[i].subsample_pattern); + + out_port_idx = + cam_ope_bus_wr_out_port_idx(in_acquire->out_res[i].res_id); + if (out_port_idx < 0) { + CAM_DBG(CAM_OPE, "Invalid in_port_idx: %d", + in_acquire->out_res[i].res_id); + rc = -EINVAL; + goto end; + } + out_port_to_wr = &wr_info->out_port_to_wm[out_port_idx]; + combo_idx = BUS_WR_YUV; + if (!out_port_to_wr->num_wm[combo_idx]) { + CAM_DBG(CAM_OPE, "Invalid format for Input port"); + rc = -EINVAL; + goto end; + } + + bus_wr_ctx->io_port_info.output_port_id[i] = + in_acquire->out_res[i].res_id; + bus_wr_ctx->io_port_info.output_format_type[i] = + in_acquire->out_res[i].format; + if (in_acquire->out_res[i].pixel_pattern > + PIXEL_PATTERN_CRYCBY) { + CAM_DBG(CAM_OPE, "Invalid pix pattern = %u", + in_acquire->out_res[i].pixel_pattern); + rc = -EINVAL; + goto end; + } + + bus_wr_ctx->io_port_info.pixel_pattern[i] = + in_acquire->out_res[i].pixel_pattern; + bus_wr_ctx->io_port_info.latency_buf_size = 4096; + CAM_DBG(CAM_OPE, "i:%d port_id = %u format %u pix_pattern = %u", + i, bus_wr_ctx->io_port_info.output_port_id[i], + bus_wr_ctx->io_port_info.output_format_type[i], + bus_wr_ctx->io_port_info.pixel_pattern[i]); + CAM_DBG(CAM_OPE, "latency_buf_size = %u", + bus_wr_ctx->io_port_info.latency_buf_size); + } + +end: + return rc; +} + +static int cam_ope_bus_wr_init(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0; + struct cam_ope_bus_wr_reg_val *bus_wr_reg_val; + struct cam_ope_bus_wr_reg *bus_wr_reg; + struct cam_ope_dev_init *dev_init = data; + + if (!ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + + wr_info->ope_hw_info = ope_hw_info; + bus_wr_reg_val = ope_hw_info->bus_wr_reg_val; + bus_wr_reg = ope_hw_info->bus_wr_reg; + bus_wr_reg->base = dev_init->core_info->ope_hw_info->ope_bus_wr_base; + + cam_io_w_mb(bus_wr_reg_val->irq_mask_0, + ope_hw_info->bus_wr_reg->base + bus_wr_reg->irq_mask_0); + cam_io_w_mb(bus_wr_reg_val->irq_mask_1, + ope_hw_info->bus_wr_reg->base + bus_wr_reg->irq_mask_1); + + return rc; +} + +static int cam_ope_bus_wr_probe(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0, i, j, combo_idx, k; + struct cam_ope_bus_wr_reg_val *bus_wr_reg_val; + struct ope_bus_out_port_to_wm *out_port_to_wm; + uint32_t output_port_idx; + uint32_t wm_idx; + + if (!ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + wr_info = kzalloc(sizeof(struct ope_bus_wr), GFP_KERNEL); + if (!wr_info) { + CAM_ERR(CAM_OPE, "Out of memory"); + return -ENOMEM; + } + + wr_info->ope_hw_info = ope_hw_info; + bus_wr_reg_val = ope_hw_info->bus_wr_reg_val; + + for (i = 0; i < bus_wr_reg_val->num_clients; i++) { + output_port_idx = + bus_wr_reg_val->wr_clients[i].output_port_id - 1; + out_port_to_wm = &wr_info->out_port_to_wm[output_port_idx]; + combo_idx = BUS_WR_YUV; + wm_idx = out_port_to_wm->num_wm[combo_idx]; + out_port_to_wm->output_port_id = + bus_wr_reg_val->wr_clients[i].output_port_id; + out_port_to_wm->wm_port_id[combo_idx][wm_idx] = + bus_wr_reg_val->wr_clients[i].wm_port_id; + if (!out_port_to_wm->num_wm[combo_idx]) + out_port_to_wm->num_combos++; + out_port_to_wm->num_wm[combo_idx]++; + } + + for (i = 0; i < OPE_OUT_RES_MAX; i++) { + out_port_to_wm = &wr_info->out_port_to_wm[i]; + CAM_DBG(CAM_OPE, "output port id = %d num_combos = %d", + out_port_to_wm->output_port_id, + out_port_to_wm->num_combos); + for (j = 0; j < out_port_to_wm->num_combos; j++) { + CAM_DBG(CAM_OPE, "combo idx = %d num_wms = %d", + j, out_port_to_wm->num_wm[j]); + for (k = 0; k < out_port_to_wm->num_wm[j]; k++) { + CAM_DBG(CAM_OPE, "wm port id = %d", + out_port_to_wm->wm_port_id[j][k]); + } + } + } + + return rc; +} + +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; + 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) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + + bus_wr_reg = ope_hw_info->bus_wr_reg; + bus_wr_reg_val = ope_hw_info->bus_wr_reg_val; + + /* Read and Clear Top Interrupt status */ + irq_status_0 = cam_io_r_mb(bus_wr_reg->base + bus_wr_reg->irq_status_0); + irq_status_1 = cam_io_r_mb(bus_wr_reg->base + bus_wr_reg->irq_status_1); + cam_io_w_mb(irq_status_0, + bus_wr_reg->base + bus_wr_reg->irq_clear_0); + cam_io_w_mb(irq_status_1, + bus_wr_reg->base + bus_wr_reg->irq_clear_1); + + cam_io_w_mb(bus_wr_reg_val->irq_set_clear, + 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) { + irq_data->error = 1; + CAM_ERR(CAM_OPE, "ope bus wr vioalation"); + } + + if (irq_status_0 & bus_wr_reg_val->img_size_violation) { + irq_data->error = 1; + CAM_ERR(CAM_OPE, "ope bus wr img_size_violation"); + } + + return rc; +} + +int cam_ope_bus_wr_process(struct ope_hw *ope_hw_info, + int32_t ctx_id, uint32_t cmd_id, void *data) +{ + int rc = 0; + + switch (cmd_id) { + case OPE_HW_PROBE: + CAM_DBG(CAM_OPE, "OPE_HW_PROBE: E"); + rc = cam_ope_bus_wr_probe(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_PROBE: X"); + break; + case OPE_HW_INIT: + CAM_DBG(CAM_OPE, "OPE_HW_INIT: E"); + rc = cam_ope_bus_wr_init(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_INIT: X"); + break; + case OPE_HW_ACQUIRE: + CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: E"); + rc = cam_ope_bus_wr_acquire(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: X"); + break; + case OPE_HW_RELEASE: + CAM_DBG(CAM_OPE, "OPE_HW_RELEASE: E"); + rc = cam_ope_bus_wr_release(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_RELEASE: X"); + break; + case OPE_HW_PREPARE: + CAM_DBG(CAM_OPE, "OPE_HW_PREPARE: E"); + rc = cam_ope_bus_wr_prepare(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_PREPARE: X"); + break; + case OPE_HW_DEINIT: + case OPE_HW_START: + case OPE_HW_STOP: + case OPE_HW_FLUSH: + case OPE_HW_CLK_UPDATE: + case OPE_HW_BW_UPDATE: + case OPE_HW_RESET: + case OPE_HW_SET_IRQ_CB: + rc = 0; + 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); + break; + default: + CAM_ERR(CAM_OPE, "Unsupported cmd: %d", cmd_id); + break; + } + + return rc; +} + 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 new file mode 100644 index 000000000000..13b42f456059 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef OPE_BUS_WR_H +#define OPE_BUS_WR_H + +#include +#include +#include +#include "ope_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" +#include "cam_soc_util.h" +#include "cam_context.h" +#include "cam_ope_context.h" +#include "cam_ope_hw_mgr.h" + +/** + * struct ope_bus_wr_cdm_info + * + * @offset: Offset + * @addr: Address + * @len: Length + */ +struct ope_bus_wr_cdm_info { + uint32_t offset; + uint32_t *addr; + uint32_t len; +}; + +/** + * struct ope_bus_wr_io_port_cdm_info + * + * @num_frames_cmds: Number of frame commands + * @f_cdm_info: Frame cdm info + * @num_stripes: Number of stripes + * @num_s_cmd_bufs: Number of stripe commands + * @s_cdm_info: Stripe cdm info + * @go_cmd_addr: GO command address + * @go_cmd_len: GO command length + */ +struct ope_bus_wr_io_port_cdm_info { + uint32_t num_frames_cmds; + struct ope_bus_wr_cdm_info f_cdm_info[MAX_WR_CLIENTS]; + uint32_t num_stripes; + uint32_t num_s_cmd_bufs[OPE_MAX_STRIPES]; + struct ope_bus_wr_cdm_info s_cdm_info[OPE_MAX_STRIPES][MAX_WR_CLIENTS]; + uint32_t *go_cmd_addr; + uint32_t go_cmd_len; +}; + +/** + * struct ope_bus_wr_io_port_cdm_batch + * + * num_batch: Number of batches + * io_port_cdm: CDM IO Port Info + */ +struct ope_bus_wr_io_port_cdm_batch { + uint32_t num_batch; + struct ope_bus_wr_io_port_cdm_info io_port_cdm[OPE_MAX_BATCH_SIZE]; +}; + +/** + * struct ope_bus_wr_wm + * + * @wm_port_id: WM port ID + * @format_type: Format type + */ +struct ope_bus_wr_wm { + uint32_t wm_port_id; + uint32_t format_type; +}; + +/** + * struct ope_bus_out_port_to_wm + * + * @output_port_id: Output port ID + * @num_combos: Number of combos + * @num_wm: Number of WMs + * @wm_port_id: WM port Id + */ +struct ope_bus_out_port_to_wm { + uint32_t output_port_id; + uint32_t num_combos; + uint32_t num_wm[BUS_WR_COMBO_MAX]; + uint32_t wm_port_id[BUS_WR_COMBO_MAX][MAX_WR_CLIENTS]; +}; + +/** + * struct ope_bus_wr_io_port_info + * + * @pixel_pattern: Pixel pattern + * @output_port_id: Port Id + * @output_format_type: Format type + * @latency_buf_size: Latency buffer size + */ +struct ope_bus_wr_io_port_info { + uint32_t pixel_pattern[OPE_OUT_RES_MAX]; + uint32_t output_port_id[OPE_OUT_RES_MAX]; + uint32_t output_format_type[OPE_OUT_RES_MAX]; + uint32_t latency_buf_size; +}; + +/** + * struct ope_bus_wr_ctx + * + * @ope_acquire: OPE acquire structure + * @security_flag: security flag + * @num_out_ports: Number of out ports + * @io_port_info: IO port info + * @io_port_cdm_batch: IO port cdm info + */ +struct ope_bus_wr_ctx { + struct ope_acquire_dev_info *ope_acquire; + bool security_flag; + uint32_t num_out_ports; + struct ope_bus_wr_io_port_info io_port_info; + struct ope_bus_wr_io_port_cdm_batch io_port_cdm_batch; +}; + +/** + * struct ope_bus_wr + * + * @ope_hw_info: OPE hardware info + * @out_port_to_wm: IO port to WM mapping + * @bus_wr_ctx: WM context + */ +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]; +}; + +#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 new file mode 100644 index 000000000000..719a9fc62e25 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c @@ -0,0 +1,1781 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "ope_core.h" +#include "ope_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "ope_hw.h" +#include "ope_dev_intf.h" +#include "cam_cdm_util.h" +#include "ope_bus_rd.h" +#include "ope_bus_wr.h" + +static int cam_ope_caps_vote(struct cam_ope_device_core_info *core_info, + struct cam_ope_dev_bw_update *cpas_vote) +{ + int rc = 0; + + if (cpas_vote->ahb_vote_valid) + rc = cam_cpas_update_ahb_vote(core_info->cpas_handle, + &cpas_vote->ahb_vote); + if (cpas_vote->axi_vote_valid) + rc = cam_cpas_update_axi_vote(core_info->cpas_handle, + &cpas_vote->axi_vote); + if (rc) + CAM_ERR(CAM_OPE, "cpas vote is failed: %d", rc); + + return rc; +} + +int cam_ope_get_hw_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size) +{ + struct cam_hw_info *ope_dev = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ope_device_core_info *core_info = NULL; + struct ope_hw_ver *ope_hw_ver; + struct cam_ope_top_reg_val *top_reg_val; + + if (!hw_priv) { + CAM_ERR(CAM_OPE, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &ope_dev->soc_info; + core_info = (struct cam_ope_device_core_info *)ope_dev->core_info; + + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_OPE, "soc_info = %x core_info = %x", + soc_info, core_info); + return -EINVAL; + } + + if (!get_hw_cap_args) { + CAM_ERR(CAM_OPE, "Invalid caps"); + return -EINVAL; + } + + top_reg_val = core_info->ope_hw_info->ope_hw->top_reg_val; + ope_hw_ver = get_hw_cap_args; + ope_hw_ver->hw_type = core_info->hw_type; + ope_hw_ver->hw_ver.major = + (core_info->hw_version & top_reg_val->major_mask) >> + top_reg_val->major_shift; + ope_hw_ver->hw_ver.minor = + (core_info->hw_version & top_reg_val->minor_mask) >> + top_reg_val->minor_shift; + ope_hw_ver->hw_ver.incr = + (core_info->hw_version & top_reg_val->incr_mask) >> + top_reg_val->incr_shift; + + return 0; +} + +int cam_ope_start(void *hw_priv, void *start_args, uint32_t arg_size) +{ + return 0; +} + +int cam_ope_stop(void *hw_priv, void *start_args, uint32_t arg_size) +{ + return 0; +} + +int cam_ope_flush(void *hw_priv, void *flush_args, uint32_t arg_size) +{ + return 0; +} + +static int cam_ope_dev_process_init(struct ope_hw *ope_hw, + void *cmd_args) +{ + int rc = 0; + + rc = cam_ope_top_process(ope_hw, 0, OPE_HW_INIT, cmd_args); + if (rc) + goto top_init_fail; + + rc = cam_ope_bus_rd_process(ope_hw, 0, OPE_HW_INIT, cmd_args); + if (rc) + goto bus_rd_init_fail; + + rc = cam_ope_bus_wr_process(ope_hw, 0, OPE_HW_INIT, cmd_args); + if (rc) + goto bus_wr_init_fail; + + return rc; + +bus_wr_init_fail: + rc = cam_ope_bus_rd_process(ope_hw, 0, + OPE_HW_DEINIT, NULL); +bus_rd_init_fail: + rc = cam_ope_top_process(ope_hw, 0, + OPE_HW_DEINIT, NULL); +top_init_fail: + return rc; +} + +static int cam_ope_process_init(struct ope_hw *ope_hw, + void *cmd_args, bool hfi_en) +{ + if (!hfi_en) + return cam_ope_dev_process_init(ope_hw, cmd_args); + + CAM_ERR(CAM_OPE, "hfi_en is not supported"); + return -EINVAL; +} + +int cam_ope_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + 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; + 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; + } + + soc_info = &ope_dev->soc_info; + core_info = (struct cam_ope_device_core_info *)ope_dev->core_info; + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_OPE, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + ope_hw = core_info->ope_hw_info->ope_hw; + + + 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 = + CAM_AXI_TRANSACTION_WRITE; + cpas_vote.axi_vote.axi_path[0].camnoc_bw = + CAM_CPAS_DEFAULT_AXI_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 = + CAM_CPAS_DEFAULT_AXI_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 = + CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote.ahb_vote, &cpas_vote.axi_vote); + if (rc) { + CAM_ERR(CAM_OPE, "cpass start failed: %d", rc); + return rc; + } + 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 { + 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); + + return rc; +} + +int cam_ope_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + 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; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_OPE, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &ope_dev->soc_info; + core_info = (struct cam_ope_device_core_info *)ope_dev->core_info; + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_OPE, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + rc = cam_ope_disable_soc_resources(soc_info, core_info->clk_enable); + if (rc) + 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_reset(struct ope_hw *ope_hw, void *cmd_args) +{ + int rc = 0; + + rc = cam_ope_top_process(ope_hw, -1, + OPE_HW_RESET, NULL); + + return rc; +} + +static int cam_ope_dev_process_release(struct ope_hw *ope_hw, void *cmd_args) +{ + int rc = 0; + struct cam_ope_dev_release *ope_dev_release; + + ope_dev_release = cmd_args; + rc = cam_ope_top_process(ope_hw, ope_dev_release->ctx_id, + OPE_HW_RELEASE, NULL); + + rc |= cam_ope_bus_rd_process(ope_hw, ope_dev_release->ctx_id, + OPE_HW_RELEASE, NULL); + + rc |= cam_ope_bus_wr_process(ope_hw, ope_dev_release->ctx_id, + OPE_HW_RELEASE, NULL); + + return rc; +} + +static int cam_ope_dev_process_acquire(struct ope_hw *ope_hw, void *cmd_args) +{ + int rc = 0; + struct cam_ope_dev_acquire *ope_dev_acquire; + + if (!cmd_args || !ope_hw) { + CAM_ERR(CAM_OPE, "Invalid arguments: %pK %pK", + cmd_args, ope_hw); + return -EINVAL; + } + + ope_dev_acquire = cmd_args; + rc = cam_ope_top_process(ope_hw, ope_dev_acquire->ctx_id, + OPE_HW_ACQUIRE, ope_dev_acquire->ope_acquire); + if (rc) + goto top_acquire_fail; + + rc = cam_ope_bus_rd_process(ope_hw, ope_dev_acquire->ctx_id, + OPE_HW_ACQUIRE, ope_dev_acquire->ope_acquire); + if (rc) + goto bus_rd_acquire_fail; + + rc = cam_ope_bus_wr_process(ope_hw, ope_dev_acquire->ctx_id, + OPE_HW_ACQUIRE, ope_dev_acquire->ope_acquire); + if (rc) + goto bus_wr_acquire_fail; + + return 0; + +bus_wr_acquire_fail: + rc = 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, + OPE_HW_RELEASE, ope_dev_acquire->ope_acquire); + if (rc) + goto top_acquire_fail; + +top_acquire_fail: + return rc; +} + +static int cam_ope_dev_prepare_cdm_request( + struct cam_ope_hw_mgr *hw_mgr, + struct cam_hw_prepare_update_args *prepare_args, + struct cam_ope_ctx *ctx_data, uint32_t req_idx, + uint32_t kmd_buf_offset, + struct cam_ope_dev_prepare_req *ope_dev_prepare_req, + uint32_t len, bool arbitrate) +{ + int i; + struct cam_ope_request *ope_request; + struct cam_cdm_bl_request *cdm_cmd; + uint32_t *kmd_buf; + + ope_request = ctx_data->req_list[req_idx]; + cdm_cmd = ope_request->cdm_cmd; + 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->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].len = len; + cdm_cmd->cmd[i].arbitrate = arbitrate; + + cdm_cmd->cmd_arrary_count++; + + CAM_DBG(CAM_OPE, "CDM cmd:Req idx = %d req_id = %lld array cnt = %d", + cdm_cmd->cookie, ope_request->request_id, + cdm_cmd->cmd_arrary_count); + CAM_DBG(CAM_OPE, "CDM cmd:mem_hdl = %d offset = %d len = %d, iova 0x%x", + ope_request->ope_kmd_buf.mem_handle, kmd_buf_offset, len, + cdm_cmd->cmd[i].bl_addr.hw_iova); + + return 0; +} + +static int dump_dmi_cmd(uint32_t print_idx, + uint32_t *print_ptr, struct cdm_dmi_cmd *dmi_cmd, + uint32_t *temp) +{ + CAM_DBG(CAM_OPE, "%d:dma_ptr:%x l:%d", + print_idx, print_ptr, + dmi_cmd->length); + CAM_DBG(CAM_OPE, "%d:cmd:%hhx addr:%x", + print_ptr, dmi_cmd->cmd, + dmi_cmd->addr); + CAM_DBG(CAM_OPE, "%d: dmiadr:%x sel:%d", + print_idx, dmi_cmd->DMIAddr, + dmi_cmd->DMISel); + CAM_DBG(CAM_OPE, "%d: %x %x %x", + print_idx, + temp[0], temp[1], temp[2]); + + return 0; +} + +static int dump_frame_direct(uint32_t print_idx, + uint32_t *print_ptr, + struct ope_frame_process *frm_proc, + int batch_idx, int cmd_buf_idx) +{ + int len; + + if (cmd_buf_idx >= OPE_MAX_CMD_BUFS || + batch_idx >= OPE_MAX_BATCH_SIZE) + return 0; + + len = frm_proc->cmd_buf[batch_idx][cmd_buf_idx].length / 4; + CAM_DBG(CAM_OPE, "Frame DB : direct: E"); + for (print_idx = 0; print_idx < len; print_idx++) + CAM_DBG(CAM_OPE, "%d: %x", print_idx, print_ptr[print_idx]); + CAM_DBG(CAM_OPE, "Frame DB : direct: X"); + + return 0; +} + +static int dump_frame_cmd(struct ope_frame_process *frm_proc, + int i, int j, uint64_t iova_addr, uint32_t *kmd_buf, uint32_t buf_len) +{ + if (j >= OPE_MAX_CMD_BUFS || i >= OPE_MAX_BATCH_SIZE) + return 0; + + CAM_DBG(CAM_OPE, "Frame DB:scope:%d buffer:%d type:%d", + frm_proc->cmd_buf[i][j].cmd_buf_scope, + frm_proc->cmd_buf[i][j].cmd_buf_buffered, + frm_proc->cmd_buf[i][j].type); + CAM_DBG(CAM_OPE, "kmdbuf:%x memhdl:%x iova:%x %pK", + kmd_buf, + frm_proc->cmd_buf[i][j].mem_handle, + iova_addr, iova_addr); + CAM_DBG(CAM_OPE, "buflen:%d len:%d offset:%d", + buf_len, + frm_proc->cmd_buf[i][j].length, + frm_proc->cmd_buf[i][j].offset); + + return 0; +} + +static int dump_stripe_cmd(struct ope_frame_process *frm_proc, + uint32_t stripe_idx, int i, int k, uint64_t iova_addr, + uint32_t *kmd_buf, uint32_t buf_len) +{ + if (k >= OPE_MAX_CMD_BUFS) + return 0; + + CAM_DBG(CAM_OPE, "Stripe:%d scope:%d buffer:%d", + stripe_idx, + frm_proc->cmd_buf[i][k].cmd_buf_scope, + frm_proc->cmd_buf[i][k].cmd_buf_buffered); + CAM_DBG(CAM_OPE, "type:%d kmdbuf:%x memhdl:%x", + frm_proc->cmd_buf[i][k].type, kmd_buf, + frm_proc->cmd_buf[i][k].mem_handle); + CAM_DBG(CAM_OPE, "iova:%x %pK buflen:%d len:%d", + iova_addr, iova_addr, buf_len, + frm_proc->cmd_buf[i][k].length); + CAM_DBG(CAM_OPE, "offset:%d", + frm_proc->cmd_buf[i][k].offset); + 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; + uint64_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, + 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; + uint64_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].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_wr(struct cam_ope_ctx *ctx_data, + struct ope_bus_wr_io_port_cdm_info *wr_cdm_info, + uint32_t *kmd_buf, struct cam_ope_request *ope_request) +{ + struct cam_cdm_utils_ops *cdm_ops; + int i; + + cdm_ops = ctx_data->ope_cdm.cdm_ops; + + for (i = 0; i < wr_cdm_info->num_frames_cmds; i++) { + kmd_buf = cdm_ops->cdm_write_indirect(kmd_buf, + (uint32_t)ope_request->ope_kmd_buf.iova_cdm_addr + + wr_cdm_info->f_cdm_info[i].offset, + wr_cdm_info->f_cdm_info[i].len); + CAM_DBG(CAM_OPE, "FrameWR:i:%d kmdbuf:%x len:%d iova:%x %pK", + i, kmd_buf, wr_cdm_info->f_cdm_info[i].len, + ope_request->ope_kmd_buf.iova_cdm_addr, + ope_request->ope_kmd_buf.iova_cdm_addr); + } + return kmd_buf; +} + +static uint32_t *ope_create_frame_rd(struct cam_ope_ctx *ctx_data, + struct ope_bus_rd_io_port_cdm_info *rd_cdm_info, + uint32_t *kmd_buf, struct cam_ope_request *ope_request) +{ + struct cam_cdm_utils_ops *cdm_ops; + int i; + + cdm_ops = ctx_data->ope_cdm.cdm_ops; + + /* Frame 0 RD */ + for (i = 0; i < rd_cdm_info->num_frames_cmds; i++) { + kmd_buf = cdm_ops->cdm_write_indirect(kmd_buf, + (uint32_t)ope_request->ope_kmd_buf.iova_cdm_addr + + rd_cdm_info->f_cdm_info[i].offset, + rd_cdm_info->f_cdm_info[i].len); + CAM_DBG(CAM_OPE, "FrameRD:i:%d kmdbuf:%x len:%d iova:%x %pK", + i, kmd_buf, rd_cdm_info->f_cdm_info[i].len, + ope_request->ope_kmd_buf.iova_cdm_addr, + ope_request->ope_kmd_buf.iova_cdm_addr); + } + return kmd_buf; +} + +static uint32_t *ope_create_frame_cmd(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, uint32_t req_idx, + uint32_t *kmd_buf, uint32_t buffered, + 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; + uint64_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]; + + for (i = 0; i < frm_proc->batch_size; i++) { + 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].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[j][i].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_stripe_cmd(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, + uint32_t *kmd_buf, + int batch_idx, + int s_idx, + uint32_t stripe_idx, + struct ope_frame_process *frm_proc) +{ + int rc = 0, i, j, k; + uint32_t temp[3]; + struct cdm_dmi_cmd *dmi_cmd; + uint64_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; + + if (s_idx >= OPE_MAX_CMD_BUFS || + batch_idx >= OPE_MAX_BATCH_SIZE) { + CAM_ERR(CAM_OPE, "Invalid inputs: %d %d", + batch_idx, s_idx); + return NULL; + } + + i = batch_idx; + j = s_idx; + cdm_ops = ctx_data->ope_cdm.cdm_ops; + /* cmd buffer stripes */ + for (k = 0; k < frm_proc->num_cmd_bufs[i]; k++) { + if (frm_proc->cmd_buf[i][k].cmd_buf_scope != + OPE_CMD_BUF_SCOPE_STRIPE) + continue; + + if (frm_proc->cmd_buf[i][k].stripe_idx != + stripe_idx) + continue; + + if (!frm_proc->cmd_buf[i][k].mem_handle) + continue; + + CAM_DBG(CAM_OPE, "process stripe %d", stripe_idx); + rc = cam_mem_get_io_buf(frm_proc->cmd_buf[i][k].mem_handle, + hw_mgr->iommu_cdm_hdl, + &iova_addr, &buf_len); + if (rc) { + CAM_DBG(CAM_OPE, "get cmd buf fail %x", + hw_mgr->iommu_hdl); + return NULL; + } + iova_addr = iova_addr + frm_proc->cmd_buf[i][k].offset; + rc = cam_mem_get_cpu_buf(frm_proc->cmd_buf[i][k].mem_handle, + &cpu_addr, &buf_len); + if (rc || !cpu_addr) { + CAM_DBG(CAM_OPE, "get cmd buf fail %x", + hw_mgr->iommu_hdl); + return NULL; + } + cpu_addr = cpu_addr + frm_proc->cmd_buf[i][k].offset; + + if (frm_proc->cmd_buf[i][k].type == OPE_CMD_BUF_TYPE_DIRECT) { + kmd_buf = cdm_ops->cdm_write_indirect( + kmd_buf, + iova_addr, + frm_proc->cmd_buf[i][k].length); + print_ptr = (uint32_t *)cpu_addr; + CAM_DBG(CAM_OPE, "Stripe:%d direct:E", + stripe_idx); + for (print_idx = 0; print_idx < + frm_proc->cmd_buf[i][k].length / 4; + print_idx++) { + CAM_DBG(CAM_OPE, "%d: %x", print_idx, + print_ptr[print_idx]); + } + CAM_DBG(CAM_OPE, "Stripe:%d direct:X", stripe_idx); + } else if (frm_proc->cmd_buf[i][k].type == + OPE_CMD_BUF_TYPE_INDIRECT) { + num_dmi = frm_proc->cmd_buf[i][j].length / + sizeof(struct cdm_dmi_cmd); + CAM_DBG(CAM_OPE, "Stripe:%d Indirect:E", stripe_idx); + 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, "Stripe:%d Indirect:X", stripe_idx); + } + dump_stripe_cmd(frm_proc, stripe_idx, i, k, + iova_addr, kmd_buf, buf_len); + } + return kmd_buf; +} + +static uint32_t *ope_create_stripe_wr(struct cam_ope_ctx *ctx_data, + uint32_t stripe_idx, struct ope_bus_wr_io_port_cdm_info *wr_cdm_info, + struct cam_ope_request *ope_request, uint32_t *kmd_buf) +{ + struct cam_cdm_utils_ops *cdm_ops; + int k; + + if (stripe_idx >= OPE_MAX_STRIPES) { + CAM_ERR(CAM_OPE, "invalid s_idx = %d", stripe_idx); + return NULL; + } + + cdm_ops = ctx_data->ope_cdm.cdm_ops; + for (k = 0; k < wr_cdm_info->num_s_cmd_bufs[stripe_idx]; k++) { + kmd_buf = cdm_ops->cdm_write_indirect(kmd_buf, + (uint32_t)ope_request->ope_kmd_buf.iova_cdm_addr + + wr_cdm_info->s_cdm_info[stripe_idx][k].offset, + wr_cdm_info->s_cdm_info[stripe_idx][k].len); + CAM_DBG(CAM_OPE, "WR stripe:%d %d kmdbuf:%x", + stripe_idx, k, kmd_buf); + CAM_DBG(CAM_OPE, "offset:%d len:%d iova:%x %pK", + wr_cdm_info->s_cdm_info[stripe_idx][k].offset, + wr_cdm_info->s_cdm_info[stripe_idx][k].len, + ope_request->ope_kmd_buf.iova_cdm_addr, + ope_request->ope_kmd_buf.iova_cdm_addr); + } + return kmd_buf; +} + +static uint32_t *ope_create_stripe_rd(struct cam_ope_ctx *ctx_data, + uint32_t stripe_idx, struct ope_bus_rd_io_port_cdm_info *rd_cdm_info, + struct cam_ope_request *ope_request, uint32_t *kmd_buf) +{ + struct cam_cdm_utils_ops *cdm_ops; + int k; + + if (stripe_idx >= OPE_MAX_STRIPES) { + CAM_ERR(CAM_OPE, "invalid s_idx = %d", stripe_idx); + return NULL; + } + + cdm_ops = ctx_data->ope_cdm.cdm_ops; + for (k = 0; k < rd_cdm_info->num_s_cmd_bufs[stripe_idx]; k++) { + kmd_buf = cdm_ops->cdm_write_indirect(kmd_buf, + (uint32_t)ope_request->ope_kmd_buf.iova_cdm_addr + + rd_cdm_info->s_cdm_info[stripe_idx][k].offset, + rd_cdm_info->s_cdm_info[stripe_idx][k].len); + CAM_DBG(CAM_OPE, "WR stripe:%d %d kmdbuf:%x", + stripe_idx, k, kmd_buf); + CAM_DBG(CAM_OPE, "offset:%d len:%d iova:%x %pK", + rd_cdm_info->s_cdm_info[stripe_idx][k].offset, + rd_cdm_info->s_cdm_info[stripe_idx][k].len, + ope_request->ope_kmd_buf.iova_cdm_addr, + ope_request->ope_kmd_buf.iova_cdm_addr); + } + return kmd_buf; +} + +static uint32_t *ope_create_stripes_batch(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, uint32_t req_idx, + uint32_t *kmd_buf, int batch_idx, + struct cam_ope_dev_prepare_req *ope_dev_prepare_req) +{ + int i, j; + struct cam_ope_request *ope_request; + 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; + uint32_t stripe_idx = 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; + + if (batch_idx >= OPE_MAX_BATCH_SIZE) { + CAM_ERR(CAM_OPE, "Invalid input: %d", batch_idx); + return NULL; + } + i = batch_idx; + /* Stripes */ + + wr_cdm_info = + &ope_dev_prepare_req->wr_cdm_batch->io_port_cdm[i]; + rd_cdm_info = + &ope_dev_prepare_req->rd_cdm_batch->io_port_cdm[i]; + for (j = 0; j < ope_request->num_stripes[i]; j++) { + /* cmd buffer stripes */ + kmd_buf = ope_create_stripe_cmd(hw_mgr, ctx_data, + kmd_buf, i, j, stripe_idx, frm_proc); + if (!kmd_buf) + goto end; + + /* WR stripes */ + kmd_buf = ope_create_stripe_wr(ctx_data, stripe_idx, + wr_cdm_info, ope_request, kmd_buf); + if (!kmd_buf) + goto end; + + /* RD stripes */ + kmd_buf = ope_create_stripe_rd(ctx_data, stripe_idx, + rd_cdm_info, ope_request, kmd_buf); + if (!kmd_buf) + goto end; + + /* add go command */ + kmd_buf = cdm_ops->cdm_write_indirect(kmd_buf, + (uint32_t)ope_request->ope_kmd_buf.iova_cdm_addr + + rd_cdm_info->go_cmd_offset, + rd_cdm_info->go_cmd_len); + + CAM_DBG(CAM_OPE, "Go cmd for stripe:%d kmd_buf:%x", + stripe_idx, kmd_buf); + CAM_DBG(CAM_OPE, "iova:%x %pK", + ope_request->ope_kmd_buf.iova_cdm_addr, + ope_request->ope_kmd_buf.iova_cdm_addr); + + /* wait for RUP done */ + kmd_buf = cdm_ops->cdm_write_wait_comp_event(kmd_buf, + OPE_WAIT_COMP_RUP, 0x0); + CAM_DBG(CAM_OPE, "wait RUP cmd stripe:%d kmd_buf:%x", + stripe_idx, kmd_buf); + stripe_idx++; + } + +end: + return kmd_buf; +} + +static uint32_t *ope_create_stripes(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, uint32_t req_idx, + uint32_t *kmd_buf, + struct cam_ope_dev_prepare_req *ope_dev_prepare_req) +{ + int i, j; + struct cam_ope_request *ope_request; + 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; + uint32_t stripe_idx = 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; + + /* Stripes */ + for (i = 0; i < frm_proc->batch_size; i++) { + wr_cdm_info = + &ope_dev_prepare_req->wr_cdm_batch->io_port_cdm[i]; + rd_cdm_info = + &ope_dev_prepare_req->rd_cdm_batch->io_port_cdm[i]; + for (j = 0; j < ope_request->num_stripes[i]; j++) { + /* cmd buffer stripes */ + kmd_buf = ope_create_stripe_cmd(hw_mgr, ctx_data, + kmd_buf, i, j, stripe_idx, frm_proc); + if (!kmd_buf) + goto end; + + /* WR stripes */ + kmd_buf = ope_create_stripe_wr(ctx_data, stripe_idx, + wr_cdm_info, ope_request, kmd_buf); + if (!kmd_buf) + goto end; + + /* RD stripes */ + kmd_buf = ope_create_stripe_rd(ctx_data, stripe_idx, + rd_cdm_info, ope_request, kmd_buf); + if (!kmd_buf) + goto end; + + /* add go command */ + kmd_buf = cdm_ops->cdm_write_indirect(kmd_buf, + (uint32_t)ope_request->ope_kmd_buf.iova_cdm_addr + + rd_cdm_info->go_cmd_offset, + rd_cdm_info->go_cmd_len); + + CAM_DBG(CAM_OPE, "Go cmd for stripe:%d kmd_buf:%x", + stripe_idx, kmd_buf); + CAM_DBG(CAM_OPE, "iova:%x %pK", + ope_request->ope_kmd_buf.iova_cdm_addr, + ope_request->ope_kmd_buf.iova_cdm_addr); + + /* wait for RUP done */ + kmd_buf = cdm_ops->cdm_write_wait_comp_event(kmd_buf, + OPE_WAIT_COMP_RUP, 0x0); + CAM_DBG(CAM_OPE, "wait RUP cmd stripe:%d kmd_buf:%x", + stripe_idx, kmd_buf); + stripe_idx++; + } + } +end: + return kmd_buf; +} + +static uint32_t *ope_create_stripes_nrt(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, uint32_t req_idx, + uint32_t *kmd_buf, + struct cam_ope_dev_prepare_req *ope_dev_prepare_req, + uint32_t kmd_buf_offset) +{ + int i, j; + struct cam_ope_request *ope_request; + 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; + uint32_t stripe_idx = 0; + struct cam_cdm_utils_ops *cdm_ops; + uint32_t len; + uint32_t *cdm_kmd_start_addr; + int num_nrt_stripes, num_arb; + + frm_proc = ope_dev_prepare_req->frame_process; + ope_request = ctx_data->req_list[req_idx]; + cdm_kmd_start_addr = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr + + (kmd_buf_offset / sizeof(len)); + num_nrt_stripes = ctx_data->ope_acquire.nrt_stripes_for_arb; + num_arb = ope_request->num_stripes[0] / + ctx_data->ope_acquire.nrt_stripes_for_arb; + if (ope_request->num_stripes[0] % + ctx_data->ope_acquire.nrt_stripes_for_arb) + num_arb++; + CAM_DBG(CAM_OPE, "Number of ARB for snap: %d", num_arb); + cdm_ops = ctx_data->ope_cdm.cdm_ops; + + /* Stripes */ + for (i = 0; i < frm_proc->batch_size; i++) { + wr_cdm_info = + &ope_dev_prepare_req->wr_cdm_batch->io_port_cdm[i]; + rd_cdm_info = + &ope_dev_prepare_req->rd_cdm_batch->io_port_cdm[i]; + for (j = 0; j < ope_request->num_stripes[i]; j++) { + CAM_DBG(CAM_OPE, "num_nrt_stripes = %d num_arb = %d", + num_nrt_stripes, num_arb); + if (!num_nrt_stripes) { + kmd_buf = cdm_ops->cdm_write_wait_comp_event( + kmd_buf, + OPE_WAIT_COMP_IDLE, 0x0); + len = (kmd_buf - cdm_kmd_start_addr) * + sizeof(uint32_t); + cam_ope_dev_prepare_cdm_request( + ope_dev_prepare_req->hw_mgr, + ope_dev_prepare_req->prepare_args, + ope_dev_prepare_req->ctx_data, + ope_dev_prepare_req->req_idx, + kmd_buf_offset, ope_dev_prepare_req, + len, true); + cdm_kmd_start_addr = kmd_buf; + kmd_buf_offset += len; + } + /* cmd buffer stripes */ + kmd_buf = ope_create_stripe_cmd(hw_mgr, ctx_data, + kmd_buf, i, j, stripe_idx, frm_proc); + if (!kmd_buf) + goto end; + + /* WR stripes */ + kmd_buf = ope_create_stripe_wr(ctx_data, stripe_idx, + wr_cdm_info, ope_request, kmd_buf); + if (!kmd_buf) + goto end; + + /* RD stripes */ + kmd_buf = ope_create_stripe_rd(ctx_data, stripe_idx, + rd_cdm_info, ope_request, kmd_buf); + if (!kmd_buf) + goto end; + + if (!num_nrt_stripes) { + /* For num_nrt_stripes create CDM BL with ARB */ + /* Add Frame level cmds in this condition */ + /* Frame 0 DB */ + kmd_buf = ope_create_frame_cmd(hw_mgr, + ctx_data, req_idx, + kmd_buf, OPE_CMD_BUF_DOUBLE_BUFFERED, + ope_dev_prepare_req); + if (!kmd_buf) + goto end; + + /* Frame 0 SB */ + kmd_buf = ope_create_frame_cmd(hw_mgr, + ctx_data, req_idx, + kmd_buf, OPE_CMD_BUF_SINGLE_BUFFERED, + ope_dev_prepare_req); + if (!kmd_buf) + goto end; + + /* Frame 0 WR */ + kmd_buf = ope_create_frame_wr(ctx_data, + wr_cdm_info, kmd_buf, ope_request); + if (!kmd_buf) + goto end; + + /* Frame 0 RD */ + kmd_buf = ope_create_frame_rd(ctx_data, + rd_cdm_info, kmd_buf, ope_request); + if (!kmd_buf) + goto end; + num_arb--; + num_nrt_stripes = + ctx_data->ope_acquire.nrt_stripes_for_arb; + } + // add go command + kmd_buf = cdm_ops->cdm_write_indirect(kmd_buf, + (uint32_t)ope_request->ope_kmd_buf.iova_cdm_addr + + rd_cdm_info->go_cmd_offset, + rd_cdm_info->go_cmd_len); + + CAM_DBG(CAM_OPE, "Go cmd for stripe:%d kmd_buf:%x", + stripe_idx, kmd_buf); + CAM_DBG(CAM_OPE, "iova:%x %pK", + ope_request->ope_kmd_buf.iova_cdm_addr, + ope_request->ope_kmd_buf.iova_cdm_addr); + + // wait for RUP done + kmd_buf = cdm_ops->cdm_write_wait_comp_event(kmd_buf, + OPE_WAIT_COMP_RUP, 0x0); + CAM_DBG(CAM_OPE, "wait RUP cmd stripe:%d kmd_buf:%x", + stripe_idx, kmd_buf); + stripe_idx++; + num_nrt_stripes--; + } + } +end: + return kmd_buf; +} + +static int cam_ope_dev_create_kmd_buf_nrt(struct cam_ope_hw_mgr *hw_mgr, + struct cam_hw_prepare_update_args *prepare_args, + struct cam_ope_ctx *ctx_data, uint32_t req_idx, + uint32_t kmd_buf_offset, + struct cam_ope_dev_prepare_req *ope_dev_prepare_req) +{ + int rc = 0; + uint32_t len; + struct cam_ope_request *ope_request; + uint32_t *kmd_buf; + uint32_t *cdm_kmd_start_addr; + 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; + struct cam_cdm_utils_ops *cdm_ops; + + frm_proc = ope_dev_prepare_req->frame_process; + ope_request = ctx_data->req_list[req_idx]; + kmd_buf = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr + + (kmd_buf_offset / sizeof(len)); + cdm_kmd_start_addr = kmd_buf; + 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]; + + cdm_ops = ctx_data->ope_cdm.cdm_ops; + + /* Frame 0 DB */ + kmd_buf = ope_create_frame_cmd(hw_mgr, + ctx_data, req_idx, + kmd_buf, OPE_CMD_BUF_DOUBLE_BUFFERED, + ope_dev_prepare_req); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Frame 0 SB */ + kmd_buf = ope_create_frame_cmd(hw_mgr, + ctx_data, req_idx, + kmd_buf, OPE_CMD_BUF_SINGLE_BUFFERED, + ope_dev_prepare_req); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Frame 0 WR */ + kmd_buf = ope_create_frame_wr(ctx_data, + wr_cdm_info, kmd_buf, ope_request); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Frame 0 RD */ + kmd_buf = ope_create_frame_rd(ctx_data, + rd_cdm_info, kmd_buf, ope_request); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Stripes */ + kmd_buf = ope_create_stripes_nrt(hw_mgr, ctx_data, req_idx, kmd_buf, + ope_dev_prepare_req, kmd_buf_offset); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Last arbitration if there are odd number of stripes */ + /* wait_idle_irq */ + kmd_buf = cdm_ops->cdm_write_wait_comp_event(kmd_buf, + OPE_WAIT_COMP_IDLE, 0x0); + + /* prepare CDM submit packet */ + len = (kmd_buf - cdm_kmd_start_addr) * sizeof(uint32_t); + cam_ope_dev_prepare_cdm_request(ope_dev_prepare_req->hw_mgr, + ope_dev_prepare_req->prepare_args, + ope_dev_prepare_req->ctx_data, ope_dev_prepare_req->req_idx, + kmd_buf_offset, ope_dev_prepare_req, + len, false); +end: + return rc; +} + +static int cam_ope_dev_create_kmd_buf_batch(struct cam_ope_hw_mgr *hw_mgr, + struct cam_hw_prepare_update_args *prepare_args, + struct cam_ope_ctx *ctx_data, uint32_t req_idx, + uint32_t kmd_buf_offset, + struct cam_ope_dev_prepare_req *ope_dev_prepare_req) +{ + int rc = 0, i; + uint32_t len; + struct cam_ope_request *ope_request; + uint32_t *kmd_buf; + uint32_t *cdm_kmd_start_addr; + 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; + struct cam_cdm_utils_ops *cdm_ops; + + frm_proc = ope_dev_prepare_req->frame_process; + ope_request = ctx_data->req_list[req_idx]; + kmd_buf = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr + + kmd_buf_offset; + cdm_kmd_start_addr = kmd_buf; + cdm_ops = ctx_data->ope_cdm.cdm_ops; + + for (i = 0; i < frm_proc->batch_size; i++) { + wr_cdm_info = + &ope_dev_prepare_req->wr_cdm_batch->io_port_cdm[i]; + rd_cdm_info = + &ope_dev_prepare_req->rd_cdm_batch->io_port_cdm[i]; + + /* 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, + OPE_WAIT_COMP_IDLE, 0x0); + } + + /* Frame i DB */ + kmd_buf = ope_create_frame_cmd_batch(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; + } + + /* Frame i SB */ + kmd_buf = ope_create_frame_cmd_batch(hw_mgr, + ctx_data, req_idx, + kmd_buf, OPE_CMD_BUF_SINGLE_BUFFERED, i, + ope_dev_prepare_req); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Frame i WR */ + kmd_buf = ope_create_frame_wr(ctx_data, + wr_cdm_info, kmd_buf, ope_request); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Frame i RD */ + kmd_buf = ope_create_frame_rd(ctx_data, + rd_cdm_info, kmd_buf, ope_request); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Stripe level programming for batch i */ + /* Stripes */ + kmd_buf = ope_create_stripes_batch(hw_mgr, ctx_data, req_idx, + kmd_buf, i, ope_dev_prepare_req); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + } + + /* wait_idle_irq */ + kmd_buf = cdm_ops->cdm_write_wait_comp_event(kmd_buf, + OPE_WAIT_COMP_IDLE, 0x0); + + /* prepare CDM submit packet */ + len = (cdm_kmd_start_addr - kmd_buf) * sizeof(uint32_t); + cam_ope_dev_prepare_cdm_request(ope_dev_prepare_req->hw_mgr, + ope_dev_prepare_req->prepare_args, + ope_dev_prepare_req->ctx_data, ope_dev_prepare_req->req_idx, + ope_dev_prepare_req->kmd_buf_offset, ope_dev_prepare_req, + len, false); + +end: + return rc; +} + +static int cam_ope_dev_create_kmd_buf(struct cam_ope_hw_mgr *hw_mgr, + struct cam_hw_prepare_update_args *prepare_args, + struct cam_ope_ctx *ctx_data, uint32_t req_idx, + uint32_t kmd_buf_offset, + struct cam_ope_dev_prepare_req *ope_dev_prepare_req) +{ + int rc = 0; + uint32_t len; + struct cam_ope_request *ope_request; + uint32_t *kmd_buf; + uint32_t *cdm_kmd_start_addr; + struct ope_bus_wr_io_port_cdm_info *wr_cdm_info; + struct ope_bus_rd_io_port_cdm_info *rd_cdm_info; + struct cam_cdm_utils_ops *cdm_ops; + + + if (ctx_data->ope_acquire.dev_type == OPE_DEV_TYPE_OPE_NRT) { + return cam_ope_dev_create_kmd_buf_nrt( + ope_dev_prepare_req->hw_mgr, + ope_dev_prepare_req->prepare_args, + ope_dev_prepare_req->ctx_data, + ope_dev_prepare_req->req_idx, + ope_dev_prepare_req->kmd_buf_offset, + ope_dev_prepare_req); + } + + if (ctx_data->ope_acquire.batch_size > 1) { + return cam_ope_dev_create_kmd_buf_batch( + ope_dev_prepare_req->hw_mgr, + ope_dev_prepare_req->prepare_args, + ope_dev_prepare_req->ctx_data, + ope_dev_prepare_req->req_idx, + ope_dev_prepare_req->kmd_buf_offset, + ope_dev_prepare_req); + } + + ope_request = ctx_data->req_list[req_idx]; + kmd_buf = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr + + (kmd_buf_offset / sizeof(len)); + cdm_kmd_start_addr = kmd_buf; + 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]; + + + CAM_DBG(CAM_OPE, "kmd_buf:%x req_idx:%d req_id:%lld offset:%d", + kmd_buf, req_idx, ope_request->request_id, kmd_buf_offset); + + /* Frame 0 DB */ + kmd_buf = ope_create_frame_cmd(hw_mgr, + ctx_data, req_idx, + kmd_buf, OPE_CMD_BUF_DOUBLE_BUFFERED, + ope_dev_prepare_req); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Frame 0 SB */ + kmd_buf = ope_create_frame_cmd(hw_mgr, + ctx_data, req_idx, + kmd_buf, OPE_CMD_BUF_SINGLE_BUFFERED, + ope_dev_prepare_req); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Frame 0 WR */ + kmd_buf = ope_create_frame_wr(ctx_data, + wr_cdm_info, kmd_buf, ope_request); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Frame 0 RD */ + kmd_buf = ope_create_frame_rd(ctx_data, + rd_cdm_info, kmd_buf, ope_request); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* Stripes */ + kmd_buf = ope_create_stripes(hw_mgr, ctx_data, req_idx, kmd_buf, + ope_dev_prepare_req); + if (!kmd_buf) { + rc = -EINVAL; + goto end; + } + + /* wait_idle_irq */ + kmd_buf = cdm_ops->cdm_write_wait_comp_event(kmd_buf, + OPE_WAIT_COMP_IDLE, 0x0); + + CAM_DBG(CAM_OPE, "wait for idle IRQ: kmd_buf:%x", kmd_buf); + + /* prepare CDM submit packet */ + len = (kmd_buf - cdm_kmd_start_addr) * sizeof(uint32_t); + CAM_DBG(CAM_OPE, "kmd_start_addr:%x kmdbuf_addr:%x len:%d", + cdm_kmd_start_addr, kmd_buf, len); + cam_ope_dev_prepare_cdm_request( + ope_dev_prepare_req->hw_mgr, + ope_dev_prepare_req->prepare_args, + ope_dev_prepare_req->ctx_data, + ope_dev_prepare_req->req_idx, + ope_dev_prepare_req->kmd_buf_offset, + ope_dev_prepare_req, + len, false); +end: + return rc; +} + +static int cam_ope_dev_process_prepare(struct ope_hw *ope_hw, void *cmd_args) +{ + int rc = 0; + struct cam_ope_dev_prepare_req *ope_dev_prepare_req; + + ope_dev_prepare_req = cmd_args; + + rc = cam_ope_top_process(ope_hw, ope_dev_prepare_req->ctx_data->ctx_id, + OPE_HW_PREPARE, ope_dev_prepare_req); + if (rc) + goto end; + + rc = cam_ope_bus_rd_process(ope_hw, + ope_dev_prepare_req->ctx_data->ctx_id, + OPE_HW_PREPARE, ope_dev_prepare_req); + if (rc) + goto end; + + rc = cam_ope_bus_wr_process(ope_hw, + ope_dev_prepare_req->ctx_data->ctx_id, + OPE_HW_PREPARE, ope_dev_prepare_req); + if (rc) + goto end; + + cam_ope_dev_create_kmd_buf(ope_dev_prepare_req->hw_mgr, + ope_dev_prepare_req->prepare_args, + ope_dev_prepare_req->ctx_data, ope_dev_prepare_req->req_idx, + ope_dev_prepare_req->kmd_buf_offset, ope_dev_prepare_req); + +end: + return rc; +} + +static int cam_ope_dev_process_probe(struct ope_hw *ope_hw, + void *cmd_args) +{ + cam_ope_top_process(ope_hw, -1, OPE_HW_PROBE, NULL); + cam_ope_bus_rd_process(ope_hw, -1, OPE_HW_PROBE, NULL); + cam_ope_bus_wr_process(ope_hw, -1, OPE_HW_PROBE, NULL); + + return 0; +} + +static int cam_ope_process_probe(struct ope_hw *ope_hw, + void *cmd_args, bool hfi_en) +{ + struct cam_ope_dev_probe *ope_probe = cmd_args; + + if (!ope_probe->hfi_en) + return cam_ope_dev_process_probe(ope_hw, cmd_args); + + return -EINVAL; +} + +static int cam_ope_process_reset(struct ope_hw *ope_hw, + void *cmd_args, bool hfi_en) +{ + if (!hfi_en) + return cam_ope_dev_process_reset(ope_hw, cmd_args); + + return -EINVAL; +} + +static int cam_ope_process_release(struct ope_hw *ope_hw, + void *cmd_args, bool hfi_en) +{ + if (!hfi_en) + return cam_ope_dev_process_release(ope_hw, cmd_args); + + return -EINVAL; +} + +static int cam_ope_process_acquire(struct ope_hw *ope_hw, + void *cmd_args, bool hfi_en) +{ + if (!hfi_en) + return cam_ope_dev_process_acquire(ope_hw, cmd_args); + + return -EINVAL; +} + +static int cam_ope_process_prepare(struct ope_hw *ope_hw, + void *cmd_args, bool hfi_en) +{ + if (!hfi_en) + return cam_ope_dev_process_prepare(ope_hw, cmd_args); + + return -EINVAL; +} + +int cam_ope_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + 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 ope_hw *ope_hw; + bool hfi_en; + unsigned long flags; + + if (!device_priv) { + CAM_ERR(CAM_OPE, "Invalid args %x for cmd %u", + device_priv, cmd_type); + return -EINVAL; + } + + soc_info = &ope_dev->soc_info; + core_info = (struct cam_ope_device_core_info *)ope_dev->core_info; + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_OPE, "soc_info = %x core_info = %x", + soc_info, core_info); + return -EINVAL; + } + + hfi_en = core_info->ope_hw_info->hfi_en; + ope_hw = core_info->ope_hw_info->ope_hw; + if (!ope_hw) { + CAM_ERR(CAM_OPE, "Invalid ope hw info"); + return -EINVAL; + } + + switch (cmd_type) { + case OPE_HW_PROBE: + rc = cam_ope_process_probe(ope_hw, cmd_args, hfi_en); + break; + case OPE_HW_ACQUIRE: + rc = cam_ope_process_acquire(ope_hw, cmd_args, hfi_en); + break; + case OPE_HW_RELEASE: + rc = cam_ope_process_release(ope_hw, cmd_args, hfi_en); + break; + case OPE_HW_PREPARE: + rc = cam_ope_process_prepare(ope_hw, cmd_args, hfi_en); + break; + case OPE_HW_START: + break; + case OPE_HW_STOP: + break; + case OPE_HW_FLUSH: + break; + case OPE_HW_RESET: + rc = cam_ope_process_reset(ope_hw, cmd_args, hfi_en); + break; + case OPE_HW_CLK_UPDATE: { + struct cam_ope_dev_clk_update *clk_upd_cmd = + (struct cam_ope_dev_clk_update *)cmd_args; + + rc = cam_ope_update_clk_rate(soc_info, clk_upd_cmd->clk_rate); + if (rc) + CAM_ERR(CAM_OPE, "Failed to update clk: %d", rc); + } + break; + case OPE_HW_BW_UPDATE: { + struct cam_ope_dev_bw_update *cpas_vote = cmd_args; + + if (!cmd_args) + return -EINVAL; + + rc = cam_ope_caps_vote(core_info, cpas_vote); + if (rc) + CAM_ERR(CAM_OPE, "failed to update bw: %d", rc); + } + break; + case OPE_HW_SET_IRQ_CB: { + struct cam_ope_set_irq_cb *irq_cb = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_OPE, "cmd args NULL"); + return -EINVAL; + } + + spin_lock_irqsave(&ope_dev->hw_lock, flags); + core_info->irq_cb.ope_hw_mgr_cb = irq_cb->ope_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + spin_unlock_irqrestore(&ope_dev->hw_lock, flags); + } + break; + default: + break; + } + + return rc; +} + +irqreturn_t cam_ope_irq(int irq_num, void *data) +{ + struct cam_hw_info *ope_dev = data; + struct cam_ope_device_core_info *core_info = NULL; + struct ope_hw *ope_hw; + struct cam_ope_irq_data irq_data; + + if (!data) { + CAM_ERR(CAM_OPE, "Invalid cam_dev_info or query_cap args"); + return IRQ_HANDLED; + } + + core_info = (struct cam_ope_device_core_info *)ope_dev->core_info; + ope_hw = core_info->ope_hw_info->ope_hw; + + irq_data.error = 0; + cam_ope_top_process(ope_hw, 0, OPE_HW_ISR, &irq_data); + cam_ope_bus_rd_process(ope_hw, 0, OPE_HW_ISR, &irq_data); + cam_ope_bus_wr_process(ope_hw, 0, OPE_HW_ISR, &irq_data); + + + spin_lock(&ope_dev->hw_lock); + if (core_info->irq_cb.ope_hw_mgr_cb && core_info->irq_cb.data) + if (irq_data.error) + core_info->irq_cb.ope_hw_mgr_cb(irq_data.error, + core_info->irq_cb.data); + spin_unlock(&ope_dev->hw_lock); + + + return IRQ_HANDLED; +} diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.h b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.h new file mode 100644 index 000000000000..cc0bfd89fc27 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_OPE_CORE_H +#define CAM_OPE_CORE_H + +#include +#include +#include +#include +#include +#include +#include "cam_cpas_api.h" +#include "ope_hw.h" +#include "ope_dev_intf.h" +/** + * struct cam_ope_cpas_vote + * @ahb_vote: AHB vote info + * @axi_vote: AXI vote info + * @ahb_vote_valid: Flag for ahb vote data + * @axi_vote_valid: flag for axi vote data + */ +struct cam_ope_cpas_vote { + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote; + uint32_t ahb_vote_valid; + uint32_t axi_vote_valid; +}; + +/** + * struct cam_ope_device_hw_info + * + * @ope_hw: OPE hardware + * @hw_idx: Hardware index + * @ope_cdm_base: Base address of CDM + * @ope_top_base: Base address of top + * @ope_qos_base: Base address of QOS + * @ope_pp_base: Base address of PP + * @ope_bus_rd_base: Base address of RD + * @ope_bus_wr_base: Base address of WM + * @hfi_en: HFI flag enable + * @reserved: Reserved + */ +struct cam_ope_device_hw_info { + struct ope_hw *ope_hw; + uint32_t hw_idx; + void *ope_cdm_base; + void *ope_top_base; + void *ope_qos_base; + void *ope_pp_base; + void *ope_bus_rd_base; + void *ope_bus_wr_base; + bool hfi_en; + uint32_t reserved; +}; + +/** + * struct cam_ope_device_core_info + * + * @ope_hw_info: OPE hardware info + * @hw_version: Hardware version + * @hw_idx: Hardware Index + * @hw_type: Hardware Type + * @cpas_handle: CPAS Handle + * @cpas_start: CPAS start flag + * @clk_enable: Clock enable flag + * @irq_cb: IRQ Callback + */ +struct cam_ope_device_core_info { + struct cam_ope_device_hw_info *ope_hw_info; + uint32_t hw_version; + uint32_t hw_idx; + uint32_t hw_type; + uint32_t cpas_handle; + bool cpas_start; + bool clk_enable; + struct cam_ope_set_irq_cb irq_cb; +}; + + +int cam_ope_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_ope_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_ope_start(void *device_priv, + void *start_args, uint32_t arg_size); +int cam_ope_stop(void *device_priv, + void *stop_args, uint32_t arg_size); +int cam_ope_flush(void *device_priv, + void *flush_args, uint32_t arg_size); +int cam_ope_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size); +int cam_ope_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +irqreturn_t cam_ope_irq(int irq_num, void *data); + +#endif /* CAM_OPE_CORE_H */ diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c new file mode 100644 index 000000000000..c6351100e85f --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "ope_core.h" +#include "ope_soc.h" +#include "cam_hw.h" +#include "ope_hw.h" +#include "cam_hw_intf.h" +#include "cam_io_util.h" +#include "cam_ope_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "ope_hw_100.h" +#include "ope_dev_intf.h" + +static struct cam_ope_device_hw_info ope_hw_info; +static struct ope_dev_soc ope_soc_info; +EXPORT_SYMBOL(ope_soc_info); + +static struct hw_version_reg ope_hw_version_reg = { + .hw_ver = 0x0, +}; + +static char ope_dev_name[8]; + +static int cam_ope_init_hw_version(struct cam_hw_soc_info *soc_info, + struct cam_ope_device_core_info *core_info) +{ + int rc = 0; + + CAM_DBG(CAM_OPE, "soc_info = %x core_info = %x", + soc_info, core_info); + CAM_DBG(CAM_OPE, "CDM:%x TOP: %x QOS: %x PP: %x RD: %x WR: %x", + soc_info->reg_map[OPE_CDM_BASE].mem_base, + soc_info->reg_map[OPE_TOP_BASE].mem_base, + soc_info->reg_map[OPE_QOS_BASE].mem_base, + soc_info->reg_map[OPE_PP_BASE].mem_base, + soc_info->reg_map[OPE_BUS_RD].mem_base, + soc_info->reg_map[OPE_BUS_WR].mem_base); + CAM_DBG(CAM_OPE, "core: %x", + core_info->ope_hw_info->ope_cdm_base); + + core_info->ope_hw_info->ope_cdm_base = + soc_info->reg_map[OPE_CDM_BASE].mem_base; + core_info->ope_hw_info->ope_top_base = + soc_info->reg_map[OPE_TOP_BASE].mem_base; + core_info->ope_hw_info->ope_qos_base = + soc_info->reg_map[OPE_QOS_BASE].mem_base; + core_info->ope_hw_info->ope_pp_base = + soc_info->reg_map[OPE_PP_BASE].mem_base; + core_info->ope_hw_info->ope_bus_rd_base = + soc_info->reg_map[OPE_BUS_RD].mem_base; + core_info->ope_hw_info->ope_bus_wr_base = + soc_info->reg_map[OPE_BUS_WR].mem_base; + + core_info->hw_version = cam_io_r_mb( + core_info->ope_hw_info->ope_top_base + + ope_hw_version_reg.hw_ver); + + switch (core_info->hw_version) { + case OPE_HW_VER_1_0_0: + core_info->ope_hw_info->ope_hw = &ope_hw_100; + break; + default: + CAM_ERR(CAM_OPE, "Unsupported version : %u", + core_info->hw_version); + rc = -EINVAL; + break; + } + + ope_hw_100.top_reg->base = core_info->ope_hw_info->ope_top_base; + ope_hw_100.bus_rd_reg->base = core_info->ope_hw_info->ope_bus_rd_base; + ope_hw_100.bus_wr_reg->base = core_info->ope_hw_info->ope_bus_wr_base; + + return rc; +} + +int cam_ope_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_ope_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = &soc_info->pdev->dev; + memcpy(cpas_register_params.identifier, "ope", sizeof("ope")); + cpas_register_params.cam_cpas_client_cb = NULL; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc < 0) { + CAM_ERR(CAM_OPE, "failed: %d", rc); + return rc; + } + core_info->cpas_handle = cpas_register_params.client_handle; + + return rc; +} + +int cam_ope_probe(struct platform_device *pdev) +{ + struct cam_hw_intf *ope_dev_intf = NULL; + struct cam_hw_info *ope_dev = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_ope_device_core_info *core_info = NULL; + int rc = 0; + uint32_t hw_idx; + struct cam_ope_dev_probe ope_probe; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &hw_idx); + + ope_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!ope_dev_intf) + return -ENOMEM; + + ope_dev_intf->hw_idx = hw_idx; + ope_dev_intf->hw_type = OPE_DEV_OPE; + ope_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!ope_dev) { + rc = -ENOMEM; + goto ope_dev_alloc_failed; + } + + memset(ope_dev_name, 0, sizeof(ope_dev_name)); + snprintf(ope_dev_name, sizeof(ope_dev_name), + "ope%1u", ope_dev_intf->hw_idx); + + ope_dev->soc_info.pdev = pdev; + ope_dev->soc_info.dev = &pdev->dev; + ope_dev->soc_info.dev_name = ope_dev_name; + ope_dev_intf->hw_priv = ope_dev; + ope_dev_intf->hw_ops.init = cam_ope_init_hw; + ope_dev_intf->hw_ops.deinit = cam_ope_deinit_hw; + ope_dev_intf->hw_ops.get_hw_caps = cam_ope_get_hw_caps; + ope_dev_intf->hw_ops.start = cam_ope_start; + ope_dev_intf->hw_ops.stop = cam_ope_stop; + ope_dev_intf->hw_ops.flush = cam_ope_flush; + ope_dev_intf->hw_ops.process_cmd = cam_ope_process_cmd; + + CAM_DBG(CAM_OPE, "type %d index %d", + ope_dev_intf->hw_type, + ope_dev_intf->hw_idx); + + platform_set_drvdata(pdev, ope_dev_intf); + + ope_dev->core_info = kzalloc(sizeof(struct cam_ope_device_core_info), + GFP_KERNEL); + if (!ope_dev->core_info) { + rc = -ENOMEM; + goto ope_core_alloc_failed; + } + core_info = (struct cam_ope_device_core_info *)ope_dev->core_info; + core_info->ope_hw_info = &ope_hw_info; + ope_dev->soc_info.soc_private = &ope_soc_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + rc = -EINVAL; + CAM_DBG(CAM_OPE, "No ope hardware info"); + goto ope_match_dev_failed; + } + + rc = cam_ope_init_soc_resources(&ope_dev->soc_info, cam_ope_irq, + ope_dev); + if (rc < 0) { + CAM_ERR(CAM_OPE, "failed to init_soc"); + goto init_soc_failed; + } + + rc = cam_ope_enable_soc_resources(&ope_dev->soc_info); + if (rc < 0) { + CAM_ERR(CAM_OPE, "enable soc resorce failed: %d", rc); + goto enable_soc_failed; + } + + rc = cam_ope_init_hw_version(&ope_dev->soc_info, ope_dev->core_info); + if (rc) + goto init_hw_failure; + + core_info->hw_type = OPE_DEV_OPE; + core_info->hw_idx = hw_idx; + rc = cam_ope_register_cpas(&ope_dev->soc_info, + core_info, ope_dev_intf->hw_idx); + if (rc < 0) + goto register_cpas_failed; + + cam_ope_disable_soc_resources(&ope_dev->soc_info, true); + ope_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + + ope_probe.hfi_en = ope_soc_info.hfi_en; + cam_ope_process_cmd(ope_dev, OPE_HW_PROBE, + &ope_probe, sizeof(ope_probe)); + mutex_init(&ope_dev->hw_mutex); + spin_lock_init(&ope_dev->hw_lock); + init_completion(&ope_dev->hw_complete); + + CAM_DBG(CAM_OPE, "OPE%d probe successful", + ope_dev_intf->hw_idx); + return rc; + +init_hw_failure: +enable_soc_failed: +register_cpas_failed: +init_soc_failed: +ope_match_dev_failed: + kfree(ope_dev->core_info); +ope_core_alloc_failed: + kfree(ope_dev); +ope_dev_alloc_failed: + kfree(ope_dev_intf); + return rc; +} + +static const struct of_device_id cam_ope_dt_match[] = { + { + .compatible = "qcom,ope", + .data = &ope_hw_version_reg, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_ope_dt_match); + +static struct platform_driver cam_ope_driver = { + .probe = cam_ope_probe, + .driver = { + .name = "ope", + .of_match_table = cam_ope_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_ope_init_module(void) +{ + return platform_driver_register(&cam_ope_driver); +} + +static void __exit cam_ope_exit_module(void) +{ + platform_driver_unregister(&cam_ope_driver); +} + +module_init(cam_ope_init_module); +module_exit(cam_ope_exit_module); +MODULE_DESCRIPTION("CAM OPE driver"); +MODULE_LICENSE("GPL v2"); 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 new file mode 100644 index 000000000000..565a1696c84b --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev_intf.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_OPE_DEV_INTF_H +#define CAM_OPE_DEV_INTF_H + +#include +#include "cam_ope_hw_mgr.h" +#include "cam_cdm_intf_api.h" +#include "cam_cpas_api.h" + + +#define OPE_HW_INIT 0x1 +#define OPE_HW_DEINIT 0x2 +#define OPE_HW_ACQUIRE 0x3 +#define OPE_HW_RELEASE 0x4 +#define OPE_HW_START 0x5 +#define OPE_HW_STOP 0x6 +#define OPE_HW_FLUSH 0x7 +#define OPE_HW_PREPARE 0x8 +#define OPE_HW_ISR 0x9 +#define OPE_HW_PROBE 0xA +#define OPE_HW_CLK_UPDATE 0xB +#define OPE_HW_BW_UPDATE 0xC +#define OPE_HW_RESET 0xD +#define OPE_HW_SET_IRQ_CB 0xE + +/** + * struct cam_ope_dev_probe + * + * @hfi_en: HFI enable flag + */ +struct cam_ope_dev_probe { + bool hfi_en; +}; + +/** + * struct cam_ope_dev_init + * + * @hfi_en: HFI enable flag + * @core_info: OPE core info + */ +struct cam_ope_dev_init { + bool hfi_en; + struct cam_ope_device_core_info *core_info; +}; + +/** + * struct cam_ope_dev_clk_update + * + * @clk_rate: Clock rate + */ +struct cam_ope_dev_clk_update { + uint32_t clk_rate; +}; + +/** + * struct cam_ope_dev_bw_update + * + * @ahb_vote: AHB vote info + * @axi_vote: AXI vote info + * @ahb_vote_valid: Flag for ahb vote + * @axi_vote_valid: Flag for axi vote + */ +struct cam_ope_dev_bw_update { + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote; + uint32_t ahb_vote_valid; + uint32_t axi_vote_valid; +}; + +/** + * struct cam_ope_dev_caps + * + * @hw_idx: Hardware index + * @hw_ver: Hardware version info + */ +struct cam_ope_dev_caps { + uint32_t hw_idx; + struct ope_hw_ver hw_ver; +}; + +/** + * struct cam_ope_dev_acquire + * + * @ctx_id: Context id + * @ope_acquire: OPE acquire info + * @bus_wr_ctx: Bus Write context + * @bus_rd_ctx: Bus Read context + */ +struct cam_ope_dev_acquire { + uint32_t ctx_id; + struct ope_acquire_dev_info *ope_acquire; + struct ope_bus_wr_ctx *bus_wr_ctx; + struct ope_bus_rd_ctx *bus_rd_ctx; +}; + +/** + * struct cam_ope_dev_release + * + * @ctx_id: Context id + * @bus_wr_ctx: Bus Write context + * @bus_rd_ctx: Bus Read context + */ +struct cam_ope_dev_release { + uint32_t ctx_id; + struct ope_bus_wr_ctx *bus_wr_ctx; + struct ope_bus_rd_ctx *bus_rd_ctx; +}; + +/** + * struct cam_ope_set_irq_cb + * + * @ope_hw_mgr_cb: Callback to hardware manager + * @data: Private data + */ +struct cam_ope_set_irq_cb { + int32_t (*ope_hw_mgr_cb)(uint32_t irq_status, void *data); + void *data; +}; + +/** + * struct cam_ope_irq_data + * + * @error: IRQ error + */ +struct cam_ope_irq_data { + uint32_t error; +}; + +/** + * struct cam_ope_dev_prepare_req + * + * @hw_mgr: OPE hardware manager + * @packet: Packet + * @prepare_args: Prepare request args + * @ctx_data: Context data + * @wr_cdm_batch: WM request + * @rd_cdm_batch: RD master request + * @frame_process: Frame process command + * @req_idx: Request Index + * @kmd_buf_offset: KMD buffer offset + */ +struct cam_ope_dev_prepare_req { + struct cam_ope_hw_mgr *hw_mgr; + struct cam_packet *packet; + struct cam_hw_prepare_update_args *prepare_args; + struct cam_ope_ctx *ctx_data; + struct ope_bus_wr_io_port_cdm_batch *wr_cdm_batch; + struct ope_bus_rd_io_port_cdm_batch *rd_cdm_batch; + struct ope_frame_process *frame_process; + uint32_t req_idx; + uint32_t kmd_buf_offset; +}; + +int cam_ope_top_process(struct ope_hw *ope_hw_info, + int32_t ctx_id, uint32_t cmd_id, void *data); + +int cam_ope_bus_rd_process(struct ope_hw *ope_hw_info, + int32_t ctx_id, uint32_t cmd_id, void *data); + +int cam_ope_bus_wr_process(struct ope_hw *ope_hw_info, + int32_t ctx_id, uint32_t cmd_id, void *data); + +#endif /* CAM_OPE_DEV_INTF_H */ + 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 new file mode 100644 index 000000000000..55e2ab21b039 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h @@ -0,0 +1,399 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_OPE_HW_H +#define CAM_OPE_HW_H + +#define OPE_HW_VER_1_0_0 0x10000000 + +#define OPE_DEV_OPE 0 +#define OPE_DEV_MAX 1 + +#define MAX_RD_CLIENTS 2 +#define MAX_WR_CLIENTS 8 + +#define OPE_CDM_BASE 0x0 +#define OPE_TOP_BASE 0x1 +#define OPE_QOS_BASE 0x2 +#define OPE_PP_BASE 0x3 +#define OPE_BUS_RD 0x4 +#define OPE_BUS_WR 0x5 +#define OPE_BASE_MAX 0x6 + + +#define BUS_RD_COMBO_BAYER_MASK 0x1 +#define BUS_RD_COMBO_YUV_MASK 0x2 +#define BUS_RD_COMBO_MAX 0x2 + +#define BUS_RD_BAYER 0x0 +#define BUS_RD_YUV 0x1 + +#define BUS_WR_COMBO_YUV_MASK 0x1 +#define BUS_WR_COMBO_MAX 0x1 + +#define BUS_WR_YUV 0x0 + +#define BUS_WR_VIDEO_Y 0x0 +#define BUS_WR_VIDEO_C 0x1 +#define BUS_WR_DISP_Y 0x2 +#define BUS_WR_DISP_C 0x3 +#define BUS_WR_ARGB 0x4 +#define BUS_WR_STATS_RS 0x5 +#define BUS_WR_STATS_IHIST 0x6 +#define BUS_WR_STATS_LTM 0x7 + +#define OPE_WAIT_COMP_RUP 0x1 +#define OPE_WAIT_COMP_WR_DONE 0x2 +#define OPE_WAIT_COMP_IDLE 0x4 +#define OPE_WAIT_COMP_GEN_IRQ 0x8 + +struct cam_ope_common { + uint32_t mode[CAM_FORMAT_MAX]; +}; + +struct cam_ope_top_reg { + void *base; + uint32_t offset; + uint32_t hw_version; + uint32_t reset_cmd; + uint32_t core_clk_cfg_ctrl_0; + uint32_t ahb_clk_cgc_ctrl; + uint32_t core_cfg; + uint32_t irq_status; + uint32_t irq_mask; + uint32_t irq_clear; + uint32_t irq_set; + uint32_t irq_cmd; + uint32_t violation_status; + uint32_t throttle_cnt_cfg; +}; + +struct cam_ope_top_reg_val { + uint32_t hw_version; + uint32_t major_mask; + uint32_t major_shift; + uint32_t minor_mask; + uint32_t minor_shift; + uint32_t incr_mask; + uint32_t incr_shift; + uint32_t irq_mask; + uint32_t irq_set_clear; + uint32_t sw_reset_cmd; + uint32_t hw_reset_cmd; + uint32_t core_clk_cfg_ctrl_0; + uint32_t ahb_clk_cgc_ctrl; + uint32_t input_format; + uint32_t input_format_mask; + uint32_t color_correct_src_sel; + uint32_t color_correct_src_sel_mask; + uint32_t stats_ihist_src_sel; + uint32_t stats_ihist_src_sel_mask; + uint32_t chroma_up_src_sel; + uint32_t chroma_up_src_sel_mask; + uint32_t argb_alpha; + uint32_t argb_alpha_mask; + uint32_t rs_throttle_cnt; + uint32_t rs_throttle_cnt_mask; + uint32_t ihist_throttle_cnt; + uint32_t ihist_throttle_cnt_mask; + uint32_t rst_done; + uint32_t we_done; + uint32_t fe_done; + uint32_t ope_violation; + uint32_t idle; +}; + +struct cam_ope_qos_reg { + void *base; + uint32_t offset; + uint32_t hw_version; + uint32_t hw_status; + uint32_t module_cfg; + uint32_t curve_cfg_0; + uint32_t curve_cfg_1; + uint32_t window_cfg; + uint32_t eos_status_0; + uint32_t eos_status_1; + uint32_t eos_status_2; +}; + +struct cam_ope_qos_reg_val { + uint32_t hw_version; + uint32_t proc_interval; + uint32_t proc_interval_mask; + uint32_t static_health; + uint32_t static_health_mask; + uint32_t module_cfg_en; + uint32_t module_cfg_en_mask; + uint32_t yexp_ymin_dec; + uint32_t yexp_ymin_dec_mask; + uint32_t ymin_inc; + uint32_t ymin_inc_mask; + uint32_t initial_delta; + uint32_t initial_delta_mask; + uint32_t window_cfg; +}; + +struct cam_ope_bus_rd_client_reg { + uint32_t core_cfg; + uint32_t ccif_meta_data; + uint32_t img_addr; + uint32_t img_cfg; + uint32_t stride; + uint32_t unpack_cfg; + uint32_t latency_buf_allocation; + uint32_t misr_cfg_0; + uint32_t misr_cfg_1; + uint32_t misr_rd_val; +}; + +struct cam_ope_bus_rd_reg { + void *base; + uint32_t offset; + uint32_t hw_version; + uint32_t sw_reset; + uint32_t cgc_override; + uint32_t irq_mask; + uint32_t irq_clear; + uint32_t irq_cmd; + uint32_t irq_status; + uint32_t input_if_cmd; + uint32_t irq_set; + uint32_t misr_reset; + uint32_t security_cfg; + uint32_t iso_cfg; + uint32_t iso_seed; + + uint32_t num_clients; + struct cam_ope_bus_rd_client_reg rd_clients[MAX_RD_CLIENTS]; +}; + +struct cam_ope_bus_rd_client_reg_val { + uint32_t core_cfg; + uint32_t stripe_location; + uint32_t stripe_location_mask; + uint32_t stripe_location_shift; + uint32_t pix_pattern; + uint32_t pix_pattern_mask; + uint32_t pix_pattern_shift; + uint32_t img_addr; + uint32_t img_width; + uint32_t img_width_mask; + uint32_t img_width_shift; + uint32_t img_height; + uint32_t img_height_mask; + uint32_t img_height_shift; + uint32_t stride; + uint32_t mode; + uint32_t mode_mask; + uint32_t mode_shift; + uint32_t alignment; + uint32_t alignment_mask; + uint32_t alignment_shift; + uint32_t latency_buf_allocation; + uint32_t misr_cfg_samp_mode; + uint32_t misr_cfg_samp_mode_mask; + uint32_t misr_cfg_en; + uint32_t misr_cfg_en_mask; + uint32_t misr_cfg_1; + uint32_t misr_rd_val; + uint32_t input_port_id; + uint32_t rm_port_id; + uint32_t format_type; + uint32_t num_combos_supported; +}; + +struct cam_ope_bus_rd_reg_val { + uint32_t hw_version; + uint32_t sw_reset; + uint32_t cgc_override; + uint32_t irq_mask; + uint32_t go_cmd; + uint32_t go_cmd_mask; + uint32_t ica_en; + uint32_t ica_en_mask; + uint32_t static_prg; + uint32_t static_prg_mask; + uint32_t go_cmd_sel; + uint32_t go_cmd_sel_mask; + uint32_t fs_sync_en; + uint32_t fs_sync_en_mask; + uint32_t misr_reset; + uint32_t security_cfg; + uint32_t iso_bpp_select; + uint32_t iso_bpp_select_mask; + uint32_t iso_pattern_select; + uint32_t iso_pattern_select_mask; + uint32_t iso_en; + uint32_t iso_en_mask; + uint32_t iso_seed; + uint32_t irq_set_clear; + uint32_t rst_done; + uint32_t rup_done; + uint32_t rd_buf_done; + uint32_t violation; + uint32_t latency_buf_size; + + uint32_t num_clients; + struct cam_ope_bus_rd_client_reg_val rd_clients[MAX_RD_CLIENTS]; +}; + +struct cam_ope_bus_wr_client_reg { + uint32_t core_cfg; + uint32_t img_addr; + uint32_t img_cfg; + uint32_t x_init; + uint32_t stride; + uint32_t pack_cfg; + uint32_t bw_limit; + uint32_t frame_header_addr; + uint32_t subsample_period; + uint32_t subsample_pattern; +}; + +struct cam_ope_bus_wr_reg { + void *base; + uint32_t offset; + uint32_t hw_version; + uint32_t cgc_override; + uint32_t irq_mask_0; + uint32_t irq_mask_1; + uint32_t irq_clear_0; + uint32_t irq_clear_1; + uint32_t irq_status_0; + uint32_t irq_status_1; + uint32_t irq_cmd; + uint32_t frame_header_cfg_0; + uint32_t local_frame_header_cfg_0; + uint32_t irq_set_0; + uint32_t irq_set_1; + uint32_t iso_cfg; + uint32_t violation_status; + uint32_t image_size_violation_status; + uint32_t misr_cfg_0; + uint32_t misr_cfg_1; + uint32_t misr_rd_sel; + uint32_t misr_reset; + uint32_t misr_val; + uint32_t num_clients; + struct cam_ope_bus_wr_client_reg wr_clients[MAX_WR_CLIENTS]; +}; + +struct cam_ope_bus_wr_client_reg_val { + uint32_t core_cfg_en; + uint32_t core_cfg_en_mask; + uint32_t core_cfg_en_shift; + uint32_t virtual_frame_en; + uint32_t virtual_frame_en_mask; + uint32_t virtual_frame_en_shift; + uint32_t frame_header_en; + uint32_t frame_header_en_mask; + uint32_t frame_header_en_shift; + uint32_t auto_recovery_en; + uint32_t auto_recovery_en_mask; + uint32_t auto_recovery_en_shift; + uint32_t mode; + uint32_t mode_mask; + uint32_t mode_shift; + uint32_t img_addr; + uint32_t width; + uint32_t width_mask; + uint32_t width_shift; + uint32_t height; + uint32_t height_mask; + uint32_t height_shift; + uint32_t x_init; + uint32_t stride; + uint32_t format; + uint32_t format_mask; + uint32_t format_shift; + uint32_t alignment; + uint32_t alignment_mask; + uint32_t alignment_shift; + uint32_t bw_limit_en; + uint32_t bw_limit_en_mask; + uint32_t bw_limit_counter; + uint32_t bw_limit_counter_mask; + uint32_t frame_header_addr; + uint32_t subsample_period; + uint32_t subsample_pattern; + uint32_t output_port_id; + uint32_t wm_port_id; + uint32_t format_type; + uint32_t num_combos_supported; +}; + +struct cam_ope_bus_wr_reg_val { + uint32_t hw_version; + uint32_t cgc_override; + uint32_t irq_mask_0; + uint32_t irq_mask_1; + uint32_t irq_set_clear; + uint32_t comp_rup_done; + uint32_t comp_buf_done; + uint32_t cons_violation; + uint32_t violation; + uint32_t img_size_violation; + uint32_t frame_header_cfg_0; + uint32_t local_frame_header_cfg_0; + uint32_t iso_cfg; + uint32_t misr_0_en; + uint32_t misr_0_en_mask; + uint32_t misr_1_en; + uint32_t misr_1_en_mask; + uint32_t misr_2_en; + uint32_t misr_2_en_mask; + uint32_t misr_3_en; + uint32_t misr_3_en_mask; + uint32_t misr_0_samp_mode; + uint32_t misr_0_samp_mode_mask; + uint32_t misr_1_samp_mode; + uint32_t misr_1_samp_mode_mask; + uint32_t misr_2_samp_mode; + uint32_t misr_2_samp_mode_mask; + uint32_t misr_3_samp_mode; + uint32_t misr_3_samp_mode_mask; + uint32_t misr_0_id; + uint32_t misr_0_id_mask; + uint32_t misr_1_id; + uint32_t misr_1_id_mask; + uint32_t misr_2_id; + uint32_t misr_2_id_mask; + uint32_t misr_3_id; + uint32_t misr_3_id_mask; + uint32_t misr_rd_misr_sel; + uint32_t misr_rd_misr_sel_mask; + uint32_t misr_rd_word_sel; + uint32_t misr_rd_word_sel_mask; + uint32_t misr_reset; + uint32_t misr_val; + + + uint32_t num_clients; + struct cam_ope_bus_wr_client_reg_val wr_clients[MAX_WR_CLIENTS]; +}; + +struct ope_hw { + struct cam_ope_top_reg *top_reg; + struct cam_ope_top_reg_val *top_reg_val; + + struct cam_ope_bus_rd_reg *bus_rd_reg; + struct cam_ope_bus_rd_reg_val *bus_rd_reg_val; + + struct cam_ope_bus_wr_reg *bus_wr_reg; + struct cam_ope_bus_wr_reg_val *bus_wr_reg_val; + + struct cam_ope_qos_reg *qos_reg; + struct cam_ope_qos_reg_val *qos_reg_val; + + struct cam_ope_common *common; +}; + +struct hw_version_reg { + uint32_t hw_ver; + uint32_t reserved; +}; + +#endif /* CAM_OPE_HW_H */ 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 new file mode 100644 index 000000000000..34548e7cac1d --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h @@ -0,0 +1,532 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_OPE_HW_100_H +#define CAM_OPE_HW_100_H + +#define OPE_BUS_RD_TYPE_BAYER 0x0 +#define OPE_BUS_RD_TYPE_YUV_Y 0x0 +#define OPE_BUS_RD_TYPE_YUC_C 0x1 + +#define OPE_BUS_WR_TYPE_VID_Y 0x0 +#define OPE_BUS_WR_TYPE_VID_C 0x1 +#define OPE_BUS_WR_TYPE_DISP_Y 0x2 +#define OPE_BUS_WR_TYPE_DISP_C 0x3 +#define OPE_BUS_WR_TYPE_ARGB 0x4 +#define OPE_BUS_WR_TYPE_RS 0x5 +#define OPE_BUS_WR_TYPE_IHIST 0x6 +#define OPE_BUS_WR_TYPE_LTM 0x7 + +enum cam_ope_bus_rd_unpacker_format { + BUS_RD_VER1_PACKER_FMT_PLAIN_128_BYPASS = 0x0, + BUS_RD_VER1_PACKER_FMT_PLAIN_8 = 0x1, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_10BPP = 0x2, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_12BPP = 0x3, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_14BPP = 0x4, + BUS_RD_VER1_PACKER_FMT_PLAIN_32_20BPP = 0x5, + BUS_RD_VER1_PACKER_FMT_ARGB16_10 = 0x6, + BUS_RD_VER1_PACKER_FMT_ARGB16_12 = 0x7, + BUS_RD_VER1_PACKER_FMT_ARGB16_14 = 0x8, + BUS_RD_VER1_PACKER_FMT_PLAIN_32 = 0x9, + BUS_RD_VER1_PACKER_FMT_PLAIN_64 = 0xA, + BUS_RD_VER1_PACKER_FMT_TP_10 = 0xB, + BUS_RD_VER1_PACKER_FMT_MIPI_8 = 0xC, + BUS_RD_VER1_PACKER_FMT_MIPI_10 = 0xD, + BUS_RD_VER1_PACKER_FMT_MIPI_12 = 0xE, + BUS_RD_VER1_PACKER_FMT_MIPI_14 = 0xF, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_16BPP = 0x10, + BUS_RD_VER1_PACKER_FMT_BYPASS_SWAP = 0x11, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_SWAP = 0x12, + BUS_RD_VER1_PACKER_FMT_MAX = 0x13, +}; + +static struct cam_ope_top_reg ope_top_reg = { + .offset = 0x400, + .hw_version = 0x0, + .reset_cmd = 0x4, + .core_clk_cfg_ctrl_0 = 0x8, + .ahb_clk_cgc_ctrl = 0xC, + .core_cfg = 0x10, + .irq_status = 0x14, + .irq_mask = 0x18, + .irq_clear = 0x1C, + .irq_set = 0x20, + .irq_cmd = 0x24, + .violation_status = 0x28, + .throttle_cnt_cfg = 0x2C, +}; + +static struct cam_ope_top_reg_val ope_top_reg_val = { + .hw_version = 0x10000000, + .major_mask = 0xFFFF, + .major_shift = 0x0, + .minor_mask = 0x0FFF0000, + .minor_shift = 0xF, + .incr_mask = 0xF0000000, + .incr_shift = 0x1B, + .irq_mask = 0x0000000F, + .sw_reset_cmd = 0x2, + .hw_reset_cmd = 0x1, + .irq_set_clear = 0x1, + .rst_done = 0x1, + .we_done = 0x2, + .fe_done = 0x4, + .ope_violation = 0x8, + .idle = 0x10, +}; + + +static struct cam_ope_bus_rd_reg_val ope_bus_rd_reg_val = { + .hw_version = 0x00050000, + .sw_reset = 0x1, + .cgc_override = 0x0, + .irq_mask = 0x30001, + .irq_set_clear = 0x1, + .rst_done = 0x1, + .rup_done = 0x2, + .rd_buf_done = 0xC, + .violation = 0x3000, + .go_cmd = 0x1, + .security_cfg = 0x0, + .latency_buf_size = 4096, + .num_clients = 0x2, + .rd_clients = { + { + .core_cfg = 0x1, + .stripe_location_mask = 0x3, + .stripe_location_shift = 0x0, + .pix_pattern_mask = 0x3F, + .pix_pattern_shift = 0x2, + .img_width_mask = 0xFFFF, + .img_width_shift = 0x10, + .img_height_mask = 0xFFFF, + .img_height_shift = 0x0, + .mode_mask = 0x1F, + .mode_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x5, + .latency_buf_allocation = 4096, + .input_port_id = OPE_IN_RES_FULL, + .rm_port_id = 0, + .format_type = BUS_RD_COMBO_BAYER_MASK | + BUS_RD_COMBO_YUV_MASK, + .num_combos_supported = 2, + }, + { + .core_cfg = 0x1, + .stripe_location_mask = 0x3, + .stripe_location_shift = 0x0, + .pix_pattern_mask = 0x3F, + .pix_pattern_shift = 0x2, + .img_width_mask = 0xFFFF, + .img_width_shift = 0x10, + .img_height_mask = 0xFFFF, + .img_height_shift = 0x0, + .mode_mask = 0x1F, + .mode_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x5, + .latency_buf_allocation = 4096, + .input_port_id = OPE_IN_RES_FULL, + .rm_port_id = 1, + .format_type = BUS_RD_COMBO_YUV_MASK, + .num_combos_supported = 1, + + }, + }, +}; + +static struct cam_ope_bus_rd_reg ope_bus_rd_reg = { + .offset = 0x4C00, + .hw_version = 0x0, + .sw_reset = 0x4, + .cgc_override = 0x8, + .irq_mask = 0xC, + .irq_clear = 0x10, + .irq_cmd = 0x14, + .irq_status = 0x18, + .input_if_cmd = 0x1C, + .irq_set = 0x20, + .misr_reset = 0x24, + .security_cfg = 0x28, + .iso_cfg = 0x2C, + .iso_seed = 0x30, + .num_clients = 0x2, + .rd_clients = { + { + .core_cfg = 0x50, + .ccif_meta_data = 0x54, + .img_addr = 0x58, + .img_cfg = 0x5C, + .stride = 0x60, + .unpack_cfg = 0x64, + .latency_buf_allocation = 0x78, + .misr_cfg_0 = 0x80, + .misr_cfg_1 = 0x84, + .misr_rd_val = 0x88, + }, + { + .core_cfg = 0xF0, + .ccif_meta_data = 0xF4, + .img_addr = 0xF8, + .img_cfg = 0xFC, + .stride = 0x100, + .unpack_cfg = 0x104, + .latency_buf_allocation = 0x118, + .misr_cfg_0 = 0x120, + .misr_cfg_1 = 0x124, + .misr_rd_val = 0x128, + }, + }, +}; + +static struct cam_ope_bus_wr_reg ope_bus_wr_reg = { + .offset = 0x4D90, + .hw_version = 0x0, + .cgc_override = 0x8, + .irq_mask_0 = 0x18, + .irq_mask_1 = 0x1C, + .irq_clear_0 = 0x20, + .irq_clear_1 = 0x24, + .irq_status_0 = 0x28, + .irq_status_1 = 0x2C, + .irq_cmd = 0x30, + .frame_header_cfg_0 = 0x34, + .local_frame_header_cfg_0 = 0x4C, + .irq_set_0 = 0x50, + .irq_set_1 = 0x54, + .iso_cfg = 0x5C, + .violation_status = 0x64, + .image_size_violation_status = 0x70, + .misr_cfg_0 = 0xB8, + .misr_cfg_1 = 0xBC, + .misr_rd_sel = 0xC8, + .misr_reset = 0xCC, + .misr_val = 0xD0, + .num_clients = 0x8, + .wr_clients = { + { + .core_cfg = 0x200, + .img_addr = 0x204, + .img_cfg = 0x20C, + .x_init = 0x210, + .stride = 0x214, + .pack_cfg = 0x218, + .bw_limit = 0x21C, + .frame_header_addr = 0x220, + .subsample_period = 0x230, + .subsample_pattern = 0x234, + }, + { + .core_cfg = 0x300, + .img_addr = 0x304, + .img_cfg = 0x30C, + .x_init = 0x310, + .stride = 0x314, + .pack_cfg = 0x318, + .bw_limit = 0x31C, + .frame_header_addr = 0x320, + .subsample_period = 0x330, + .subsample_pattern = 0x334, + }, + { + .core_cfg = 0x400, + .img_addr = 0x404, + .img_cfg = 0x40C, + .x_init = 0x410, + .stride = 0x414, + .pack_cfg = 0x418, + .bw_limit = 0x41C, + .frame_header_addr = 0x420, + .subsample_period = 0x430, + .subsample_pattern = 0x434, + }, + { + .core_cfg = 0x500, + .img_addr = 0x504, + .img_cfg = 0x50C, + .x_init = 0x510, + .stride = 0x514, + .pack_cfg = 0x518, + .bw_limit = 0x51C, + .frame_header_addr = 0x520, + .subsample_period = 0x530, + .subsample_pattern = 0x534, + }, + { + .core_cfg = 0x600, + .img_addr = 0x604, + .img_cfg = 0x60C, + .x_init = 0x610, + .stride = 0x614, + .pack_cfg = 0x618, + .bw_limit = 0x61C, + .frame_header_addr = 0x620, + .subsample_period = 0x630, + .subsample_pattern = 0x634, + }, + { + .core_cfg = 0x700, + .img_addr = 0x704, + .img_cfg = 0x70C, + .x_init = 0x710, + .stride = 0x714, + .pack_cfg = 0x718, + .bw_limit = 0x71C, + .frame_header_addr = 0x720, + .subsample_period = 0x730, + .subsample_pattern = 0x734, + }, + { + .core_cfg = 0x800, + .img_addr = 0x804, + .img_cfg = 0x80C, + .x_init = 0x810, + .stride = 0x814, + .pack_cfg = 0x818, + .bw_limit = 0x81C, + .frame_header_addr = 0x820, + .subsample_period = 0x830, + .subsample_pattern = 0x834, + }, + { + .core_cfg = 0x900, + .img_addr = 0x904, + .img_cfg = 0x90C, + .x_init = 0x910, + .stride = 0x914, + .pack_cfg = 0x918, + .bw_limit = 0x91C, + .frame_header_addr = 0x920, + .subsample_period = 0x930, + .subsample_pattern = 0x934, + }, + }, +}; + +static struct cam_ope_bus_wr_reg_val ope_bus_wr_reg_val = { + .hw_version = 0x20010000, + .irq_mask_0 = 0xD0000000, + .irq_mask_1 = 0x0, + .irq_set_clear = 0x1, + .comp_rup_done = 0x1, + .comp_buf_done = 0x100, + .cons_violation = 0x10000000, + .violation = 0x40000000, + .img_size_violation = 0x80000000, + .num_clients = 0x8, + .wr_clients = { + { + .core_cfg_en = 0x1, + .core_cfg_en_mask = 0x1, + .core_cfg_en_shift = 0x0, + .virtual_frame_en_mask = 0x1, + .virtual_frame_en_shift = 0x1, + .frame_header_en_mask = 0x1, + .frame_header_en_shift = 0x2, + .auto_recovery_en_mask = 0x1, + .auto_recovery_en_shift = 0x4, + .mode_mask = 0x3, + .mode_shift = 0x10, + .width_mask = 0xFFFF, + .width_shift = 0x0, + .height_mask = 0xFFFF, + .height_shift = 0x10, + .format_mask = 0xF, + .format_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x4, + .output_port_id = OPE_OUT_RES_VIDEO, + .wm_port_id = BUS_WR_VIDEO_Y, + .format_type = BUS_WR_COMBO_YUV_MASK, + .num_combos_supported = 1, + }, + { + .core_cfg_en = 0x1, + .core_cfg_en_mask = 0x1, + .core_cfg_en_shift = 0x0, + .virtual_frame_en_mask = 0x1, + .virtual_frame_en_shift = 0x1, + .frame_header_en_mask = 0x1, + .frame_header_en_shift = 0x2, + .auto_recovery_en_mask = 0x1, + .auto_recovery_en_shift = 0x4, + .mode_mask = 0x3, + .mode_shift = 0x10, + .width_mask = 0xFFFF, + .width_shift = 0x0, + .height_mask = 0xFFFF, + .height_shift = 0x10, + .format_mask = 0xF, + .format_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x4, + .output_port_id = OPE_OUT_RES_VIDEO, + .wm_port_id = BUS_WR_VIDEO_C, + .format_type = BUS_WR_COMBO_YUV_MASK, + .num_combos_supported = 1, + }, + { + .core_cfg_en = 0x1, + .core_cfg_en_mask = 0x1, + .core_cfg_en_shift = 0x0, + .virtual_frame_en_mask = 0x1, + .virtual_frame_en_shift = 0x1, + .frame_header_en_mask = 0x1, + .frame_header_en_shift = 0x2, + .auto_recovery_en_mask = 0x1, + .auto_recovery_en_shift = 0x4, + .mode_mask = 0x3, + .mode_shift = 0x10, + .width_mask = 0xFFFF, + .width_shift = 0x0, + .height_mask = 0xFFFF, + .height_shift = 0x10, + .format_mask = 0xF, + .format_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x4, + .output_port_id = OPE_OUT_RES_DISP, + .wm_port_id = BUS_WR_DISP_Y, + .format_type = BUS_WR_COMBO_YUV_MASK, + .num_combos_supported = 1, + }, + { + .core_cfg_en = 0x1, + .core_cfg_en_mask = 0x1, + .core_cfg_en_shift = 0x0, + .virtual_frame_en_mask = 0x1, + .virtual_frame_en_shift = 0x1, + .frame_header_en_mask = 0x1, + .frame_header_en_shift = 0x2, + .auto_recovery_en_mask = 0x1, + .auto_recovery_en_shift = 0x4, + .mode_mask = 0x3, + .mode_shift = 0x10, + .width_mask = 0xFFFF, + .width_shift = 0x0, + .height_mask = 0xFFFF, + .height_shift = 0x10, + .format_mask = 0xF, + .format_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x4, + .output_port_id = OPE_OUT_RES_DISP, + .wm_port_id = BUS_WR_DISP_C, + .format_type = BUS_WR_COMBO_YUV_MASK, + .num_combos_supported = 1, + }, + { + .core_cfg_en = 0x1, + .core_cfg_en_mask = 0x1, + .core_cfg_en_shift = 0x0, + .virtual_frame_en_mask = 0x1, + .virtual_frame_en_shift = 0x1, + .frame_header_en_mask = 0x1, + .frame_header_en_shift = 0x2, + .auto_recovery_en_mask = 0x1, + .auto_recovery_en_shift = 0x4, + .mode_mask = 0x3, + .mode_shift = 0x10, + .width_mask = 0xFFFF, + .width_shift = 0x0, + .height_mask = 0xFFFF, + .height_shift = 0x10, + .format_mask = 0xF, + .format_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x4, + .output_port_id = OPE_OUT_RES_ARGB, + .wm_port_id = BUS_WR_ARGB, + .format_type = BUS_WR_COMBO_YUV_MASK, + .num_combos_supported = 1, + }, + { + .core_cfg_en = 0x1, + .core_cfg_en_mask = 0x1, + .core_cfg_en_shift = 0x0, + .virtual_frame_en_mask = 0x1, + .virtual_frame_en_shift = 0x1, + .frame_header_en_mask = 0x1, + .frame_header_en_shift = 0x2, + .auto_recovery_en_mask = 0x1, + .auto_recovery_en_shift = 0x4, + .mode_mask = 0x3, + .mode_shift = 0x10, + .width_mask = 0xFFFF, + .width_shift = 0x0, + .height_mask = 0xFFFF, + .height_shift = 0x10, + .format_mask = 0xF, + .format_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x4, + .output_port_id = OPE_OUT_RES_STATS_RS, + .wm_port_id = BUS_WR_STATS_RS, + .format_type = BUS_WR_COMBO_YUV_MASK, + .num_combos_supported = 1, + }, + { + .core_cfg_en = 0x1, + .core_cfg_en_mask = 0x1, + .core_cfg_en_shift = 0x0, + .virtual_frame_en_mask = 0x1, + .virtual_frame_en_shift = 0x1, + .frame_header_en_mask = 0x1, + .frame_header_en_shift = 0x2, + .auto_recovery_en_mask = 0x1, + .auto_recovery_en_shift = 0x4, + .mode_mask = 0x3, + .mode_shift = 0x10, + .width_mask = 0xFFFF, + .width_shift = 0x0, + .height_mask = 0xFFFF, + .height_shift = 0x10, + .format_mask = 0xF, + .format_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x4, + .output_port_id = OPE_OUT_RES_STATS_IHIST, + .wm_port_id = BUS_WR_STATS_IHIST, + .format_type = BUS_WR_COMBO_YUV_MASK, + .num_combos_supported = 1, + }, + { + .core_cfg_en = 0x1, + .core_cfg_en_mask = 0x1, + .core_cfg_en_shift = 0x0, + .virtual_frame_en_mask = 0x1, + .virtual_frame_en_shift = 0x1, + .frame_header_en_mask = 0x1, + .frame_header_en_shift = 0x2, + .auto_recovery_en_mask = 0x1, + .auto_recovery_en_shift = 0x4, + .mode_mask = 0x3, + .mode_shift = 0x10, + .width_mask = 0xFFFF, + .width_shift = 0x0, + .height_mask = 0xFFFF, + .height_shift = 0x10, + .format_mask = 0xF, + .format_shift = 0x0, + .alignment_mask = 0x1, + .alignment_shift = 0x4, + .output_port_id = OPE_OUT_RES_STATS_LTM, + .wm_port_id = BUS_WR_STATS_LTM, + .format_type = BUS_WR_COMBO_YUV_MASK, + .num_combos_supported = 1, + }, + }, +}; +static struct ope_hw ope_hw_100 = { + .top_reg = &ope_top_reg, + .top_reg_val = &ope_top_reg_val, + .bus_rd_reg = &ope_bus_rd_reg, + .bus_rd_reg_val = &ope_bus_rd_reg_val, + .bus_wr_reg = &ope_bus_wr_reg, + .bus_wr_reg_val = &ope_bus_wr_reg_val, +}; + +#endif /* CAM_OPE_HW_100_H */ diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c new file mode 100644 index 000000000000..7537bafd0ba9 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "ope_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + + +static int cam_ope_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct platform_device *pdev = NULL; + struct device_node *of_node = NULL; + struct ope_dev_soc *ope_soc_info; + + if (!soc_info) { + CAM_ERR(CAM_OPE, "soc_info is NULL"); + return -EINVAL; + } + + pdev = soc_info->pdev; + of_node = pdev->dev.of_node; + ope_soc_info = soc_info->soc_private; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) + CAM_ERR(CAM_OPE, "get ope dt prop is failed: %d", rc); + + ope_soc_info->hfi_en = of_property_read_bool(of_node, "hfi_en"); + + return rc; +} + +static int cam_ope_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t ope_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, ope_irq_handler, + irq_data); + + return rc; +} + +int cam_ope_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t ope_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_ope_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + rc = cam_ope_request_platform_resource(soc_info, ope_irq_handler, + irq_data); + if (rc < 0) + return rc; + + return rc; +} + +int cam_ope_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) { + CAM_ERR(CAM_OPE, "enable platform failed"); + return rc; + } + + return rc; +} + +int cam_ope_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, disable_clk, + true); + if (rc) + CAM_ERR(CAM_OPE, "enable platform failed"); + + return rc; +} + +int cam_ope_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate) +{ + int32_t src_clk_idx; + + if (!soc_info) { + CAM_ERR(CAM_OPE, "Invalid soc info"); + return -EINVAL; + } + + src_clk_idx = soc_info->src_clk_idx; + + CAM_DBG(CAM_OPE, "clk_rate = %u src_clk_index = %d", + clk_rate, src_clk_idx); + if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) && + (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && + (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { + CAM_DBG(CAM_OPE, "clk_rate %d greater than max, reset to %d", + clk_rate, + soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); + clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; + } + + CAM_DBG(CAM_OPE, "clk_rate = %u src_clk_index = %d", + clk_rate, src_clk_idx); + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); +} + +int cam_ope_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) +{ + int rc = 0; + + if (clk_enable) + rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE); + else + cam_soc_util_clk_disable_default(soc_info); + + return rc; +} diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.h b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.h new file mode 100644 index 000000000000..4582f19bf424 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_OPE_SOC_H +#define CAM_OPE_SOC_H + +#include "cam_soc_util.h" + +/** + * struct ope_dev_soc + * + * @hfi_en: HFI enable flag + */ +struct ope_dev_soc { + uint32_t hfi_en; +}; + +int cam_ope_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t ope_irq_handler, void *irq_data); + + +int cam_ope_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_ope_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk); + +int cam_ope_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate); + +int cam_ope_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable); +#endif /* CAM_OPE_SOC_H */ diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/top/Makefile b/drivers/cam_ope/ope_hw_mgr/ope_hw/top/Makefile new file mode 100644 index 000000000000..2740c13d2f73 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/top/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_ope/ope_hw_mgr/ope_hw/top +ccflags-y += -I$(srctree)/techpack/camera/drivers +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += ope_top.o 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 new file mode 100644 index 000000000000..e71ab9cef552 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "ope_core.h" +#include "ope_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "ope_hw.h" +#include "ope_dev_intf.h" +#include "ope_top.h" + +static struct ope_top ope_top_info; + +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; + + if (!ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + + top_reg = ope_hw_info->top_reg; + top_reg_val = ope_hw_info->top_reg_val; + + 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); + + /* OPE SW RESET */ + cam_io_w_mb(top_reg_val->sw_reset_cmd, + ope_hw_info->top_reg->base + top_reg->reset_cmd); + + rc = wait_for_completion_timeout( + &ope_top_info.reset_complete, + msecs_to_jiffies(30)); + + if (!rc || rc < 0) { + CAM_ERR(CAM_OPE, "reset error result = %d", rc); + if (!rc) + rc = -ETIMEDOUT; + } else { + rc = 0; + } + + return rc; +} + +static int cam_ope_top_release(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0; + + if (ctx_id < 0) { + CAM_ERR(CAM_OPE, "Invalid data: %d", ctx_id); + return -EINVAL; + } + + ope_top_info.top_ctx[ctx_id].ope_acquire = NULL; + + return rc; +} + +static int cam_ope_top_acquire(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0; + + if (ctx_id < 0 || !data) { + CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data); + return -EINVAL; + } + + ope_top_info.top_ctx[ctx_id].ope_acquire = data; + + return rc; +} + +static int cam_ope_top_init(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; + struct cam_ope_dev_init *dev_init = data; + + if (!ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + + top_reg = ope_hw_info->top_reg; + top_reg_val = ope_hw_info->top_reg_val; + + top_reg->base = dev_init->core_info->ope_hw_info->ope_top_base; + + /* 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); + + rc = wait_for_completion_timeout( + &ope_top_info.reset_complete, + msecs_to_jiffies(30)); + + if (!rc || rc < 0) { + CAM_ERR(CAM_OPE, "reset error result = %d", rc); + if (!rc) + rc = -ETIMEDOUT; + } else { + rc = 0; + } + + return rc; +} + +static int cam_ope_top_probe(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0; + + if (!ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + + ope_top_info.ope_hw_info = ope_hw_info; + + return rc; +} + +static int cam_ope_top_isr(struct ope_hw *ope_hw_info, + int32_t ctx_id, void *data) +{ + int rc = 0; + uint32_t irq_status; + uint32_t violation_status; + struct cam_ope_top_reg *top_reg; + struct cam_ope_top_reg_val *top_reg_val; + struct cam_ope_irq_data *irq_data = data; + + if (!ope_hw_info) { + CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); + return -EINVAL; + } + + top_reg = ope_hw_info->top_reg; + top_reg_val = ope_hw_info->top_reg_val; + + /* Read and Clear Top Interrupt status */ + irq_status = cam_io_r_mb(top_reg->base + top_reg->irq_status); + cam_io_w_mb(irq_status, + top_reg->base + top_reg->irq_clear); + + cam_io_w_mb(top_reg_val->irq_set_clear, + top_reg->base + top_reg->irq_cmd); + + if (irq_status & top_reg_val->rst_done) { + CAM_DBG(CAM_OPE, "ope reset done"); + complete(&ope_top_info.reset_complete); + } + + if (irq_status & top_reg_val->ope_violation) { + violation_status = cam_io_r_mb(top_reg->base + + top_reg->violation_status); + irq_data->error = 1; + CAM_ERR(CAM_OPE, "ope violation: %x", violation_status); + } + + return rc; +} + +int cam_ope_top_process(struct ope_hw *ope_hw_info, + int32_t ctx_id, uint32_t cmd_id, void *data) +{ + int rc = 0; + + switch (cmd_id) { + case OPE_HW_PROBE: + CAM_DBG(CAM_OPE, "OPE_HW_PROBE: E"); + rc = cam_ope_top_probe(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_PROBE: X"); + break; + case OPE_HW_INIT: + CAM_DBG(CAM_OPE, "OPE_HW_INIT: E"); + rc = cam_ope_top_init(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_INIT: X"); + break; + case OPE_HW_DEINIT: + break; + case OPE_HW_ACQUIRE: + CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: E"); + rc = cam_ope_top_acquire(ope_hw_info, ctx_id, data); + CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: X"); + break; + case OPE_HW_PREPARE: + break; + case OPE_HW_RELEASE: + rc = cam_ope_top_release(ope_hw_info, ctx_id, data); + break; + case OPE_HW_START: + break; + case OPE_HW_STOP: + break; + case OPE_HW_FLUSH: + break; + case OPE_HW_ISR: + rc = cam_ope_top_isr(ope_hw_info, 0, data); + break; + case OPE_HW_RESET: + rc = cam_ope_top_reset(ope_hw_info, 0, 0); + break; + default: + break; + } + + return rc; +} 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 new file mode 100644 index 000000000000..cb22521f1310 --- /dev/null +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef OPE_TOP_H +#define OPE_TOP_H + +#include +#include +#include +#include "ope_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" +#include "cam_soc_util.h" +#include "cam_context.h" +#include "cam_ope_context.h" +#include "cam_ope_hw_mgr.h" + +/** + * struct ope_top_ctx + * + * @ope_acquire: OPE acquire info + */ +struct ope_top_ctx { + struct ope_acquire_dev_info *ope_acquire; +}; + +/** + * struct ope_top + * + * @ope_hw_info: OPE hardware info + * @top_ctx: OPE top context + * @reset_complete: Reset complete flag + */ +struct ope_top { + struct ope_hw *ope_hw_info; + struct ope_top_ctx top_ctx[OPE_CTX_MAX]; + struct completion reset_complete; +}; +#endif /* OPE_TOP_H */ diff --git a/drivers/cam_utils/cam_debug_util.c b/drivers/cam_utils/cam_debug_util.c index 274980f8bb64..e0957890dc8b 100644 --- a/drivers/cam_utils/cam_debug_util.c +++ b/drivers/cam_utils/cam_debug_util.c @@ -93,6 +93,11 @@ const char *cam_get_module_name(unsigned int module_id) break; case CAM_CUSTOM: name = "CAM-CUSTOM"; + case CAM_OPE: + name = "CAM-OPE"; + break; + case CAM_PRESIL: + name = "CAM-PRESIL"; break; default: name = "CAM"; diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h index 181a1558a904..03f8019cfea2 100644 --- a/drivers/cam_utils/cam_debug_util.h +++ b/drivers/cam_utils/cam_debug_util.h @@ -39,6 +39,8 @@ /* CAM_PERF: Used for performance (clock, BW etc) logs */ #define CAM_PERF (1 << 25) #define CAM_CUSTOM (1 << 26) +#define CAM_OPE (1 << 28) +#define CAM_PRESIL (1 << 27) #define STR_BUFFER_MAX_LENGTH 1024 diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index ce73b79f9590..23b4ba98f92a 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -178,6 +178,16 @@ struct cam_iommu_handle { #define CAM_FORMAT_ARGB_16 48 #define CAM_FORMAT_MAX 49 +/* Pixel Patterns */ +#define PIXEL_PATTERN_RGRGRG 0x0 +#define PIXEL_PATTERN_GRGRGR 0x1 +#define PIXEL_PATTERN_BGBGBG 0x2 +#define PIXEL_PATTERN_GBGBGB 0x3 +#define PIXEL_PATTERN_YCBYCR 0x4 +#define PIXEL_PATTERN_YCRYCB 0x5 +#define PIXEL_PATTERN_CBYCRY 0x6 +#define PIXEL_PATTERN_CRYCBY 0x7 + /* camera rotaion */ #define CAM_ROTATE_CW_0_DEGREE 0 #define CAM_ROTATE_CW_90_DEGREE 1 @@ -217,7 +227,9 @@ struct cam_iommu_handle { #define CAM_PACKET_DEV_IFE 15 #define CAM_PACKET_DEV_ICP 16 #define CAM_PACKET_DEV_LRME 17 -#define CAM_PACKET_DEV_MAX 18 +#define CAM_PACKET_DEV_TFE 18 +#define CAM_PACKET_DEV_OPE 19 +#define CAM_PACKET_DEV_MAX 20 /* Register base type */ #define CAM_REG_DUMP_BASE_TYPE_ISP_LEFT 1 diff --git a/include/uapi/media/cam_ope.h b/include/uapi/media/cam_ope.h new file mode 100644 index 000000000000..7b4ed57b778e --- /dev/null +++ b/include/uapi/media/cam_ope.h @@ -0,0 +1,333 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_OPE_H__ +#define __UAPI_OPE_H__ + +#include "cam_defs.h" +#include "cam_cpas.h" + +#define OPE_DEV_NAME_SIZE 128 + +/* OPE HW TYPE */ +#define OPE_HW_TYPE_OPE 0x1 +#define OPE_HW_TYPE_OPE_CDM 0x2 +#define OPE_HW_TYPE_MAX 0x3 + +/* OPE Device type */ +#define OPE_DEV_TYPE_OPE_RT 0x1 +#define OPE_DEV_TYPE_OPE_NRT 0x2 +#define OPE_DEV_TYPE_OPE_SEMI_RT 0x3 +#define OPE_DEV_TYPE_MAX 0x4 + +/* OPE Input Res Ports */ +#define OPE_IN_RES_FULL 0x1 +#define OPE_IN_RES_MAX OPE_IN_RES_FULL + +/* OPE Output Res Ports */ +#define OPE_OUT_RES_VIDEO 0x1 +#define OPE_OUT_RES_DISP 0x2 +#define OPE_OUT_RES_ARGB 0x3 +#define OPE_OUT_RES_STATS_RS 0x4 +#define OPE_OUT_RES_STATS_IHIST 0x5 +#define OPE_OUT_RES_STATS_LTM 0x6 +#define OPE_OUT_RES_MAX OPE_OUT_RES_STATS_LTM + +/* OPE packet opcodes */ +#define OPE_OPCODE_CONFIG 0x1 + +/* OPE Command Buffer Scope */ +#define OPE_CMD_BUF_SCOPE_BATCH 0x1 +#define OPE_CMD_BUF_SCOPE_FRAME 0x2 +#define OPE_CMD_BUF_SCOPE_PASS 0x3 +#define OPE_CMD_BUF_SCOPE_STRIPE 0x4 + +/* OPE Command Buffer Types */ +#define OPE_CMD_BUF_TYPE_DIRECT 0x1 +#define OPE_CMD_BUF_TYPE_INDIRECT 0x2 + +/* OPE Command Buffer Usage */ +#define OPE_CMD_BUF_UMD 0x1 +#define OPE_CMD_BUF_KMD 0x2 +#define OPE_CMD_BUF_DEBUG 0x3 + +/* OPE Single/Double Buffered */ +#define OPE_CMD_BUF_SINGLE_BUFFERED 0x1 +#define OPE_CMD_BUF_DOUBLE_BUFFERED 0x2 + +/* Command meta types */ +#define OPE_CMD_META_GENERIC_BLOB 0x1 + +/* Generic blob types */ +#define OPE_CMD_GENERIC_BLOB_CLK_V2 0x1 + +/* Stripe location */ +#define OPE_STRIPE_FULL 0x0 +#define OPE_STRIPE_LEFT 0x1 +#define OPE_STRIPE_RIGHT 0x2 +#define OPE_STRIPE_MIDDLE 0x3 + +#define OPE_MAX_CMD_BUFS 64 +#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_BATCH_SIZE 16 + +/** + * struct ope_stripe_info - OPE stripe Info + * + * @offset: Offset in Bytes + * @x_init: X_init + * @stripe_location: Stripe location (OPE_STRIPE_XXX) + * @width: Width of a stripe + * @disable_bus: Flag to disable BUS master + * @reserved: Reserved + * + */ +struct ope_stripe_info { + uint32_t offset; + uint32_t x_init; + uint32_t stripe_location; + uint32_t width; + uint32_t disable_bus; + uint32_t reserved; +}; + +/** + * struct ope_io_buf_info - OPE IO buffers meta + * + * @direction: Direction of a buffer of a port(Input/Output) + * @resource_type: Port type + * @num_planes: Number of planes for a port + * @reserved: Reserved + * @num_stripes: Stripes per plane + * @mem_handle: Memhandles of each Input/Output Port + * @plane_offset: Offsets of planes + * @length: Length of a plane buffer + * @plane_stride: Plane stride + * @height: Height of a plane buffer + * @format: Format + * @fence: Fence of a Port + * @stripe_info: Stripe Info + * + */ +struct ope_io_buf_info { + uint32_t direction; + uint32_t resource_type; + uint32_t num_planes; + uint32_t reserved; + uint32_t num_stripes[OPE_MAX_PLANES]; + uint32_t mem_handle[OPE_MAX_PLANES]; + uint32_t plane_offset[OPE_MAX_PLANES]; + uint32_t length[OPE_MAX_PLANES]; + uint32_t plane_stride[OPE_MAX_PLANES]; + uint32_t height[OPE_MAX_PLANES]; + uint32_t format; + uint32_t fence; + struct ope_stripe_info stripe_info[OPE_MAX_PLANES][OPE_MAX_STRIPES]; +}; + +/** + * struct ope_frame_set - OPE frameset + * + * @num_io_bufs: Number of I/O buffers + * @reserved: Reserved + * @io_buf: IO buffer info for all Input and Output ports + * + */ +struct ope_frame_set { + uint32_t num_io_bufs; + uint32_t reserved; + struct ope_io_buf_info io_buf[OPE_MAX_IO_BUFS]; +}; + +/** + * struct ope_cmd_buf_info - OPE command buffer meta + * + * @mem_handle: Memory handle for command buffer + * @offset: Offset of a command buffer + * @size: Size of command buffer + * @length: Length of a command buffer + * @cmd_buf_scope : Scope of a command buffer (OPE_CMD_BUF_SCOPE_XXX) + * @type: Command buffer type (OPE_CMD_BUF_TYPE_XXX) + * @cmd_buf_usage: Usage of command buffer ( OPE_CMD_BUF_USAGE_XXX) + * @stripe_idx: Stripe index in a req, It is valid for SCOPE_STRIPE + * @cmd_buf_pass_idx: Pass index + * @prefetch_disable: Prefecth disable flag + * + */ + +struct ope_cmd_buf_info { + uint32_t mem_handle; + uint32_t offset; + uint32_t size; + uint32_t length; + uint32_t cmd_buf_scope; + uint32_t type; + uint32_t cmd_buf_usage; + uint32_t cmd_buf_buffered; + uint32_t stripe_idx; + uint32_t cmd_buf_pass_idx; + uint32_t prefetch_disable; +}; + +/** + * struct ope_packet_payload - payload for a request + * + * @num_cmd_bufs: Number of command buffers + * @batch_size: Batch size in HFR mode + * @ope_cmd_buf_info: Command buffer meta data + * @ope_io_buf_info: Io buffer Info + * + */ +struct ope_frame_process { + uint32_t num_cmd_bufs[OPE_MAX_BATCH_SIZE]; + uint32_t batch_size; + struct ope_cmd_buf_info cmd_buf[OPE_MAX_BATCH_SIZE][OPE_MAX_CMD_BUFS]; + struct ope_frame_set frame_set[OPE_MAX_BATCH_SIZE]; +}; + +/** + * struct ope_clk_bw_request_v2 - clock and bandwidth for a request + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @reserved: For memory alignment + * @axi_path: Per path vote info for OPE + * + */ +struct ope_clk_bw_request_v2 { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint32_t reserved; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +}; + +/** + * struct ope_hw_ver - Device information for OPE + * + * This is used to get device version info of + * OPE, CDM and use this info in CAM_QUERY_CAP IOCTL + * + * @hw_type: Hardware type for the cap info(OPE_HW_TYPE_XXX) + * @reserved: Reserved field + * @hw_ver: Major, minor and incr values of a hardware version + * + */ +struct ope_hw_ver { + uint32_t hw_type; + uint32_t reserved; + struct cam_hw_version hw_ver; +}; + +/** + * struct ope_query_cap_cmd - OPE query device capability payload + * + * @dev_iommu_handle: OPE iommu handles for secure/non secure modes + * @cdm_iommu_handle: CDM iommu handles for secure/non secure modes + * @num_ope: Number of OPEs + * @reserved: Reserved Parameter + * @hw_ver: Hardware capability array + */ +struct ope_query_cap_cmd { + struct cam_iommu_handle dev_iommu_handle; + struct cam_iommu_handle cdm_iommu_handle; + uint32_t num_ope; + uint32_t reserved; + struct ope_hw_ver hw_ver[OPE_DEV_TYPE_MAX]; +}; + +/** + * struct ope_out_res_info - OPE Output resource info + * + * @res_id: Resource ID + * @format: Output resource format + * @width: Output width + * @height: Output Height + * @alignment: Alignment + * @packer_format: Packer format + * @subsample_period: Subsample period in HFR + * @subsample_pattern: Subsample pattern in HFR + * @pixel_pattern: Pixel pattern + * @reserved: Reserved Parameter + * + */ +struct ope_out_res_info { + uint32_t res_id; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t alignment; + uint32_t packer_format; + uint32_t subsample_period; + uint32_t subsample_pattern; + uint32_t pixel_pattern; + uint32_t reserved; +}; + +/** + * struct ope_in_res_info - OPE Input resource info + * + * @res_id: Resource ID + * @format: Input resource format + * @width: Input width + * @height: Input Height + * @pixel_pattern: Pixel pattern + * @alignment: Alignment + * @unpacker_format: Unpacker format + * @max_stripe_size: Max stripe size supported for this instance configuration + * @fps: Frames per second + * @reserved: Reserved Parameter + * + */ +struct ope_in_res_info { + uint32_t res_id; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t pixel_pattern; + uint32_t alignment; + uint32_t unpacker_format; + uint32_t max_stripe_size; + uint32_t fps; + uint32_t reserved; +}; + +/** + * struct ope_acquire_dev_info - OPE Acquire Info + * + * @hw_type: OPE HW Types (OPE) + * @dev_type: Nature of Device Instance (RT/NRT) + * @dev_name: Name of Device Instance + * @nrt_stripes_for_arb: Program num stripes in OPE CDM for NRT device + * before setting ARB bit + * @secure_mode: Mode of Device operation (Secure or Non Secure) + * @batch_size: Batch size + * @num_in_res: Number of input resources (OPE_IN_RES_XXX) + * @in_res: Input resource info + * @num_out_res: Number of output resources (OPE_OUT_RES_XXX) + * @reserved: Reserved Parameter + * @out_res: Output resource info + * + */ +struct ope_acquire_dev_info { + uint32_t hw_type; + uint32_t dev_type; + char dev_name[OPE_DEV_NAME_SIZE]; + uint32_t nrt_stripes_for_arb; + uint32_t secure_mode; + uint32_t batch_size; + uint32_t num_in_res; + struct ope_in_res_info in_res[OPE_IN_RES_MAX]; + uint32_t num_out_res; + uint32_t reserved; + struct ope_out_res_info out_res[OPE_OUT_RES_MAX]; +} __attribute__((__packed__)); + +#endif /* __UAPI_OPE_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 36471a290ad3..197dda0c6b6a 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -30,6 +30,7 @@ #define CAM_EEPROM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 12) #define CAM_OIS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 13) #define CAM_CUSTOM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 14) +#define CAM_OPE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 15) /* cam_req_mgr hdl info */ #define CAM_REQ_MGR_HDL_IDX_POS 8 -- GitLab From 5ee1d6bd0983eb156adff80480b27696bc73d730 Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Fri, 16 Aug 2019 15:57:24 +0530 Subject: [PATCH 003/295] msm: camera: ope: Add dynamic clock support Dynamic clock and bandwidth support is added to OPE. CRs-Fixed: 2520602 Change-Id: I4ba4bb3b24e4ef47dea35810564cae69912ef72e Signed-off-by: Suresh Vankadara --- drivers/cam_ope/cam_ope_context.c | 2 +- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 1008 ++++++++++++++++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 120 ++ drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 17 + .../cam_ope/ope_hw_mgr/ope_hw/ope_dev_intf.h | 30 +- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c | 2 +- include/uapi/media/cam_cpas.h | 9 + 7 files changed, 1143 insertions(+), 45 deletions(-) diff --git a/drivers/cam_ope/cam_ope_context.c b/drivers/cam_ope/cam_ope_context.c index ba35176b0d45..487881a21f69 100644 --- a/drivers/cam_ope/cam_ope_context.c +++ b/drivers/cam_ope/cam_ope_context.c @@ -40,7 +40,7 @@ static int cam_ope_context_dump_active_request(void *data, unsigned long iova, mutex_lock(&ctx->ctx_mutex); if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) { - CAM_ERR(CAM_ICP, "Invalid state icp ctx %d state %d", + CAM_ERR(CAM_OPE, "Invalid state ope ctx %d state %d", ctx->ctx_id, ctx->state); goto end; } 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 659279992d04..45a96f2b0dc5 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 @@ -125,11 +125,30 @@ static int cam_ope_mgr_reset_hw(void) return rc; } +static void cam_ope_device_timer_stop(struct cam_ope_hw_mgr *hw_mgr) +{ + if (hw_mgr->clk_info.watch_dog) { + hw_mgr->clk_info.watch_dog_reset_counter = 0; + crm_timer_exit(&hw_mgr->clk_info.watch_dog); + hw_mgr->clk_info.watch_dog = NULL; + } +} + +static void cam_ope_device_timer_reset(struct cam_ope_hw_mgr *hw_mgr) +{ + + if (hw_mgr->clk_info.watch_dog) { + CAM_DBG(CAM_OPE, "reset timer"); + crm_timer_reset(hw_mgr->clk_info.watch_dog); + hw_mgr->clk_info.watch_dog_reset_counter++; + } +} + static int cam_ope_req_timer_modify(struct cam_ope_ctx *ctx_data, int32_t expires) { if (ctx_data->req_watch_dog) { - CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + CAM_DBG(CAM_OPE, "stop timer : ctx_id = %d", ctx_data->ctx_id); crm_timer_modify(ctx_data->req_watch_dog, expires); } return 0; @@ -138,7 +157,8 @@ static int cam_ope_req_timer_modify(struct cam_ope_ctx *ctx_data, static int cam_ope_req_timer_stop(struct cam_ope_ctx *ctx_data) { if (ctx_data->req_watch_dog) { - CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + CAM_DBG(CAM_OPE, "stop timer : ctx_id = %d", ctx_data->ctx_id); + ctx_data->req_watch_dog_reset_counter = 0; crm_timer_exit(&ctx_data->req_watch_dog); ctx_data->req_watch_dog = NULL; } @@ -147,8 +167,13 @@ static int cam_ope_req_timer_stop(struct cam_ope_ctx *ctx_data) static int cam_ope_req_timer_reset(struct cam_ope_ctx *ctx_data) { - if (ctx_data && ctx_data->req_watch_dog) + if (ctx_data && ctx_data->req_watch_dog) { + ctx_data->req_watch_dog_reset_counter++; + CAM_DBG(CAM_OPE, "reset timer : ctx_id = %d, counter=%d", + ctx_data->ctx_id, + ctx_data->req_watch_dog_reset_counter); crm_timer_reset(ctx_data->req_watch_dog); + } return 0; } @@ -192,14 +217,123 @@ 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 cam_ope_hw_mgr *hw_mgr = ope_hw_mgr; + uint32_t id; + struct cam_hw_intf *dev_intf = NULL; + struct cam_ope_clk_info *clk_info; + struct cam_ope_dev_bw_update clk_update; + int i = 0; + int device_share_ratio = 1; + int path_index; + + if (!ctx_data) { + CAM_ERR(CAM_OPE, "ctx_data is NULL, failed to update clk"); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + if ((ctx_data->ctx_state != OPE_CTX_STATE_ACQUIRED) || + (ctx_data->req_watch_dog_reset_counter == 0)) { + CAM_DBG(CAM_OPE, "state %d counter = %d", ctx_data->ctx_state, + ctx_data->req_watch_dog_reset_counter); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } 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); cam_ope_req_timer_reset(ctx_data); - } else { - cam_ope_req_timer_modify(ctx_data, ~0); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + cam_ope_req_timer_modify(ctx_data, ~0); + /* Remove context BW */ + dev_intf = hw_mgr->ope_dev_intf[0]; + if (!dev_intf) { + CAM_ERR(CAM_OPE, "OPE dev intf is NULL"); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + + clk_info = &hw_mgr->clk_info; + id = OPE_HW_BW_UPDATE; + device_share_ratio = hw_mgr->num_ope; + + clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC; + clk_update.ahb_vote.vote.freq = 0; + clk_update.ahb_vote_valid = false; + + /* + * Remove previous vote of this context from hw mgr first. + * hw_mgr_clk_info has all valid paths, with each path in its + * own index. BW that we wanted to vote now is after removing + * current context's vote from hw mgr consolidated vote + */ + 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; + } + + clk_info->axi_path[path_index].camnoc_bw -= + ctx_data->clk_info.axi_path[i].camnoc_bw; + clk_info->axi_path[path_index].mnoc_ab_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ab_bw; + clk_info->axi_path[path_index].mnoc_ib_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ib_bw; + clk_info->axi_path[path_index].ddr_ab_bw -= + ctx_data->clk_info.axi_path[i].ddr_ab_bw; + clk_info->axi_path[path_index].ddr_ib_bw -= + ctx_data->clk_info.axi_path[i].ddr_ib_bw; + } + + memset(&ctx_data->clk_info.axi_path[0], 0, + CAM_OPE_MAX_PER_PATH_VOTES * + sizeof(struct cam_axi_per_path_bw_vote)); + ctx_data->clk_info.curr_fc = 0; + ctx_data->clk_info.base_clk = 0; + + clk_update.axi_vote.num_paths = clk_info->num_paths; + memcpy(&clk_update.axi_vote.axi_path[0], + &clk_info->axi_path[0], + clk_update.axi_vote.num_paths * + sizeof(struct cam_axi_per_path_bw_vote)); + + if (device_share_ratio > 1) { + for (i = 0; i < clk_update.axi_vote.num_paths; i++) { + clk_update.axi_vote.axi_path[i].camnoc_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].mnoc_ab_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].mnoc_ib_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].ddr_ab_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].ddr_ib_bw /= + device_share_ratio; + } } + + clk_update.axi_vote_valid = true; + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_update, sizeof(clk_update)); + + CAM_DBG(CAM_OPE, "X :ctx_id = %d curr_fc = %u bc = %u", + ctx_data->ctx_id, ctx_data->clk_info.curr_fc, + ctx_data->clk_info.base_clk); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; } @@ -235,7 +369,153 @@ static int cam_ope_start_req_timer(struct cam_ope_ctx *ctx_data) rc = crm_timer_init(&ctx_data->req_watch_dog, 200, ctx_data, &cam_ope_req_timer_cb); if (rc) - CAM_ERR(CAM_ICP, "Failed to start timer"); + CAM_ERR(CAM_OPE, "Failed to start timer"); + + ctx_data->req_watch_dog_reset_counter = 0; + + return rc; +} + +static int cam_ope_supported_clk_rates(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data) +{ + int i; + struct cam_hw_soc_info *soc_info; + struct cam_hw_intf *dev_intf = NULL; + struct cam_hw_info *dev = NULL; + + dev_intf = hw_mgr->ope_dev_intf[0]; + if (!dev_intf) { + CAM_ERR(CAM_OPE, "dev_intf is invalid"); + return -EINVAL; + } + + dev = (struct cam_hw_info *)dev_intf->hw_priv; + soc_info = &dev->soc_info; + + for (i = 0; i < CAM_MAX_VOTE; i++) { + ctx_data->clk_info.clk_rate[i] = + soc_info->clk_rate[i][soc_info->src_clk_idx]; + CAM_DBG(CAM_OPE, "clk_info[%d] = %d", + i, ctx_data->clk_info.clk_rate[i]); + } + + return 0; +} + +static int cam_ope_ctx_clk_info_init(struct cam_ope_ctx *ctx_data) +{ + int i; + + ctx_data->clk_info.curr_fc = 0; + ctx_data->clk_info.base_clk = 0; + ctx_data->clk_info.uncompressed_bw = 0; + ctx_data->clk_info.compressed_bw = 0; + + for (i = 0; i < CAM_OPE_MAX_PER_PATH_VOTES; i++) { + ctx_data->clk_info.axi_path[i].camnoc_bw = 0; + ctx_data->clk_info.axi_path[i].mnoc_ab_bw = 0; + ctx_data->clk_info.axi_path[i].mnoc_ib_bw = 0; + } + + cam_ope_supported_clk_rates(ope_hw_mgr, ctx_data); + + return 0; +} + +static int32_t cam_ope_deinit_idle_clk(void *priv, void *data) +{ + struct cam_ope_hw_mgr *hw_mgr = (struct cam_ope_hw_mgr *)priv; + struct ope_clk_work_data *task_data = (struct ope_clk_work_data *)data; + struct cam_ope_clk_info *clk_info = + (struct cam_ope_clk_info *)task_data->data; + uint32_t id; + uint32_t i; + struct cam_ope_ctx *ctx_data; + struct cam_hw_intf *dev_intf = NULL; + int rc = 0; + bool busy = false; + + clk_info->base_clk = 0; + clk_info->curr_clk = 0; + clk_info->over_clked = 0; + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + for (i = 0; i < OPE_CTX_MAX; i++) { + ctx_data = &hw_mgr->ctx[i]; + mutex_lock(&ctx_data->ctx_mutex); + if (ctx_data->ctx_state == OPE_CTX_STATE_ACQUIRED) { + busy = cam_ope_is_pending_request(ctx_data); + if (busy) { + mutex_unlock(&ctx_data->ctx_mutex); + break; + } + cam_ope_ctx_clk_info_init(ctx_data); + } + mutex_unlock(&ctx_data->ctx_mutex); + } + + if (busy) { + cam_ope_device_timer_reset(hw_mgr); + rc = -EBUSY; + goto done; + } + + dev_intf = hw_mgr->ope_dev_intf[0]; + id = OPE_HW_CLK_DISABLE; + + CAM_DBG(CAM_OPE, "Disable %d", clk_info->hw_type); + + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, NULL, 0); + +done: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static void cam_ope_device_timer_cb(struct timer_list *timer_data) +{ + unsigned long flags; + struct crm_workq_task *task; + struct ope_clk_work_data *task_data; + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + + spin_lock_irqsave(&ope_hw_mgr->hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task(ope_hw_mgr->timer_work); + if (!task) { + CAM_ERR(CAM_OPE, "no empty task"); + spin_unlock_irqrestore(&ope_hw_mgr->hw_mgr_lock, flags); + return; + } + + task_data = (struct ope_clk_work_data *)task->payload; + task_data->data = timer->parent; + task_data->type = OPE_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_ope_deinit_idle_clk; + cam_req_mgr_workq_enqueue_task(task, &ope_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&ope_hw_mgr->hw_mgr_lock, flags); +} + +static int cam_ope_device_timer_start(struct cam_ope_hw_mgr *hw_mgr) +{ + int rc = 0; + int i; + + for (i = 0; i < CLK_HW_MAX; i++) { + if (!hw_mgr->clk_info.watch_dog) { + rc = crm_timer_init(&hw_mgr->clk_info.watch_dog, + OPE_DEVICE_IDLE_TIMEOUT, &hw_mgr->clk_info, + &cam_ope_device_timer_cb); + + if (rc) + CAM_ERR(CAM_OPE, "Failed to start timer %d", i); + + hw_mgr->clk_info.watch_dog_reset_counter = 0; + } + } return rc; } @@ -245,7 +525,6 @@ 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; @@ -254,6 +533,551 @@ static int cam_get_valid_ctx_id(void) return i; } +static int cam_ope_get_actual_clk_rate_idx( + struct cam_ope_ctx *ctx_data, uint32_t base_clk) +{ + int i; + + for (i = 0; i < CAM_MAX_VOTE; i++) + if (ctx_data->clk_info.clk_rate[i] >= base_clk) + return i; + + /* + * Caller has to ensure returned index is within array + * size bounds while accessing that index. + */ + + return i; +} + +static bool cam_ope_is_over_clk(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, + struct cam_ope_clk_info *hw_mgr_clk_info) +{ + int base_clk_idx; + int curr_clk_idx; + + base_clk_idx = cam_ope_get_actual_clk_rate_idx(ctx_data, + hw_mgr_clk_info->base_clk); + + curr_clk_idx = cam_ope_get_actual_clk_rate_idx(ctx_data, + hw_mgr_clk_info->curr_clk); + + CAM_DBG(CAM_OPE, "bc_idx = %d cc_idx = %d %d %d", + base_clk_idx, curr_clk_idx, hw_mgr_clk_info->base_clk, + hw_mgr_clk_info->curr_clk); + + if (curr_clk_idx > base_clk_idx) + return true; + + return false; +} + + +static int cam_ope_get_lower_clk_rate(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, uint32_t base_clk) +{ + int i; + + i = cam_ope_get_actual_clk_rate_idx(ctx_data, base_clk); + + if (i > 0) + return ctx_data->clk_info.clk_rate[i - 1]; + + CAM_DBG(CAM_OPE, "Already clk at lower level"); + + return base_clk; +} + +static int cam_ope_get_next_clk_rate(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, uint32_t base_clk) +{ + int i; + + i = cam_ope_get_actual_clk_rate_idx(ctx_data, base_clk); + + if (i < CAM_MAX_VOTE - 1) + return ctx_data->clk_info.clk_rate[i + 1]; + + CAM_DBG(CAM_OPE, "Already clk at higher level"); + + return base_clk; +} + +static int cam_ope_get_actual_clk_rate(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, uint32_t base_clk) +{ + int i; + + for (i = 0; i < CAM_MAX_VOTE; i++) + if (ctx_data->clk_info.clk_rate[i] >= base_clk) + return ctx_data->clk_info.clk_rate[i]; + + return base_clk; +} + +static int cam_ope_calc_total_clk(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_clk_info *hw_mgr_clk_info, uint32_t dev_type) +{ + int i; + struct cam_ope_ctx *ctx_data; + + hw_mgr_clk_info->base_clk = 0; + for (i = 0; i < OPE_CTX_MAX; i++) { + ctx_data = &hw_mgr->ctx[i]; + if (ctx_data->ctx_state == OPE_CTX_STATE_ACQUIRED && + ctx_data->ope_acquire.dev_type == dev_type) + hw_mgr_clk_info->base_clk += + ctx_data->clk_info.base_clk; + } + + return 0; +} + +static uint32_t cam_ope_mgr_calc_base_clk(uint32_t frame_cycles, + uint64_t budget) +{ + uint64_t base_clk; + uint64_t mul = 1000000000; + + base_clk = (frame_cycles * mul) / budget; + + CAM_DBG(CAM_OPE, "budget = %lld fc = %d ib = %lld base_clk = %lld", + budget, frame_cycles, + (long long)(frame_cycles * mul), base_clk); + + return base_clk; +} + +static bool cam_ope_update_clk_overclk_free(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, + struct cam_ope_clk_info *hw_mgr_clk_info, + struct cam_ope_clk_bw_request *clk_info, + uint32_t base_clk) +{ + int rc = false; + + /* + * In caseof no pending packets case + * 1. In caseof overclk cnt is less than threshold, increase + * overclk count and no update in the clock rate + * 2. In caseof overclk cnt is greater than or equal to threshold + * then lower clock rate by one level and update hw_mgr current + * clock value. + * a. In case of new clock rate greater than sum of clock + * rates, reset overclk count value to zero if it is + * overclock + * b. if it is less than sum of base clocks then go to next + * level of clock and make overclk count to zero + * c. if it is same as sum of base clock rates update overclock + * cnt to 0 + */ + if (hw_mgr_clk_info->over_clked < hw_mgr_clk_info->threshold) { + hw_mgr_clk_info->over_clked++; + rc = false; + } else { + hw_mgr_clk_info->curr_clk = + cam_ope_get_lower_clk_rate(hw_mgr, ctx_data, + hw_mgr_clk_info->curr_clk); + if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk) { + if (cam_ope_is_over_clk(hw_mgr, ctx_data, + hw_mgr_clk_info)) + hw_mgr_clk_info->over_clked = 0; + } else if (hw_mgr_clk_info->curr_clk < + hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->curr_clk = + cam_ope_get_next_clk_rate(hw_mgr, ctx_data, + hw_mgr_clk_info->curr_clk); + hw_mgr_clk_info->over_clked = 0; + } else if (hw_mgr_clk_info->curr_clk == + hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->over_clked = 0; + } + rc = true; + } + + return rc; +} + +static bool cam_ope_update_clk_free(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, + struct cam_ope_clk_info *hw_mgr_clk_info, + struct cam_ope_clk_bw_request *clk_info, + uint32_t base_clk) +{ + int rc = false; + bool over_clocked = false; + + ctx_data->clk_info.curr_fc = clk_info->frame_cycles; + ctx_data->clk_info.base_clk = base_clk; + cam_ope_calc_total_clk(hw_mgr, hw_mgr_clk_info, + ctx_data->ope_acquire.dev_type); + + /* + * Current clock is not always sum of base clocks, due to + * clock scales update to next higher or lower levels, it + * equals to one of discrete clock values supported by hardware. + * So even current clock is higher than sum of base clocks, we + * can not consider it is over clocked. if it is greater than + * discrete clock level then only it is considered as over clock. + * 1. Handle over clock case + * 2. If current clock is less than sum of base clocks + * update current clock + * 3. If current clock is same as sum of base clocks no action + */ + + over_clocked = cam_ope_is_over_clk(hw_mgr, ctx_data, + hw_mgr_clk_info); + + if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk && + over_clocked) { + rc = cam_ope_update_clk_overclk_free(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, base_clk); + } else if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->over_clked = 0; + rc = false; + } else if (hw_mgr_clk_info->curr_clk < hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->curr_clk = cam_ope_get_actual_clk_rate(hw_mgr, + ctx_data, hw_mgr_clk_info->base_clk); + rc = true; + } + + return rc; +} + +static bool cam_ope_update_clk_busy(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, + struct cam_ope_clk_info *hw_mgr_clk_info, + struct cam_ope_clk_bw_request *clk_info, + uint32_t base_clk) +{ + uint32_t next_clk_level; + uint32_t actual_clk; + bool rc = false; + + /* 1. if current request frame cycles(fc) are more than previous + * frame fc + * Calculate the new base clock. + * if sum of base clocks are more than next available clk level + * Update clock rate, change curr_clk_rate to sum of base clock + * rates and make over_clked to zero + * else + * Update clock rate to next level, update curr_clk_rate and make + * overclked cnt to zero + * 2. if current fc is less than or equal to previous frame fc + * Still Bump up the clock to next available level + * if it is available, then update clock, make overclk cnt to + * zero. If the clock is already at highest clock rate then + * no need to update the clock + */ + ctx_data->clk_info.base_clk = base_clk; + hw_mgr_clk_info->over_clked = 0; + if (clk_info->frame_cycles > ctx_data->clk_info.curr_fc) { + cam_ope_calc_total_clk(hw_mgr, hw_mgr_clk_info, + ctx_data->ope_acquire.dev_type); + actual_clk = cam_ope_get_actual_clk_rate(hw_mgr, + ctx_data, base_clk); + if (hw_mgr_clk_info->base_clk > actual_clk) { + hw_mgr_clk_info->curr_clk = hw_mgr_clk_info->base_clk; + } else { + next_clk_level = cam_ope_get_next_clk_rate(hw_mgr, + ctx_data, hw_mgr_clk_info->curr_clk); + hw_mgr_clk_info->curr_clk = next_clk_level; + } + rc = true; + } else { + next_clk_level = + cam_ope_get_next_clk_rate(hw_mgr, ctx_data, + hw_mgr_clk_info->curr_clk); + if (hw_mgr_clk_info->curr_clk < next_clk_level) { + hw_mgr_clk_info->curr_clk = next_clk_level; + rc = true; + } + } + ctx_data->clk_info.curr_fc = clk_info->frame_cycles; + + return rc; +} + +static bool cam_ope_check_clk_update(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, int idx) +{ + bool busy = false, rc = false; + uint32_t base_clk; + struct cam_ope_clk_bw_request *clk_info; + uint64_t req_id; + struct cam_ope_clk_info *hw_mgr_clk_info; + + /* TODO: Have default clock rates update */ + /* TODO: Add support for debug clock updates */ + cam_ope_req_timer_reset(ctx_data); + cam_ope_device_timer_reset(hw_mgr); + hw_mgr_clk_info = &hw_mgr->clk_info; + req_id = ctx_data->req_list[idx]->request_id; + if (ctx_data->req_cnt > 1) + busy = true; + + CAM_DBG(CAM_OPE, "busy = %d req_id = %lld", busy, req_id); + + clk_info = &ctx_data->req_list[idx]->clk_info; + + /* Calculate base clk rate */ + base_clk = cam_ope_mgr_calc_base_clk( + clk_info->frame_cycles, clk_info->budget_ns); + ctx_data->clk_info.rt_flag = clk_info->rt_flag; + + if (busy) + rc = cam_ope_update_clk_busy(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, base_clk); + else + rc = cam_ope_update_clk_free(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, base_clk); + + CAM_DBG(CAM_OPE, "bc = %d cc = %d busy = %d overclk = %d uc = %d", + hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk, + busy, hw_mgr_clk_info->over_clked, rc); + + return rc; +} + +static int cam_ope_mgr_update_clk_rate(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data) +{ + struct cam_ope_dev_clk_update clk_upd_cmd; + int i; + + clk_upd_cmd.clk_rate = hw_mgr->clk_info.curr_clk; + + CAM_DBG(CAM_PERF, "clk_rate %u for dev_type %d", clk_upd_cmd.clk_rate, + ctx_data->ope_acquire.dev_type); + + for (i = 0; i < ope_hw_mgr->num_ope; i++) { + hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( + hw_mgr->ope_dev_intf[i]->hw_priv, + OPE_HW_CLK_UPDATE, + &clk_upd_cmd, sizeof(clk_upd_cmd)); + } + + return 0; +} + +static bool cam_ope_update_bw_v2(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, + struct cam_ope_clk_info *hw_mgr_clk_info, + struct cam_ope_clk_bw_req_internal_v2 *clk_info, + bool busy) +{ + int i, path_index; + bool update_required = true; + + /* + * If current request bandwidth is different from previous frames, then + * recalculate bandwidth of all contexts of same hardware and update + * voting of bandwidth + */ + + for (i = 0; i < clk_info->num_paths; i++) + CAM_DBG(CAM_OPE, "clk_info camnoc = %lld busy = %d", + clk_info->axi_path[i].camnoc_bw, busy); + + if (clk_info->num_paths == ctx_data->clk_info.num_paths) { + update_required = false; + for (i = 0; i < clk_info->num_paths; i++) { + if ((clk_info->axi_path[i].transac_type == + ctx_data->clk_info.axi_path[i].transac_type) && + (clk_info->axi_path[i].path_data_type == + ctx_data->clk_info.axi_path[i].path_data_type) && + (clk_info->axi_path[i].camnoc_bw == + ctx_data->clk_info.axi_path[i].camnoc_bw) && + (clk_info->axi_path[i].mnoc_ab_bw == + ctx_data->clk_info.axi_path[i].mnoc_ab_bw)) { + continue; + } else { + update_required = true; + break; + } + } + } + + if (!update_required) { + CAM_DBG(CAM_OPE, + "Incoming BW hasn't changed, no update required"); + return false; + } + + if (busy) { + for (i = 0; i < clk_info->num_paths; i++) { + if (ctx_data->clk_info.axi_path[i].camnoc_bw > + clk_info->axi_path[i].camnoc_bw) + return false; + } + } + + /* + * Remove previous vote of this context from hw mgr first. + * hw_mgr_clk_info has all valid paths, with each path in its own index + */ + 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; + } + + ctx_data->clk_info.num_paths = clk_info->num_paths; + + memcpy(&ctx_data->clk_info.axi_path[0], + &clk_info->axi_path[0], + clk_info->num_paths * sizeof(struct cam_axi_per_path_bw_vote)); + + /* + * Add new vote of this context in hw mgr. + * hw_mgr_clk_info has all paths, with each path in its own index + */ + 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].path_data_type = + ctx_data->clk_info.axi_path[i].path_data_type; + hw_mgr_clk_info->axi_path[path_index].transac_type = + ctx_data->clk_info.axi_path[i].transac_type; + 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; + CAM_DBG(CAM_OPE, + "Consolidate Path Vote : Dev[%s] i[%d] path_idx[%d] : [%s %s] [%lld %lld]", + ctx_data->ope_acquire.dev_name, + i, path_index, + cam_cpas_axi_util_trans_type_to_string( + hw_mgr_clk_info->axi_path[path_index].transac_type), + cam_cpas_axi_util_path_type_to_string( + hw_mgr_clk_info->axi_path[path_index].path_data_type), + hw_mgr_clk_info->axi_path[path_index].camnoc_bw, + hw_mgr_clk_info->axi_path[path_index].mnoc_ab_bw); + } + + if (hw_mgr_clk_info->num_paths < ctx_data->clk_info.num_paths) + hw_mgr_clk_info->num_paths = ctx_data->clk_info.num_paths; + + return true; +} + +static bool cam_ope_check_bw_update(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, int idx) +{ + bool busy = false, bw_updated = false; + int i; + struct cam_ope_clk_bw_req_internal_v2 *clk_info_v2; + struct cam_ope_clk_info *hw_mgr_clk_info; + uint64_t req_id; + + hw_mgr_clk_info = &hw_mgr->clk_info; + req_id = ctx_data->req_list[idx]->request_id; + if (ctx_data->req_cnt > 1) + busy = true; + + clk_info_v2 = &ctx_data->req_list[idx]->clk_info_v2; + + bw_updated = cam_ope_update_bw_v2(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info_v2, busy); + + for (i = 0; i < hw_mgr_clk_info->num_paths; i++) { + CAM_DBG(CAM_OPE, + "Final path_type: %s, transac_type: %s, camnoc_bw = %lld mnoc_ab_bw = %lld, mnoc_ib_bw = %lld, device: %s", + cam_cpas_axi_util_path_type_to_string( + hw_mgr_clk_info->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + hw_mgr_clk_info->axi_path[i].transac_type), + hw_mgr_clk_info->axi_path[i].camnoc_bw, + hw_mgr_clk_info->axi_path[i].mnoc_ab_bw, + hw_mgr_clk_info->axi_path[i].mnoc_ib_bw, + ctx_data->ope_acquire.dev_name); + } + + return bw_updated; +} + +static int cam_ope_update_cpas_vote(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data) +{ + int i = 0; + struct cam_ope_clk_info *clk_info; + struct cam_ope_dev_bw_update bw_update = {{0}, {0}, 0, 0}; + + clk_info = &hw_mgr->clk_info; + + bw_update.ahb_vote.type = CAM_VOTE_DYNAMIC; + bw_update.ahb_vote.vote.freq = 0; + bw_update.ahb_vote_valid = false; + + + bw_update.axi_vote.num_paths = clk_info->num_paths; + memcpy(&bw_update.axi_vote.axi_path[0], + &clk_info->axi_path[0], + bw_update.axi_vote.num_paths * + sizeof(struct cam_axi_per_path_bw_vote)); + + bw_update.axi_vote_valid = true; + for (i = 0; i < ope_hw_mgr->num_ope; i++) { + 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)); + } + + return 0; +} + +static int cam_ope_mgr_ope_clk_update(struct cam_ope_hw_mgr *hw_mgr, + struct cam_ope_ctx *ctx_data, int idx) +{ + int rc = 0; + + if (cam_ope_check_clk_update(hw_mgr, ctx_data, idx)) + rc = cam_ope_mgr_update_clk_rate(hw_mgr, ctx_data); + + if (cam_ope_check_bw_update(hw_mgr, ctx_data, idx)) + rc |= cam_ope_update_cpas_vote(hw_mgr, ctx_data); + + return rc; +} static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, enum cam_cdm_cb_status status, uint64_t cookie) @@ -289,6 +1113,7 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, handle, userdata, status, cookie, ope_req->request_id, ctx->ctx_id); cam_ope_req_timer_reset(ctx); + cam_ope_device_timer_reset(ope_hw_mgr); } else if (status == CAM_CDM_CB_STATUS_HW_RESUBMIT) { CAM_INFO(CAM_OPE, "After reset of CDM and OPE, reapply req"); rc = cam_ope_mgr_reapply_config(ope_hw_mgr, ctx, ope_req); @@ -1344,10 +2169,12 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) } cam_ope_start_req_timer(ctx); + cam_ope_device_timer_start(hw_mgr); hw_mgr->ope_ctx_cnt++; ctx->context_priv = args->context_data; args->ctxt_to_hw_map = ctx; ctx->ctxt_event_cb = args->event_cb; + cam_ope_ctx_clk_info_init(ctx); ctx->ctx_state = OPE_CTX_STATE_ACQUIRED; mutex_unlock(&ctx->ctx_mutex); @@ -1502,29 +2329,26 @@ static int cam_ope_mgr_release_hw(void *hw_priv, void *hw_release_args) rc = cam_ope_mgr_release_ctx(hw_mgr, ctx_id); if (!hw_mgr->ope_ctx_cnt) { CAM_DBG(CAM_OPE, "Last Release"); - if (!hw_mgr->ope_ctx_cnt) { - for (i = 0; i < ope_hw_mgr->num_ope; i++) { - dev_intf = hw_mgr->ope_dev_intf[i]; - irq_cb.ope_hw_mgr_cb = NULL; - irq_cb.data = NULL; - rc = dev_intf->hw_ops.process_cmd( - hw_mgr->ope_dev_intf[i]->hw_priv, - OPE_HW_SET_IRQ_CB, - &irq_cb, sizeof(irq_cb)); - if (rc) - CAM_ERR(CAM_OPE, "IRQ dereg failed: %d", - rc); - } - for (i = 0; i < ope_hw_mgr->num_ope; i++) { - dev_intf = hw_mgr->ope_dev_intf[i]; - rc = dev_intf->hw_ops.deinit( - hw_mgr->ope_dev_intf[i]->hw_priv, - NULL, 0); - if (rc) - CAM_ERR(CAM_OPE, "deinit failed: %d", - rc); - } + for (i = 0; i < ope_hw_mgr->num_ope; i++) { + dev_intf = hw_mgr->ope_dev_intf[i]; + irq_cb.ope_hw_mgr_cb = NULL; + irq_cb.data = NULL; + rc = dev_intf->hw_ops.process_cmd( + hw_mgr->ope_dev_intf[i]->hw_priv, + OPE_HW_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + CAM_ERR(CAM_OPE, "IRQ dereg failed: %d", rc); } + for (i = 0; i < ope_hw_mgr->num_ope; i++) { + dev_intf = hw_mgr->ope_dev_intf[i]; + rc = dev_intf->hw_ops.deinit( + hw_mgr->ope_dev_intf[i]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_OPE, "deinit failed: %d", rc); + } + cam_ope_device_timer_stop(hw_mgr); } mutex_unlock(&hw_mgr->hw_mgr_mutex); @@ -1533,6 +2357,123 @@ static int cam_ope_mgr_release_hw(void *hw_priv, void *hw_release_args) return rc; } +static int cam_ope_packet_generic_blob_handler(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) +{ + struct cam_ope_clk_bw_request *clk_info; + struct ope_clk_bw_request_v2 *soc_req_v2; + struct cam_ope_clk_bw_req_internal_v2 *clk_info_v2; + struct ope_cmd_generic_blob *blob; + struct cam_ope_ctx *ctx_data; + uint32_t index; + size_t clk_update_size; + int rc = 0; + + if (!blob_data || (blob_size == 0)) { + CAM_ERR(CAM_OPE, "Invalid blob info %pK %d", blob_data, + blob_size); + return -EINVAL; + } + + blob = (struct ope_cmd_generic_blob *)user_data; + ctx_data = blob->ctx; + index = blob->req_idx; + + switch (blob_type) { + case OPE_CMD_GENERIC_BLOB_CLK_V2: + if (blob_size < sizeof(struct ope_clk_bw_request_v2)) { + CAM_ERR(CAM_OPE, "Mismatch blob size %d expected %lu", + blob_size, + sizeof(struct ope_clk_bw_request_v2)); + return -EINVAL; + } + + soc_req_v2 = (struct ope_clk_bw_request_v2 *)blob_data; + if (soc_req_v2->num_paths > CAM_OPE_MAX_PER_PATH_VOTES) { + CAM_ERR(CAM_OPE, "Invalid num paths: %d", + soc_req_v2->num_paths); + return -EINVAL; + } + + /* Check for integer overflow */ + if (soc_req_v2->num_paths != 1) { + if (sizeof(struct cam_axi_per_path_bw_vote) > + ((UINT_MAX - + sizeof(struct ope_clk_bw_request_v2)) / + (soc_req_v2->num_paths - 1))) { + CAM_ERR(CAM_OPE, + "Size exceeds limit paths:%u size per path:%lu", + soc_req_v2->num_paths - 1, + sizeof( + struct cam_axi_per_path_bw_vote)); + return -EINVAL; + } + } + + clk_update_size = sizeof(struct ope_clk_bw_request_v2) + + ((soc_req_v2->num_paths - 1) * + sizeof(struct cam_axi_per_path_bw_vote)); + if (blob_size < clk_update_size) { + CAM_ERR(CAM_OPE, "Invalid blob size: %u", + blob_size); + return -EINVAL; + } + + clk_info = &ctx_data->req_list[index]->clk_info; + clk_info_v2 = &ctx_data->req_list[index]->clk_info_v2; + + memcpy(clk_info_v2, soc_req_v2, clk_update_size); + + /* Use v1 structure for clk fields */ + clk_info->budget_ns = clk_info_v2->budget_ns; + clk_info->frame_cycles = clk_info_v2->frame_cycles; + clk_info->rt_flag = clk_info_v2->rt_flag; + + CAM_DBG(CAM_OPE, "budget=%llu, frame_cycle=%llu, rt_flag=%d", + clk_info_v2->budget_ns, clk_info_v2->frame_cycles, + clk_info_v2->rt_flag); + break; + + default: + CAM_WARN(CAM_OPE, "Invalid blob type %d", blob_type); + break; + } + return rc; +} + +static int cam_ope_process_generic_cmd_buffer( + struct cam_packet *packet, + struct cam_ope_ctx *ctx_data, + int32_t index, + uint64_t *io_buf_addr) +{ + int i, rc = 0; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct ope_cmd_generic_blob cmd_generic_blob; + + cmd_generic_blob.ctx = ctx_data; + cmd_generic_blob.req_idx = index; + cmd_generic_blob.io_buf_addr = io_buf_addr; + + 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].length) + continue; + + if (cmd_desc[i].meta_data != OPE_CMD_META_GENERIC_BLOB) + continue; + + rc = cam_packet_util_process_generic_cmd_buffer(&cmd_desc[i], + cam_ope_packet_generic_blob_handler, &cmd_generic_blob); + if (rc) + CAM_ERR(CAM_OPE, "Failed in processing blobs %d", rc); + } + + return rc; +} + static int cam_ope_mgr_prepare_hw_update(void *hw_priv, void *hw_prepare_update_args) { @@ -1641,6 +2582,13 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, goto end; } + rc = cam_ope_process_generic_cmd_buffer(packet, ctx_data, + request_idx, NULL); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + CAM_ERR(CAM_OPE, "Failed: %d", rc); + 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; @@ -1755,6 +2703,8 @@ static int cam_ope_mgr_config_hw(void *hw_priv, void *hw_config_args) config_args->hw_update_entries->addr; cdm_cmd->cookie = ope_req->req_idx; + cam_ope_mgr_ope_clk_update(hw_mgr, ctx_data, ope_req->req_idx); + rc = cam_ope_mgr_enqueue_config(hw_mgr, ctx_data, config_args); if (rc) goto config_err; 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 5544573c7ec7..aa29a05f90e3 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 @@ -52,6 +52,112 @@ #define OPE_MAX_CDM_BLS 16 +#define CAM_OPE_MAX_PER_PATH_VOTES 6 +#define CAM_OPE_BW_CONFIG_UNKNOWN 0 +#define CAM_OPE_BW_CONFIG_V2 2 + +#define CLK_HW_OPE 0x0 +#define CLK_HW_MAX 0x1 + +#define OPE_DEVICE_IDLE_TIMEOUT 400 + + +/** + * struct cam_ope_clk_bw_request_v2 + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @num_paths: Number of paths for per path bw vote + * @axi_path: Per path vote info for OPE + */ +struct cam_ope_clk_bw_req_internal_v2 { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_OPE_MAX_PER_PATH_VOTES]; +}; + +/** + * struct cam_ope_clk_bw_request + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @uncompressed_bw: Bandwidth required to process frame + * @compressed_bw: Compressed bandwidth to process frame + */ +struct cam_ope_clk_bw_request { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint64_t uncompressed_bw; + uint64_t compressed_bw; +}; + +/** + * struct cam_ctx_clk_info + * @curr_fc: Context latest request frame cycles + * @rt_flag: Flag to indicate real time request + * @base_clk: Base clock to process the request + * @reserved: Reserved field + * @uncompressed_bw: Current bandwidth voting + * @compressed_bw: Current compressed bandwidth voting + * @clk_rate: Supported clock rates for the context + * @num_paths: Number of valid AXI paths + * @axi_path: ctx based per path bw vote + */ +struct cam_ctx_clk_info { + uint32_t curr_fc; + uint32_t rt_flag; + uint32_t base_clk; + uint32_t reserved; + uint64_t uncompressed_bw; + uint64_t compressed_bw; + int32_t clk_rate[CAM_MAX_VOTE]; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_OPE_MAX_PER_PATH_VOTES]; +}; + +/** + * struct ope_cmd_generic_blob + * @ctx: Current context info + * @req_info_idx: Index used for request + * @io_buf_addr: pointer to io buffer address + */ +struct ope_cmd_generic_blob { + struct cam_ope_ctx *ctx; + uint32_t req_idx; + uint64_t *io_buf_addr; +}; + +/** + * struct cam_ope_clk_info + * @base_clk: Base clock to process request + * @curr_clk: Current clock of hadrware + * @threshold: Threshold for overclk count + * @over_clked: Over clock count + * @uncompressed_bw: Current bandwidth voting + * @compressed_bw: Current compressed bandwidth voting + * @num_paths: Number of AXI vote paths + * @axi_path: Current per path bw vote info + * @hw_type: IPE/BPS device type + * @watch_dog: watchdog timer handle + * @watch_dog_reset_counter: Counter for watch dog reset + */ +struct cam_ope_clk_info { + uint32_t base_clk; + uint32_t curr_clk; + uint32_t threshold; + uint32_t over_clked; + uint64_t uncompressed_bw; + uint64_t compressed_bw; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_OPE_MAX_PER_PATH_VOTES]; + uint32_t hw_type; + struct cam_req_mgr_timer *watch_dog; + uint32_t watch_dog_reset_counter; +}; + /** * struct ope_cmd_work_data * @@ -273,6 +379,8 @@ struct ope_io_buf { * @ope_debug_buf: Debug buffer * @io_buf: IO config info of a request * @cdm_cmd: CDM command for OPE CDM + * @clk_info: Clock Info V1 + * @clk_info_v2: Clock Info V2 */ struct cam_ope_request { uint64_t request_id; @@ -290,6 +398,8 @@ struct cam_ope_request { struct ope_debug_buffer ope_debug_buf; 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; }; /** @@ -320,6 +430,10 @@ struct cam_ope_cdm { * @req_list: Request List * @ope_cdm: OPE CDM info * @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 */ struct cam_ope_ctx { void *context_priv; @@ -336,6 +450,10 @@ struct cam_ope_ctx { struct cam_ope_request *req_list[CAM_CTX_REQ_MAX]; struct cam_ope_cdm ope_cdm; 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; }; /** @@ -366,6 +484,7 @@ struct cam_ope_ctx { * @timer_work_data: Timer work data * @ope_dev_intf: OPE device interface * @cdm_reg_map: OPE CDM register map + * @clk_info: OPE clock Info for HW manager */ struct cam_ope_hw_mgr { int32_t open_cnt; @@ -394,6 +513,7 @@ struct cam_ope_hw_mgr { struct ope_clk_work_data *timer_work_data; struct cam_hw_intf *ope_dev_intf[OPE_DEV_MAX]; struct cam_soc_reg_map *cdm_reg_map[OPE_DEV_MAX][OPE_BASE_MAX]; + struct cam_ope_clk_info clk_info; }; #endif /* CAM_OPE_HW_MGR_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 719a9fc62e25..e92a520dbdaa 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 @@ -1711,11 +1711,28 @@ int cam_ope_process_cmd(void *device_priv, uint32_t cmd_type, struct cam_ope_dev_clk_update *clk_upd_cmd = (struct cam_ope_dev_clk_update *)cmd_args; + if (core_info->clk_enable == false) { + rc = cam_soc_util_clk_enable_default(soc_info, + CAM_SVS_VOTE); + if (rc) { + CAM_ERR(CAM_OPE, "Clock enable is failed"); + return rc; + } + core_info->clk_enable = true; + } + rc = cam_ope_update_clk_rate(soc_info, clk_upd_cmd->clk_rate); if (rc) CAM_ERR(CAM_OPE, "Failed to update clk: %d", rc); } break; + case OPE_HW_CLK_DISABLE: { + if (core_info->clk_enable == true) + cam_soc_util_clk_disable_default(soc_info); + + core_info->clk_enable = false; + } + break; case OPE_HW_BW_UPDATE: { struct cam_ope_dev_bw_update *cpas_vote = cmd_args; 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 565a1696c84b..41e317168faa 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 @@ -12,20 +12,22 @@ #include "cam_cpas_api.h" -#define OPE_HW_INIT 0x1 -#define OPE_HW_DEINIT 0x2 -#define OPE_HW_ACQUIRE 0x3 -#define OPE_HW_RELEASE 0x4 -#define OPE_HW_START 0x5 -#define OPE_HW_STOP 0x6 -#define OPE_HW_FLUSH 0x7 -#define OPE_HW_PREPARE 0x8 -#define OPE_HW_ISR 0x9 -#define OPE_HW_PROBE 0xA -#define OPE_HW_CLK_UPDATE 0xB -#define OPE_HW_BW_UPDATE 0xC -#define OPE_HW_RESET 0xD -#define OPE_HW_SET_IRQ_CB 0xE +#define OPE_HW_INIT 0x1 +#define OPE_HW_DEINIT 0x2 +#define OPE_HW_ACQUIRE 0x3 +#define OPE_HW_RELEASE 0x4 +#define OPE_HW_START 0x5 +#define OPE_HW_STOP 0x6 +#define OPE_HW_FLUSH 0x7 +#define OPE_HW_PREPARE 0x8 +#define OPE_HW_ISR 0x9 +#define OPE_HW_PROBE 0xA +#define OPE_HW_CLK_UPDATE 0xB +#define OPE_HW_BW_UPDATE 0xC +#define OPE_HW_RESET 0xD +#define OPE_HW_SET_IRQ_CB 0xE +#define OPE_HW_CLK_DISABLE 0xF +#define OPE_HW_CLK_ENABLE 0x10 /** * struct cam_ope_dev_probe diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c index 7537bafd0ba9..0fbd46a73b70 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "ope_soc.h" #include "cam_soc_util.h" #include "cam_debug_util.h" diff --git a/include/uapi/media/cam_cpas.h b/include/uapi/media/cam_cpas.h index b85ab068f9e8..2a44d93497b4 100644 --- a/include/uapi/media/cam_cpas.h +++ b/include/uapi/media/cam_cpas.h @@ -43,6 +43,15 @@ #define CAM_AXI_PATH_DATA_IPE_MAX_OFFSET \ (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 31) +#define CAM_AXI_PATH_DATA_OPE_START_OFFSET 64 +#define CAM_AXI_PATH_DATA_OPE_RD_IN (CAM_AXI_PATH_DATA_OPE_START_OFFSET + 0) +#define CAM_AXI_PATH_DATA_OPE_RD_REF (CAM_AXI_PATH_DATA_OPE_START_OFFSET + 1) +#define CAM_AXI_PATH_DATA_OPE_WR_VID (CAM_AXI_PATH_DATA_OPE_START_OFFSET + 2) +#define CAM_AXI_PATH_DATA_OPE_WR_DISP (CAM_AXI_PATH_DATA_OPE_START_OFFSET + 3) +#define CAM_AXI_PATH_DATA_OPE_WR_REF (CAM_AXI_PATH_DATA_OPE_START_OFFSET + 4) +#define CAM_AXI_PATH_DATA_OPE_MAX_OFFSET \ + (CAM_AXI_PATH_DATA_OPE_START_OFFSET + 31) + #define CAM_AXI_PATH_DATA_ALL 256 /** -- GitLab From fefda431c1ab05bf555345d46dfbdb68cf3ab565 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Wed, 16 Oct 2019 18:07:20 +0530 Subject: [PATCH 004/295] msm: camera: ope: Corrected batch mode and stripe for ope Corrected the striping creation for non real time device. Disabled the ope stripe base bus. Corrected the batch mode creation for ope bus read. CRs-Fixed: 2520602 Change-Id: I87adbab25b84d74162a6a8ce2db1412a6d9058d0 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 2 ++ .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 14 +++++++---- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 23 ++++++++----------- 3 files changed, 21 insertions(+), 18 deletions(-) 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 45a96f2b0dc5..45ce11371517 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 @@ -1504,6 +1504,8 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, stripe_info->pack_format = pack_format; stripe_info->unpack_format = unpack_format; + stripe_info->disable_bus = + in_stripe_info->disable_bus; cam_ope_mgr_print_stripe_info(i, j, k, l, stripe_info, iova_addr); } 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 6053401d208c..13737462faf4 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 @@ -346,11 +346,15 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, header_size = cdm_ops->cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); - io_port_cdm->go_cmd_addr = kmd_buf; - io_port_cdm->go_cmd_len = - sizeof(temp) * (count + header_size); - io_port_cdm->go_cmd_offset = - prepare->kmd_buf_offset; + for (i = 0; i < ope_request->num_batch; i++) { + io_port_cdm = + &bus_rd_ctx->io_port_cdm_batch.io_port_cdm[i]; + io_port_cdm->go_cmd_addr = kmd_buf; + io_port_cdm->go_cmd_len = + sizeof(temp) * (count + header_size); + io_port_cdm->go_cmd_offset = + prepare->kmd_buf_offset; + } kmd_buf = cdm_ops->cdm_write_regrandom( kmd_buf, count/2, temp_reg); prepare->kmd_buf_offset += 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 e92a520dbdaa..65cc477aecd6 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 @@ -772,7 +772,7 @@ static uint32_t *ope_create_frame_cmd(struct cam_ope_hw_mgr *hw_mgr, hw_mgr->iommu_hdl); return NULL; } - iova_addr = iova_addr + frm_proc->cmd_buf[j][i].offset; + 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, @@ -1123,7 +1123,7 @@ static uint32_t *ope_create_stripes_nrt(struct cam_ope_hw_mgr *hw_mgr, struct cam_ope_ctx *ctx_data, uint32_t req_idx, uint32_t *kmd_buf, struct cam_ope_dev_prepare_req *ope_dev_prepare_req, - uint32_t kmd_buf_offset) + uint32_t *kmd_buf_offset, uint32_t **cdm_kmd_start_addr) { int i, j; struct cam_ope_request *ope_request; @@ -1133,13 +1133,10 @@ static uint32_t *ope_create_stripes_nrt(struct cam_ope_hw_mgr *hw_mgr, uint32_t stripe_idx = 0; struct cam_cdm_utils_ops *cdm_ops; uint32_t len; - uint32_t *cdm_kmd_start_addr; int num_nrt_stripes, num_arb; frm_proc = ope_dev_prepare_req->frame_process; ope_request = ctx_data->req_list[req_idx]; - cdm_kmd_start_addr = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr + - (kmd_buf_offset / sizeof(len)); num_nrt_stripes = ctx_data->ope_acquire.nrt_stripes_for_arb; num_arb = ope_request->num_stripes[0] / ctx_data->ope_acquire.nrt_stripes_for_arb; @@ -1162,17 +1159,17 @@ static uint32_t *ope_create_stripes_nrt(struct cam_ope_hw_mgr *hw_mgr, kmd_buf = cdm_ops->cdm_write_wait_comp_event( kmd_buf, OPE_WAIT_COMP_IDLE, 0x0); - len = (kmd_buf - cdm_kmd_start_addr) * + len = (kmd_buf - *cdm_kmd_start_addr) * sizeof(uint32_t); cam_ope_dev_prepare_cdm_request( ope_dev_prepare_req->hw_mgr, ope_dev_prepare_req->prepare_args, ope_dev_prepare_req->ctx_data, ope_dev_prepare_req->req_idx, - kmd_buf_offset, ope_dev_prepare_req, + *kmd_buf_offset, ope_dev_prepare_req, len, true); - cdm_kmd_start_addr = kmd_buf; - kmd_buf_offset += len; + *cdm_kmd_start_addr = kmd_buf; + *kmd_buf_offset += len; } /* cmd buffer stripes */ kmd_buf = ope_create_stripe_cmd(hw_mgr, ctx_data, @@ -1317,7 +1314,7 @@ static int cam_ope_dev_create_kmd_buf_nrt(struct cam_ope_hw_mgr *hw_mgr, /* Stripes */ kmd_buf = ope_create_stripes_nrt(hw_mgr, ctx_data, req_idx, kmd_buf, - ope_dev_prepare_req, kmd_buf_offset); + ope_dev_prepare_req, &kmd_buf_offset, &cdm_kmd_start_addr); if (!kmd_buf) { rc = -EINVAL; goto end; @@ -1358,7 +1355,7 @@ static int cam_ope_dev_create_kmd_buf_batch(struct cam_ope_hw_mgr *hw_mgr, frm_proc = ope_dev_prepare_req->frame_process; ope_request = ctx_data->req_list[req_idx]; kmd_buf = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr + - kmd_buf_offset; + (kmd_buf_offset / sizeof(len)); cdm_kmd_start_addr = kmd_buf; cdm_ops = ctx_data->ope_cdm.cdm_ops; @@ -1436,11 +1433,11 @@ static int cam_ope_dev_create_kmd_buf_batch(struct cam_ope_hw_mgr *hw_mgr, OPE_WAIT_COMP_IDLE, 0x0); /* prepare CDM submit packet */ - len = (cdm_kmd_start_addr - kmd_buf) * sizeof(uint32_t); + len = (kmd_buf - cdm_kmd_start_addr) * sizeof(uint32_t); cam_ope_dev_prepare_cdm_request(ope_dev_prepare_req->hw_mgr, ope_dev_prepare_req->prepare_args, ope_dev_prepare_req->ctx_data, ope_dev_prepare_req->req_idx, - ope_dev_prepare_req->kmd_buf_offset, ope_dev_prepare_req, + kmd_buf_offset, ope_dev_prepare_req, len, false); end: -- GitLab From 3d5af3d2f1bc09a0dae07a7d601033b90080f4b9 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Wed, 28 Aug 2019 11:17:51 +0530 Subject: [PATCH 005/295] msm: camera: isp: Move the ife hw manager resource to isp hw manager Hardware manager resource is generic. Move the resource definition to isp hw manager so that it can be used by other hw manager. Remove the parent and child graph in the hardware manager resource as it is not used. Use the common isp resource type everywhere. CRs-Fixed: 2545590 Change-Id: I41d49af0855f3bd3768450d850b1284ff1e3fea9 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 310 ++++++++---------- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 81 ++--- drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h | 48 ++- .../hw_utils/cam_isp_packet_parser.c | 51 +-- .../hw_utils/include/cam_isp_packet_parser.h | 14 +- .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 4 +- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 7 - .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 1 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 7 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 8 +- 10 files changed, 243 insertions(+), 288 deletions(-) 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 c43cb21c44e5..5c50555553fd 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 @@ -63,8 +63,8 @@ static int cam_ife_mgr_regspace_data_cb(uint32_t reg_base_type, uint32_t *reg_base_idx) { int rc = 0; - struct cam_ife_hw_mgr_res *hw_mgr_res; - struct cam_ife_hw_mgr_res *hw_mgr_res_temp; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res_temp; struct cam_hw_soc_info *soc_info = NULL; struct cam_ife_hw_mgr_ctx *ctx = (struct cam_ife_hw_mgr_ctx *) hw_mgr_ctx; @@ -261,7 +261,7 @@ static int cam_ife_hw_mgr_is_rdi_res(uint32_t res_id) } static int cam_ife_hw_mgr_reset_csid_res( - struct cam_ife_hw_mgr_res *isp_hw_res) + struct cam_isp_hw_mgr_res *isp_hw_res) { int i; int rc = 0; @@ -294,7 +294,7 @@ static int cam_ife_hw_mgr_reset_csid_res( } static int cam_ife_hw_mgr_init_hw_res( - struct cam_ife_hw_mgr_res *isp_hw_res) + struct cam_isp_hw_mgr_res *isp_hw_res) { int i; int rc = -1; @@ -323,7 +323,7 @@ static int cam_ife_hw_mgr_init_hw_res( } static int cam_ife_hw_mgr_start_hw_res( - struct cam_ife_hw_mgr_res *isp_hw_res, + struct cam_isp_hw_mgr_res *isp_hw_res, struct cam_ife_hw_mgr_ctx *ctx) { int i; @@ -359,7 +359,7 @@ static int cam_ife_hw_mgr_start_hw_res( } static void cam_ife_hw_mgr_stop_hw_res( - struct cam_ife_hw_mgr_res *isp_hw_res) + struct cam_isp_hw_mgr_res *isp_hw_res) { int i; struct cam_hw_intf *hw_intf; @@ -381,7 +381,7 @@ static void cam_ife_hw_mgr_stop_hw_res( else CAM_ERR(CAM_ISP, "stop null"); if (hw_intf->hw_ops.process_cmd && - isp_hw_res->res_type == CAM_IFE_HW_MGR_RES_IFE_OUT) { + isp_hw_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, &dummy_args, sizeof(dummy_args)); @@ -390,7 +390,7 @@ static void cam_ife_hw_mgr_stop_hw_res( } static void cam_ife_hw_mgr_deinit_hw_res( - struct cam_ife_hw_mgr_res *isp_hw_res) + struct cam_isp_hw_mgr_res *isp_hw_res) { int i; struct cam_hw_intf *hw_intf; @@ -409,7 +409,7 @@ static void cam_ife_hw_mgr_deinit_hw_res( static void cam_ife_hw_mgr_deinit_hw( struct cam_ife_hw_mgr_ctx *ctx) { - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; int i = 0; if (!ctx->init_done) { @@ -449,7 +449,7 @@ static void cam_ife_hw_mgr_deinit_hw( static int cam_ife_hw_mgr_init_hw( struct cam_ife_hw_mgr_ctx *ctx) { - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; int rc = 0, i; CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d", @@ -523,10 +523,10 @@ static int cam_ife_hw_mgr_init_hw( static int cam_ife_hw_mgr_put_res( struct list_head *src_list, - struct cam_ife_hw_mgr_res **res) + struct cam_isp_hw_mgr_res **res) { int rc = 0; - struct cam_ife_hw_mgr_res *res_ptr = NULL; + struct cam_isp_hw_mgr_res *res_ptr = NULL; res_ptr = *res; if (res_ptr) @@ -537,14 +537,14 @@ static int cam_ife_hw_mgr_put_res( static int cam_ife_hw_mgr_get_res( struct list_head *src_list, - struct cam_ife_hw_mgr_res **res) + struct cam_isp_hw_mgr_res **res) { int rc = 0; - struct cam_ife_hw_mgr_res *res_ptr = NULL; + struct cam_isp_hw_mgr_res *res_ptr = NULL; if (!list_empty(src_list)) { res_ptr = list_first_entry(src_list, - struct cam_ife_hw_mgr_res, list); + struct cam_isp_hw_mgr_res, list); list_del_init(&res_ptr->list); } else { CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx"); @@ -556,7 +556,7 @@ static int cam_ife_hw_mgr_get_res( } static int cam_ife_hw_mgr_free_hw_res( - struct cam_ife_hw_mgr_res *isp_hw_res) + struct cam_isp_hw_mgr_res *isp_hw_res) { int rc = 0; int i; @@ -657,8 +657,8 @@ static void cam_ife_hw_mgr_dump_src_acq_info( struct cam_ife_hw_mgr_ctx *hwr_mgr_ctx, uint32_t num_pix_port, uint32_t num_rdi_port) { - struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; + struct cam_isp_hw_mgr_res *hw_mgr_res = NULL; + struct cam_isp_hw_mgr_res *hw_mgr_res_temp = NULL; struct cam_isp_resource_node *hw_res = NULL; int i = 0; @@ -685,8 +685,8 @@ static void cam_ife_hw_mgr_dump_src_acq_info( static void cam_ife_hw_mgr_dump_acq_data( struct cam_ife_hw_mgr_ctx *hwr_mgr_ctx) { - struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; + struct cam_isp_hw_mgr_res *hw_mgr_res = NULL; + struct cam_isp_hw_mgr_res *hw_mgr_res_temp = NULL; struct cam_isp_resource_node *hw_res = NULL; struct timespec64 *ts = NULL; uint64_t ms, tmp, hrs, min, sec; @@ -793,7 +793,7 @@ static int cam_ife_mgr_csid_stop_hw( struct cam_ife_hw_mgr_ctx *ctx, struct list_head *stop_list, uint32_t base_idx, uint32_t stop_cmd) { - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_isp_resource_node *isp_res; struct cam_isp_resource_node *stop_res[CAM_IFE_PIX_PATH_RES_MAX - 1]; struct cam_csid_hw_stop_args stop; @@ -833,8 +833,8 @@ static int cam_ife_hw_mgr_release_hw_for_ctx( struct cam_ife_hw_mgr_ctx *ife_ctx) { uint32_t i; - struct cam_ife_hw_mgr_res *hw_mgr_res; - struct cam_ife_hw_mgr_res *hw_mgr_res_temp; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res_temp; /* ife leaf resource */ for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) @@ -869,7 +869,7 @@ static int cam_ife_hw_mgr_release_hw_for_ctx( } /* ife root node */ - if (ife_ctx->res_list_ife_in.res_type != CAM_IFE_HW_MGR_RES_UNINIT) + if (ife_ctx->res_list_ife_in.res_type != CAM_ISP_RESOURCE_UNINT) cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_in); /* clean up the callback function */ @@ -962,7 +962,7 @@ static void cam_ife_mgr_add_base_info( static int cam_ife_mgr_process_base_info( struct cam_ife_hw_mgr_ctx *ctx) { - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_isp_resource_node *res = NULL; uint32_t i; @@ -973,7 +973,7 @@ static int cam_ife_mgr_process_base_info( /* IFE mux in resources */ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { - if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT) continue; for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { @@ -998,9 +998,9 @@ static int cam_ife_hw_mgr_acquire_res_bus_rd( { int rc = -EINVAL; struct cam_vfe_acquire_args vfe_acquire; - struct cam_ife_hw_mgr_res *ife_in_rd_res; + struct cam_isp_hw_mgr_res *ife_in_rd_res; struct cam_hw_intf *hw_intf; - struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_isp_hw_mgr_res *ife_src_res; int i; CAM_DBG(CAM_ISP, "Enter"); @@ -1023,7 +1023,7 @@ static int cam_ife_hw_mgr_acquire_res_bus_rd( vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; vfe_acquire.priv = ife_ctx; vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; - vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; + vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_isp; for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { if (!ife_src_res->hw_res[i]) continue; @@ -1032,7 +1032,7 @@ static int cam_ife_hw_mgr_acquire_res_bus_rd( if (i == CAM_ISP_HW_SPLIT_LEFT) { vfe_acquire.vfe_out.split_id = CAM_ISP_HW_SPLIT_LEFT; - if (ife_src_res->is_dual_vfe) { + if (ife_src_res->is_dual_isp) { /*TBD */ vfe_acquire.vfe_out.is_master = 1; vfe_acquire.vfe_out.dual_slave_core = @@ -1066,9 +1066,8 @@ static int cam_ife_hw_mgr_acquire_res_bus_rd( ife_in_rd_res->hw_res[i]->res_id); } - ife_in_rd_res->is_dual_vfe = in_port->usage_type; - ife_in_rd_res->res_type = (enum cam_ife_hw_mgr_res_type) - CAM_ISP_RESOURCE_VFE_BUS_RD; + ife_in_rd_res->is_dual_isp = in_port->usage_type; + ife_in_rd_res->res_type = CAM_ISP_RESOURCE_VFE_BUS_RD; } return 0; @@ -1079,13 +1078,13 @@ static int cam_ife_hw_mgr_acquire_res_bus_rd( static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_ife_hw_mgr_res *ife_src_res, - struct cam_isp_in_port_generic_info *in_port) + struct cam_isp_hw_mgr_res *ife_src_res, + struct cam_isp_in_port_generic_info *in_port) { int rc = -EINVAL; struct cam_vfe_acquire_args vfe_acquire; struct cam_isp_out_port_generic_info *out_port = NULL; - struct cam_ife_hw_mgr_res *ife_out_res; + struct cam_isp_hw_mgr_res *ife_out_res; struct cam_hw_intf *hw_intf; uint32_t i, vfe_out_res_id, vfe_in_res_id; @@ -1152,13 +1151,10 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( } ife_out_res->hw_res[0] = vfe_acquire.vfe_out.rsrc_node; - ife_out_res->is_dual_vfe = 0; + ife_out_res->is_dual_isp = 0; ife_out_res->res_id = vfe_out_res_id; - ife_out_res->res_type = (enum cam_ife_hw_mgr_res_type) - CAM_ISP_RESOURCE_VFE_OUT; - ife_src_res->child[ife_src_res->num_children++] = ife_out_res; - CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", - ife_src_res->num_children); + ife_out_res->res_type = CAM_ISP_RESOURCE_VFE_OUT; + ife_src_res->num_children++; return 0; err: @@ -1166,16 +1162,16 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( } static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( - struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_ife_hw_mgr_res *ife_src_res, + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_hw_mgr_res *ife_src_res, struct cam_isp_in_port_generic_info *in_port, - bool acquire_lcr) + bool acquire_lcr) { int rc = -1; uint32_t i, j, k; struct cam_vfe_acquire_args vfe_acquire; struct cam_isp_out_port_generic_info *out_port; - struct cam_ife_hw_mgr_res *ife_out_res; + struct cam_isp_hw_mgr_res *ife_out_res; struct cam_hw_intf *hw_intf; for (i = 0; i < in_port->num_out_res; i++) { @@ -1205,14 +1201,14 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( CAM_DBG(CAM_ISP, "res_type 0x%x", out_port->res_type); ife_out_res = &ife_ctx->res_list_ife_out[k]; - ife_out_res->is_dual_vfe = in_port->usage_type; + ife_out_res->is_dual_isp = in_port->usage_type; vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_OUT; vfe_acquire.tasklet = ife_ctx->common.tasklet_info; vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; vfe_acquire.priv = ife_ctx; vfe_acquire.vfe_out.out_port_info = out_port; - vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; + vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_isp; vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; @@ -1225,7 +1221,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( if (j == CAM_ISP_HW_SPLIT_LEFT) { vfe_acquire.vfe_out.split_id = CAM_ISP_HW_SPLIT_LEFT; - if (ife_src_res->is_dual_vfe) { + if (ife_src_res->is_dual_isp) { /*TBD */ vfe_acquire.vfe_out.is_master = 1; vfe_acquire.vfe_out.dual_slave_core = @@ -1260,13 +1256,9 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( ife_out_res->hw_res[j]->res_id); } - ife_out_res->res_type = - (enum cam_ife_hw_mgr_res_type)CAM_ISP_RESOURCE_VFE_OUT; + ife_out_res->res_type = CAM_ISP_RESOURCE_VFE_OUT; ife_out_res->res_id = out_port->res_type; - ife_out_res->parent = ife_src_res; - ife_src_res->child[ife_src_res->num_children++] = ife_out_res; - CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", - ife_src_res->num_children); + ife_src_res->num_children++; } return 0; @@ -1280,7 +1272,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out( struct cam_isp_in_port_generic_info *in_port) { int rc = -EINVAL; - struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_isp_hw_mgr_res *ife_src_res; list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) { if (ife_src_res->num_children) @@ -1324,8 +1316,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_rd_src( struct cam_isp_in_port_generic_info *in_port) { int rc = -1; - struct cam_ife_hw_mgr_res *csid_res; - struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_isp_hw_mgr_res *csid_res; + struct cam_isp_hw_mgr_res *ife_src_res; struct cam_vfe_acquire_args vfe_acquire; struct cam_hw_intf *hw_intf; struct cam_ife_hw_mgr *ife_hw_mgr; @@ -1357,10 +1349,9 @@ static int cam_ife_hw_mgr_acquire_res_ife_rd_src( vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RD; vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; - ife_src_res->res_type = - (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_src_res->res_type = vfe_acquire.rsrc_type; ife_src_res->res_id = vfe_acquire.vfe_in.res_id; - ife_src_res->is_dual_vfe = csid_res->is_dual_vfe; + ife_src_res->is_dual_isp = csid_res->is_dual_isp; hw_intf = ife_hw_mgr->ife_devices[csid_res->hw_res[ @@ -1372,7 +1363,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_rd_src( /* * fill in more acquire information as needed */ - if (ife_src_res->is_dual_vfe) + if (ife_src_res->is_dual_isp) vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER; rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, @@ -1392,7 +1383,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_rd_src( ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_type, ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_id); - if (!ife_src_res->is_dual_vfe) + if (!ife_src_res->is_dual_isp) goto acq; for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { @@ -1430,13 +1421,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_rd_src( * It should be one to one mapping between * csid resource and ife source resource */ - csid_res->child[0] = ife_src_res; - ife_src_res->parent = csid_res; - csid_res->child[csid_res->num_children++] = ife_src_res; - CAM_DBG(CAM_ISP, - "csid_res=%d CSID num_children=%d ife_src_res=%d", - csid_res->res_id, csid_res->num_children, - ife_src_res->res_id); + csid_res->num_children++; } err: @@ -1522,8 +1507,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( { int rc = -1; int i; - struct cam_ife_hw_mgr_res *csid_res; - struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_isp_hw_mgr_res *csid_res; + struct cam_isp_hw_mgr_res *ife_src_res; struct cam_vfe_acquire_args vfe_acquire; struct cam_hw_intf *hw_intf; struct cam_ife_hw_mgr *ife_hw_mgr; @@ -1561,7 +1546,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( else vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_LCR; - if (csid_res->is_dual_vfe) + if (csid_res->is_dual_isp) vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER; else @@ -1595,10 +1580,9 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( CAM_ERR(CAM_ISP, "Wrong IFE CSID Resource Node"); goto err; } - ife_src_res->res_type = - (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_src_res->res_type = vfe_acquire.rsrc_type; ife_src_res->res_id = vfe_acquire.vfe_in.res_id; - ife_src_res->is_dual_vfe = csid_res->is_dual_vfe; + ife_src_res->is_dual_isp = csid_res->is_dual_isp; for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { if (!csid_res->hw_res[i]) @@ -1610,7 +1594,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( /* fill in more acquire information as needed */ /* slave Camif resource, */ if (i == CAM_ISP_HW_SPLIT_RIGHT && - ife_src_res->is_dual_vfe) + ife_src_res->is_dual_isp) vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_SLAVE; @@ -1644,13 +1628,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( ife_src_res->hw_res[i]->res_id); } - - ife_src_res->parent = csid_res; - csid_res->child[csid_res->num_children++] = ife_src_res; - CAM_DBG(CAM_ISP, - "csid_res=%d CSID num_children=%d ife_src_res=%d", - csid_res->res_id, csid_res->num_children, - ife_src_res->res_id); + csid_res->num_children++; } return 0; @@ -1660,16 +1638,16 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( } static int cam_ife_mgr_acquire_cid_res( - struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_generic_info *in_port, - struct cam_ife_hw_mgr_res **cid_res, - enum cam_ife_pix_path_res_id path_res_id) + struct cam_isp_hw_mgr_res **cid_res, + enum cam_ife_pix_path_res_id path_res_id) { int rc = -1; int i, j; - struct cam_ife_hw_mgr *ife_hw_mgr; - struct cam_hw_intf *hw_intf; - struct cam_ife_hw_mgr_res *cid_res_temp, *cid_res_iterator; + struct cam_ife_hw_mgr *ife_hw_mgr; + struct cam_hw_intf *hw_intf; + struct cam_isp_hw_mgr_res *cid_res_temp, *cid_res_iterator; struct cam_csid_hw_reserve_resource_args csid_acquire; uint32_t acquired_cnt = 0; struct cam_isp_out_port_generic_info *out_port = NULL; @@ -1802,10 +1780,10 @@ static int cam_ife_mgr_acquire_cid_res( CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d", in_port->usage_type); - cid_res_temp->res_type = CAM_IFE_HW_MGR_RES_CID; + cid_res_temp->res_type = CAM_ISP_RESOURCE_CID; /* CID(DT_ID) value of acquire device, require for path */ cid_res_temp->res_id = csid_acquire.node_res->res_id; - cid_res_temp->is_dual_vfe = in_port->usage_type; + cid_res_temp->is_dual_isp = in_port->usage_type; ife_ctx->is_dual = (bool)in_port->usage_type; if (in_port->num_out_res) @@ -1817,7 +1795,7 @@ static int cam_ife_mgr_acquire_cid_res( * Acquire Right if not already acquired. * Dual IFE for RDI and PPP is not currently supported. */ - if (cid_res_temp->is_dual_vfe && path_res_id + if (cid_res_temp->is_dual_isp && path_res_id == CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) { csid_acquire.node_res = NULL; csid_acquire.res_type = CAM_ISP_RESOURCE_CID; @@ -1847,11 +1825,6 @@ static int cam_ife_mgr_acquire_cid_res( CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d", in_port->usage_type); } - cid_res_temp->parent = &ife_ctx->res_list_ife_in; - ife_ctx->res_list_ife_in.child[ - ife_ctx->res_list_ife_in.num_children++] = cid_res_temp; - CAM_DBG(CAM_ISP, "IFE IN num_children = %d", - ife_ctx->res_list_ife_in.num_children); return 0; put_res: @@ -1872,8 +1845,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( int master_idx = -1; struct cam_ife_hw_mgr *ife_hw_mgr; - struct cam_ife_hw_mgr_res *csid_res; - struct cam_ife_hw_mgr_res *cid_res; + struct cam_isp_hw_mgr_res *csid_res; + struct cam_isp_hw_mgr_res *cid_res; struct cam_hw_intf *hw_intf; struct cam_csid_hw_reserve_resource_args csid_acquire; enum cam_ife_pix_path_res_id path_res_id; @@ -1899,22 +1872,21 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( goto end; } - csid_res->res_type = - (enum cam_ife_hw_mgr_res_type)CAM_ISP_RESOURCE_PIX_PATH; + csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; csid_res->res_id = path_res_id; if (in_port->usage_type && is_ipp) - csid_res->is_dual_vfe = 1; + csid_res->is_dual_isp = 1; else { - csid_res->is_dual_vfe = 0; + csid_res->is_dual_isp = 0; csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; } CAM_DBG(CAM_ISP, "CSID Acq: E"); /* IPP resource needs to be from same HW as CID resource */ - for (i = 0; i <= csid_res->is_dual_vfe; i++) { - CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe); + for (i = 0; i <= csid_res->is_dual_isp; i++) { + CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_isp); csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; csid_acquire.res_id = path_res_id; @@ -1927,7 +1899,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( hw_intf = cid_res->hw_res[i]->hw_intf; - if (csid_res->is_dual_vfe) { + if (csid_res->is_dual_isp) { if (i == CAM_ISP_HW_SPLIT_LEFT) { master_idx = hw_intf->hw_idx; csid_acquire.sync_mode = @@ -1960,12 +1932,11 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( (is_ipp) ? "IPP" : "PPP"); } cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); - - csid_res->parent = cid_res; - cid_res->child[cid_res->num_children++] = csid_res; + cid_res->num_children++; CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", csid_acquire.res_id, cid_res->num_children); + return 0; put_res: cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); @@ -2011,11 +1982,11 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( int rc = -EINVAL; int i; - struct cam_ife_hw_mgr *ife_hw_mgr; - struct cam_ife_hw_mgr_res *csid_res; - struct cam_ife_hw_mgr_res *cid_res; - struct cam_hw_intf *hw_intf; - struct cam_isp_out_port_generic_info *out_port; + struct cam_ife_hw_mgr *ife_hw_mgr; + struct cam_isp_hw_mgr_res *csid_res; + struct cam_isp_hw_mgr_res *cid_res; + struct cam_hw_intf *hw_intf; + struct cam_isp_out_port_generic_info *out_port; struct cam_csid_hw_reserve_resource_args csid_acquire; enum cam_ife_pix_path_res_id path_res_id; @@ -2082,19 +2053,13 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( goto put_res; } - csid_res->res_type = (enum cam_ife_hw_mgr_res_type) - CAM_ISP_RESOURCE_PIX_PATH; + csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; csid_res->res_id = csid_acquire.res_id; - csid_res->is_dual_vfe = 0; + csid_res->is_dual_isp = 0; csid_res->hw_res[0] = csid_acquire.node_res; csid_res->hw_res[1] = NULL; - csid_res->parent = cid_res; - cid_res->child[cid_res->num_children++] = - csid_res; - CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", - csid_acquire.res_id, cid_res->num_children); cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); - + cid_res->num_children++; } return 0; @@ -2110,11 +2075,11 @@ static int cam_ife_hw_mgr_acquire_res_root( { int rc = -1; - if (ife_ctx->res_list_ife_in.res_type == CAM_IFE_HW_MGR_RES_UNINIT) { + if (ife_ctx->res_list_ife_in.res_type == CAM_ISP_RESOURCE_UNINT) { /* first acquire */ - ife_ctx->res_list_ife_in.res_type = CAM_IFE_HW_MGR_RES_ROOT; + ife_ctx->res_list_ife_in.res_type = CAM_ISP_RESOURCE_SRC; ife_ctx->res_list_ife_in.res_id = in_port->res_type; - ife_ctx->res_list_ife_in.is_dual_vfe = in_port->usage_type; + ife_ctx->res_list_ife_in.is_dual_isp = in_port->usage_type; } else if ((ife_ctx->res_list_ife_in.res_id != in_port->res_type) && (!ife_ctx->is_fe_enable)) { CAM_ERR(CAM_ISP, "No Free resource for this context"); @@ -2304,7 +2269,7 @@ static int cam_ife_mgr_acquire_hw_for_ctx( uint32_t *acquired_hw_id, uint32_t *acquired_hw_path) { int rc = -1; - int is_dual_vfe = 0; + int is_dual_isp = 0; int ipp_count = 0; int rdi_count = 0; int ppp_count = 0; @@ -2312,12 +2277,11 @@ static int cam_ife_mgr_acquire_hw_for_ctx( int lcr_count = 0; bool crop_enable = true; - is_dual_vfe = in_port->usage_type; - + is_dual_isp = in_port->usage_type; /* get root node resource */ rc = cam_ife_hw_mgr_acquire_res_root(ife_ctx, in_port); if (rc) { - CAM_ERR(CAM_ISP, "Can not acquire csid rx resource"); + CAM_ERR(CAM_ISP, "Can not acquire root resource"); goto err; } @@ -2430,7 +2394,7 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, } hw_update_data = (struct cam_isp_prepare_hw_update_data *)userdata; - ctx = (struct cam_ife_hw_mgr_ctx *)hw_update_data->ife_mgr_ctx; + ctx = (struct cam_ife_hw_mgr_ctx *)hw_update_data->isp_mgr_ctx; if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { complete_all(&ctx->config_done_complete); @@ -3091,7 +3055,7 @@ static const char *cam_isp_util_usage_data_to_string( } static int cam_isp_classify_vote_info( - struct cam_ife_hw_mgr_res *hw_mgr_res, + struct cam_isp_hw_mgr_res *hw_mgr_res, struct cam_isp_bw_config_v2 *bw_config, struct cam_axi_vote *isp_vote, uint32_t split_idx, @@ -3188,7 +3152,7 @@ static int cam_isp_blob_bw_update_v2( struct cam_isp_bw_config_v2 *bw_config, struct cam_ife_hw_mgr_ctx *ctx) { - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; struct cam_vfe_bw_update_args_v2 bw_upd_args; int rc = -EINVAL; @@ -3255,7 +3219,7 @@ static int cam_isp_blob_bw_update( struct cam_isp_bw_config *bw_config, struct cam_ife_hw_mgr_ctx *ctx) { - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; struct cam_vfe_bw_update_args bw_upd_args; uint64_t cam_bw_bps = 0; @@ -3380,7 +3344,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, return -EINVAL; hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; - hw_update_data->ife_mgr_ctx = ctx; + hw_update_data->isp_mgr_ctx = ctx; CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld", ctx, ctx->ctx_index, cfg->request_id); @@ -3490,7 +3454,7 @@ static int cam_ife_mgr_stop_hw_in_overflow(void *stop_hw_args) { int rc = 0; struct cam_hw_stop_args *stop_args = stop_hw_args; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_ife_hw_mgr_ctx *ctx; uint32_t i, master_base_idx = 0; @@ -3575,7 +3539,7 @@ static int cam_ife_mgr_stop_hw_in_overflow(void *stop_hw_args) static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx, enum cam_vfe_bw_control_action action) { - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; struct cam_vfe_bw_control_args bw_ctrl_args; int rc = -EINVAL; @@ -3620,7 +3584,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) int rc = 0; struct cam_hw_stop_args *stop_args = stop_hw_args; struct cam_isp_stop_args *stop_isp; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_ife_hw_mgr_ctx *ctx; enum cam_ife_csid_halt_cmd csid_halt_type; uint32_t i, master_base_idx = 0; @@ -3783,7 +3747,7 @@ static int cam_ife_mgr_restart_hw(void *start_hw_args) int rc = -1; struct cam_hw_start_args *start_args = start_hw_args; struct cam_ife_hw_mgr_ctx *ctx; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; uint32_t i; if (!start_hw_args) { @@ -3862,7 +3826,7 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) struct cam_hw_stop_args stop_args; struct cam_isp_stop_args stop_isp; struct cam_ife_hw_mgr_ctx *ctx; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_isp_resource_node *rsrc_node = NULL; uint32_t i, camif_debug; bool res_rdi_context_set = false; @@ -4096,7 +4060,7 @@ static int cam_ife_mgr_reset(void *hw_mgr_priv, void *hw_reset_args) struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; struct cam_hw_reset_args *reset_args = hw_reset_args; struct cam_ife_hw_mgr_ctx *ctx; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; int rc = 0, i = 0; if (!hw_mgr_priv || !hw_reset_args) { @@ -4197,7 +4161,7 @@ static int cam_isp_blob_fe_update( struct cam_hw_prepare_update_args *prepare) { struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; int rc = -EINVAL; uint32_t i; @@ -4271,7 +4235,7 @@ static int cam_isp_blob_ubwc_update( struct cam_ubwc_plane_cfg_v1 *ubwc_plane_cfg; struct cam_kmd_buf_info *kmd_buf_info; struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; uint32_t res_id_out, i; uint32_t total_used_bytes = 0; uint32_t kmd_buf_remain_size; @@ -4442,7 +4406,7 @@ static int cam_isp_blob_ubwc_update_v2( struct cam_ubwc_plane_cfg_v2 *ubwc_plane_cfg; struct cam_kmd_buf_info *kmd_buf_info; struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; uint32_t res_id_out, i; uint32_t total_used_bytes = 0; uint32_t kmd_buf_remain_size; @@ -4560,7 +4524,7 @@ static int cam_isp_blob_hfr_update( struct cam_isp_port_hfr_config *port_hfr_config; struct cam_kmd_buf_info *kmd_buf_info; struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; uint32_t res_id_out, i; uint32_t total_used_bytes = 0; uint32_t kmd_buf_remain_size; @@ -4656,7 +4620,7 @@ static int cam_isp_blob_csid_clock_update( struct cam_hw_prepare_update_args *prepare) { struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; struct cam_ife_csid_clock_update_args csid_clock_upd_args; uint64_t clk_rate = 0; @@ -4703,7 +4667,7 @@ static int cam_isp_blob_csid_qcfa_update( struct cam_hw_prepare_update_args *prepare) { struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; struct cam_ife_csid_qcfa_update_args csid_qcfa_upd_args; int rc = -EINVAL; @@ -4751,7 +4715,7 @@ static int cam_isp_blob_core_cfg_update( struct cam_hw_prepare_update_args *prepare) { struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; uint64_t clk_rate = 0; int rc = 0, i; @@ -4799,7 +4763,7 @@ static int cam_isp_blob_clock_update( struct cam_hw_prepare_update_args *prepare) { struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; struct cam_vfe_clock_update_args clock_upd_args; uint64_t clk_rate = 0; @@ -4910,7 +4874,7 @@ static int cam_isp_blob_vfe_out_update( struct cam_isp_vfe_wm_config *wm_config; struct cam_kmd_buf_info *kmd_buf_info; struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *ife_out_res; + struct cam_isp_hw_mgr_res *ife_out_res; uint32_t res_id_out, i; uint32_t total_used_bytes = 0; uint32_t kmd_buf_remain_size; @@ -5650,7 +5614,7 @@ static int cam_ife_mgr_sof_irq_debug( { int rc = 0; uint32_t i = 0; - struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_isp_hw_mgr_res *hw_mgr_res = NULL; struct cam_hw_intf *hw_intf = NULL; struct cam_isp_resource_node *rsrc_node = NULL; @@ -5886,7 +5850,7 @@ static int cam_ife_mgr_cmd_get_sof_timestamp( { int rc = -EINVAL; uint32_t i; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; struct cam_csid_get_time_stamp_args csid_get_time; @@ -5938,12 +5902,12 @@ static int cam_ife_mgr_cmd_get_sof_timestamp( static int cam_ife_mgr_process_recovery_cb(void *priv, void *data) { int32_t rc = 0; - struct cam_hw_event_recovery_data *recovery_data = data; - struct cam_hw_start_args start_args; - struct cam_hw_stop_args stop_args; - struct cam_ife_hw_mgr *ife_hw_mgr = priv; - struct cam_ife_hw_mgr_res *hw_mgr_res; - uint32_t i = 0; + struct cam_ife_hw_event_recovery_data *recovery_data = data; + struct cam_hw_start_args start_args; + struct cam_hw_stop_args stop_args; + struct cam_ife_hw_mgr *ife_hw_mgr = priv; + struct cam_isp_hw_mgr_res *hw_mgr_res; + uint32_t i = 0; uint32_t error_type = recovery_data->error_type; struct cam_ife_hw_mgr_ctx *ctx = NULL; @@ -6030,19 +5994,19 @@ static int cam_ife_mgr_process_recovery_cb(void *priv, void *data) } static int cam_ife_hw_mgr_do_error_recovery( - struct cam_hw_event_recovery_data *ife_mgr_recovery_data) + struct cam_ife_hw_event_recovery_data *ife_mgr_recovery_data) { - int32_t rc = 0; - struct crm_workq_task *task = NULL; - struct cam_hw_event_recovery_data *recovery_data = NULL; + int32_t rc = 0; + struct crm_workq_task *task = NULL; + struct cam_ife_hw_event_recovery_data *recovery_data = NULL; - recovery_data = kzalloc(sizeof(struct cam_hw_event_recovery_data), + recovery_data = kzalloc(sizeof(struct cam_ife_hw_event_recovery_data), GFP_ATOMIC); if (!recovery_data) return -ENOMEM; memcpy(recovery_data, ife_mgr_recovery_data, - sizeof(struct cam_hw_event_recovery_data)); + sizeof(struct cam_ife_hw_event_recovery_data)); CAM_DBG(CAM_ISP, "Enter: error_type (%d)", recovery_data->error_type); @@ -6115,9 +6079,9 @@ static bool cam_ife_hw_mgr_is_ctx_affected( * b. Notify CTX with fatal error */ static int cam_ife_hw_mgr_find_affected_ctx( - struct cam_isp_hw_error_event_data *error_event_data, - uint32_t curr_core_idx, - struct cam_hw_event_recovery_data *recovery_data) + struct cam_isp_hw_error_event_data *error_event_data, + uint32_t curr_core_idx, + struct cam_ife_hw_event_recovery_data *recovery_data) { uint32_t affected_core[CAM_IFE_HW_NUM_MAX] = {0}; struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = NULL; @@ -6177,11 +6141,11 @@ static int cam_ife_hw_mgr_find_affected_ctx( static int cam_ife_hw_mgr_handle_hw_err( void *evt_info) { - struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_isp_hw_event_info *event_info = evt_info; uint32_t core_idx; - struct cam_isp_hw_error_event_data error_event_data = {0}; - struct cam_hw_event_recovery_data recovery_data = {0}; - int rc = -EINVAL; + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_ife_hw_event_recovery_data recovery_data = {0}; + int rc = -EINVAL; if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) error_event_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; @@ -6699,7 +6663,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) int i, j; struct cam_iommu_handle cdm_handles; struct cam_ife_hw_mgr_ctx *ctx_pool; - struct cam_ife_hw_mgr_res *res_list_ife_out; + struct cam_isp_hw_mgr_res *res_list_ife_out; CAM_DBG(CAM_ISP, "Enter"); diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 7e6b91bab916..6ca5a8f42314 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -13,68 +13,11 @@ #include "cam_ife_csid_hw_intf.h" #include "cam_tasklet_util.h" -/* enum cam_ife_hw_mgr_res_type - manager resource node type */ -enum cam_ife_hw_mgr_res_type { - CAM_IFE_HW_MGR_RES_UNINIT, - CAM_IFE_HW_MGR_RES_ROOT, - CAM_IFE_HW_MGR_RES_CID, - CAM_IFE_HW_MGR_RES_CSID, - CAM_IFE_HW_MGR_RES_IFE_SRC, - CAM_IFE_HW_MGR_RES_IFE_IN_RD, - CAM_IFE_HW_MGR_RES_IFE_OUT, -}; - /* IFE resource constants */ #define CAM_IFE_HW_IN_RES_MAX (CAM_ISP_IFE_IN_RES_MAX & 0xFF) #define CAM_IFE_HW_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_MAX & 0xFF) #define CAM_IFE_HW_RES_POOL_MAX 64 -/** - * struct cam_vfe_hw_mgr_res- HW resources for the VFE manager - * - * @list: used by the resource list - * @res_type: IFE manager resource type - * @res_id: resource id based on the resource type for root or - * leaf resource, it matches the KMD interface port id. - * For branch resrouce, it is defined by the ISP HW - * layer - * @hw_res: hw layer resource array. For single VFE, only one VFE - * hw resrouce will be acquired. For dual VFE, two hw - * resources from different VFE HW device will be - * acquired - * @parent: point to the parent resource node. - * @children: point to the children resource nodes - * @child_num: numbe of the child resource node. - * @is_secure informs whether the resource is in secure mode or not - * - */ -struct cam_ife_hw_mgr_res { - struct list_head list; - enum cam_ife_hw_mgr_res_type res_type; - uint32_t res_id; - uint32_t is_dual_vfe; - struct cam_isp_resource_node *hw_res[CAM_ISP_HW_SPLIT_MAX]; - - /* graph */ - struct cam_ife_hw_mgr_res *parent; - struct cam_ife_hw_mgr_res *child[CAM_IFE_HW_OUT_RES_MAX]; - uint32_t num_children; - uint32_t is_secure; -}; - - -/** - * struct ctx_base_info - Base hardware information for the context - * - * @idx: Base resource index - * @split_id: Split info for the base resource - * - */ -struct ctx_base_info { - uint32_t idx; - enum cam_isp_hw_split_id split_id; -}; - /** * struct cam_ife_hw_mgr_debug - contain the debug information * @@ -147,20 +90,20 @@ struct cam_ife_hw_mgr_ctx { struct cam_ife_hw_mgr *hw_mgr; uint32_t ctx_in_use; - struct cam_ife_hw_mgr_res res_list_ife_in; + struct cam_isp_hw_mgr_res res_list_ife_in; struct list_head res_list_ife_cid; struct list_head res_list_ife_csid; struct list_head res_list_ife_src; struct list_head res_list_ife_in_rd; - struct cam_ife_hw_mgr_res res_list_ife_out[ + struct cam_isp_hw_mgr_res res_list_ife_out[ CAM_IFE_HW_OUT_RES_MAX]; struct list_head free_res_list; - struct cam_ife_hw_mgr_res res_pool[CAM_IFE_HW_RES_POOL_MAX]; + struct cam_isp_hw_mgr_res res_pool[CAM_IFE_HW_RES_POOL_MAX]; uint32_t irq_status0_mask[CAM_IFE_HW_NUM_MAX]; uint32_t irq_status1_mask[CAM_IFE_HW_NUM_MAX]; - struct ctx_base_info base[CAM_IFE_HW_NUM_MAX]; + struct cam_isp_ctx_base_info base[CAM_IFE_HW_NUM_MAX]; uint32_t num_base; uint32_t cdm_handle; struct cam_cdm_utils_ops *cdm_ops; @@ -221,6 +164,22 @@ struct cam_ife_hw_mgr { struct cam_ife_hw_mgr_debug debug_cfg; }; +/** + * struct cam_ife_hw_event_recovery_data - Payload for the recovery procedure + * + * @error_type: Error type that causes the recovery + * @affected_core: Array of the hardware cores that are affected + * @affected_ctx: Array of the hardware contexts that are affected + * @no_of_context: Actual number of the affected context + * + */ +struct cam_ife_hw_event_recovery_data { + uint32_t error_type; + uint32_t affected_core[CAM_ISP_HW_NUM_MAX]; + struct cam_ife_hw_mgr_ctx *affected_ctx[CAM_CTX_MAX]; + uint32_t no_of_context; +}; + /** * cam_ife_hw_mgr_init() * diff --git a/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h index 69e24bcc8625..99f665de82e2 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h @@ -6,8 +6,11 @@ #ifndef _CAM_ISP_HW_MGR_H_ #define _CAM_ISP_HW_MGR_H_ +#include #include "cam_isp_hw_mgr_intf.h" #include "cam_tasklet_util.h" +#include "cam_isp_hw.h" + #define CAM_ISP_HW_NUM_MAX 7 @@ -50,18 +53,43 @@ struct cam_isp_hw_mgr { }; /** - * struct cam_hw_event_recovery_data - Payload for the recovery procedure + * struct cam_isp_hw_mgr_res- HW resources for the ISP hw manager + * + * @list: used by the resource list + * @res_type: ISP manager resource type + * @res_id: resource id based on the resource type for root or + * leaf resource, it matches the KMD interface port id. + * For branch resrouce, it is defined by the ISP HW + * layer + * @is_dual_isp is dual isp hw resource + * @hw_res: hw layer resource array. For single ISP, only one ISP + * hw resrouce will be acquired. For dual ISP, two hw + * resources from different ISP HW device will be + * acquired + * @is_secure informs whether the resource is in secure mode or not + * @num_children: number of the child resource node. + * + */ +struct cam_isp_hw_mgr_res { + struct list_head list; + enum cam_isp_resource_type res_type; + uint32_t res_id; + uint32_t is_dual_isp; + struct cam_isp_resource_node *hw_res[CAM_ISP_HW_SPLIT_MAX]; + uint32_t is_secure; + uint32_t num_children; +}; + + +/** + * struct cam_isp_ctx_base_info - Base hardware information for the context * - * @error_type: Error type that causes the recovery - * @affected_core: Array of the hardware cores that are affected - * @affected_ctx: Array of the hardware contexts that are affected - * @no_of_context: Actual number of the affected context + * @idx: Base resource index + * @split_id: Split info for the base resource * */ -struct cam_hw_event_recovery_data { - uint32_t error_type; - uint32_t affected_core[CAM_ISP_HW_NUM_MAX]; - struct cam_ife_hw_mgr_ctx *affected_ctx[CAM_CTX_MAX]; - uint32_t no_of_context; +struct cam_isp_ctx_base_info { + uint32_t idx; + enum cam_isp_hw_split_id split_id; }; #endif /* _CAM_ISP_HW_MGR_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 86a14229915f..b87326694424 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -18,7 +18,7 @@ int cam_isp_add_change_base( struct cam_kmd_buf_info *kmd_buf_info) { int rc = -EINVAL; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_isp_resource_node *res; struct cam_isp_hw_get_cmd_update get_base; struct cam_hw_update_entry *hw_entry; @@ -35,7 +35,7 @@ int cam_isp_add_change_base( } list_for_each_entry(hw_mgr_res, res_list_isp_src, list) { - if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT) continue; for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { @@ -91,12 +91,12 @@ static int cam_isp_update_dual_config( struct cam_cmd_buf_desc *cmd_desc, uint32_t split_id, uint32_t base_idx, - struct cam_ife_hw_mgr_res *res_list_isp_out, + struct cam_isp_hw_mgr_res *res_list_isp_out, uint32_t size_isp_out) { int rc = -EINVAL; struct cam_isp_dual_config *dual_config; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_isp_resource_node *res; struct cam_isp_hw_dual_isp_update_args dual_isp_update_args; uint32_t outport_id; @@ -180,7 +180,7 @@ static int cam_isp_update_dual_config( } int cam_isp_add_cmd_buf_update( - struct cam_ife_hw_mgr_res *hw_mgr_res, + struct cam_isp_hw_mgr_res *hw_mgr_res, uint32_t cmd_type, uint32_t hw_cmd_type, uint32_t base_idx, @@ -195,7 +195,7 @@ int cam_isp_add_cmd_buf_update( uint32_t i; uint32_t total_used_bytes = 0; - if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) { + if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT) { CAM_ERR(CAM_ISP, "io res id:%d not valid", hw_mgr_res->res_type); return -EINVAL; @@ -243,9 +243,9 @@ int cam_isp_add_cmd_buf_update( int cam_isp_add_command_buffers( struct cam_hw_prepare_update_args *prepare, struct cam_kmd_buf_info *kmd_buf_info, - struct ctx_base_info *base_info, + struct cam_isp_ctx_base_info *base_info, cam_packet_generic_blob_handler blob_handler_cb, - struct cam_ife_hw_mgr_res *res_list_isp_out, + struct cam_isp_hw_mgr_res *res_list_isp_out, uint32_t size_isp_out) { int rc = 0; @@ -460,7 +460,7 @@ int cam_isp_add_io_buffers( struct cam_hw_prepare_update_args *prepare, uint32_t base_idx, struct cam_kmd_buf_info *kmd_buf_info, - struct cam_ife_hw_mgr_res *res_list_isp_out, + struct cam_isp_hw_mgr_res *res_list_isp_out, struct list_head *res_list_ife_in_rd, uint32_t size_isp_out, bool fill_fence) @@ -469,7 +469,7 @@ int cam_isp_add_io_buffers( dma_addr_t io_addr[CAM_PACKET_MAX_PLANES]; struct cam_buf_io_cfg *io_cfg; struct cam_isp_resource_node *res; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_isp_hw_get_cmd_update update_buf; struct cam_isp_hw_get_wm_update wm_update; struct cam_isp_hw_get_wm_update bus_rd_update; @@ -540,7 +540,7 @@ int cam_isp_add_io_buffers( } hw_mgr_res = &res_list_isp_out[res_id_out]; - if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) { + if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT) { CAM_ERR(CAM_ISP, "io res id:%d not valid", io_cfg[i].resource_type); return -EINVAL; @@ -550,10 +550,15 @@ int cam_isp_add_io_buffers( CAM_DBG(CAM_ISP, "configure input io with fill fence %d", fill_fence); + if (!res_list_ife_in_rd) { + CAM_ERR(CAM_ISP, + "No ISP in Read supported"); + return -EINVAL; + } if (!list_empty(res_list_ife_in_rd)) { hw_mgr_res = list_first_entry(res_list_ife_in_rd, - struct cam_ife_hw_mgr_res, list); + struct cam_isp_hw_mgr_res, list); } else { CAM_ERR(CAM_ISP, "No IFE in Read resource"); @@ -606,10 +611,11 @@ int cam_isp_add_io_buffers( break; hdl = io_cfg[i].mem_handle[plane_id]; - if (res->process_cmd(res, - CAM_ISP_HW_CMD_GET_SECURE_MODE, - &mode, - sizeof(bool))) + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + &mode, sizeof(bool)); + if (rc) return -EINVAL; is_buf_secure = cam_mem_is_secure_buf(hdl); @@ -716,10 +722,11 @@ int cam_isp_add_io_buffers( break; hdl = io_cfg[i].mem_handle[plane_id]; - if (res->process_cmd(res, - CAM_ISP_HW_CMD_GET_SECURE_MODE, - &mode, - sizeof(bool))) + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + &mode, sizeof(bool)); + if (rc) return -EINVAL; is_buf_secure = cam_mem_is_secure_buf(hdl); @@ -852,7 +859,7 @@ int cam_isp_add_reg_update( { int rc = -EINVAL; struct cam_isp_resource_node *res; - struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_update_entry *hw_entry; struct cam_isp_hw_get_cmd_update get_regup; uint32_t kmd_buf_remain_size, num_ent, i, reg_update_size; @@ -869,7 +876,7 @@ int cam_isp_add_reg_update( reg_update_size = 0; list_for_each_entry(hw_mgr_res, res_list_isp_src, list) { - if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT) continue; for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h index c9bd4c4430e9..4f3d9324d245 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h @@ -9,7 +9,7 @@ #include #include #include "cam_isp_hw_mgr_intf.h" -#include "cam_ife_hw_mgr.h" +#include "cam_isp_hw_mgr.h" #include "cam_hw_intf.h" #include "cam_packet_util.h" @@ -25,12 +25,12 @@ enum cam_isp_cdm_bl_type { * struct cam_isp_generic_blob_info * * @prepare: Payload for prepare command - * @ctx_base_info: Base hardware information for the context + * @base_info: Base hardware information for the context * @kmd_buf_info: Kmd buffer to store the custom cmd data */ struct cam_isp_generic_blob_info { struct cam_hw_prepare_update_args *prepare; - struct ctx_base_info *base_info; + struct cam_isp_ctx_base_info *base_info; struct cam_kmd_buf_info *kmd_buf_info; }; @@ -77,7 +77,7 @@ int cam_isp_add_change_base( * otherwise returns bytes used */ int cam_isp_add_cmd_buf_update( - struct cam_ife_hw_mgr_res *hw_mgr_res, + struct cam_isp_hw_mgr_res *hw_mgr_res, uint32_t cmd_type, uint32_t hw_cmd_type, uint32_t base_idx, @@ -105,9 +105,9 @@ int cam_isp_add_cmd_buf_update( int cam_isp_add_command_buffers( struct cam_hw_prepare_update_args *prepare, struct cam_kmd_buf_info *kmd_buf_info, - struct ctx_base_info *base_info, + struct cam_isp_ctx_base_info *base_info, cam_packet_generic_blob_handler blob_handler_cb, - struct cam_ife_hw_mgr_res *res_list_isp_out, + struct cam_isp_hw_mgr_res *res_list_isp_out, uint32_t size_isp_out); /* @@ -137,7 +137,7 @@ int cam_isp_add_io_buffers( struct cam_hw_prepare_update_args *prepare, uint32_t base_idx, struct cam_kmd_buf_info *kmd_buf_info, - struct cam_ife_hw_mgr_res *res_list_isp_out, + struct cam_isp_hw_mgr_res *res_list_isp_out, struct list_head *res_list_ife_in_rd, uint32_t size_isp_out, bool fill_fence); diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 6d5d0fd61c88..f83f392edc92 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -115,7 +115,7 @@ struct cam_isp_bw_config_internal { /** * struct cam_isp_prepare_hw_update_data - hw prepare data * - * @ife_mgr_ctx: IFE HW manager Context for current request + * @isp_mgr_ctx: ISP HW manager Context for current request * @packet_opcode_type: Packet header opcode in the packet header * this opcode defines, packet is init packet or * update packet @@ -129,7 +129,7 @@ struct cam_isp_bw_config_internal { * */ struct cam_isp_prepare_hw_update_data { - struct cam_ife_hw_mgr_ctx *ife_mgr_ctx; + void *isp_mgr_ctx; uint32_t packet_opcode_type; uint32_t bw_config_version; struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX]; 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 7ac79feb2a9f..29a414b71297 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 @@ -224,13 +224,6 @@ struct cam_isp_hw_get_cmd_update { void *data; struct cam_isp_hw_get_wm_update *wm_update; struct cam_isp_hw_get_wm_update *rm_update; - struct cam_isp_port_hfr_config *hfr_update; - struct cam_isp_clock_config *clock_update; - struct cam_isp_bw_config *bw_update; - struct cam_ubwc_plane_cfg_v1 *ubwc_update; - struct cam_fe_config *fe_update; - struct cam_vfe_generic_ubwc_config *ubwc_config; - struct cam_isp_vfe_wm_config *wm_config; }; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 11d6a602117c..a9dbcf5d001f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -604,6 +604,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_UBWC_UPDATE: case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: + case CAM_ISP_HW_CMD_GET_SECURE_MODE: rc = core_info->vfe_bus->hw_ops.process_cmd( core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 9094f1409a66..450de00b7b48 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -3004,7 +3004,7 @@ static int cam_vfe_bus_update_hfr(void *priv, void *cmd_args, } reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; - hfr_cfg = update_hfr->hfr_update; + hfr_cfg = (struct cam_isp_port_hfr_config *)update_hfr->data; for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { @@ -3116,7 +3116,7 @@ static int cam_vfe_bus_update_ubwc_config(void *cmd_args) goto end; } - ubwc_plane_cfg = update_ubwc->ubwc_update; + ubwc_plane_cfg = (struct cam_ubwc_plane_cfg_v1 *)update_ubwc->data; for (i = 0; i < vfe_out_data->num_wm; i++) { @@ -3226,7 +3226,8 @@ static int cam_vfe_bus_update_ubwc_config_v2(void *cmd_args) goto end; } - ubwc_generic_cfg = update_ubwc->ubwc_config; + ubwc_generic_cfg = (struct cam_vfe_generic_ubwc_config *) + update_ubwc->data; for (i = 0; i < vfe_out_data->num_wm; i++) { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index cae125315895..5146b81a5f03 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -3200,7 +3200,7 @@ static int cam_vfe_bus_ver3_update_hfr(void *priv, void *cmd_args, } reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; - hfr_cfg = update_hfr->hfr_update; + hfr_cfg = (struct cam_isp_port_hfr_config *)update_hfr->data; for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { @@ -3315,7 +3315,8 @@ static int cam_vfe_bus_ver3_update_ubwc_config_v2(void *cmd_args) goto end; } - ubwc_generic_cfg = update_ubwc->ubwc_config; + ubwc_generic_cfg = (struct cam_vfe_generic_ubwc_config *) + update_ubwc->data; for (i = 0; i < vfe_out_data->num_wm; i++) { @@ -3483,7 +3484,8 @@ static int cam_vfe_bus_ver3_update_wm_config( wm_config_update = cmd_args; vfe_out_data = wm_config_update->res->res_priv; - wm_config = wm_config_update->wm_config; + wm_config = (struct cam_isp_vfe_wm_config *) + wm_config_update->data; if (!vfe_out_data || !vfe_out_data->cdm_util_ops || !wm_config) { CAM_ERR(CAM_ISP, "Invalid data"); -- GitLab From 71322ba5d55617d13375b80e5146ac586c55898b Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Fri, 20 Sep 2019 11:55:13 +0530 Subject: [PATCH 006/295] msm: camera: cpas: Add support for Bengal camnoc Bengal has different version of camnoc which requires separate register space and camnoc interface changes. This change adds the same. CRs-Fixed: 2531812 Change-Id: I2a8e6cb8894444cb669ab1c4da5fa706dc6543ad Signed-off-by: Rishabh Jain --- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 20 +- drivers/cam_cpas/cpas_top/cam_cpastop_hw.h | 4 + drivers/cam_cpas/cpas_top/cpastop_v540_100.h | 241 +++++++++++++++++++ drivers/cam_cpas/include/cam_cpas_api.h | 1 + 4 files changed, 261 insertions(+), 5 deletions(-) create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v540_100.h diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 0543397a8482..643a72277dc8 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -22,6 +22,7 @@ #include "cpastop_v175_120.h" #include "cpastop_v175_130.h" #include "cpastop_v480_100.h" +#include "cpastop_v540_100.h" struct cam_camnoc_info *camnoc_info; @@ -122,6 +123,10 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, (hw_caps->camera_version.minor == 8) && (hw_caps->camera_version.incr == 0)) { soc_info->hw_version = CAM_CPAS_TITAN_480_V100; + } else if ((hw_caps->camera_version.major == 5) && + (hw_caps->camera_version.minor == 4) && + (hw_caps->camera_version.incr == 0)) { + soc_info->hw_version = CAM_CPAS_TITAN_540_V100; } CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); @@ -517,8 +522,7 @@ static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) int i; struct cam_cpas_hw_errata_wa_list *errata_wa_list = camnoc_info->errata_wa_list; - struct cam_cpas_hw_errata_wa *errata_wa = - &errata_wa_list->tcsr_camera_hf_sf_ares_glitch; + struct cam_cpas_hw_errata_wa *errata_wa; cam_cpastop_reset_irq(cpas_hw); for (i = 0; i < camnoc_info->specific_size; i++) { @@ -540,9 +544,12 @@ static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) } } - if (errata_wa->enable) { - scm_io_write(errata_wa->data.reg_info.offset, - errata_wa->data.reg_info.value); + if (errata_wa_list) { + errata_wa = &errata_wa_list->tcsr_camera_hf_sf_ares_glitch; + if (errata_wa->enable) { + scm_io_write(errata_wa->data.reg_info.offset, + errata_wa->data.reg_info.value); + } } return 0; @@ -623,6 +630,9 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, case CAM_CPAS_TITAN_480_V100: camnoc_info = &cam480_cpas100_camnoc_info; break; + case CAM_CPAS_TITAN_540_V100: + camnoc_info = &cam540_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/cam_cpastop_hw.h b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h index a4d44a3feff6..1804d93354ed 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h @@ -106,6 +106,8 @@ enum cam_camnoc_hw_irq_type { * @CAM_CAMNOC_JPEG: Indicates JPEG HW connection to camnoc * @CAM_CAMNOC_FD: Indicates FD HW connection to camnoc * @CAM_CAMNOC_ICP: Indicates ICP HW connection to camnoc + * @CAM_CAMNOC_TFE: Indicates TFE HW connection to camnoc + * @CAM_CAMNOC_OPE: Indicates OPE HW connection to camnoc */ enum cam_camnoc_port_type { CAM_CAMNOC_CDM, @@ -128,6 +130,8 @@ enum cam_camnoc_port_type { CAM_CAMNOC_JPEG, CAM_CAMNOC_FD, CAM_CAMNOC_ICP, + CAM_CAMNOC_TFE, + CAM_CAMNOC_OPE, }; /** diff --git a/drivers/cam_cpas/cpas_top/cpastop_v540_100.h b/drivers/cam_cpas/cpas_top/cpastop_v540_100.h new file mode 100644 index 000000000000..6ad0b91afd37 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v540_100.h @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V540_100_H_ +#define _CPASTOP_V540_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v540_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_v540_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, + }, + }, +}; + + +// TODO: Need to update cam_cpas_v540_100_camnoc_specific values based on QoS +static struct cam_camnoc_specific + cam_cpas_v540_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 = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE34, /* CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE38, /* CDM_URGENCY_LOW */ + .value = 0x2, + }, + .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 = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_HIGH */ + .offset = 0x34, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x38, /* TFE_URGENCY_LOW */ + .value = 0X10030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x40, /* TFE_DANGERLUT_LOW */ + .value = 0xFFAA5500, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x48, /* TFE_SAFELUT_LOW */ + .value = 0xFF00, + }, + .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 = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* OPE_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x438, /* OPE_URGENCY_LOW */ + .value = 0x3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* OPE_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .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 cam540_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 cam540_cpas100_camnoc_info = { + .specific = &cam_cpas_v540_100_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v540_100_camnoc_specific), + .irq_sbm = &cam_cpas_v540_100_irq_sbm, + .irq_err = &cam_cpas_v540_100_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v540_100_irq_err), + .err_logger = &cam540_cpas100_err_logger_offsets, + .errata_wa_list = NULL, +}; + +#endif /* _CPASTOP_V540_100_H_ */ diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 7c551dfcf8a5..ab8634f7119e 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -46,6 +46,7 @@ enum cam_cpas_hw_version { CAM_CPAS_TITAN_175_V120 = 0x175120, CAM_CPAS_TITAN_175_V130 = 0x175130, CAM_CPAS_TITAN_480_V100 = 0x480100, + CAM_CPAS_TITAN_540_V100 = 0x540100, CAM_CPAS_TITAN_MAX }; -- GitLab From f4473f657c4d9d08b4ed8b05d097eaa461ae145e Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Thu, 3 Oct 2019 16:13:47 +0530 Subject: [PATCH 007/295] msm: camera: ope: Support 32 bit arch Update datatypes to work with 32 bit kernel. CRs-Fixed: 2543730 Change-Id: I72d628152134770d7e09c3684443e25c47d9d1dc Signed-off-by: Trishansh Bhardwaj --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 6 +++--- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) 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 45ce11371517..bdda9f5ee576 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 @@ -1363,7 +1363,7 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, { int rc = 0; int i, j, k, l; - uint64_t iova_addr; + dma_addr_t iova_addr; size_t len; struct ope_frame_process *in_frame_process; struct ope_frame_set *in_frame_set; @@ -1522,8 +1522,8 @@ static int cam_ope_mgr_process_cmd_buf_req(struct cam_ope_hw_mgr *hw_mgr, { int rc = 0; int i, j; - uint64_t iova_addr; - uint64_t iova_cdm_addr; + dma_addr_t iova_addr; + dma_addr_t iova_cdm_addr; uintptr_t cpu_addr; size_t len; struct ope_frame_process *frame_process; 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 65cc477aecd6..63c0207c72a2 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 @@ -462,7 +462,7 @@ static uint32_t *ope_create_frame_cmd_prefetch_dis( 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; - uint64_t iova_addr; + dma_addr_t iova_addr; uintptr_t cpu_addr; size_t buf_len; uint32_t print_idx; @@ -574,7 +574,7 @@ static uint32_t *ope_create_frame_cmd_batch(struct cam_ope_hw_mgr *hw_mgr, 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; - uint64_t iova_addr; + dma_addr_t iova_addr; uintptr_t cpu_addr; size_t buf_len; uint32_t print_idx; @@ -729,7 +729,7 @@ static uint32_t *ope_create_frame_cmd(struct cam_ope_hw_mgr *hw_mgr, 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; - uint64_t iova_addr; + dma_addr_t iova_addr; uintptr_t cpu_addr; size_t buf_len; uint32_t print_idx; @@ -833,7 +833,7 @@ static uint32_t *ope_create_stripe_cmd(struct cam_ope_hw_mgr *hw_mgr, int rc = 0, i, j, k; uint32_t temp[3]; struct cdm_dmi_cmd *dmi_cmd; - uint64_t iova_addr; + dma_addr_t iova_addr; uintptr_t cpu_addr; size_t buf_len; uint32_t print_idx; -- GitLab From 66a75b70a88bade5288ad5c0d7e06b8a9dad5aa0 Mon Sep 17 00:00:00 2001 From: Abhilash Kumar Date: Fri, 8 Nov 2019 14:54:03 +0530 Subject: [PATCH 008/295] msm: camera: cdm: Correct bitvalue for burst enable The bit corrresponding to enabling burst is 4th bit. This change fixes its value by assigning the same. Change-Id: Ibeec3fd4460f9040255fa77f60fd565aed824c1c Signed-off-by: Abhilash Kumar --- drivers/cam_cdm/cam_cdm_core_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.h b/drivers/cam_cdm/cam_cdm_core_common.h index c7a55b58e0c6..5cde7c504fa2 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.h +++ b/drivers/cam_cdm/cam_cdm_core_common.h @@ -17,7 +17,7 @@ #define CAM_CDM_AHB_BURST_LEN_4 (BIT(2) - 1) #define CAM_CDM_AHB_BURST_LEN_8 (BIT(3) - 1) #define CAM_CDM_AHB_BURST_LEN_16 (BIT(4) - 1) -#define CAM_CDM_AHB_BURST_EN BIT(5) +#define CAM_CDM_AHB_BURST_EN BIT(4) #define CAM_CDM_AHB_STOP_ON_ERROR BIT(8) #define CAM_CDM_ARB_SEL_RR BIT(16) #define CAM_CDM_IMPLICIT_WAIT_EN BIT(17) -- GitLab From 235f2967675d594d189ee6a4a9d7e4a547fe0cbe Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Wed, 30 Oct 2019 15:22:06 +0530 Subject: [PATCH 009/295] msm: camera: common: Fix integer overflow in shift Various drivers are using right shift by 32 to check if dma address is 32 bit addressable. This will result in shift count overflow in 32 bit arch. CRs-Fixed: 2543730 Change-Id: I57e30bc9c0a8179c8d74f3bd3b6567bdfff60741 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 2 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index a02adb4cb202..e82c04b44890 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -4490,7 +4490,7 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, "get src buf address fail rc %d", rc); continue; } - if (iova_addr >> 32) { + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { CAM_ERR(CAM_ICP, "Invalid mapped address"); rc = -EINVAL; continue; 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 5c50555553fd..afa45ef05521 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 @@ -5707,7 +5707,7 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, io_cfg[i].mem_handle[j]); continue; } - if (iova_addr >> 32) { + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { CAM_ERR(CAM_ISP, "Invalid mapped address"); rc = -EINVAL; continue; diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index e5cbc66e066d..532b426437b9 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -660,7 +660,7 @@ static void cam_jpeg_mgr_print_io_bufs(struct cam_packet *packet, CAM_ERR(CAM_UTIL, "get src buf address fail"); continue; } - if (iova_addr >> 32) { + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { CAM_ERR(CAM_JPEG, "Invalid mapped address"); rc = -EINVAL; continue; -- GitLab From 55246ba70b6d175661b038fd29d1580fffe3219b Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Fri, 18 Oct 2019 14:41:33 +0530 Subject: [PATCH 010/295] msm: camera: tfe: Add support to TFE driver TFE is thin front end hardware that capture and process the real time image. Support is added to enable the TFE hardware. CRs-Fixed: 2545590 Change-Id: Ie8efef77fabeeea28d70380c398089e6351e35e3 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/cam_isp_context.c | 69 +- drivers/cam_isp/cam_isp_context.h | 7 +- drivers/cam_isp/cam_isp_dev.c | 25 +- drivers/cam_isp/isp_hw_mgr/Makefile | 2 +- drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c | 15 +- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 5282 +++++++++++++++++ drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h | 196 + .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 6 +- drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile | 4 +- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 19 +- .../isp_hw/include/cam_tfe_csid_hw_intf.h | 179 + .../isp_hw/include/cam_tfe_hw_intf.h | 253 + .../isp_hw/include/cam_top_tpg_hw_intf.h | 74 + .../isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile | 15 + .../isp_hw/tfe_csid_hw/cam_tfe_csid530.c | 53 + .../isp_hw/tfe_csid_hw/cam_tfe_csid530.h | 222 + .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 2822 +++++++++ .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.h | 412 ++ .../isp_hw/tfe_csid_hw/cam_tfe_csid_dev.c | 139 + .../isp_hw/tfe_csid_hw/cam_tfe_csid_dev.h | 16 + .../isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c | 209 + .../isp_hw/tfe_csid_hw/cam_tfe_csid_soc.h | 119 + .../cam_isp/isp_hw_mgr/isp_hw/tfe_hw/Makefile | 13 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe.c | 44 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe530.h | 813 +++ .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 2149 +++++++ .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.h | 240 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 2529 ++++++++ .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h | 272 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.c | 197 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.h | 35 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_irq.h | 31 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c | 240 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.h | 117 + .../isp_hw_mgr/isp_hw/top_tpg/Makefile | 15 + .../isp_hw/top_tpg/cam_top_tpg_core.c | 671 +++ .../isp_hw/top_tpg/cam_top_tpg_core.h | 153 + .../isp_hw/top_tpg/cam_top_tpg_dev.c | 140 + .../isp_hw/top_tpg/cam_top_tpg_dev.h | 12 + .../isp_hw/top_tpg/cam_top_tpg_soc.c | 152 + .../isp_hw/top_tpg/cam_top_tpg_soc.h | 78 + .../isp_hw/top_tpg/cam_top_tpg_v1.c | 55 + .../isp_hw/top_tpg/cam_top_tpg_v1.h | 53 + include/uapi/media/cam_isp_tfe.h | 35 + include/uapi/media/cam_req_mgr.h | 1 + include/uapi/media/cam_tfe.h | 391 ++ 46 files changed, 18544 insertions(+), 30 deletions(-) create mode 100644 drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c create mode 100644 drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_hw_intf.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_top_tpg_hw_intf.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_dev.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_dev.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe530.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_irq.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_dev.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_dev.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_soc.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_soc.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.h create mode 100644 include/uapi/media/cam_isp_tfe.h create mode 100644 include/uapi/media/cam_tfe.h diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index b251d75ac2f5..5f8506ad0cfa 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -376,6 +376,38 @@ static const char *__cam_isp_resource_handle_id_to_type( } } +static const char *__cam_isp_tfe_resource_handle_id_to_type( + uint32_t resource_handle) +{ + + switch (resource_handle) { + case CAM_ISP_TFE_OUT_RES_FULL: + return "FULL"; + case CAM_ISP_TFE_OUT_RES_RAW_DUMP: + return "RAW_DUMP"; + case CAM_ISP_TFE_OUT_RES_PDAF: + return "PDAF"; + case CAM_ISP_TFE_OUT_RES_RDI_0: + return "RDI_0"; + case CAM_ISP_TFE_OUT_RES_RDI_1: + return "RDI_1"; + case CAM_ISP_TFE_OUT_RES_RDI_2: + return "RDI_2"; + case CAM_ISP_TFE_OUT_RES_STATS_HDR_BE: + return "STATS_HDR_BE"; + case CAM_ISP_TFE_OUT_RES_STATS_HDR_BHIST: + return "STATS_HDR_BHIST"; + case CAM_ISP_TFE_OUT_RES_STATS_TL_BG: + return "STATS_TL_BG"; + case CAM_ISP_TFE_OUT_RES_STATS_BF: + return "STATS_BF"; + case CAM_ISP_TFE_OUT_RES_STATS_AWB_BG: + return "STATS_AWB_BG"; + default: + return "CAM_ISP_Invalid_Resource_Type"; + } +} + static uint64_t __cam_isp_ctx_get_event_ts(uint32_t evt_id, void *evt_data) { uint64_t ts = 0; @@ -471,9 +503,11 @@ static void __cam_isp_ctx_send_sof_timestamp( } static void __cam_isp_ctx_handle_buf_done_fail_log( - uint64_t request_id, struct cam_isp_ctx_req *req_isp) + uint64_t request_id, struct cam_isp_ctx_req *req_isp, + uint32_t isp_device_type) { int i; + const char *handle_type; if (req_isp->num_fence_map_out >= CAM_ISP_CTX_RES_MAX) { CAM_ERR(CAM_ISP, @@ -490,10 +524,18 @@ static void __cam_isp_ctx_handle_buf_done_fail_log( "Resource Handles that fail to generate buf_done in prev frame"); for (i = 0; i < req_isp->num_fence_map_out; i++) { if (req_isp->fence_map_out[i].sync_id != -1) { + if (isp_device_type == CAM_IFE_DEVICE_TYPE) + handle_type = + __cam_isp_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle); + else + handle_type = + __cam_isp_tfe_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle); + CAM_WARN(CAM_ISP, "Resource_Handle: [%s][0x%x] Sync_ID: [0x%x]", - __cam_isp_resource_handle_id_to_type( - req_isp->fence_map_out[i].resource_handle), + handle_type, req_isp->fence_map_out[i].resource_handle, req_isp->fence_map_out[i].sync_id); } @@ -512,6 +554,7 @@ static int __cam_isp_ctx_handle_buf_done_for_request( struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; uint64_t buf_done_req_id; + const char *handle_type; trace_cam_buf_done("ISP", ctx, req); @@ -541,11 +584,18 @@ static int __cam_isp_ctx_handle_buf_done_for_request( } if (req_isp->fence_map_out[j].sync_id == -1) { + if (ctx_isp->isp_device_type == CAM_IFE_DEVICE_TYPE) + handle_type = + __cam_isp_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle); + else + handle_type = + __cam_isp_tfe_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle); + CAM_WARN(CAM_ISP, "Duplicate BUF_DONE for req %lld : i=%d, j=%d, res=%s", - req->request_id, i, j, - __cam_isp_resource_handle_id_to_type( - done->resource_handle[i])); + req->request_id, i, j, handle_type); if (done_next_req) { done_next_req->resource_handle @@ -1967,7 +2017,8 @@ static int __cam_isp_ctx_apply_req_in_activated_state( active_req_isp = (struct cam_isp_ctx_req *) active_req->req_priv; __cam_isp_ctx_handle_buf_done_fail_log( - active_req->request_id, active_req_isp); + active_req->request_id, active_req_isp, + ctx_isp->isp_device_type); } rc = -EFAULT; @@ -4345,7 +4396,8 @@ int cam_isp_context_init(struct cam_isp_context *ctx, struct cam_context *ctx_base, struct cam_req_mgr_kmd_ops *crm_node_intf, struct cam_hw_mgr_intf *hw_intf, - uint32_t ctx_id) + uint32_t ctx_id, + uint32_t isp_device_type) { int rc = -1; @@ -4369,6 +4421,7 @@ int cam_isp_context_init(struct cam_isp_context *ctx, ctx->substate_machine = cam_isp_ctx_activated_state_machine; ctx->substate_machine_irq = cam_isp_ctx_activated_state_machine_irq; ctx->init_timestamp = jiffies_to_msecs(jiffies); + ctx->isp_device_type = isp_device_type; for (i = 0; i < CAM_CTX_REQ_MAX; i++) { ctx->req_base[i].req_priv = &ctx->req_isp[i]; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 34f899f65b27..a0908710ffd9 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "cam_context.h" #include "cam_isp_hw_mgr_intf.h" @@ -177,6 +178,7 @@ struct cam_isp_context_state_monitor { * @init_received: Indicate whether init config packet is received * @split_acquire: Indicate whether a separate acquire is expected * @init_timestamp: Timestamp at which this context is initialized + * @isp_device_type ISP device type * */ struct cam_isp_context { @@ -207,6 +209,7 @@ struct cam_isp_context { bool init_received; bool split_acquire; unsigned int init_timestamp; + uint32_t isp_device_type; }; /** @@ -218,13 +221,15 @@ struct cam_isp_context { * @bridge_ops: Bridge call back funciton * @hw_intf: ISP hw manager interface * @ctx_id: ID for this context + * @isp_device_type Isp device type * */ int cam_isp_context_init(struct cam_isp_context *ctx, struct cam_context *ctx_base, struct cam_req_mgr_kmd_ops *bridge_ops, struct cam_hw_mgr_intf *hw_intf, - uint32_t ctx_id); + uint32_t ctx_id, + uint32_t isp_device_type); /** * cam_isp_context_deinit() diff --git a/drivers/cam_isp/cam_isp_dev.c b/drivers/cam_isp/cam_isp_dev.c index 9c3f33181ae6..81ae824164ba 100644 --- a/drivers/cam_isp/cam_isp_dev.c +++ b/drivers/cam_isp/cam_isp_dev.c @@ -117,12 +117,30 @@ static int cam_isp_dev_probe(struct platform_device *pdev) int i; struct cam_hw_mgr_intf hw_mgr_intf; struct cam_node *node; + const char *compat_str = NULL; + uint32_t isp_device_type; + int iommu_hdl = -1; + rc = of_property_read_string_index(pdev->dev.of_node, "arch-compat", 0, + (const char **)&compat_str); + g_isp_dev.sd.internal_ops = &cam_isp_subdev_internal_ops; /* Initialize the v4l2 subdevice first. (create cam_node) */ - rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, + if (strnstr(compat_str, "ife", strlen(compat_str))) { + rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, CAM_IFE_DEVICE_TYPE); + isp_device_type = CAM_IFE_DEVICE_TYPE; + } else if (strnstr(compat_str, "tfe", strlen(compat_str))) { + rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, + CAM_TFE_DEVICE_TYPE); + isp_device_type = CAM_TFE_DEVICE_TYPE; + } else { + CAM_ERR(CAM_ISP, "Invalid ISP hw type %s", compat_str); + rc = -EINVAL; + goto err; + } + if (rc) { CAM_ERR(CAM_ISP, "ISP cam_subdev_probe failed!"); goto err; @@ -130,7 +148,7 @@ static int cam_isp_dev_probe(struct platform_device *pdev) node = (struct cam_node *) g_isp_dev.sd.token; memset(&hw_mgr_intf, 0, sizeof(hw_mgr_intf)); - rc = cam_isp_hw_mgr_init(pdev->dev.of_node, &hw_mgr_intf, &iommu_hdl); + rc = cam_isp_hw_mgr_init(compat_str, &hw_mgr_intf, &iommu_hdl); if (rc != 0) { CAM_ERR(CAM_ISP, "Can not initialized ISP HW manager!"); goto unregister; @@ -141,7 +159,8 @@ static int cam_isp_dev_probe(struct platform_device *pdev) &g_isp_dev.ctx[i], &node->crm_node_intf, &node->hw_mgr_intf, - i); + i, + isp_device_type); if (rc) { CAM_ERR(CAM_ISP, "ISP context init failed!"); goto unregister; diff --git a/drivers/cam_isp/isp_hw_mgr/Makefile b/drivers/cam_isp/isp_hw_mgr/Makefile index 33b808c934e3..b13c4fc1a8fd 100644 --- a/drivers/cam_isp/isp_hw_mgr/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/Makefile @@ -14,4 +14,4 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(src) obj-$(CONFIG_SPECTRA_CAMERA) += hw_utils/ isp_hw/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_hw_mgr.o cam_ife_hw_mgr.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_hw_mgr.o cam_ife_hw_mgr.o cam_tfe_hw_mgr.o diff --git a/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c index b1567d6b9cd8..ff1ca4833003 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c @@ -1,26 +1,25 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #include "cam_isp_hw_mgr_intf.h" #include "cam_ife_hw_mgr.h" #include "cam_debug_util.h" +#include "cam_tfe_hw_mgr.h" -int cam_isp_hw_mgr_init(struct device_node *of_node, +int cam_isp_hw_mgr_init(const char *device_name_str, struct cam_hw_mgr_intf *hw_mgr, int *iommu_hdl) { int rc = 0; - const char *compat_str = NULL; - rc = of_property_read_string_index(of_node, "arch-compat", 0, - (const char **)&compat_str); - - if (strnstr(compat_str, "ife", strlen(compat_str))) + if (strnstr(device_name_str, "ife", strlen(device_name_str))) rc = cam_ife_hw_mgr_init(hw_mgr, iommu_hdl); + else if (strnstr(device_name_str, "tfe", strlen(device_name_str))) + rc = cam_tfe_hw_mgr_init(hw_mgr, iommu_hdl); else { - CAM_ERR(CAM_ISP, "Invalid ISP hw type"); + CAM_ERR(CAM_ISP, "Invalid ISP hw type :%s", device_name_str); rc = -EINVAL; } 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 new file mode 100644 index 000000000000..7803f3a66b07 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c @@ -0,0 +1,5282 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "cam_smmu_api.h" +#include "cam_req_mgr_workq.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_tfe_csid_hw_intf.h" +#include "cam_tfe_hw_intf.h" +#include "cam_isp_packet_parser.h" +#include "cam_tfe_hw_mgr.h" +#include "cam_cdm_intf_api.h" +#include "cam_packet_util.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" +#include "cam_mem_mgr_api.h" +#include "cam_common_util.h" + +#define CAM_TFE_HW_ENTRIES_MAX 20 +#define CAM_TFE_HW_CONFIG_TIMEOUT 60 + +#define TZ_SVC_SMMU_PROGRAM 0x15 +#define TZ_SAFE_SYSCALL_ID 0x3 +#define CAM_TFE_SAFE_DISABLE 0 +#define CAM_TFE_SAFE_ENABLE 1 +#define SMMU_SE_TFE 0 + + +static struct cam_tfe_hw_mgr g_tfe_hw_mgr; + +static int cam_tfe_hw_mgr_event_handler( + void *priv, + uint32_t evt_id, + void *evt_info); + +static int cam_tfe_mgr_regspace_data_cb(uint32_t reg_base_type, + void *hw_mgr_ctx, struct cam_hw_soc_info **soc_info_ptr, + uint32_t *reg_base_idx) +{ + int rc = 0; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_isp_resource_node *res; + struct cam_tfe_hw_mgr_ctx *ctx = + (struct cam_tfe_hw_mgr_ctx *) hw_mgr_ctx; + + *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) + continue; + + switch (reg_base_type) { + case CAM_REG_DUMP_BASE_TYPE_CAMNOC: + case CAM_REG_DUMP_BASE_TYPE_ISP_LEFT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]) + continue; + + res = hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]; + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, + &soc_info, sizeof(void *)); + + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_LEFT, rc); + return rc; + } + + if (reg_base_type == CAM_REG_DUMP_BASE_TYPE_ISP_LEFT) + *reg_base_idx = 0; + else + *reg_base_idx = 1; + + *soc_info_ptr = soc_info; + break; + case CAM_REG_DUMP_BASE_TYPE_ISP_RIGHT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT]) + continue; + + + res = hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT]; + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, + &soc_info, sizeof(void *)); + + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_RIGHT, rc); + return rc; + } + + *reg_base_idx = 0; + *soc_info_ptr = soc_info; + break; + default: + CAM_ERR(CAM_ISP, + "Unrecognized reg base type: %d", + reg_base_type); + return -EINVAL; + } + } + + return rc; +} + +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) +{ + int rc, i; + + if (!num_reg_dump_buf || !reg_dump_buf_desc) { + CAM_DBG(CAM_ISP, + "Invalid args for reg dump req_id: [%llu] ctx idx: [%u] meta_type: [%u] num_reg_dump_buf: [%u] reg_dump_buf_desc: [%pK]", + ctx->applied_req_id, ctx->ctx_index, meta_type, + num_reg_dump_buf, reg_dump_buf_desc); + return rc; + } + + if (!atomic_read(&ctx->cdm_done)) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "Reg dump values might be from more than one request"); + + for (i = 0; i < num_reg_dump_buf; i++) { + CAM_DBG(CAM_ISP, "Reg dump cmd meta data: %u req_type: %u", + reg_dump_buf_desc[i].meta_data, meta_type); + if (reg_dump_buf_desc[i].meta_data == meta_type) { + rc = cam_soc_util_reg_dump_to_cmd_buf(ctx, + ®_dump_buf_desc[i], + ctx->applied_req_id, + cam_tfe_mgr_regspace_data_cb); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %u", + i, rc, ctx->applied_req_id, meta_type); + return rc; + } + } + } + + return 0; +} + +static int cam_tfe_mgr_get_hw_caps(void *hw_mgr_priv, + void *hw_caps_args) +{ + int rc = 0; + int i; + uint32_t num_dev = 0; + struct cam_tfe_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query = hw_caps_args; + struct cam_isp_tfe_query_cap_cmd query_isp; + + CAM_DBG(CAM_ISP, "enter"); + + if (copy_from_user(&query_isp, + u64_to_user_ptr(query->caps_handle), + sizeof(struct cam_isp_tfe_query_cap_cmd))) { + rc = -EFAULT; + return rc; + } + + query_isp.device_iommu.non_secure = hw_mgr->mgr_common.img_iommu_hdl; + query_isp.device_iommu.secure = hw_mgr->mgr_common.img_iommu_hdl_secure; + query_isp.cdm_iommu.non_secure = hw_mgr->mgr_common.cmd_iommu_hdl; + query_isp.cdm_iommu.secure = hw_mgr->mgr_common.cmd_iommu_hdl_secure; + + for (i = 0; i < CAM_TFE_CSID_HW_NUM_MAX; i++) { + if (!hw_mgr->csid_devices[i]) + continue; + + query_isp.dev_caps[i].hw_type = CAM_ISP_TFE_HW_TFE; + query_isp.dev_caps[i].hw_version.major = 5; + query_isp.dev_caps[i].hw_version.minor = 3; + query_isp.dev_caps[i].hw_version.incr = 0; + + /* + * device number is based on number of full tfe + * if pix is not supported, set reserve to 1 + */ + if (hw_mgr->tfe_csid_dev_caps[i].num_pix) { + query_isp.dev_caps[i].hw_version.reserved = 0; + num_dev++; + } else + query_isp.dev_caps[i].hw_version.reserved = 1; + } + + query_isp.num_dev = num_dev; + + if (copy_to_user(u64_to_user_ptr(query->caps_handle), + &query_isp, sizeof(struct cam_isp_tfe_query_cap_cmd))) + rc = -EFAULT; + + CAM_DBG(CAM_ISP, "exit rc :%d", rc); + + return rc; +} + +static int cam_tfe_hw_mgr_is_rdi_res(uint32_t res_id) +{ + int rc = 0; + + switch (res_id) { + case CAM_ISP_TFE_OUT_RES_RDI_0: + case CAM_ISP_TFE_OUT_RES_RDI_1: + case CAM_ISP_TFE_OUT_RES_RDI_2: + rc = 1; + break; + default: + break; + } + + return rc; +} + +static int cam_tfe_hw_mgr_convert_rdi_out_res_id_to_in_res(int res_id) +{ + if (res_id == CAM_ISP_TFE_OUT_RES_RDI_0) + return CAM_ISP_HW_TFE_IN_RDI0; + else if (res_id == CAM_ISP_TFE_OUT_RES_RDI_1) + return CAM_ISP_HW_TFE_IN_RDI1; + else if (res_id == CAM_ISP_TFE_OUT_RES_RDI_2) + return CAM_ISP_HW_TFE_IN_RDI1; + + return CAM_ISP_HW_TFE_IN_MAX; +} + +static int cam_tfe_hw_mgr_reset_csid_res( + struct cam_isp_hw_mgr_res *isp_hw_res) +{ + int i; + int rc = 0; + struct cam_hw_intf *hw_intf; + struct cam_tfe_csid_reset_cfg_args csid_reset_args; + + csid_reset_args.reset_type = CAM_TFE_CSID_RESET_PATH; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + csid_reset_args.node_res = isp_hw_res->hw_res[i]; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + CAM_DBG(CAM_ISP, "Resetting csid hardware %d", + hw_intf->hw_idx); + if (hw_intf->hw_ops.reset) { + rc = hw_intf->hw_ops.reset(hw_intf->hw_priv, + &csid_reset_args, + sizeof(struct cam_tfe_csid_reset_cfg_args)); + if (rc <= 0) + goto err; + } + } + + return 0; +err: + CAM_ERR(CAM_ISP, "RESET HW res failed: (type:%d, id:%d)", + isp_hw_res->res_type, isp_hw_res->res_id); + return rc; +} + +static int cam_tfe_hw_mgr_init_hw_res( + struct cam_isp_hw_mgr_res *isp_hw_res) +{ + int i; + int rc = -EINVAL; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + CAM_DBG(CAM_ISP, "hw type %d hw index:%d", + hw_intf->hw_type, hw_intf->hw_idx); + if (hw_intf->hw_ops.init) { + rc = hw_intf->hw_ops.init(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + if (rc) + goto err; + } + } + + return 0; +err: + CAM_ERR(CAM_ISP, "INIT HW res failed: (type:%d, id:%d)", + isp_hw_res->res_type, isp_hw_res->res_id); + return rc; +} + +static int cam_tfe_hw_mgr_start_hw_res( + struct cam_isp_hw_mgr_res *isp_hw_res, + struct cam_tfe_hw_mgr_ctx *ctx) +{ + int i; + int rc = -EINVAL; + struct cam_hw_intf *hw_intf; + + /* Start slave (which is right split) first */ + for (i = CAM_ISP_HW_SPLIT_MAX - 1; i >= 0; i--) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.start) { + rc = hw_intf->hw_ops.start(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start HW resources"); + goto err; + } + CAM_DBG(CAM_ISP, "Start hw type:%d HW idx %d Res %d", + hw_intf->hw_type, + hw_intf->hw_idx, + isp_hw_res->hw_res[i]->res_id); + } else { + CAM_ERR(CAM_ISP, "function null"); + goto err; + } + } + + return 0; +err: + CAM_ERR(CAM_ISP, "Start hw res failed (type:%d, id:%d)", + isp_hw_res->res_type, isp_hw_res->res_id); + return rc; +} + +static void cam_tfe_hw_mgr_stop_hw_res( + struct cam_isp_hw_mgr_res *isp_hw_res) +{ + int i; + struct cam_hw_intf *hw_intf; + uint32_t dummy_args; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + + if (isp_hw_res->hw_res[i]->res_state != + CAM_ISP_RESOURCE_STATE_STREAMING) + continue; + + if (hw_intf->hw_ops.stop) + hw_intf->hw_ops.stop(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + else + CAM_ERR(CAM_ISP, "stop null"); + if (hw_intf->hw_ops.process_cmd && + isp_hw_res->res_type == CAM_ISP_RESOURCE_TFE_OUT) { + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, + &dummy_args, sizeof(dummy_args)); + } + } +} + +static void cam_tfe_hw_mgr_deinit_hw_res( + struct cam_isp_hw_mgr_res *isp_hw_res) +{ + int i; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.deinit) + hw_intf->hw_ops.deinit(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + } +} + +static void cam_tfe_hw_mgr_deinit_hw( + struct cam_tfe_hw_mgr_ctx *ctx) +{ + struct cam_isp_hw_mgr_res *hw_mgr_res; + + if (!ctx->init_done) { + CAM_WARN(CAM_ISP, "ctx is not in init state"); + return; + } + + /* Deinit TFE CSID hw */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, list) { + CAM_DBG(CAM_ISP, "Going to DeInit TFE CSID"); + cam_tfe_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deint TFE HW */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + cam_tfe_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + if (ctx->is_tpg) + cam_tfe_hw_mgr_deinit_hw_res(&ctx->res_list_tpg); + + ctx->init_done = false; +} + +static int cam_tfe_hw_mgr_init_hw( + struct cam_tfe_hw_mgr_ctx *ctx) +{ + struct cam_isp_hw_mgr_res *hw_mgr_res; + int rc = 0; + + if (ctx->is_tpg) { + CAM_DBG(CAM_ISP, "INIT TPG ... in ctx id:%d", + ctx->ctx_index); + rc = cam_tfe_hw_mgr_init_hw_res(&ctx->res_list_tpg); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT TFE TPG(id :%d)", + ctx->res_list_tpg.hw_res[0]->hw_intf->hw_idx); + goto deinit; + } + } + + CAM_DBG(CAM_ISP, "INIT TFE csid ... in ctx id:%d", + ctx->ctx_index); + /* INIT TFE csid */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, list) { + rc = cam_tfe_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT TFE CSID(id :%d)", + hw_mgr_res->res_id); + goto deinit; + } + } + + /* INIT TFE IN */ + CAM_DBG(CAM_ISP, "INIT TFE in resource ctx id:%d", + ctx->ctx_index); + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + rc = cam_tfe_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT TFE SRC (%d)", + hw_mgr_res->res_id); + goto deinit; + } + } + + return rc; +deinit: + ctx->init_done = true; + cam_tfe_hw_mgr_deinit_hw(ctx); + return rc; +} + +static int cam_tfe_hw_mgr_put_res( + struct list_head *src_list, + struct cam_isp_hw_mgr_res **res) +{ + struct cam_isp_hw_mgr_res *res_ptr = NULL; + + res_ptr = *res; + if (res_ptr) + list_add_tail(&res_ptr->list, src_list); + + return 0; +} + +static int cam_tfe_hw_mgr_get_res( + struct list_head *src_list, + struct cam_isp_hw_mgr_res **res) +{ + int rc = 0; + struct cam_isp_hw_mgr_res *res_ptr = NULL; + + if (!list_empty(src_list)) { + res_ptr = list_first_entry(src_list, + struct cam_isp_hw_mgr_res, list); + list_del_init(&res_ptr->list); + } else { + CAM_ERR(CAM_ISP, "No more free tfe hw mgr ctx"); + rc = -EINVAL; + } + *res = res_ptr; + + return rc; +} + +static int cam_tfe_hw_mgr_free_hw_res( + struct cam_isp_hw_mgr_res *isp_hw_res) +{ + int rc = 0; + int i; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.release) { + rc = hw_intf->hw_ops.release(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + if (rc) + CAM_ERR(CAM_ISP, + "Release hw resource id %d failed", + isp_hw_res->res_id); + isp_hw_res->hw_res[i] = NULL; + } else + CAM_ERR(CAM_ISP, "Release null"); + } + /* caller should make sure the resource is in a list */ + list_del_init(&isp_hw_res->list); + memset(isp_hw_res, 0, sizeof(*isp_hw_res)); + INIT_LIST_HEAD(&isp_hw_res->list); + + return 0; +} + +static int cam_tfe_mgr_csid_stop_hw( + struct cam_tfe_hw_mgr_ctx *ctx, struct list_head *stop_list, + uint32_t base_idx, uint32_t stop_cmd) +{ + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *isp_res; + struct cam_isp_resource_node *stop_res[CAM_TFE_CSID_PATH_RES_MAX]; + struct cam_tfe_csid_hw_stop_args stop; + struct cam_hw_intf *hw_intf; + uint32_t i, cnt; + + cnt = 0; + list_for_each_entry(hw_mgr_res, stop_list, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i] || + (hw_mgr_res->hw_res[i]->res_state != + CAM_ISP_RESOURCE_STATE_STREAMING)) + continue; + + isp_res = hw_mgr_res->hw_res[i]; + if (isp_res->hw_intf->hw_idx != base_idx) + continue; + CAM_DBG(CAM_ISP, "base_idx %d res_id %d cnt %u", + base_idx, isp_res->res_id, cnt); + stop_res[cnt] = isp_res; + cnt++; + } + } + + if (cnt) { + hw_intf = stop_res[0]->hw_intf; + stop.num_res = cnt; + stop.node_res = stop_res; + stop.stop_cmd = stop_cmd; + hw_intf->hw_ops.stop(hw_intf->hw_priv, &stop, sizeof(stop)); + } + + return 0; +} + +static int cam_tfe_hw_mgr_release_hw_for_ctx( + struct cam_tfe_hw_mgr_ctx *tfe_ctx) +{ + uint32_t i; + int rc = 0; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_mgr_res *hw_mgr_res_temp; + struct cam_hw_intf *hw_intf; + + /* tfe out resource */ + for (i = 0; i < CAM_TFE_HW_OUT_RES_MAX; i++) + cam_tfe_hw_mgr_free_hw_res(&tfe_ctx->res_list_tfe_out[i]); + + /* tfe in resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &tfe_ctx->res_list_tfe_in, list) { + cam_tfe_hw_mgr_free_hw_res(hw_mgr_res); + cam_tfe_hw_mgr_put_res(&tfe_ctx->free_res_list, &hw_mgr_res); + } + + /* tfe csid resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &tfe_ctx->res_list_tfe_csid, list) { + cam_tfe_hw_mgr_free_hw_res(hw_mgr_res); + cam_tfe_hw_mgr_put_res(&tfe_ctx->free_res_list, &hw_mgr_res); + } + + /* release tpg resource */ + if (tfe_ctx->is_tpg) { + hw_intf = tfe_ctx->res_list_tpg.hw_res[0]->hw_intf; + if (hw_intf->hw_ops.release) { + rc = hw_intf->hw_ops.release(hw_intf->hw_priv, + tfe_ctx->res_list_tpg.hw_res[0], + sizeof(struct cam_isp_resource_node)); + if (rc) + CAM_ERR(CAM_ISP, + "TPG Release hw failed"); + tfe_ctx->res_list_tpg.hw_res[0] = NULL; + } else + CAM_ERR(CAM_ISP, "TPG resource Release null"); + } + + /* clean up the callback function */ + tfe_ctx->common.cb_priv = NULL; + memset(tfe_ctx->common.event_cb, 0, sizeof(tfe_ctx->common.event_cb)); + + CAM_DBG(CAM_ISP, "release context completed ctx id:%d", + tfe_ctx->ctx_index); + + return 0; +} + + +static int cam_tfe_hw_mgr_put_ctx( + struct list_head *src_list, + struct cam_tfe_hw_mgr_ctx **tfe_ctx) +{ + struct cam_tfe_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_tfe_hw_mgr.ctx_mutex); + ctx_ptr = *tfe_ctx; + if (ctx_ptr) + list_add_tail(&ctx_ptr->list, src_list); + *tfe_ctx = NULL; + mutex_unlock(&g_tfe_hw_mgr.ctx_mutex); + return 0; +} + +static int cam_tfe_hw_mgr_get_ctx( + struct list_head *src_list, + struct cam_tfe_hw_mgr_ctx **tfe_ctx) +{ + int rc = 0; + struct cam_tfe_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_tfe_hw_mgr.ctx_mutex); + if (!list_empty(src_list)) { + ctx_ptr = list_first_entry(src_list, + struct cam_tfe_hw_mgr_ctx, list); + list_del_init(&ctx_ptr->list); + } else { + CAM_ERR(CAM_ISP, "No more free tfe hw mgr ctx"); + rc = -EINVAL; + } + *tfe_ctx = ctx_ptr; + mutex_unlock(&g_tfe_hw_mgr.ctx_mutex); + + return rc; +} + +static void cam_tfe_hw_mgr_dump_all_ctx(void) +{ + uint32_t i; + struct cam_tfe_hw_mgr_ctx *ctx; + struct cam_isp_hw_mgr_res *hw_mgr_res; + + mutex_lock(&g_tfe_hw_mgr.ctx_mutex); + list_for_each_entry(ctx, &g_tfe_hw_mgr.used_ctx_list, list) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "ctx id:%d is_dual:%d is_tpg:%d num_base:%d rdi only:%d", + ctx->ctx_index, ctx->is_dual, ctx->is_tpg, + ctx->num_base, ctx->is_rdi_only_context); + + if (ctx->res_list_tpg.res_type == CAM_ISP_RESOURCE_TPG) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "Acquired TPG HW:%d", + ctx->res_list_tpg.hw_res[0]->hw_intf->hw_idx); + } + + 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]) + continue; + + CAM_INFO_RATE_LIMIT(CAM_ISP, + "csid:%d res_type:%d res_id:%d res_state:%d", + hw_mgr_res->hw_res[i]->hw_intf->hw_idx, + hw_mgr_res->hw_res[i]->res_type, + hw_mgr_res->hw_res[i]->res_id, + hw_mgr_res->hw_res[i]->res_state); + } + } + + 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]) + continue; + + CAM_INFO_RATE_LIMIT(CAM_ISP, + "TFE IN:%d res_type:%d res_id:%d res_state:%d", + hw_mgr_res->hw_res[i]->hw_intf->hw_idx, + hw_mgr_res->hw_res[i]->res_type, + hw_mgr_res->hw_res[i]->res_id, + hw_mgr_res->hw_res[i]->res_state); + } + } + } + mutex_unlock(&g_tfe_hw_mgr.ctx_mutex); + +} + +static void cam_tfe_mgr_add_base_info( + struct cam_tfe_hw_mgr_ctx *ctx, + enum cam_isp_hw_split_id split_id, + uint32_t base_idx) +{ + uint32_t i; + + if (!ctx->num_base) { + ctx->base[0].split_id = split_id; + ctx->base[0].idx = base_idx; + ctx->num_base++; + CAM_DBG(CAM_ISP, + "Add split id = %d for base idx = %d num_base=%d", + split_id, base_idx, ctx->num_base); + } else { + /*Check if base index already exists in the list */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == base_idx) { + if (split_id != CAM_ISP_HW_SPLIT_MAX && + ctx->base[i].split_id == + CAM_ISP_HW_SPLIT_MAX) + ctx->base[i].split_id = split_id; + + break; + } + } + + if (i == ctx->num_base) { + ctx->base[ctx->num_base].split_id = split_id; + ctx->base[ctx->num_base].idx = base_idx; + ctx->num_base++; + CAM_DBG(CAM_ISP, + "Add split_id=%d for base idx=%d num_base=%d", + split_id, base_idx, ctx->num_base); + } + } +} + +static int cam_tfe_mgr_process_base_info( + struct cam_tfe_hw_mgr_ctx *ctx) +{ + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *res = NULL; + uint32_t i; + + if (list_empty(&ctx->res_list_tfe_in)) { + CAM_ERR(CAM_ISP, "tfe in list empty"); + return -ENODEV; + } + + /* TFE in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + res = hw_mgr_res->hw_res[i]; + cam_tfe_mgr_add_base_info(ctx, i, + res->hw_intf->hw_idx); + CAM_DBG(CAM_ISP, "add base info for hw %d", + res->hw_intf->hw_idx); + } + } + CAM_DBG(CAM_ISP, "ctx base num = %d", ctx->num_base); + + return 0; +} + +static int cam_tfe_hw_mgr_acquire_res_tfe_out_rdi( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_isp_hw_mgr_res *tfe_in_res, + struct cam_isp_tfe_in_port_info *in_port) +{ + int rc = -EINVAL; + struct cam_tfe_acquire_args tfe_acquire; + struct cam_isp_tfe_out_port_info *out_port = NULL; + struct cam_isp_hw_mgr_res *tfe_out_res; + struct cam_hw_intf *hw_intf; + uint32_t i, tfe_out_res_id, tfe_in_res_id; + + /* take left resource */ + tfe_in_res_id = tfe_in_res->hw_res[0]->res_id; + + switch (tfe_in_res_id) { + case CAM_ISP_HW_TFE_IN_RDI0: + tfe_out_res_id = CAM_ISP_TFE_OUT_RES_RDI_0; + break; + case CAM_ISP_HW_TFE_IN_RDI1: + tfe_out_res_id = CAM_ISP_TFE_OUT_RES_RDI_1; + break; + case CAM_ISP_HW_TFE_IN_RDI2: + tfe_out_res_id = CAM_ISP_TFE_OUT_RES_RDI_2; + break; + default: + CAM_ERR(CAM_ISP, "invalid resource type"); + goto err; + } + CAM_DBG(CAM_ISP, "tfe_in_res_id = %d, tfe_out_red_id = %d", + tfe_in_res_id, tfe_out_res_id); + + tfe_acquire.rsrc_type = CAM_ISP_RESOURCE_TFE_OUT; + tfe_acquire.tasklet = tfe_ctx->common.tasklet_info; + + tfe_out_res = &tfe_ctx->res_list_tfe_out[tfe_out_res_id & 0xFF]; + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + + CAM_DBG(CAM_ISP, "i = %d, tfe_out_res_id = %d, out_port: %d", + i, tfe_out_res_id, out_port->res_id); + + if (tfe_out_res_id != out_port->res_id) + continue; + + tfe_acquire.tfe_out.cdm_ops = tfe_ctx->cdm_ops; + tfe_acquire.priv = tfe_ctx; + tfe_acquire.tfe_out.out_port_info = out_port; + tfe_acquire.tfe_out.split_id = CAM_ISP_HW_SPLIT_LEFT; + tfe_acquire.tfe_out.unique_id = tfe_ctx->ctx_index; + tfe_acquire.tfe_out.is_dual = 0; + tfe_acquire.event_cb = cam_tfe_hw_mgr_event_handler; + hw_intf = tfe_in_res->hw_res[0]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &tfe_acquire, + sizeof(struct cam_tfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, "Can not acquire out resource 0x%x", + out_port->res_id); + goto err; + } + break; + } + + if (i == in_port->num_out_res) { + CAM_ERR(CAM_ISP, + "Cannot acquire out resource, i=%d, num_out_res=%d", + i, in_port->num_out_res); + goto err; + } + + tfe_out_res->hw_res[0] = tfe_acquire.tfe_out.rsrc_node; + tfe_out_res->is_dual_isp = 0; + tfe_out_res->res_id = tfe_out_res_id; + tfe_out_res->res_type = CAM_ISP_RESOURCE_TFE_OUT; + tfe_in_res->num_children++; + + return 0; +err: + return rc; +} + +static int cam_tfe_hw_mgr_acquire_res_tfe_out_pixel( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_isp_hw_mgr_res *tfe_in_res, + struct cam_isp_tfe_in_port_info *in_port) +{ + int rc = -EINVAL; + uint32_t i, j, k; + struct cam_tfe_acquire_args tfe_acquire; + struct cam_isp_tfe_out_port_info *out_port; + struct cam_isp_hw_mgr_res *tfe_out_res; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + k = out_port->res_id & 0xFF; + if (k >= CAM_TFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "invalid output resource type 0x%x", + out_port->res_id); + continue; + } + + if (cam_tfe_hw_mgr_is_rdi_res(out_port->res_id)) + continue; + + CAM_DBG(CAM_ISP, "res_type 0x%x", out_port->res_id); + + tfe_out_res = &tfe_ctx->res_list_tfe_out[k]; + tfe_out_res->is_dual_isp = in_port->usage_type; + + tfe_acquire.rsrc_type = CAM_ISP_RESOURCE_TFE_OUT; + tfe_acquire.tasklet = tfe_ctx->common.tasklet_info; + tfe_acquire.tfe_out.cdm_ops = tfe_ctx->cdm_ops; + tfe_acquire.priv = tfe_ctx; + tfe_acquire.tfe_out.out_port_info = out_port; + tfe_acquire.tfe_out.is_dual = tfe_in_res->is_dual_isp; + tfe_acquire.tfe_out.unique_id = tfe_ctx->ctx_index; + tfe_acquire.event_cb = cam_tfe_hw_mgr_event_handler; + + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + if (!tfe_in_res->hw_res[j]) + continue; + + hw_intf = tfe_in_res->hw_res[j]->hw_intf; + + if (j == CAM_ISP_HW_SPLIT_LEFT) { + tfe_acquire.tfe_out.split_id = + CAM_ISP_HW_SPLIT_LEFT; + if (tfe_in_res->is_dual_isp) + tfe_acquire.tfe_out.is_master = 1; + else + tfe_acquire.tfe_out.is_master = 0; + } else { + tfe_acquire.tfe_out.split_id = + CAM_ISP_HW_SPLIT_RIGHT; + tfe_acquire.tfe_out.is_master = 0; + } + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &tfe_acquire, + sizeof(struct cam_tfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire out resource 0x%x", + out_port->res_id); + goto err; + } + + tfe_out_res->hw_res[j] = + tfe_acquire.tfe_out.rsrc_node; + CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x", + tfe_out_res->hw_res[j]->res_type, + tfe_out_res->hw_res[j]->res_id); + + } + tfe_out_res->res_type = CAM_ISP_RESOURCE_TFE_OUT; + tfe_out_res->res_id = out_port->res_id; + tfe_in_res->num_children++; + } + + return 0; +err: + /* release resource at the entry function */ + return rc; +} + +static int cam_tfe_hw_mgr_acquire_res_tfe_out( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_isp_tfe_in_port_info *in_port) +{ + int rc = -EINVAL; + struct cam_isp_hw_mgr_res *tfe_in_res; + + list_for_each_entry(tfe_in_res, &tfe_ctx->res_list_tfe_in, list) { + if (tfe_in_res->num_children) + continue; + + switch (tfe_in_res->res_id) { + case CAM_ISP_HW_TFE_IN_CAMIF: + rc = cam_tfe_hw_mgr_acquire_res_tfe_out_pixel(tfe_ctx, + tfe_in_res, in_port); + break; + case CAM_ISP_HW_TFE_IN_RDI0: + case CAM_ISP_HW_TFE_IN_RDI1: + case CAM_ISP_HW_TFE_IN_RDI2: + rc = cam_tfe_hw_mgr_acquire_res_tfe_out_rdi(tfe_ctx, + tfe_in_res, in_port); + break; + default: + CAM_ERR(CAM_ISP, "Unknown TFE SRC resource: %d", + tfe_in_res->res_id); + break; + } + if (rc) + goto err; + } + + return 0; +err: + /* release resource on entry function */ + return rc; +} + +static int cam_tfe_hw_mgr_acquire_res_tfe_in( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_isp_tfe_in_port_info *in_port, + uint32_t *pdaf_enable) +{ + int rc = -EINVAL; + int i; + struct cam_isp_hw_mgr_res *csid_res; + struct cam_isp_hw_mgr_res *tfe_src_res; + struct cam_tfe_acquire_args tfe_acquire; + struct cam_hw_intf *hw_intf; + struct cam_tfe_hw_mgr *tfe_hw_mgr; + + tfe_hw_mgr = tfe_ctx->hw_mgr; + + list_for_each_entry(csid_res, &tfe_ctx->res_list_tfe_csid, list) { + if (csid_res->num_children) + continue; + + rc = cam_tfe_hw_mgr_get_res(&tfe_ctx->free_res_list, + &tfe_src_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_tfe_hw_mgr_put_res(&tfe_ctx->res_list_tfe_in, + &tfe_src_res); + tfe_src_res->hw_res[0] = NULL; + tfe_src_res->hw_res[1] = NULL; + + tfe_acquire.rsrc_type = CAM_ISP_RESOURCE_TFE_IN; + tfe_acquire.tasklet = tfe_ctx->common.tasklet_info; + tfe_acquire.tfe_in.cdm_ops = tfe_ctx->cdm_ops; + tfe_acquire.tfe_in.in_port = in_port; + tfe_acquire.tfe_in.camif_pd_enable = *pdaf_enable; + tfe_acquire.priv = tfe_ctx; + tfe_acquire.event_cb = cam_tfe_hw_mgr_event_handler; + + switch (csid_res->res_id) { + case CAM_TFE_CSID_PATH_RES_IPP: + tfe_acquire.tfe_in.res_id = + CAM_ISP_HW_TFE_IN_CAMIF; + + if (csid_res->is_dual_isp) + tfe_acquire.tfe_in.sync_mode = + CAM_ISP_HW_SYNC_MASTER; + else + tfe_acquire.tfe_in.sync_mode = + CAM_ISP_HW_SYNC_NONE; + + break; + case CAM_TFE_CSID_PATH_RES_RDI_0: + tfe_acquire.tfe_in.res_id = CAM_ISP_HW_TFE_IN_RDI0; + tfe_acquire.tfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + case CAM_TFE_CSID_PATH_RES_RDI_1: + tfe_acquire.tfe_in.res_id = CAM_ISP_HW_TFE_IN_RDI1; + tfe_acquire.tfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + case CAM_TFE_CSID_PATH_RES_RDI_2: + tfe_acquire.tfe_in.res_id = CAM_ISP_HW_TFE_IN_RDI2; + tfe_acquire.tfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + default: + CAM_ERR(CAM_ISP, "Wrong TFE CSID Resource Node"); + goto err; + } + tfe_src_res->res_type = tfe_acquire.rsrc_type; + tfe_src_res->res_id = tfe_acquire.tfe_in.res_id; + tfe_src_res->is_dual_isp = csid_res->is_dual_isp; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!csid_res->hw_res[i]) + continue; + + hw_intf = tfe_hw_mgr->tfe_devices[ + csid_res->hw_res[i]->hw_intf->hw_idx]; + + /* fill in more acquire information as needed */ + /* slave Camif resource, */ + if (i == CAM_ISP_HW_SPLIT_RIGHT && + tfe_src_res->is_dual_isp) { + tfe_acquire.tfe_in.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + tfe_acquire.tfe_in.dual_tfe_sync_sel_idx = + csid_res->hw_res[0]->hw_intf->hw_idx; + } else if (i == CAM_ISP_HW_SPLIT_LEFT && + tfe_src_res->is_dual_isp) + tfe_acquire.tfe_in.dual_tfe_sync_sel_idx = + csid_res->hw_res[1]->hw_intf->hw_idx; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &tfe_acquire, + sizeof(struct cam_tfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire TFE HW res %d", + csid_res->res_id); + goto err; + } + tfe_src_res->hw_res[i] = tfe_acquire.tfe_in.rsrc_node; + CAM_DBG(CAM_ISP, + "acquire success TFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + tfe_src_res->hw_res[i]->res_type, + tfe_src_res->hw_res[i]->res_id); + + } + csid_res->num_children++; + } + + return 0; +err: + /* release resource at the entry function */ + return rc; +} + +static int cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_isp_tfe_in_port_info *in_port) +{ + int rc = -EINVAL; + int i, j; + uint32_t acquired_cnt = 0; + struct cam_tfe_hw_mgr *tfe_hw_mgr; + struct cam_isp_hw_mgr_res *csid_res; + struct cam_hw_intf *hw_intf; + struct cam_tfe_csid_hw_reserve_resource_args csid_acquire; + enum cam_tfe_csid_path_res_id path_res_id; + struct cam_isp_hw_mgr_res *csid_res_temp, *csid_res_iterator; + struct cam_isp_tfe_out_port_info *out_port = NULL; + + tfe_hw_mgr = tfe_ctx->hw_mgr; + /* get csid resource */ + path_res_id = CAM_TFE_CSID_PATH_RES_IPP; + + rc = cam_tfe_hw_mgr_get_res(&tfe_ctx->free_res_list, &csid_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto end; + } + + csid_res_temp = csid_res; + + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_id = path_res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = in_port->data; + csid_acquire.node_res = NULL; + csid_acquire.event_cb_prv = tfe_ctx; + csid_acquire.event_cb = cam_tfe_hw_mgr_event_handler; + if (in_port->num_out_res) + out_port = &(in_port->data[0]); + + if (tfe_ctx->is_tpg) { + if (tfe_ctx->res_list_tpg.hw_res[0]->hw_intf->hw_idx == 0) + csid_acquire.phy_sel = CAM_ISP_TFE_IN_RES_PHY_0; + else + csid_acquire.phy_sel = CAM_ISP_TFE_IN_RES_PHY_1; + } + + if (in_port->usage_type) + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_MASTER; + else + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + + /* Try acquiring CSID resource from previously acquired HW */ + list_for_each_entry(csid_res_iterator, &tfe_ctx->res_list_tfe_csid, + list) { + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!csid_res_iterator->hw_res[i]) + continue; + + if (csid_res_iterator->is_secure == 1 || + (csid_res_iterator->is_secure == 0 && + in_port->num_out_res && + out_port->secure_mode == 1)) + continue; + + hw_intf = csid_res_iterator->hw_res[i]->hw_intf; + csid_acquire.master_idx = hw_intf->hw_idx; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_DBG(CAM_ISP, + "No tfe csid resource from hw %d", + hw_intf->hw_idx); + continue; + } + + csid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + + CAM_DBG(CAM_ISP, + "acquired from old csid(%s)=%d CSID rsrc successfully", + (i == 0) ? "left" : "right", + hw_intf->hw_idx); + + if (in_port->usage_type && acquired_cnt == 1 && + path_res_id == CAM_TFE_CSID_PATH_RES_IPP) + /* + * Continue to acquire Right for IPP. + * Dual TFE for RDI is not currently + * supported. + */ + continue; + + if (acquired_cnt) + /* + * If successfully acquired CSID from + * previously acquired HW, skip the next + * part + */ + goto acquire_successful; + } + } + + /* + * If successfully acquired CSID from + * previously acquired HW, skip the next + * part + */ + if (acquired_cnt) + goto acquire_successful; + + /* Acquire Left if not already acquired */ + if (in_port->usage_type) { + for (i = 0; i < CAM_TFE_CSID_HW_NUM_MAX; i++) { + if (!tfe_hw_mgr->csid_devices[i]) + continue; + + hw_intf = tfe_hw_mgr->csid_devices[i]; + csid_acquire.master_idx = hw_intf->hw_idx; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + csid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } + } + + if (i == CAM_TFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire tfe csid path resource %d", + path_res_id); + goto put_res; + } + } else { + for (i = (CAM_TFE_CSID_HW_NUM_MAX - 1); i >= 0; i--) { + if (!tfe_hw_mgr->csid_devices[i]) + continue; + + hw_intf = tfe_hw_mgr->csid_devices[i]; + csid_acquire.master_idx = hw_intf->hw_idx; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + csid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } + } + + if (i == -1 || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire tfe csid path resource %d", + path_res_id); + goto put_res; + } + } +acquire_successful: + CAM_DBG(CAM_ISP, "CSID path left acquired success. is_dual %d", + in_port->usage_type); + + csid_res_temp->res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_res_temp->res_id = path_res_id; + + if (in_port->usage_type) { + csid_res_temp->is_dual_isp = 1; + tfe_ctx->is_dual = true; + tfe_ctx->master_hw_idx = + csid_res_temp->hw_res[0]->hw_intf->hw_idx; + } else + csid_res_temp->is_dual_isp = 0; + + if (in_port->num_out_res) + csid_res_temp->is_secure = out_port->secure_mode; + + cam_tfe_hw_mgr_put_res(&tfe_ctx->res_list_tfe_csid, &csid_res); + + /* + * Acquire Right if not already acquired. + * Dual TFE for RDI is not currently supported. + */ + if (in_port->usage_type && (path_res_id == CAM_TFE_CSID_PATH_RES_IPP) + && (acquired_cnt == 1)) { + memset(&csid_acquire, 0, sizeof(csid_acquire)); + csid_acquire.node_res = NULL; + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_id = path_res_id; + csid_acquire.in_port = in_port; + csid_acquire.master_idx = + csid_res_temp->hw_res[0]->hw_intf->hw_idx; + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_SLAVE; + csid_acquire.node_res = NULL; + csid_acquire.out_port = in_port->data; + csid_acquire.event_cb_prv = tfe_ctx; + csid_acquire.event_cb = cam_tfe_hw_mgr_event_handler; + + if (tfe_ctx->is_tpg) { + if (tfe_ctx->res_list_tpg.hw_res[0]->hw_intf->hw_idx + == 0) + csid_acquire.phy_sel = CAM_ISP_TFE_IN_RES_PHY_0; + else + csid_acquire.phy_sel = CAM_ISP_TFE_IN_RES_PHY_1; + } + + for (j = 0; j < CAM_TFE_CSID_HW_NUM_MAX; j++) { + if (!tfe_hw_mgr->csid_devices[j]) + continue; + + if (j == csid_res_temp->hw_res[0]->hw_intf->hw_idx) + continue; + + hw_intf = tfe_hw_mgr->csid_devices[j]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else + break; + } + + if (j == CAM_TFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, + "Can not acquire tfe csid pixel resource"); + goto end; + } + csid_res_temp->hw_res[1] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, "CSID right acquired success is_dual %d", + in_port->usage_type); + } + + return 0; +put_res: + cam_tfe_hw_mgr_put_res(&tfe_ctx->free_res_list, &csid_res); +end: + return rc; +} + +static int cam_tfe_hw_mgr_acquire_tpg( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_isp_tfe_in_port_info **in_port, + uint32_t num_inport) +{ + int rc = -EINVAL; + uint32_t i, j = 0; + struct cam_tfe_hw_mgr *tfe_hw_mgr; + struct cam_hw_intf *hw_intf; + struct cam_top_tpg_hw_reserve_resource_args tpg_reserve; + + tfe_hw_mgr = tfe_ctx->hw_mgr; + + for (i = 0; i < CAM_TOP_TPG_HW_NUM_MAX; i++) { + if (!tfe_hw_mgr->tpg_devices[i]) + continue; + + hw_intf = tfe_hw_mgr->tpg_devices[i]; + tpg_reserve.num_inport = num_inport; + tpg_reserve.node_res = NULL; + for (j = 0; j < num_inport; j++) + tpg_reserve.in_port[j] = in_port[j]; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &tpg_reserve, sizeof(tpg_reserve)); + if (!rc) + break; + } + + if (i == CAM_TOP_TPG_HW_NUM_MAX || !tpg_reserve.node_res) { + CAM_ERR(CAM_ISP, "Can not acquire tfe TPG"); + rc = -EINVAL; + goto end; + } + + tfe_ctx->res_list_tpg.res_type = CAM_ISP_RESOURCE_TPG; + tfe_ctx->res_list_tpg.hw_res[0] = tpg_reserve.node_res; + +end: + return rc; +} + +static enum cam_tfe_csid_path_res_id + cam_tfe_hw_mgr_get_tfe_csid_rdi_res_type( + uint32_t out_port_type) +{ + enum cam_tfe_csid_path_res_id path_id; + + CAM_DBG(CAM_ISP, "out_port_type %x", out_port_type); + switch (out_port_type) { + case CAM_ISP_TFE_OUT_RES_RDI_0: + path_id = CAM_TFE_CSID_PATH_RES_RDI_0; + break; + case CAM_ISP_TFE_OUT_RES_RDI_1: + path_id = CAM_TFE_CSID_PATH_RES_RDI_1; + break; + case CAM_ISP_TFE_OUT_RES_RDI_2: + path_id = CAM_TFE_CSID_PATH_RES_RDI_2; + break; + default: + path_id = CAM_TFE_CSID_PATH_RES_MAX; + CAM_DBG(CAM_ISP, "maximum rdi type exceeded out_port_type:%d ", + out_port_type); + break; + } + + CAM_DBG(CAM_ISP, "out_port %x path_id %d", out_port_type, path_id); + + return path_id; +} + +static int cam_tfe_hw_mgr_acquire_res_tfe_csid_rdi( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_isp_tfe_in_port_info *in_port) +{ + int rc = -EINVAL; + int i, j; + + struct cam_tfe_hw_mgr *tfe_hw_mgr; + struct cam_isp_hw_mgr_res *csid_res; + struct cam_hw_intf *hw_intf; + struct cam_isp_tfe_out_port_info *out_port; + struct cam_tfe_csid_hw_reserve_resource_args csid_acquire; + struct cam_isp_hw_mgr_res *csid_res_iterator; + enum cam_tfe_csid_path_res_id path_res_id; + + tfe_hw_mgr = tfe_ctx->hw_mgr; + + for (j = 0; j < in_port->num_out_res; j++) { + out_port = &in_port->data[j]; + path_res_id = cam_tfe_hw_mgr_get_tfe_csid_rdi_res_type( + out_port->res_id); + + if (path_res_id == CAM_TFE_CSID_PATH_RES_MAX) + continue; + + rc = cam_tfe_hw_mgr_get_res(&tfe_ctx->free_res_list, &csid_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto end; + } + + memset(&csid_acquire, 0, sizeof(csid_acquire)); + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_id = path_res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = in_port->data; + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + csid_acquire.node_res = NULL; + + if (tfe_ctx->is_tpg) { + if (tfe_ctx->res_list_tpg.hw_res[0]->hw_intf->hw_idx == + 0) + csid_acquire.phy_sel = CAM_ISP_TFE_IN_RES_PHY_0; + else + csid_acquire.phy_sel = CAM_ISP_TFE_IN_RES_PHY_1; + } + + /* Try acquiring CSID resource from previously acquired HW */ + list_for_each_entry(csid_res_iterator, + &tfe_ctx->res_list_tfe_csid, list) { + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!csid_res_iterator->hw_res[i]) + continue; + + if (csid_res_iterator->is_secure == 1 || + (csid_res_iterator->is_secure == 0 && + in_port->num_out_res && + out_port->secure_mode == 1)) + continue; + + hw_intf = csid_res_iterator->hw_res[i]->hw_intf; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_DBG(CAM_ISP, + "No tfe csid resource from hw %d", + hw_intf->hw_idx); + continue; + } + + if (csid_acquire.node_res == NULL) { + CAM_ERR(CAM_ISP, + "Acquire RDI:%d rsrc failed", + path_res_id); + goto put_res; + } + + csid_res->hw_res[0] = csid_acquire.node_res; + + CAM_DBG(CAM_ISP, + "acquired from old csid(%s)=%d CSID rsrc successfully", + (i == 0) ? "left" : "right", + hw_intf->hw_idx); + /* + * If successfully acquired CSID from + * previously acquired HW, skip the next + * part + */ + goto acquire_successful; + } + } + + /* Acquire if not already acquired */ + if (tfe_ctx->is_dual) { + for (i = 0; i < CAM_TFE_CSID_HW_NUM_MAX; i++) { + if (!tfe_hw_mgr->csid_devices[i]) + continue; + + hw_intf = tfe_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + csid_res->hw_res[0] = + csid_acquire.node_res; + break; + } + } + + if (i == CAM_TFE_CSID_HW_NUM_MAX || + !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire tfe csid rdi path%d", + path_res_id); + + rc = -EINVAL; + goto put_res; + } + } else { + for (i = CAM_TFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { + if (!tfe_hw_mgr->csid_devices[i]) + continue; + + hw_intf = tfe_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + csid_res->hw_res[0] = + csid_acquire.node_res; + break; + } + } + + if (i == -1 || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire tfe csid rdi path %d", + path_res_id); + + rc = -EINVAL; + goto put_res; + } + } + +acquire_successful: + CAM_DBG(CAM_ISP, "CSID path :%d acquired success", path_res_id); + csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_res->res_id = path_res_id; + csid_res->hw_res[1] = NULL; + csid_res->is_dual_isp = 0; + + if (in_port->num_out_res) + csid_res->is_secure = out_port->secure_mode; + + cam_tfe_hw_mgr_put_res(&tfe_ctx->res_list_tfe_csid, &csid_res); + } + + return 0; +put_res: + cam_tfe_hw_mgr_put_res(&tfe_ctx->free_res_list, &csid_res); +end: + return rc; +} + +static int cam_tfe_hw_mgr_preprocess_port( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_isp_tfe_in_port_info *in_port, + int *ipp_count, + int *rdi_count, + int *pdaf_enable) +{ + int ipp_num = 0; + int rdi_num = 0; + bool rdi2_enable = false; + uint32_t i; + struct cam_isp_tfe_out_port_info *out_port; + struct cam_tfe_hw_mgr *tfe_hw_mgr; + + tfe_hw_mgr = tfe_ctx->hw_mgr; + + + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + CAM_DBG(CAM_ISP, "out_res id %d", out_port->res_id); + + if (cam_tfe_hw_mgr_is_rdi_res(out_port->res_id)) { + rdi_num++; + if (out_port->res_id == CAM_ISP_TFE_OUT_RES_RDI_2) + rdi2_enable = true; + } else { + ipp_num++; + if (out_port->res_id == CAM_ISP_TFE_OUT_RES_PDAF) + *pdaf_enable = 1; + } + } + + if (*pdaf_enable && rdi2_enable) { + CAM_ERR(CAM_ISP, "invalid outports both RDI2 and PDAF enabled"); + return -EINVAL; + } + + *ipp_count = ipp_num; + *rdi_count = rdi_num; + + CAM_DBG(CAM_ISP, "rdi: %d ipp: %d pdaf:%d", rdi_num, ipp_num, + *pdaf_enable); + + return 0; +} + +static int cam_tfe_mgr_acquire_hw_for_ctx( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + struct cam_isp_tfe_in_port_info *in_port, + uint32_t *num_pix_port, uint32_t *num_rdi_port, + uint32_t *pdaf_enable) +{ + int rc = -EINVAL; + int is_dual_isp = 0; + int ipp_count = 0; + int rdi_count = 0; + + is_dual_isp = in_port->usage_type; + + cam_tfe_hw_mgr_preprocess_port(tfe_ctx, in_port, &ipp_count, + &rdi_count, pdaf_enable); + + if (!ipp_count && !rdi_count) { + CAM_ERR(CAM_ISP, + "No PIX or RDI"); + return -EINVAL; + } + + if (ipp_count) { + /* get tfe csid IPP resource */ + rc = cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl(tfe_ctx, + in_port); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire TFE CSID IPP resource Failed"); + goto err; + } + } + + if (rdi_count) { + /* get tfe csid rdi resource */ + 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"); + goto err; + } + } + + 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"); + 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"); + goto err; + } + + *num_pix_port += ipp_count; + *num_rdi_port += rdi_count; + + return 0; +err: + /* release resource at the acquire entry funciton */ + return rc; +} + +void cam_tfe_cam_cdm_callback(uint32_t handle, void *userdata, + enum cam_cdm_cb_status status, uint64_t cookie) +{ + struct cam_isp_prepare_hw_update_data *hw_update_data = NULL; + struct cam_tfe_hw_mgr_ctx *ctx = NULL; + + if (!userdata) { + CAM_ERR(CAM_ISP, "Invalid args"); + return; + } + + hw_update_data = (struct cam_isp_prepare_hw_update_data *)userdata; + ctx = (struct cam_tfe_hw_mgr_ctx *)hw_update_data->isp_mgr_ctx; + + if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { + complete_all(&ctx->config_done_complete); + atomic_set(&ctx->cdm_done, 1); + if (g_tfe_hw_mgr.debug_cfg.per_req_reg_dump) + 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_DBG(CAM_ISP, + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", + handle, userdata, status, cookie, ctx->ctx_index); + } else { + CAM_WARN(CAM_ISP, + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", + handle, userdata, status, cookie); + } +} + +/* entry function: acquire_hw */ +static int cam_tfe_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) +{ + struct cam_tfe_hw_mgr *tfe_hw_mgr = hw_mgr_priv; + struct cam_hw_acquire_args *acquire_args = acquire_hw_args; + int rc = -EINVAL; + int i, j; + struct cam_tfe_hw_mgr_ctx *tfe_ctx; + struct cam_isp_tfe_in_port_info *in_port = NULL; + struct cam_cdm_acquire_data cdm_acquire; + uint32_t num_pix_port_per_in = 0; + uint32_t num_rdi_port_per_in = 0; + uint32_t pdaf_enable = 0; + uint32_t total_pix_port = 0; + uint32_t total_rdi_port = 0; + uint32_t in_port_length = 0; + uint32_t total_in_port_length = 0; + struct cam_isp_tfe_acquire_hw_info *acquire_hw_info = NULL; + struct cam_isp_tfe_in_port_info + *tpg_inport[CAM_TOP_TPG_MAX_SUPPORTED_DT] = {0, 0, 0, 0}; + + CAM_DBG(CAM_ISP, "Enter..."); + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error"); + return -EINVAL; + } + + /* get the tfe ctx */ + rc = cam_tfe_hw_mgr_get_ctx(&tfe_hw_mgr->free_ctx_list, &tfe_ctx); + if (rc || !tfe_ctx) { + CAM_ERR(CAM_ISP, "Get tfe hw context failed"); + goto err; + } + + tfe_ctx->common.cb_priv = acquire_args->context_data; + for (i = 0; i < CAM_ISP_HW_EVENT_MAX; i++) + tfe_ctx->common.event_cb[i] = acquire_args->event_cb; + + tfe_ctx->hw_mgr = tfe_hw_mgr; + + memcpy(cdm_acquire.identifier, "tfe", sizeof("tfe")); + cdm_acquire.cell_index = 0; + cdm_acquire.handle = 0; + cdm_acquire.userdata = tfe_ctx; + cdm_acquire.priority = CAM_CDM_BL_FIFO_0; + cdm_acquire.base_array_cnt = CAM_TFE_HW_NUM_MAX; + for (i = 0, j = 0; i < CAM_TFE_HW_NUM_MAX; i++) { + if (tfe_hw_mgr->cdm_reg_map[i]) + cdm_acquire.base_array[j++] = + tfe_hw_mgr->cdm_reg_map[i]; + } + cdm_acquire.base_array_cnt = j; + + + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.cam_cdm_callback = cam_tfe_cam_cdm_callback; + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to acquire the CDM HW"); + goto free_ctx; + } + + CAM_DBG(CAM_ISP, "Successfully acquired the CDM HW hdl=%x", + cdm_acquire.handle); + tfe_ctx->cdm_handle = cdm_acquire.handle; + tfe_ctx->cdm_ops = cdm_acquire.ops; + atomic_set(&tfe_ctx->cdm_done, 1); + + acquire_hw_info = (struct cam_isp_tfe_acquire_hw_info *) + acquire_args->acquire_info; + in_port = (struct cam_isp_tfe_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + + /* Check any inport has dual tfe usage */ + tfe_ctx->is_dual = false; + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + if (in_port->usage_type) + tfe_ctx->is_dual = true; + + in_port_length = + sizeof(struct cam_isp_tfe_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_tfe_out_port_info); + total_in_port_length += in_port_length; + if (total_in_port_length > + acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, + "buffer size is not enough %d %d", + total_in_port_length, + acquire_hw_info->input_info_size); + rc = -EINVAL; + goto free_cdm; + } + + in_port = (struct cam_isp_tfe_in_port_info *) + ((uint8_t *)in_port + in_port_length); + } + + in_port_length = 0; + total_in_port_length = 0; + in_port = (struct cam_isp_tfe_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + + if (in_port->res_id == CAM_ISP_TFE_IN_RES_TPG) { + if (acquire_hw_info->num_inputs > + CAM_TOP_TPG_MAX_SUPPORTED_DT) { + CAM_ERR(CAM_ISP, "too many number inport:%d for TPG ", + acquire_hw_info->num_inputs); + rc = -EINVAL; + goto free_cdm; + } + + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + if (in_port->res_id != CAM_ISP_TFE_IN_RES_TPG) { + CAM_ERR(CAM_ISP, "Inval :%d inport res id:0x%x", + i, in_port->res_id); + rc = -EINVAL; + goto free_cdm; + } + + tpg_inport[i] = in_port; + in_port_length = + sizeof(struct cam_isp_tfe_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_tfe_out_port_info); + total_in_port_length += in_port_length; + if (total_in_port_length > + acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, + "buffer size is not enough %d %d", + total_in_port_length, + acquire_hw_info->input_info_size); + rc = -EINVAL; + goto free_cdm; + } + + in_port = (struct cam_isp_tfe_in_port_info *) + ((uint8_t *)in_port + in_port_length); + } + + rc = cam_tfe_hw_mgr_acquire_tpg(tfe_ctx, tpg_inport, + acquire_hw_info->num_inputs); + if (rc) + goto free_cdm; + + tfe_ctx->is_tpg = true; + } + + in_port = (struct cam_isp_tfe_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + in_port_length = 0; + total_in_port_length = 0; + + /* acquire HW resources */ + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + + if (in_port->num_out_res > CAM_TFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "too many output res %d", + in_port->num_out_res); + rc = -EINVAL; + goto free_res; + } + + in_port_length = sizeof(struct cam_isp_tfe_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_tfe_out_port_info); + total_in_port_length += in_port_length; + + if (total_in_port_length > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + rc = -EINVAL; + goto free_res; + } + CAM_DBG(CAM_ISP, "in_res_id %x", in_port->res_id); + rc = cam_tfe_mgr_acquire_hw_for_ctx(tfe_ctx, in_port, + &num_pix_port_per_in, &num_rdi_port_per_in, + &pdaf_enable); + total_pix_port += num_pix_port_per_in; + total_rdi_port += num_rdi_port_per_in; + + if (rc) { + CAM_ERR(CAM_ISP, "can not acquire resource"); + goto free_res; + } + in_port = (struct cam_isp_tfe_in_port_info *) + ((uint8_t *)in_port + in_port_length); + } + + /* Check whether context has only RDI resource */ + if (!total_pix_port) { + tfe_ctx->is_rdi_only_context = 1; + CAM_DBG(CAM_ISP, "RDI only context"); + } else + tfe_ctx->is_rdi_only_context = 0; + + /* Process base info */ + rc = cam_tfe_mgr_process_base_info(tfe_ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Process base info failed"); + goto free_res; + } + + acquire_args->ctxt_to_hw_map = tfe_ctx; + tfe_ctx->ctx_in_use = 1; + + cam_tfe_hw_mgr_put_ctx(&tfe_hw_mgr->used_ctx_list, &tfe_ctx); + + CAM_DBG(CAM_ISP, "Exit...(success)"); + + return 0; +free_res: + cam_tfe_hw_mgr_release_hw_for_ctx(tfe_ctx); + tfe_ctx->ctx_in_use = 0; + tfe_ctx->is_rdi_only_context = 0; + tfe_ctx->cdm_handle = 0; + tfe_ctx->cdm_ops = NULL; + tfe_ctx->init_done = false; + tfe_ctx->is_dual = false; + tfe_ctx->is_tpg = false; + tfe_ctx->res_list_tpg.res_type = CAM_ISP_RESOURCE_MAX; +free_cdm: + cam_cdm_release(tfe_ctx->cdm_handle); +free_ctx: + cam_tfe_hw_mgr_put_ctx(&tfe_hw_mgr->free_ctx_list, &tfe_ctx); +err: + /* Dump all the current acquired HW */ + cam_tfe_hw_mgr_dump_all_ctx(); + + CAM_ERR_RATE_LIMIT(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +/* entry function: acquire_hw */ +static int cam_tfe_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) +{ + struct cam_tfe_hw_mgr *tfe_hw_mgr = hw_mgr_priv; + struct cam_hw_acquire_args *acquire_args = acquire_hw_args; + int rc = -EINVAL; + int i, j; + struct cam_tfe_hw_mgr_ctx *tfe_ctx; + struct cam_isp_tfe_in_port_info *in_port = NULL; + struct cam_isp_resource *isp_resource = NULL; + struct cam_cdm_acquire_data cdm_acquire; + uint32_t num_pix_port_per_in = 0; + uint32_t num_rdi_port_per_in = 0; + uint32_t pdad_enable = 0; + uint32_t total_pix_port = 0; + uint32_t total_rdi_port = 0; + uint32_t in_port_length = 0; + + CAM_DBG(CAM_ISP, "Enter..."); + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error"); + return -EINVAL; + } + + /* get the tfe ctx */ + rc = cam_tfe_hw_mgr_get_ctx(&tfe_hw_mgr->free_ctx_list, &tfe_ctx); + if (rc || !tfe_ctx) { + CAM_ERR(CAM_ISP, "Get tfe hw context failed"); + goto err; + } + + tfe_ctx->common.cb_priv = acquire_args->context_data; + for (i = 0; i < CAM_ISP_HW_EVENT_MAX; i++) + tfe_ctx->common.event_cb[i] = acquire_args->event_cb; + + tfe_ctx->hw_mgr = tfe_hw_mgr; + + memcpy(cdm_acquire.identifier, "tfe", sizeof("tfe")); + cdm_acquire.cell_index = 0; + cdm_acquire.handle = 0; + cdm_acquire.userdata = tfe_ctx; + cdm_acquire.base_array_cnt = CAM_TFE_HW_NUM_MAX; + for (i = 0, j = 0; i < CAM_TFE_HW_NUM_MAX; i++) { + if (tfe_hw_mgr->cdm_reg_map[i]) + cdm_acquire.base_array[j++] = + tfe_hw_mgr->cdm_reg_map[i]; + } + cdm_acquire.base_array_cnt = j; + + + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.cam_cdm_callback = cam_tfe_cam_cdm_callback; + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to acquire the CDM HW"); + goto free_ctx; + } + + CAM_DBG(CAM_ISP, "Successfully acquired the CDM HW hdl=%x", + cdm_acquire.handle); + tfe_ctx->cdm_handle = cdm_acquire.handle; + tfe_ctx->cdm_ops = cdm_acquire.ops; + atomic_set(&tfe_ctx->cdm_done, 1); + + isp_resource = (struct cam_isp_resource *)acquire_args->acquire_info; + + /* acquire HW resources */ + for (i = 0; i < acquire_args->num_acq; i++) { + if (isp_resource[i].resource_id != CAM_ISP_RES_ID_PORT) + continue; + + CAM_DBG(CAM_ISP, "acquire no = %d total = %d", i, + acquire_args->num_acq); + CAM_DBG(CAM_ISP, + "start copy from user handle %lld with len = %d", + isp_resource[i].res_hdl, + isp_resource[i].length); + + in_port_length = sizeof(struct cam_isp_tfe_in_port_info); + + if (in_port_length > isp_resource[i].length) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + rc = -EINVAL; + goto free_res; + } + + in_port = memdup_user( + u64_to_user_ptr(isp_resource[i].res_hdl), + isp_resource[i].length); + if (!IS_ERR(in_port)) { + if (in_port->num_out_res > CAM_TFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "too many output res %d", + in_port->num_out_res); + rc = -EINVAL; + kfree(in_port); + goto free_res; + } + + in_port_length = + sizeof(struct cam_isp_tfe_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_tfe_out_port_info); + if (in_port_length > isp_resource[i].length) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + rc = -EINVAL; + kfree(in_port); + goto free_res; + } + + rc = cam_tfe_mgr_acquire_hw_for_ctx(tfe_ctx, in_port, + &num_pix_port_per_in, &num_rdi_port_per_in, + &pdad_enable); + total_pix_port += num_pix_port_per_in; + total_rdi_port += num_rdi_port_per_in; + + kfree(in_port); + if (rc) { + CAM_ERR(CAM_ISP, "can not acquire resource"); + goto free_res; + } + } else { + CAM_ERR(CAM_ISP, + "Copy from user failed with in_port = %pK", + in_port); + rc = -EFAULT; + goto free_res; + } + } + + /* Check whether context has only RDI resource */ + if (!total_pix_port) { + tfe_ctx->is_rdi_only_context = 1; + CAM_DBG(CAM_ISP, "RDI only context"); + } else + tfe_ctx->is_rdi_only_context = 0; + + /* Process base info */ + rc = cam_tfe_mgr_process_base_info(tfe_ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Process base info failed"); + goto free_res; + } + + acquire_args->ctxt_to_hw_map = tfe_ctx; + tfe_ctx->ctx_in_use = 1; + + cam_tfe_hw_mgr_put_ctx(&tfe_hw_mgr->used_ctx_list, &tfe_ctx); + + CAM_DBG(CAM_ISP, "Exit...(success)"); + + return 0; +free_res: + cam_tfe_hw_mgr_release_hw_for_ctx(tfe_ctx); + cam_cdm_release(tfe_ctx->cdm_handle); +free_ctx: + cam_tfe_hw_mgr_put_ctx(&tfe_hw_mgr->free_ctx_list, &tfe_ctx); +err: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +/* entry function: acquire_hw */ +static int cam_tfe_mgr_acquire(void *hw_mgr_priv, + void *acquire_hw_args) +{ + struct cam_hw_acquire_args *acquire_args = acquire_hw_args; + int rc = -EINVAL; + + CAM_DBG(CAM_ISP, "Enter..."); + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error"); + return -EINVAL; + } + + if (acquire_args->num_acq == CAM_API_COMPAT_CONSTANT) + rc = cam_tfe_mgr_acquire_hw(hw_mgr_priv, acquire_hw_args); + else + rc = cam_tfe_mgr_acquire_dev(hw_mgr_priv, acquire_hw_args); + + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +static const char *cam_tfe_util_usage_data_to_string( + uint32_t usage_data) +{ + switch (usage_data) { + case CAM_ISP_TFE_USAGE_LEFT_PX: + return "LEFT_PX"; + case CAM_ISP_TFE_USAGE_RIGHT_PX: + return "RIGHT_PX"; + case CAM_ISP_TFE_USAGE_RDI: + return "RDI"; + default: + return "USAGE_INVALID"; + } +} + +static int cam_tfe_classify_vote_info( + struct cam_isp_hw_mgr_res *hw_mgr_res, + struct cam_isp_bw_config_internal_v2 *bw_config, + struct cam_axi_vote *isp_vote, + uint32_t split_idx, + bool *camif_l_bw_updated, + bool *camif_r_bw_updated) +{ + int rc = 0, i, j = 0; + + if (hw_mgr_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) { + if (split_idx == CAM_ISP_HW_SPLIT_LEFT) { + if (*camif_l_bw_updated) + return rc; + + for (i = 0; i < bw_config->num_paths; i++) { + if (bw_config->axi_path[i].usage_data == + CAM_ISP_TFE_USAGE_LEFT_PX) { + memcpy(&isp_vote->axi_path[j], + &bw_config->axi_path[i], + sizeof(struct + cam_axi_per_path_bw_vote)); + j++; + } + } + isp_vote->num_paths = j; + + *camif_l_bw_updated = true; + } else { + if (*camif_r_bw_updated) + return rc; + + for (i = 0; i < bw_config->num_paths; i++) { + if (bw_config->axi_path[i].usage_data == + CAM_ISP_TFE_USAGE_RIGHT_PX) { + memcpy(&isp_vote->axi_path[j], + &bw_config->axi_path[i], + sizeof(struct + cam_axi_per_path_bw_vote)); + j++; + } + } + isp_vote->num_paths = j; + + *camif_r_bw_updated = true; + } + } else if ((hw_mgr_res->res_id >= CAM_ISP_HW_TFE_IN_RDI0) + && (hw_mgr_res->res_id <= + CAM_ISP_HW_TFE_IN_RDI2)) { + for (i = 0; i < bw_config->num_paths; i++) { + if ((bw_config->axi_path[i].usage_data == + CAM_ISP_TFE_USAGE_RDI) && + ((bw_config->axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_IFE_RDI0) == + (hw_mgr_res->res_id - + CAM_ISP_HW_TFE_IN_RDI0))) { + memcpy(&isp_vote->axi_path[j], + &bw_config->axi_path[i], + sizeof(struct + cam_axi_per_path_bw_vote)); + j++; + } + } + isp_vote->num_paths = j; + + } else { + if (hw_mgr_res->hw_res[split_idx]) { + CAM_ERR(CAM_ISP, "Invalid res_id %u, split_idx: %u", + hw_mgr_res->res_id, split_idx); + rc = -EINVAL; + return rc; + } + } + + for (i = 0; i < isp_vote->num_paths; i++) { + CAM_DBG(CAM_PERF, + "CLASSIFY_VOTE [%s] [%s] [%s] [%llu] [%llu] [%llu]", + cam_tfe_util_usage_data_to_string( + isp_vote->axi_path[i].usage_data), + cam_cpas_axi_util_path_type_to_string( + isp_vote->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + isp_vote->axi_path[i].transac_type), + isp_vote->axi_path[i].camnoc_bw, + isp_vote->axi_path[i].mnoc_ab_bw, + isp_vote->axi_path[i].mnoc_ib_bw); + } + + return rc; +} + +static int cam_isp_tfe_blob_bw_update( + struct cam_isp_bw_config_internal_v2 *bw_config, + struct cam_tfe_hw_mgr_ctx *ctx) +{ + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_tfe_bw_update_args bw_upd_args; + int rc = -EINVAL; + uint32_t i, split_idx; + bool camif_l_bw_updated = false; + bool camif_r_bw_updated = false; + + for (i = 0; i < bw_config->num_paths; i++) { + CAM_DBG(CAM_PERF, + "ISP_BLOB usage_type=%u [%s] [%s] [%s] [%llu] [%llu] [%llu]", + bw_config->usage_type, + cam_tfe_util_usage_data_to_string( + bw_config->axi_path[i].usage_data), + cam_cpas_axi_util_path_type_to_string( + bw_config->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + bw_config->axi_path[i].transac_type), + bw_config->axi_path[i].camnoc_bw, + bw_config->axi_path[i].mnoc_ab_bw, + bw_config->axi_path[i].mnoc_ib_bw); + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + for (split_idx = 0; split_idx < CAM_ISP_HW_SPLIT_MAX; + split_idx++) { + if (!hw_mgr_res->hw_res[split_idx]) + continue; + + memset(&bw_upd_args.isp_vote, 0, + sizeof(struct cam_axi_vote)); + rc = cam_tfe_classify_vote_info(hw_mgr_res, bw_config, + &bw_upd_args.isp_vote, split_idx, + &camif_l_bw_updated, &camif_r_bw_updated); + if (rc) + return rc; + + if (!bw_upd_args.isp_vote.num_paths) + continue; + + hw_intf = hw_mgr_res->hw_res[split_idx]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + bw_upd_args.node_res = + hw_mgr_res->hw_res[split_idx]; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_BW_UPDATE_V2, + &bw_upd_args, + sizeof( + struct cam_tfe_bw_update_args)); + if (rc) + CAM_ERR(CAM_ISP, + "BW Update failed rc: %d", rc); + } else { + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + } + + return rc; +} + +/* entry function: config_hw */ +static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, + void *config_hw_args) +{ + int rc = -EINVAL, i, skip = 0; + struct cam_hw_config_args *cfg; + struct cam_hw_update_entry *cmd; + struct cam_cdm_bl_request *cdm_cmd; + struct cam_tfe_hw_mgr_ctx *ctx; + struct cam_isp_prepare_hw_update_data *hw_update_data; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_mgr_priv || !config_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + cfg = config_hw_args; + ctx = (struct cam_tfe_hw_mgr_ctx *)cfg->ctxt_to_hw_map; + if (!ctx) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + if (!ctx->ctx_in_use || !ctx->cdm_cmd) { + CAM_ERR(CAM_ISP, "Invalid context parameters"); + return -EPERM; + } + if (atomic_read(&ctx->overflow_pending)) + return -EINVAL; + + hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; + + for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) { + if (hw_update_data->bw_config_valid[i] == true) { + + CAM_DBG(CAM_ISP, "idx=%d, bw_config_version=%d", + ctx, ctx->ctx_index, i, + hw_update_data->bw_config_version); + if (hw_update_data->bw_config_version == + CAM_ISP_BW_CONFIG_V2) { + rc = cam_isp_tfe_blob_bw_update( + &hw_update_data->bw_config_v2[i], ctx); + if (rc) + CAM_ERR(CAM_ISP, + "Bandwidth Update Failed rc: %d", rc); + } else { + CAM_ERR(CAM_ISP, + "Invalid bw config version: %d", + hw_update_data->bw_config_version); + } + } + } + + CAM_DBG(CAM_ISP, + "Enter ctx id:%d num_hw_upd_entries %d request id: %llu", + ctx->ctx_index, cfg->num_hw_update_entries, cfg->request_id); + + if (cfg->num_hw_update_entries > 0) { + cdm_cmd = ctx->cdm_cmd; + cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = true; + cdm_cmd->userdata = hw_update_data; + cdm_cmd->cookie = cfg->request_id; + cdm_cmd->gen_irq_arb = false; + + for (i = 0 ; i < cfg->num_hw_update_entries; i++) { + cmd = (cfg->hw_update_entries + i); + if (cfg->reapply && cmd->flags == CAM_ISP_IQ_BL) { + skip++; + continue; + } + + if (cmd->flags == CAM_ISP_UNUSED_BL || + cmd->flags >= CAM_ISP_BL_MAX) + CAM_ERR(CAM_ISP, "Unexpected BL type %d", + cmd->flags); + + cdm_cmd->cmd[i - skip].bl_addr.mem_handle = cmd->handle; + cdm_cmd->cmd[i - skip].offset = cmd->offset; + cdm_cmd->cmd[i - skip].len = cmd->len; + cdm_cmd->cmd[i - skip].arbitrate = false; + } + cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries - skip; + + reinit_completion(&ctx->config_done_complete); + ctx->applied_req_id = cfg->request_id; + + CAM_DBG(CAM_ISP, "Submit to CDM"); + atomic_set(&ctx->cdm_done, 0); + rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to apply the configs"); + return rc; + } + + if (cfg->init_packet) { + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies(CAM_TFE_HW_CONFIG_TIMEOUT)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, + "config done completion timeout for req_id=%llu rc=%d ctx_index %d", + cfg->request_id, rc, ctx->ctx_index); + if (rc == 0) + rc = -ETIMEDOUT; + } else { + rc = 0; + CAM_DBG(CAM_ISP, + "config done Success for req_id=%llu ctx_index %d", + cfg->request_id, ctx->ctx_index); + } + } + } else { + CAM_ERR(CAM_ISP, "No commands to config"); + } + CAM_DBG(CAM_ISP, "Exit: Config Done: %llu", cfg->request_id); + + return rc; +} + +static int cam_tfe_mgr_stop_hw_in_overflow(void *stop_hw_args) +{ + int rc = 0; + struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_tfe_hw_mgr_ctx *ctx; + uint32_t i, master_base_idx = 0; + + if (!stop_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + ctx = (struct cam_tfe_hw_mgr_ctx *)stop_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "Enter...ctx id:%d", + ctx->ctx_index); + + if (!ctx->num_base) { + CAM_ERR(CAM_ISP, "Number of bases are zero"); + return -EINVAL; + } + + /* get master base index first */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) { + master_base_idx = ctx->base[i].idx; + break; + } + } + + if (i == ctx->num_base) + master_base_idx = ctx->base[0].idx; + + + /* stop the master CSID path first */ + cam_tfe_mgr_csid_stop_hw(ctx, &ctx->res_list_tfe_csid, + master_base_idx, CAM_TFE_CSID_HALT_IMMEDIATELY); + + /* Stop rest of the CSID paths */ + for (i = 0; i < ctx->num_base; i++) { + if (i == master_base_idx) + continue; + + cam_tfe_mgr_csid_stop_hw(ctx, &ctx->res_list_tfe_csid, + ctx->base[i].idx, CAM_TFE_CSID_HALT_IMMEDIATELY); + } + + /* TFE in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + cam_tfe_hw_mgr_stop_hw_res(hw_mgr_res); + } + + /* TFE out resources */ + for (i = 0; i < CAM_TFE_HW_OUT_RES_MAX; i++) + cam_tfe_hw_mgr_stop_hw_res(&ctx->res_list_tfe_out[i]); + + if (ctx->is_tpg) + cam_tfe_hw_mgr_stop_hw_res(&ctx->res_list_tpg); + + /* Stop tasklet for context */ + cam_tasklet_stop(ctx->common.tasklet_info); + CAM_DBG(CAM_ISP, "Exit...ctx id:%d rc :%d", + ctx->ctx_index, rc); + + return rc; +} + +static int cam_tfe_mgr_bw_control(struct cam_tfe_hw_mgr_ctx *ctx, + enum cam_tfe_bw_control_action action) +{ + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_tfe_bw_control_args bw_ctrl_args; + int rc = -EINVAL; + uint32_t i; + + CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index); + + 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]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + bw_ctrl_args.node_res = + hw_mgr_res->hw_res[i]; + bw_ctrl_args.action = action; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_BW_CONTROL, + &bw_ctrl_args, + sizeof(struct cam_tfe_bw_control_args)); + if (rc) + CAM_ERR(CAM_ISP, "BW Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +static int cam_tfe_mgr_pause_hw(struct cam_tfe_hw_mgr_ctx *ctx) +{ + return cam_tfe_mgr_bw_control(ctx, CAM_TFE_BW_CONTROL_EXCLUDE); +} + +/* entry function: stop_hw */ +static int cam_tfe_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) +{ + int rc = 0; + struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_isp_stop_args *stop_isp; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_tfe_hw_mgr_ctx *ctx; + enum cam_tfe_csid_halt_cmd csid_halt_type; + uint32_t i, master_base_idx = 0; + + if (!hw_mgr_priv || !stop_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_tfe_hw_mgr_ctx *)stop_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, " Enter...ctx id:%d", ctx->ctx_index); + stop_isp = (struct cam_isp_stop_args *)stop_args->args; + + /* Set the csid halt command */ + if (stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY) + csid_halt_type = CAM_TFE_CSID_HALT_AT_FRAME_BOUNDARY; + else + csid_halt_type = CAM_TFE_CSID_HALT_IMMEDIATELY; + + /* Note:stop resource will remove the irq mask from the hardware */ + + if (!ctx->num_base) { + CAM_ERR(CAM_ISP, "number of bases are zero"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Halting CSIDs"); + + /* get master base index first */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) { + master_base_idx = ctx->base[i].idx; + break; + } + } + + /* + * If Context does not have PIX resources and has only RDI resource + * then take the first base index. + */ + if (i == ctx->num_base) + master_base_idx = ctx->base[0].idx; + CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx); + + /* Stop the master CSID path first */ + cam_tfe_mgr_csid_stop_hw(ctx, &ctx->res_list_tfe_csid, + master_base_idx, csid_halt_type); + + /* stop rest of the CSID paths */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == master_base_idx) + continue; + CAM_DBG(CAM_ISP, "Stopping CSID idx %d i %d master %d", + ctx->base[i].idx, i, master_base_idx); + + cam_tfe_mgr_csid_stop_hw(ctx, &ctx->res_list_tfe_csid, + ctx->base[i].idx, csid_halt_type); + } + + CAM_DBG(CAM_ISP, "Going to stop TFE Out"); + + /* TFE out resources */ + for (i = 0; i < CAM_TFE_HW_OUT_RES_MAX; i++) + cam_tfe_hw_mgr_stop_hw_res(&ctx->res_list_tfe_out[i]); + + CAM_DBG(CAM_ISP, "Going to stop TFE IN"); + + /* TFE in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + cam_tfe_hw_mgr_stop_hw_res(hw_mgr_res); + } + + cam_tasklet_stop(ctx->common.tasklet_info); + + cam_tfe_mgr_pause_hw(ctx); + + wait_for_completion(&ctx->config_done_complete); + + if (stop_isp->stop_only) + goto end; + + if (cam_cdm_stream_off(ctx->cdm_handle)) + CAM_ERR(CAM_ISP, "CDM stream off failed %d", ctx->cdm_handle); + + if (ctx->is_tpg) + cam_tfe_hw_mgr_stop_hw_res(&ctx->res_list_tpg); + + cam_tfe_hw_mgr_deinit_hw(ctx); + + CAM_DBG(CAM_ISP, + "Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc); + + mutex_lock(&g_tfe_hw_mgr.ctx_mutex); + atomic_dec_return(&g_tfe_hw_mgr.active_ctx_cnt); + mutex_unlock(&g_tfe_hw_mgr.ctx_mutex); + +end: + return rc; +} + +static int cam_tfe_mgr_reset_tfe_hw(struct cam_tfe_hw_mgr *hw_mgr, + uint32_t hw_idx) +{ + uint32_t i = 0; + struct cam_hw_intf *tfe_hw_intf; + uint32_t tfe_reset_type; + + if (!hw_mgr) { + CAM_DBG(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + /* Reset TFE HW*/ + tfe_reset_type = CAM_TFE_HW_RESET_HW; + + for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) { + if (hw_idx != hw_mgr->tfe_devices[i]->hw_idx) + continue; + CAM_DBG(CAM_ISP, "TFE (id = %d) reset", hw_idx); + tfe_hw_intf = hw_mgr->tfe_devices[i]; + tfe_hw_intf->hw_ops.reset(tfe_hw_intf->hw_priv, + &tfe_reset_type, sizeof(tfe_reset_type)); + break; + } + + CAM_DBG(CAM_ISP, "Exit Successfully"); + return 0; +} + +static int cam_tfe_mgr_restart_hw(void *start_hw_args) +{ + int rc = -EINVAL; + struct cam_hw_start_args *start_args = start_hw_args; + struct cam_tfe_hw_mgr_ctx *ctx; + struct cam_isp_hw_mgr_res *hw_mgr_res; + uint32_t i; + + if (!start_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_tfe_hw_mgr_ctx *)start_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "START TFE OUT ... in ctx id:%d", ctx->ctx_index); + + cam_tasklet_start(ctx->common.tasklet_info); + + /* start the TFE out devices */ + for (i = 0; i < CAM_TFE_HW_OUT_RES_MAX; i++) { + rc = cam_tfe_hw_mgr_start_hw_res( + &ctx->res_list_tfe_out[i], ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start TFE OUT (%d)", i); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START TFE SRC ... in ctx id:%d", ctx->ctx_index); + + /* Start the TFE in devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + rc = cam_tfe_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start TFE IN (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d", ctx->ctx_index); + /* Start the TFE CSID HW devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, list) { + rc = cam_tfe_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start TFE CSID (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "Exit...(success)"); + return 0; + +err: + cam_tfe_mgr_stop_hw_in_overflow(start_hw_args); + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +static int cam_tfe_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) +{ + int rc = -EINVAL; + struct cam_isp_start_args *start_isp = start_hw_args; + struct cam_hw_stop_args stop_args; + struct cam_isp_stop_args stop_isp; + struct cam_tfe_hw_mgr_ctx *ctx; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *rsrc_node = NULL; + uint32_t i, camif_debug; + bool res_rdi_context_set = false; + uint32_t primary_rdi_in_res; + uint32_t primary_rdi_out_res; + + primary_rdi_in_res = CAM_ISP_HW_TFE_IN_MAX; + primary_rdi_out_res = CAM_ISP_TFE_OUT_RES_MAX; + + if (!hw_mgr_priv || !start_isp) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_tfe_hw_mgr_ctx *) + start_isp->hw_config.ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + if ((!ctx->init_done) && start_isp->start_only) { + CAM_ERR(CAM_ISP, "Invalid args init_done %d start_only %d", + ctx->init_done, start_isp->start_only); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enter... ctx id:%d", + ctx->ctx_index); + + /* update Bandwidth should be done at the hw layer */ + + cam_tasklet_start(ctx->common.tasklet_info); + + if (ctx->init_done && start_isp->start_only) + goto start_only; + + /* set current csid debug information to CSID HW */ + for (i = 0; i < CAM_TFE_CSID_HW_NUM_MAX; i++) { + if (g_tfe_hw_mgr.csid_devices[i]) + rc = g_tfe_hw_mgr.csid_devices[i]->hw_ops.process_cmd( + g_tfe_hw_mgr.csid_devices[i]->hw_priv, + CAM_TFE_CSID_SET_CSID_DEBUG, + &g_tfe_hw_mgr.debug_cfg.csid_debug, + sizeof(g_tfe_hw_mgr.debug_cfg.csid_debug)); + } + + camif_debug = g_tfe_hw_mgr.debug_cfg.camif_debug; + 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]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->process_cmd && (rsrc_node->res_id == + CAM_ISP_HW_TFE_IN_CAMIF)) { + rc = hw_mgr_res->hw_res[i]->process_cmd( + hw_mgr_res->hw_res[i], + CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, + &camif_debug, + sizeof(camif_debug)); + } + } + } + + rc = cam_tfe_hw_mgr_init_hw(ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Init failed"); + goto tasklet_stop; + } + + ctx->init_done = true; + + mutex_lock(&g_tfe_hw_mgr.ctx_mutex); + atomic_fetch_inc(&g_tfe_hw_mgr.active_ctx_cnt); + mutex_unlock(&g_tfe_hw_mgr.ctx_mutex); + + CAM_DBG(CAM_ISP, "start cdm interface"); + rc = cam_cdm_stream_on(ctx->cdm_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start cdm (%d)", + ctx->cdm_handle); + goto deinit_hw; + } + +start_only: + /* Apply initial configuration */ + CAM_DBG(CAM_ISP, "Config HW"); + rc = cam_tfe_mgr_config_hw(hw_mgr_priv, &start_isp->hw_config); + if (rc) { + CAM_ERR(CAM_ISP, "Config HW failed"); + goto cdm_streamoff; + } + + CAM_DBG(CAM_ISP, "START TFE OUT ... in ctx id:%d", + ctx->ctx_index); + /* start the TFE out devices */ + for (i = 0; i < CAM_TFE_HW_OUT_RES_MAX; i++) { + hw_mgr_res = &ctx->res_list_tfe_out[i]; + switch (hw_mgr_res->res_id) { + case CAM_ISP_TFE_OUT_RES_RDI_0: + case CAM_ISP_TFE_OUT_RES_RDI_1: + case CAM_ISP_TFE_OUT_RES_RDI_2: + if (!res_rdi_context_set && ctx->is_rdi_only_context) { + hw_mgr_res->hw_res[0]->rdi_only_ctx = + ctx->is_rdi_only_context; + res_rdi_context_set = true; + primary_rdi_out_res = hw_mgr_res->res_id; + } + } + + rc = cam_tfe_hw_mgr_start_hw_res( + &ctx->res_list_tfe_out[i], ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start TFE OUT (%d)", + i); + goto err; + } + } + + if (primary_rdi_out_res < CAM_ISP_TFE_OUT_RES_MAX) + primary_rdi_in_res = + cam_tfe_hw_mgr_convert_rdi_out_res_id_to_in_res( + primary_rdi_out_res); + + CAM_DBG(CAM_ISP, "START TFE IN ... in ctx id:%d", + ctx->ctx_index); + /* Start the TFE in resources devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + /* + * if rdi only context has two rdi resources then only one irq + * subscription should be sufficient + */ + if (primary_rdi_in_res == hw_mgr_res->res_id) + hw_mgr_res->hw_res[0]->rdi_only_ctx = + ctx->is_rdi_only_context; + + rc = cam_tfe_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start TFE in resource (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d", + ctx->ctx_index); + /* Start the TFE CSID HW devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, list) { + rc = cam_tfe_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start TFE CSID (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + if (ctx->is_tpg) { + CAM_DBG(CAM_ISP, "START TPG HW ... in ctx id:%d", + ctx->ctx_index); + rc = cam_tfe_hw_mgr_start_hw_res(&ctx->res_list_tpg, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start TFE TPG (%d)", + ctx->res_list_tpg.res_id); + goto err; + } + } + + return 0; + +err: + stop_isp.stop_only = false; + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + stop_args.ctxt_to_hw_map = start_isp->hw_config.ctxt_to_hw_map; + stop_args.args = (void *)(&stop_isp); + + cam_tfe_mgr_stop_hw(hw_mgr_priv, &stop_args); + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; + +cdm_streamoff: + cam_cdm_stream_off(ctx->cdm_handle); + +deinit_hw: + cam_tfe_hw_mgr_deinit_hw(ctx); + +tasklet_stop: + cam_tasklet_stop(ctx->common.tasklet_info); + + return rc; +} + +static int cam_tfe_mgr_read(void *hw_mgr_priv, void *read_args) +{ + return -EPERM; +} + +static int cam_tfe_mgr_write(void *hw_mgr_priv, void *write_args) +{ + return -EPERM; +} + +static int cam_tfe_mgr_reset(void *hw_mgr_priv, void *hw_reset_args) +{ + struct cam_tfe_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_reset_args *reset_args = hw_reset_args; + struct cam_tfe_hw_mgr_ctx *ctx; + struct cam_isp_hw_mgr_res *hw_mgr_res; + int rc = 0, i = 0; + + if (!hw_mgr_priv || !hw_reset_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_tfe_hw_mgr_ctx *)reset_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "Reset CSID and TFE"); + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, list) { + rc = cam_tfe_hw_mgr_reset_csid_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to reset CSID:%d rc: %d", + hw_mgr_res->res_id, rc); + goto end; + } + } + + for (i = 0; i < ctx->num_base; i++) { + rc = cam_tfe_mgr_reset_tfe_hw(hw_mgr, ctx->base[i].idx); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to reset TFE:%d rc: %d", + ctx->base[i].idx, rc); + goto end; + } + } + +end: + return rc; +} + +static int cam_tfe_mgr_release_hw(void *hw_mgr_priv, + void *release_hw_args) +{ + int rc = 0; + struct cam_hw_release_args *release_args = release_hw_args; + struct cam_tfe_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_tfe_hw_mgr_ctx *ctx; + uint32_t i; + + if (!hw_mgr_priv || !release_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_tfe_hw_mgr_ctx *)release_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "Enter...ctx id:%d", + ctx->ctx_index); + + if (ctx->init_done) + cam_tfe_hw_mgr_deinit_hw(ctx); + + /* we should called the stop hw before this already */ + cam_tfe_hw_mgr_release_hw_for_ctx(ctx); + + /* reset base info */ + ctx->num_base = 0; + memset(ctx->base, 0, sizeof(ctx->base)); + + /* release cdm handle */ + cam_cdm_release(ctx->cdm_handle); + + /* clean context */ + list_del_init(&ctx->list); + ctx->ctx_in_use = 0; + ctx->is_rdi_only_context = 0; + ctx->cdm_handle = 0; + ctx->cdm_ops = NULL; + ctx->init_done = false; + ctx->is_dual = false; + ctx->is_tpg = false; + 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++) { + ctx->sof_cnt[i] = 0; + ctx->eof_cnt[i] = 0; + ctx->epoch_cnt[i] = 0; + } + CAM_DBG(CAM_ISP, "Exit...ctx id:%d", + ctx->ctx_index); + cam_tfe_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx); + return rc; +} + + +static int cam_isp_tfe_blob_hfr_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_tfe_resource_hfr_config *hfr_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_isp_tfe_port_hfr_config *port_hfr_config; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_tfe_hw_mgr_ctx *ctx = NULL; + struct cam_isp_hw_mgr_res *hw_mgr_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + + ctx = prepare->ctxt_to_hw_map; + CAM_DBG(CAM_ISP, "num_ports= %d", hfr_config->num_ports); + + /* Max one hw entries required for hfr config update */ + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < hfr_config->num_ports; i++) { + port_hfr_config = &hfr_config->port_hfr_config[i]; + res_id_out = port_hfr_config->resource_type & 0xFF; + + CAM_DBG(CAM_ISP, "hfr config idx %d, type=%d", i, + res_id_out); + + if (res_id_out >= CAM_TFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "invalid out restype:%x", + port_hfr_config->resource_type); + return -EINVAL; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + blob_info->base_info->idx); + rc = -ENOMEM; + return rc; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + total_used_bytes/4; + hw_mgr_res = &ctx->res_list_tfe_out[res_id_out]; + + rc = cam_isp_add_cmd_buf_update( + hw_mgr_res, blob_type, CAM_ISP_HW_CMD_GET_HFR_UPDATE, + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)port_hfr_config, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed cmd_update, base_idx=%d, rc=%d", + blob_info->base_info->idx, bytes_used); + return rc; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + + return rc; +} + +static int cam_isp_tfe_blob_csid_clock_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_tfe_csid_clock_config *clock_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_tfe_hw_mgr_ctx *ctx = NULL; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_tfe_csid_clock_update_args csid_clock_upd_args; + struct cam_top_tpg_clock_update_args tpg_clock_upd_args; + uint64_t clk_rate = 0; + int rc = -EINVAL; + uint32_t i; + + ctx = prepare->ctxt_to_hw_map; + + CAM_DBG(CAM_ISP, "csid clk=%llu", clock_config->csid_clock); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + clk_rate = 0; + if (!hw_mgr_res->hw_res[i]) + continue; + clk_rate = clock_config->csid_clock; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + csid_clock_upd_args.clk_rate = clk_rate; + CAM_DBG(CAM_ISP, "i= %d csid clk=%llu", + i, csid_clock_upd_args.clk_rate); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, + &csid_clock_upd_args, + sizeof( + struct cam_tfe_csid_clock_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update failed"); + } else + CAM_ERR(CAM_ISP, "NULL hw_intf!"); + } + } + + if (ctx->res_list_tpg.res_type == CAM_ISP_RESOURCE_TPG) { + tpg_clock_upd_args.clk_rate = clock_config->phy_clock; + hw_intf = ctx->res_list_tpg.hw_res[0]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + CAM_DBG(CAM_ISP, "i= %d phy clk=%llu", + tpg_clock_upd_args.clk_rate); + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE, + &tpg_clock_upd_args, + sizeof(struct cam_top_tpg_clock_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update failed"); + } else + CAM_ERR(CAM_ISP, "NULL hw_intf!"); + } + + return rc; +} + +static int cam_isp_tfe_blob_clock_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_tfe_clock_config *clock_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_tfe_hw_mgr_ctx *ctx = NULL; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_tfe_clock_update_args clock_upd_args; + uint64_t clk_rate = 0; + int rc = -EINVAL; + uint32_t i; + uint32_t j; + bool camif_l_clk_updated = false; + bool camif_r_clk_updated = false; + + ctx = prepare->ctxt_to_hw_map; + + CAM_DBG(CAM_PERF, + "usage=%u left_clk= %lu right_clk=%lu", + clock_config->usage_type, + clock_config->left_pix_hz, + clock_config->right_pix_hz); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + clk_rate = 0; + if (!hw_mgr_res->hw_res[i]) + continue; + + if (hw_mgr_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + if (camif_l_clk_updated) + continue; + + clk_rate = + clock_config->left_pix_hz; + + camif_l_clk_updated = true; + } else { + if (camif_r_clk_updated) + continue; + + clk_rate = + clock_config->right_pix_hz; + + camif_r_clk_updated = true; + } + } else if ((hw_mgr_res->res_id >= + CAM_ISP_HW_TFE_IN_RDI0) && (hw_mgr_res->res_id + <= CAM_ISP_HW_TFE_IN_RDI2)) { + for (j = 0; j < clock_config->num_rdi; j++) + clk_rate = max(clock_config->rdi_hz[j], + clk_rate); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id %u", + hw_mgr_res->res_id); + rc = -EINVAL; + return rc; + } + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + clock_upd_args.node_res = + hw_mgr_res->hw_res[i]; + CAM_DBG(CAM_ISP, + "res_id=%u i= %d clk=%llu", + hw_mgr_res->res_id, i, clk_rate); + + clock_upd_args.clk_rate = clk_rate; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CLOCK_UPDATE, + &clock_upd_args, + sizeof( + struct cam_tfe_clock_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +static int cam_isp_tfe_packet_generic_blob_handler(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) +{ + int rc = 0; + struct cam_isp_generic_blob_info *blob_info = user_data; + struct cam_hw_prepare_update_args *prepare = NULL; + + if (!blob_data || (blob_size == 0) || !blob_info) { + CAM_ERR(CAM_ISP, "Invalid args data %pK size %d info %pK", + blob_data, blob_size, blob_info); + return -EINVAL; + } + + prepare = blob_info->prepare; + if (!prepare) { + CAM_ERR(CAM_ISP, "Failed. prepare is NULL, blob_type %d", + blob_type); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "BLOB Type: %d", blob_type); + switch (blob_type) { + case CAM_ISP_TFE_GENERIC_BLOB_TYPE_HFR_CONFIG: { + struct cam_isp_tfe_resource_hfr_config *hfr_config = + (struct cam_isp_tfe_resource_hfr_config *)blob_data; + + if (blob_size < + sizeof(struct cam_isp_tfe_resource_hfr_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + if (hfr_config->num_ports > CAM_ISP_TFE_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in hfr config", + hfr_config->num_ports); + return -EINVAL; + } + + /* Check for integer overflow */ + if (hfr_config->num_ports > 1) { + if (sizeof(struct cam_isp_tfe_resource_hfr_config) > + ((UINT_MAX - + sizeof(struct cam_isp_tfe_resource_hfr_config)) + / (hfr_config->num_ports - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in hfr config num_ports:%u size per port:%lu", + hfr_config->num_ports, + sizeof(struct + cam_isp_tfe_resource_hfr_config)); + return -EINVAL; + } + } + + if ((hfr_config->num_ports != 0) && (blob_size < + (sizeof(struct cam_isp_tfe_resource_hfr_config) + + (hfr_config->num_ports - 1) * + sizeof(struct cam_isp_tfe_resource_hfr_config)))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(struct cam_isp_tfe_resource_hfr_config) + + (hfr_config->num_ports - 1) * + sizeof(struct cam_isp_tfe_resource_hfr_config)); + return -EINVAL; + } + + rc = cam_isp_tfe_blob_hfr_update(blob_type, blob_info, + hfr_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "HFR Update Failed"); + } + break; + case CAM_ISP_TFE_GENERIC_BLOB_TYPE_CLOCK_CONFIG: { + struct cam_isp_tfe_clock_config *clock_config = + (struct cam_isp_tfe_clock_config *)blob_data; + + if (blob_size < sizeof(struct cam_isp_tfe_clock_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + if (clock_config->num_rdi > CAM_TFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in clock config", + clock_config->num_rdi); + return -EINVAL; + } + /* Check integer overflow */ + if (clock_config->num_rdi > 1) { + if (sizeof(uint64_t) > ((UINT_MAX- + sizeof(struct cam_isp_tfe_clock_config))/ + (clock_config->num_rdi - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in clock config num_rdi:%u size per port:%lu", + clock_config->num_rdi, + sizeof(uint64_t)); + return -EINVAL; + } + } + + if ((clock_config->num_rdi != 0) && (blob_size < + (sizeof(struct cam_isp_tfe_clock_config) + + sizeof(uint64_t) * (clock_config->num_rdi - 1)))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(uint32_t) * 2 + sizeof(uint64_t) * + (clock_config->num_rdi + 2)); + return -EINVAL; + } + + rc = cam_isp_tfe_blob_clock_update(blob_type, blob_info, + clock_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update Failed"); + } + break; + case CAM_ISP_TFE_GENERIC_BLOB_TYPE_BW_CONFIG_V2: { + size_t bw_config_size = 0; + struct cam_isp_tfe_bw_config_v2 *bw_config = + (struct cam_isp_tfe_bw_config_v2 *)blob_data; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + if (blob_size < sizeof(struct cam_isp_tfe_bw_config_v2)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + if (bw_config->num_paths > CAM_ISP_MAX_PER_PATH_VOTES) { + CAM_ERR(CAM_ISP, "Invalid num paths %d", + bw_config->num_paths); + return -EINVAL; + } + + /* Check for integer overflow */ + if (bw_config->num_paths > 1) { + if (sizeof(struct cam_axi_per_path_bw_vote) > + ((UINT_MAX - + sizeof(struct cam_isp_tfe_bw_config_v2)) / + (bw_config->num_paths - 1))) { + CAM_ERR(CAM_ISP, + "Size exceeds limit paths:%u size per path:%lu", + bw_config->num_paths - 1, + sizeof( + struct cam_axi_per_path_bw_vote)); + return -EINVAL; + } + } + + if ((bw_config->num_paths != 0) && (blob_size < + (sizeof(struct cam_isp_tfe_bw_config_v2) + + ((bw_config->num_paths - 1) * + sizeof(struct cam_axi_per_path_bw_vote))))) { + CAM_ERR(CAM_ISP, + "Invalid blob size: %u, num_paths: %u, bw_config size: %lu, per_path_vote size: %lu", + blob_size, bw_config->num_paths, + sizeof(struct cam_isp_tfe_bw_config_v2), + sizeof(struct cam_axi_per_path_bw_vote)); + return -EINVAL; + } + + if (!prepare || !prepare->priv || + (bw_config->usage_type >= CAM_TFE_HW_NUM_MAX)) { + CAM_ERR(CAM_ISP, "Invalid inputs"); + return -EINVAL; + } + + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + + memset(&prepare_hw_data->bw_config_v2[bw_config->usage_type], + 0, sizeof( + prepare_hw_data->bw_config_v2[bw_config->usage_type])); + bw_config_size = sizeof(struct cam_isp_bw_config_internal_v2) + + ((bw_config->num_paths - 1) * + sizeof(struct cam_axi_per_path_bw_vote)); + memcpy(&prepare_hw_data->bw_config_v2[bw_config->usage_type], + bw_config, bw_config_size); + + prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V2; + prepare_hw_data->bw_config_valid[bw_config->usage_type] = true; + } + + break; + case CAM_ISP_TFE_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG: { + struct cam_isp_tfe_csid_clock_config *clock_config = + (struct cam_isp_tfe_csid_clock_config *)blob_data; + + if (blob_size < sizeof(struct cam_isp_tfe_csid_clock_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %u", + blob_size, + sizeof(struct cam_isp_tfe_csid_clock_config)); + return -EINVAL; + } + rc = cam_isp_tfe_blob_csid_clock_update(blob_type, blob_info, + clock_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update Failed"); + } + break; + default: + CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); + break; + } + + return rc; +} + +static int cam_tfe_update_dual_config( + struct cam_hw_prepare_update_args *prepare, + struct cam_cmd_buf_desc *cmd_desc, + uint32_t split_id, + uint32_t base_idx, + struct cam_isp_hw_mgr_res *res_list_isp_out, + uint32_t size_isp_out) +{ + int rc = -EINVAL; + struct cam_isp_tfe_dual_config *dual_config; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *res; + struct cam_tfe_dual_update_args dual_isp_update_args; + uint32_t outport_id; + size_t len = 0, remain_len = 0; + uint32_t *cpu_addr; + uint32_t i, j, stp_index; + + CAM_DBG(CAM_ISP, "cmd des size %d, length: %d", + cmd_desc->size, cmd_desc->length); + + rc = cam_packet_util_get_cmd_mem_addr( + cmd_desc->mem_handle, &cpu_addr, &len); + if (rc) { + CAM_DBG(CAM_ISP, "unable to get cmd mem addr handle:0x%x", + cmd_desc->mem_handle); + return rc; + } + + if ((len < sizeof(struct cam_isp_tfe_dual_config)) || + (cmd_desc->offset >= + (len - sizeof(struct cam_isp_tfe_dual_config)))) { + CAM_ERR(CAM_ISP, "not enough buffer provided"); + return -EINVAL; + } + + remain_len = len - cmd_desc->offset; + cpu_addr += (cmd_desc->offset / 4); + dual_config = (struct cam_isp_tfe_dual_config *)cpu_addr; + + if ((dual_config->num_ports * + sizeof(struct cam_isp_tfe_dual_stripe_config)) > + (remain_len - + offsetof(struct cam_isp_tfe_dual_config, stripes))) { + CAM_ERR(CAM_ISP, "not enough buffer for all the dual configs"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "num_ports:%d", dual_config->num_ports); + if (dual_config->num_ports >= size_isp_out) { + CAM_ERR(CAM_UTIL, + "inval num ports %d max num tfe ports:%d", + dual_config->num_ports, size_isp_out); + rc = -EINVAL; + goto end; + } + + for (i = 0; i < dual_config->num_ports; i++) { + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + stp_index = (i * CAM_PACKET_MAX_PLANES) + + (j * (CAM_PACKET_MAX_PLANES * + dual_config->num_ports)); + + if (!dual_config->stripes[stp_index].port_id) + continue; + + outport_id = dual_config->stripes[stp_index].port_id; + if (outport_id >= size_isp_out) { + CAM_ERR(CAM_UTIL, + "inval outport id:%d i:%d j:%d num ports:%d ", + outport_id, i, j, + dual_config->num_ports); + rc = -EINVAL; + goto end; + } + + hw_mgr_res = &res_list_isp_out[outport_id]; + if (!hw_mgr_res->hw_res[j]) + continue; + + if (hw_mgr_res->hw_res[j]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[j]; + + if (res->res_id < CAM_ISP_TFE_OUT_RES_BASE || + res->res_id >= CAM_ISP_TFE_OUT_RES_MAX) { + CAM_DBG(CAM_ISP, "res id :%d", res->res_id); + continue; + } + + dual_isp_update_args.split_id = j; + dual_isp_update_args.res = res; + dual_isp_update_args.stripe_config = + &dual_config->stripes[stp_index]; + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_STRIPE_UPDATE, + &dual_isp_update_args, + sizeof(struct cam_tfe_dual_update_args)); + if (rc) + goto end; + } + } + +end: + return rc; +} + +int cam_tfe_add_command_buffers( + struct cam_hw_prepare_update_args *prepare, + struct cam_kmd_buf_info *kmd_buf_info, + struct cam_isp_ctx_base_info *base_info, + cam_packet_generic_blob_handler blob_handler_cb, + struct cam_isp_hw_mgr_res *res_list_isp_out, + uint32_t size_isp_out) +{ + int rc = 0; + uint32_t cmd_meta_data, num_ent, i; + uint32_t base_idx; + enum cam_isp_hw_split_id split_id; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_hw_update_entry *hw_entry; + + hw_entry = prepare->hw_update_entries; + split_id = base_info->split_id; + base_idx = base_info->idx; + + /* + * set the cmd_desc to point the first command descriptor in the + * packet + */ + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint8_t *)&prepare->packet->payload + + prepare->packet->cmd_buf_offset); + + CAM_DBG(CAM_ISP, "split id = %d, number of command buffers:%d", + split_id, prepare->packet->num_cmd_buf); + + for (i = 0; i < prepare->packet->num_cmd_buf; i++) { + num_ent = prepare->num_hw_update_entries; + if (!cmd_desc[i].length) + continue; + + /* One hw entry space required for left or right or common */ + if (num_ent + 1 >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); + if (rc) + return rc; + + cmd_meta_data = cmd_desc[i].meta_data; + + CAM_DBG(CAM_ISP, "meta type: %d, split_id: %d", + cmd_meta_data, split_id); + + switch (cmd_meta_data) { + case CAM_ISP_TFE_PACKET_META_BASE: + case CAM_ISP_TFE_PACKET_META_LEFT: + if (split_id == CAM_ISP_HW_SPLIT_LEFT) { + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].handle = + cmd_desc[i].mem_handle; + hw_entry[num_ent].offset = cmd_desc[i].offset; + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; + CAM_DBG(CAM_ISP, + "Meta_Left num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + + num_ent++; + } + break; + case CAM_ISP_TFE_PACKET_META_RIGHT: + if (split_id == CAM_ISP_HW_SPLIT_RIGHT) { + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].handle = + cmd_desc[i].mem_handle; + hw_entry[num_ent].offset = cmd_desc[i].offset; + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; + CAM_DBG(CAM_ISP, + "Meta_Right num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + + num_ent++; + } + break; + case CAM_ISP_TFE_PACKET_META_COMMON: + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].handle = + cmd_desc[i].mem_handle; + hw_entry[num_ent].offset = cmd_desc[i].offset; + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; + CAM_DBG(CAM_ISP, + "Meta_Common num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_COMMON) + hw_entry[num_ent].flags = 0x1; + + num_ent++; + break; + case CAM_ISP_TFE_PACKET_META_DUAL_CONFIG: + + rc = cam_tfe_update_dual_config(prepare, + &cmd_desc[i], split_id, base_idx, + res_list_isp_out, size_isp_out); + + if (rc) + return rc; + break; + case CAM_ISP_TFE_PACKET_META_GENERIC_BLOB_COMMON: { + struct cam_isp_generic_blob_info blob_info; + + prepare->num_hw_update_entries = num_ent; + blob_info.prepare = prepare; + blob_info.base_info = base_info; + blob_info.kmd_buf_info = kmd_buf_info; + + rc = cam_packet_util_process_generic_cmd_buffer( + &cmd_desc[i], + blob_handler_cb, + &blob_info); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in processing blobs %d", rc); + return rc; + } + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; + num_ent = prepare->num_hw_update_entries; + } + break; + case CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_FLUSH: + case CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_ERROR: + if (split_id == CAM_ISP_HW_SPLIT_LEFT) { + if (prepare->num_reg_dump_buf >= + CAM_REG_DUMP_MAX_BUF_ENTRIES) { + CAM_ERR(CAM_ISP, + "Descriptor count out of bounds: %d", + prepare->num_reg_dump_buf); + return -EINVAL; + } + prepare->reg_dump_buf_desc[ + prepare->num_reg_dump_buf] = + cmd_desc[i]; + prepare->num_reg_dump_buf++; + CAM_DBG(CAM_ISP, + "Added command buffer: %d desc_count: %d", + cmd_desc[i].meta_data, + prepare->num_reg_dump_buf); + } + break; + default: + CAM_ERR(CAM_ISP, "invalid cdm command meta data %d", + cmd_meta_data); + return -EINVAL; + } + prepare->num_hw_update_entries = num_ent; + } + + return rc; +} + +static int cam_tfe_mgr_prepare_hw_update(void *hw_mgr_priv, + void *prepare_hw_update_args) +{ + int rc = 0; + struct cam_hw_prepare_update_args *prepare = + (struct cam_hw_prepare_update_args *) prepare_hw_update_args; + struct cam_tfe_hw_mgr_ctx *ctx; + struct cam_tfe_hw_mgr *hw_mgr; + struct cam_kmd_buf_info kmd_buf; + uint32_t i; + bool fill_fence = true; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + if (!hw_mgr_priv || !prepare_hw_update_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + CAM_DBG(CAM_REQ, "Enter for req_id %lld", + prepare->packet->header.request_id); + + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + + ctx = (struct cam_tfe_hw_mgr_ctx *) prepare->ctxt_to_hw_map; + hw_mgr = (struct cam_tfe_hw_mgr *)hw_mgr_priv; + + rc = cam_packet_util_validate_packet(prepare->packet, + prepare->remain_len); + if (rc) + return rc; + + /* Pre parse the packet*/ + rc = cam_packet_util_get_kmd_buffer(prepare->packet, &kmd_buf); + if (rc) + return rc; + + rc = cam_packet_util_process_patches(prepare->packet, + hw_mgr->mgr_common.cmd_iommu_hdl, + hw_mgr->mgr_common.cmd_iommu_hdl_secure); + if (rc) { + CAM_ERR(CAM_ISP, "Patch ISP packet failed."); + return rc; + } + + prepare->num_hw_update_entries = 0; + prepare->num_in_map_entries = 0; + prepare->num_out_map_entries = 0; + prepare->num_reg_dump_buf = 0; + + memset(&prepare_hw_data->bw_config[0], 0x0, + sizeof(prepare_hw_data->bw_config[0]) * + CAM_TFE_HW_NUM_MAX); + memset(&prepare_hw_data->bw_config_valid[0], 0x0, + sizeof(prepare_hw_data->bw_config_valid[0]) * + CAM_TFE_HW_NUM_MAX); + + for (i = 0; i < ctx->num_base; i++) { + CAM_DBG(CAM_ISP, "process cmd buffer for device %d", i); + + CAM_DBG(CAM_ISP, + "change base i=%d, idx=%d", + i, ctx->base[i].idx); + + /* Add change base */ + rc = cam_isp_add_change_base(prepare, &ctx->res_list_tfe_in, + ctx->base[i].idx, &kmd_buf); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in change base i=%d, idx=%d, rc=%d", + i, ctx->base[i].idx, rc); + goto end; + } + + + /* get command buffers */ + if (ctx->base[i].split_id != CAM_ISP_HW_SPLIT_MAX) { + rc = cam_tfe_add_command_buffers(prepare, &kmd_buf, + &ctx->base[i], + cam_isp_tfe_packet_generic_blob_handler, + ctx->res_list_tfe_out, CAM_TFE_HW_OUT_RES_MAX); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in add cmdbuf, i=%d, split_id=%d, rc=%d", + i, ctx->base[i].split_id, rc); + goto end; + } + } + + /* get IO buffers */ + rc = cam_isp_add_io_buffers(hw_mgr->mgr_common.img_iommu_hdl, + hw_mgr->mgr_common.img_iommu_hdl_secure, + prepare, ctx->base[i].idx, + &kmd_buf, ctx->res_list_tfe_out, + NULL, + CAM_TFE_HW_OUT_RES_MAX, fill_fence); + + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in io buffers, i=%d, rc=%d", + i, rc); + goto end; + } + + /* fence map table entries need to fill only once in the loop */ + if (fill_fence) + 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); + } + + /* 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; + goto end; + } else + prepare_hw_data->packet_opcode_type = + CAM_ISP_TFE_PACKET_CONFIG_DEV; + + /* add reg update commands */ + for (i = 0; i < ctx->num_base; i++) { + /* Add change base */ + rc = cam_isp_add_change_base(prepare, &ctx->res_list_tfe_in, + ctx->base[i].idx, &kmd_buf); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in change base adding reg_update cmd i=%d, idx=%d, rc=%d", + i, ctx->base[i].idx, rc); + goto end; + } + + /*Add reg update */ + rc = cam_isp_add_reg_update(prepare, &ctx->res_list_tfe_in, + ctx->base[i].idx, &kmd_buf); + if (rc) { + CAM_ERR(CAM_ISP, + "Add Reg_update cmd Failed i=%d, idx=%d, rc=%d", + i, ctx->base[i].idx, rc); + goto end; + } + } + +end: + return rc; +} + +static int cam_tfe_mgr_resume_hw(struct cam_tfe_hw_mgr_ctx *ctx) +{ + return cam_tfe_mgr_bw_control(ctx, CAM_TFE_BW_CONTROL_INCLUDE); +} + +static int cam_tfe_mgr_sof_irq_debug( + struct cam_tfe_hw_mgr_ctx *ctx, + uint32_t sof_irq_enable) +{ + int rc = 0; + uint32_t i = 0; + struct cam_isp_hw_mgr_res *hw_mgr_res = NULL; + struct cam_hw_intf *hw_intf = NULL; + struct cam_isp_resource_node *rsrc_node = NULL; + + 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]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + rc |= hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_TFE_CSID_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + 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]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->process_cmd && (rsrc_node->res_id == + CAM_ISP_HW_TFE_IN_CAMIF)) { + rc |= hw_mgr_res->hw_res[i]->process_cmd( + hw_mgr_res->hw_res[i], + CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + return rc; +} + +static void cam_tfe_mgr_print_io_bufs(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, + bool *mem_found) +{ + dma_addr_t iova_addr; + size_t src_buf_size; + int i, j; + int rc = 0; + int32_t mmu_hdl; + + struct cam_buf_io_cfg *io_cfg = NULL; + + if (mem_found) + *mem_found = false; + + io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + + for (i = 0; i < packet->num_io_configs; i++) { + for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { + if (!io_cfg[i].mem_handle[j]) + break; + + if (pf_buf_info && + GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + GET_FD_FROM_HANDLE(pf_buf_info)) { + CAM_INFO(CAM_ISP, + "Found PF at port: 0x%x mem 0x%x fd: 0x%x", + io_cfg[i].resource_type, + io_cfg[i].mem_handle[j], + pf_buf_info); + if (mem_found) + *mem_found = true; + } + + CAM_INFO(CAM_ISP, "port: 0x%x f: %u format: %d dir %d", + io_cfg[i].resource_type, + io_cfg[i].fence, + io_cfg[i].format, + io_cfg[i].direction); + + mmu_hdl = cam_mem_is_secure_buf( + io_cfg[i].mem_handle[j]) ? sec_mmu_hdl : + iommu_hdl; + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j], + mmu_hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "get src buf address fail mem_handle 0x%x", + io_cfg[i].mem_handle[j]); + continue; + } + if (iova_addr >> 32) { + CAM_ERR(CAM_ISP, "Invalid mapped address"); + rc = -EINVAL; + continue; + } + + CAM_INFO(CAM_ISP, + "pln %d w %d h %d s %u size 0x%x addr 0x%x end_addr 0x%x offset %x memh %x", + j, io_cfg[i].planes[j].width, + io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + (unsigned int)src_buf_size, + (unsigned int)iova_addr, + (unsigned int)iova_addr + + (unsigned int)src_buf_size, + io_cfg[i].offsets[j], + io_cfg[i].mem_handle[j]); + } + } +} + +static void cam_tfe_mgr_ctx_irq_dump(struct cam_tfe_hw_mgr_ctx *ctx) +{ + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_isp_hw_get_cmd_update cmd_update; + int i = 0; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { + if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT) + continue; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + switch (hw_mgr_res->hw_res[i]->res_id) { + case CAM_ISP_HW_TFE_IN_CAMIF: + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + cmd_update.res = hw_mgr_res->hw_res[i]; + cmd_update.cmd_type = + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP; + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, + &cmd_update, sizeof(cmd_update)); + break; + default: + break; + } + } + } +} + +static int cam_tfe_mgr_cmd(void *hw_mgr_priv, void *cmd_args) +{ + int rc = 0; + struct cam_hw_cmd_args *hw_cmd_args = cmd_args; + struct cam_tfe_hw_mgr *hw_mgr = hw_mgr_priv; + 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; + + if (!hw_mgr_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Fatal: Invalid context is used"); + return -EPERM; + } + + switch (hw_cmd_args->cmd_type) { + case CAM_HW_MGR_CMD_INTERNAL: + if (!hw_cmd_args->u.internal_args) { + CAM_ERR(CAM_ISP, "Invalid cmd arguments"); + return -EINVAL; + } + + isp_hw_cmd_args = (struct cam_isp_hw_cmd_args *) + hw_cmd_args->u.internal_args; + + switch (isp_hw_cmd_args->cmd_type) { + case CAM_ISP_HW_MGR_CMD_PAUSE_HW: + cam_tfe_mgr_pause_hw(ctx); + break; + case CAM_ISP_HW_MGR_CMD_RESUME_HW: + cam_tfe_mgr_resume_hw(ctx); + break; + case CAM_ISP_HW_MGR_CMD_SOF_DEBUG: + cam_tfe_mgr_sof_irq_debug(ctx, + isp_hw_cmd_args->u.sof_irq_enable); + break; + case CAM_ISP_HW_MGR_CMD_CTX_TYPE: + if (ctx->is_rdi_only_context) + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_RDI; + else + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_PIX; + break; + default: + CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", + hw_cmd_args->cmd_type); + rc = -EINVAL; + break; + } + break; + case CAM_HW_MGR_CMD_DUMP_PF_INFO: + cam_tfe_mgr_print_io_bufs( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr->mgr_common.img_iommu_hdl, + hw_mgr->mgr_common.img_iommu_hdl_secure, + hw_cmd_args->u.pf_args.buf_info, + hw_cmd_args->u.pf_args.mem_found); + break; + case CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH: + if (ctx->last_dump_flush_req_id == ctx->applied_req_id) + return 0; + + ctx->last_dump_flush_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_FLUSH); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump on flush failed req id: %llu rc: %d", + ctx->applied_req_id, rc); + return rc; + } + + break; + case CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR: + if (ctx->last_dump_err_req_id == ctx->applied_req_id) + return 0; + + 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); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump on error failed req id: %llu rc: %d", + ctx->applied_req_id, rc); + return rc; + } + break; + + default: + CAM_ERR(CAM_ISP, "Invalid cmd"); + } + + return rc; +} + +static int cam_tfe_mgr_cmd_get_sof_timestamp( + struct cam_tfe_hw_mgr_ctx *tfe_ctx, + uint64_t *time_stamp, + uint64_t *boot_time_stamp) +{ + int rc = -EINVAL; + uint32_t i; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_tfe_csid_get_time_stamp_args csid_get_time; + + 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; + + /* + * Get the SOF time stamp from left resource only. + * Left resource is master for dual tfe case and + * Rdi only context case left resource only hold + * the RDI resource + */ + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + /* + * Single TFE case, Get the time stamp from + * available one csid hw in the context + * Dual TFE case, get the time stamp from + * master(left) would be sufficient + */ + + csid_get_time.node_res = + hw_mgr_res->hw_res[i]; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_TFE_CSID_CMD_GET_TIME_STAMP, + &csid_get_time, + sizeof(struct + cam_tfe_csid_get_time_stamp_args)); + if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { + *time_stamp = + csid_get_time.time_stamp_val; + *boot_time_stamp = + csid_get_time.boot_timestamp; + } + } + } + } + + if (rc) + CAM_ERR_RATE_LIMIT(CAM_ISP, "Getting sof time stamp failed"); + + return rc; +} + +static void cam_tfe_mgr_ctx_reg_dump(struct cam_tfe_hw_mgr_ctx *ctx) +{ + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_isp_hw_get_cmd_update cmd_update; + int i = 0; + + + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, + list) { + if (hw_mgr_res->res_type == CAM_ISP_RESOURCE_UNINT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + switch (hw_mgr_res->hw_res[i]->res_id) { + case CAM_ISP_HW_TFE_IN_CAMIF: + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + cmd_update.res = hw_mgr_res->hw_res[i]; + cmd_update.cmd_type = + CAM_ISP_HW_CMD_GET_REG_DUMP; + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_REG_DUMP, + &cmd_update, sizeof(cmd_update)); + break; + default: + break; + } + } + } + + /* Dump the TFE CSID registers */ + 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]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_TFE_CSID_CMD_GET_REG_DUMP, + hw_mgr_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + } + } + } +} + +static int cam_tfe_mgr_process_recovery_cb(void *priv, void *data) +{ + int32_t rc = 0; + struct cam_tfe_hw_event_recovery_data *recovery_data = data; + struct cam_hw_start_args start_args; + struct cam_hw_stop_args stop_args; + struct cam_tfe_hw_mgr *tfe_hw_mgr = priv; + struct cam_isp_hw_mgr_res *hw_mgr_res; + struct cam_tfe_hw_mgr_ctx *tfe_hw_mgr_ctx; + uint32_t i = 0; + + uint32_t error_type = recovery_data->error_type; + struct cam_tfe_hw_mgr_ctx *ctx = NULL; + + /* Here recovery is performed */ + CAM_DBG(CAM_ISP, "ErrorType = %d", error_type); + + switch (error_type) { + case CAM_ISP_HW_ERROR_OVERFLOW: + case CAM_ISP_HW_ERROR_BUSIF_OVERFLOW: + if (!recovery_data->affected_ctx[0]) { + CAM_ERR(CAM_ISP, + "No context is affected but recovery called"); + kfree(recovery_data); + return 0; + } + + /* stop resources here */ + CAM_DBG(CAM_ISP, "STOP: Number of affected context: %d", + recovery_data->no_of_context); + for (i = 0; i < recovery_data->no_of_context; i++) { + stop_args.ctxt_to_hw_map = + recovery_data->affected_ctx[i]; + tfe_hw_mgr_ctx = recovery_data->affected_ctx[i]; + + if (g_tfe_hw_mgr.debug_cfg.enable_reg_dump) + cam_tfe_mgr_ctx_reg_dump(tfe_hw_mgr_ctx); + + if (g_tfe_hw_mgr.debug_cfg.enable_recovery) { + rc = cam_tfe_mgr_stop_hw_in_overflow( + &stop_args); + if (rc) { + CAM_ERR(CAM_ISP, + "CTX stop failed(%d)", rc); + return rc; + } + } + } + + if (!g_tfe_hw_mgr.debug_cfg.enable_recovery) { + CAM_INFO(CAM_ISP, "reg dumping is done "); + return 0; + } + + CAM_DBG(CAM_ISP, "RESET: CSID PATH"); + for (i = 0; i < recovery_data->no_of_context; i++) { + ctx = recovery_data->affected_ctx[i]; + list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, + list) { + rc = cam_tfe_hw_mgr_reset_csid_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Failed RESET (%d)", + hw_mgr_res->res_id); + return rc; + } + } + } + + CAM_DBG(CAM_ISP, "RESET: Calling TFE reset"); + + for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) { + if (recovery_data->affected_core[i]) + cam_tfe_mgr_reset_tfe_hw(tfe_hw_mgr, i); + } + + CAM_DBG(CAM_ISP, "START: Number of affected context: %d", + recovery_data->no_of_context); + + for (i = 0; i < recovery_data->no_of_context; i++) { + ctx = recovery_data->affected_ctx[i]; + start_args.ctxt_to_hw_map = ctx; + + atomic_set(&ctx->overflow_pending, 0); + + rc = cam_tfe_mgr_restart_hw(&start_args); + if (rc) { + CAM_ERR(CAM_ISP, "CTX start failed(%d)", rc); + return rc; + } + CAM_DBG(CAM_ISP, "Started resources rc (%d)", rc); + } + CAM_DBG(CAM_ISP, "Recovery Done rc (%d)", rc); + + break; + + case CAM_ISP_HW_ERROR_P2I_ERROR: + break; + + case CAM_ISP_HW_ERROR_VIOLATION: + break; + + default: + CAM_ERR(CAM_ISP, "Invalid Error"); + } + CAM_DBG(CAM_ISP, "Exit: ErrorType = %d", error_type); + + kfree(recovery_data); + return rc; +} + +static int cam_tfe_hw_mgr_do_error_recovery( + struct cam_tfe_hw_event_recovery_data *tfe_mgr_recovery_data) +{ + int32_t rc = 0; + struct crm_workq_task *task = NULL; + struct cam_tfe_hw_event_recovery_data *recovery_data = NULL; + + recovery_data = kmemdup(tfe_mgr_recovery_data, + sizeof(struct cam_tfe_hw_event_recovery_data), GFP_ATOMIC); + + if (!recovery_data) + return -ENOMEM; + + CAM_DBG(CAM_ISP, "Enter: error_type (%d)", recovery_data->error_type); + + task = cam_req_mgr_workq_get_task(g_tfe_hw_mgr.workq); + if (!task) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No empty task frame"); + kfree(recovery_data); + return -ENOMEM; + } + + task->process_cb = &cam_tfe_mgr_process_recovery_cb; + task->payload = recovery_data; + rc = cam_req_mgr_workq_enqueue_task(task, + recovery_data->affected_ctx[0]->hw_mgr, + CRM_TASK_PRIORITY_0); + + return rc; +} + +/* + * This function checks if any of the valid entry in affected_core[] + * is associated with this context. if YES + * a. It fills the other cores associated with this context.in + * affected_core[] + * b. Return true + */ +static bool cam_tfe_hw_mgr_is_ctx_affected( + struct cam_tfe_hw_mgr_ctx *tfe_hwr_mgr_ctx, + uint32_t *affected_core, + uint32_t size) +{ + + bool rc = false; + uint32_t i = 0, j = 0; + uint32_t max_idx = tfe_hwr_mgr_ctx->num_base; + uint32_t ctx_affected_core_idx[CAM_TFE_HW_NUM_MAX] = {0}; + + CAM_DBG(CAM_ISP, "Enter:max_idx = %d", max_idx); + + if ((max_idx >= CAM_TFE_HW_NUM_MAX) || (size > CAM_TFE_HW_NUM_MAX)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "invalid parameter = %d", max_idx); + return rc; + } + + for (i = 0; i < max_idx; i++) { + if (affected_core[tfe_hwr_mgr_ctx->base[i].idx]) + rc = true; + else { + ctx_affected_core_idx[j] = tfe_hwr_mgr_ctx->base[i].idx; + j = j + 1; + } + } + + if (rc) { + while (j) { + if (affected_core[ctx_affected_core_idx[j-1]] != 1) + affected_core[ctx_affected_core_idx[j-1]] = 1; + j = j - 1; + } + } + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +/* + * For any dual TFE context, if non-affected TFE is also serving + * another context, then that context should also be notified with fatal error + * So Loop through each context and - + * a. match core_idx + * b. Notify CTX with fatal error + */ +static int cam_tfe_hw_mgr_find_affected_ctx( + struct cam_isp_hw_error_event_data *error_event_data, + uint32_t curr_core_idx, + struct cam_tfe_hw_event_recovery_data *recovery_data) +{ + uint32_t affected_core[CAM_TFE_HW_NUM_MAX] = {0}; + struct cam_tfe_hw_mgr_ctx *tfe_hwr_mgr_ctx = NULL; + cam_hw_event_cb_func notify_err_cb; + struct cam_tfe_hw_mgr *tfe_hwr_mgr = NULL; + enum cam_isp_hw_event_type event_type = CAM_ISP_HW_EVENT_ERROR; + uint32_t i = 0; + + if (!recovery_data) { + CAM_ERR(CAM_ISP, "recovery_data parameter is NULL"); + return -EINVAL; + } + + recovery_data->no_of_context = 0; + affected_core[curr_core_idx] = 1; + tfe_hwr_mgr = &g_tfe_hw_mgr; + + list_for_each_entry(tfe_hwr_mgr_ctx, + &tfe_hwr_mgr->used_ctx_list, list) { + /* + * Check if current core_idx matches the HW associated + * with this context + */ + if (!cam_tfe_hw_mgr_is_ctx_affected(tfe_hwr_mgr_ctx, + affected_core, CAM_TFE_HW_NUM_MAX)) + continue; + + atomic_set(&tfe_hwr_mgr_ctx->overflow_pending, 1); + notify_err_cb = tfe_hwr_mgr_ctx->common.event_cb[event_type]; + + /* Add affected_context in list of recovery data */ + CAM_DBG(CAM_ISP, "Add affected ctx %d to list", + tfe_hwr_mgr_ctx->ctx_index); + if (recovery_data->no_of_context < CAM_CTX_MAX) + recovery_data->affected_ctx[ + recovery_data->no_of_context++] = + tfe_hwr_mgr_ctx; + + /* + * In the call back function corresponding ISP context + * will update CRM about fatal Error + */ + notify_err_cb(tfe_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_ERROR, error_event_data); + } + + /* fill the affected_core in recovery data */ + for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) { + recovery_data->affected_core[i] = affected_core[i]; + CAM_DBG(CAM_ISP, "tfe core %d is affected (%d)", + i, recovery_data->affected_core[i]); + } + + return 0; +} + +static int cam_tfe_hw_mgr_handle_hw_err( + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_tfe_hw_event_recovery_data recovery_data = {0}; + int rc = -EINVAL; + uint32_t core_idx; + + if (event_info->err_type == CAM_TFE_IRQ_STATUS_VIOLATION) + error_event_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; + else if (event_info->res_type == CAM_ISP_RESOURCE_TFE_IN || + event_info->res_type == CAM_ISP_RESOURCE_PIX_PATH) + error_event_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; + else if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT) + error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + + core_idx = event_info->hw_idx; + + if (g_tfe_hw_mgr.debug_cfg.enable_recovery) + error_event_data.recovery_enabled = true; + else + error_event_data.recovery_enabled = false; + + rc = cam_tfe_hw_mgr_find_affected_ctx(&error_event_data, + core_idx, &recovery_data); + + if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT) + return rc; + + if (g_tfe_hw_mgr.debug_cfg.enable_recovery) { + /* Trigger for recovery */ + if (event_info->err_type == CAM_TFE_IRQ_STATUS_VIOLATION) + recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; + else + recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; + cam_tfe_hw_mgr_do_error_recovery(&recovery_data); + } else { + CAM_DBG(CAM_ISP, "recovery is not enabled"); + rc = 0; + } + + return rc; +} + +static int cam_tfe_hw_mgr_handle_hw_rup( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_tfe_hw_mgr_ctx *tfe_hw_mgr_ctx = ctx; + cam_hw_event_cb_func tfe_hwr_irq_rup_cb; + struct cam_isp_hw_reg_update_event_data rup_event_data; + + tfe_hwr_irq_rup_cb = + tfe_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_REG_UPDATE]; + + switch (event_info->res_id) { + case CAM_ISP_HW_TFE_IN_CAMIF: + if (tfe_hw_mgr_ctx->is_dual) + if (event_info->hw_idx != tfe_hw_mgr_ctx->master_hw_idx) + break; + + if (atomic_read(&tfe_hw_mgr_ctx->overflow_pending)) + break; + + tfe_hwr_irq_rup_cb(tfe_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_REG_UPDATE, &rup_event_data); + break; + + case CAM_ISP_HW_TFE_IN_RDI0: + case CAM_ISP_HW_TFE_IN_RDI1: + case CAM_ISP_HW_TFE_IN_RDI2: + if (!tfe_hw_mgr_ctx->is_rdi_only_context) + break; + if (atomic_read(&tfe_hw_mgr_ctx->overflow_pending)) + break; + tfe_hwr_irq_rup_cb(tfe_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_REG_UPDATE, &rup_event_data); + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "RUP done for TFE source %d", + event_info->res_id); + + return 0; +} + +static int cam_tfe_hw_mgr_check_irq_for_dual_tfe( + struct cam_tfe_hw_mgr_ctx *tfe_hw_mgr_ctx, + uint32_t hw_event_type) +{ + int32_t rc = -EINVAL; + uint32_t *event_cnt = NULL; + uint32_t core_idx0 = 0; + uint32_t core_idx1 = 1; + + if (!tfe_hw_mgr_ctx->is_dual) + return 0; + + switch (hw_event_type) { + case CAM_ISP_HW_EVENT_SOF: + event_cnt = tfe_hw_mgr_ctx->sof_cnt; + break; + case CAM_ISP_HW_EVENT_EPOCH: + event_cnt = tfe_hw_mgr_ctx->epoch_cnt; + break; + case CAM_ISP_HW_EVENT_EOF: + event_cnt = tfe_hw_mgr_ctx->eof_cnt; + break; + default: + return 0; + } + + if (event_cnt[core_idx0] == event_cnt[core_idx1]) { + + event_cnt[core_idx0] = 0; + event_cnt[core_idx1] = 0; + + rc = 0; + return rc; + } + + 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 (tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt > 10) { + rc = -1; + return rc; + } + + 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]--; + tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt++; + } + if (event_cnt[core_idx1] >= 2) { + event_cnt[core_idx1]--; + tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt++; + } + + if (tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt == 1) + cam_tfe_mgr_ctx_irq_dump(tfe_hw_mgr_ctx); + rc = 0; + } + + CAM_DBG(CAM_ISP, "Only one core_index has given hw event %d", + hw_event_type); + + return rc; +} + +static int cam_tfe_hw_mgr_handle_hw_epoch( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_tfe_hw_mgr_ctx *tfe_hw_mgr_ctx = ctx; + cam_hw_event_cb_func tfe_hw_irq_epoch_cb; + struct cam_isp_hw_epoch_event_data epoch_done_event_data; + int rc = 0; + + tfe_hw_irq_epoch_cb = + tfe_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EPOCH]; + + switch (event_info->res_id) { + case CAM_ISP_HW_TFE_IN_CAMIF: + tfe_hw_mgr_ctx->epoch_cnt[event_info->hw_idx]++; + rc = cam_tfe_hw_mgr_check_irq_for_dual_tfe(tfe_hw_mgr_ctx, + CAM_ISP_HW_EVENT_EPOCH); + if (!rc) { + if (atomic_read(&tfe_hw_mgr_ctx->overflow_pending)) + break; + tfe_hw_irq_epoch_cb(tfe_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EPOCH, &epoch_done_event_data); + } + break; + + case CAM_ISP_HW_TFE_IN_RDI0: + case CAM_ISP_HW_TFE_IN_RDI1: + case CAM_ISP_HW_TFE_IN_RDI2: + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "Epoch for TFE source %d", event_info->res_id); + + return 0; +} + +static int cam_tfe_hw_mgr_handle_hw_sof( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_tfe_hw_mgr_ctx *tfe_hw_mgr_ctx = ctx; + cam_hw_event_cb_func tfe_hw_irq_sof_cb; + struct cam_isp_hw_sof_event_data sof_done_event_data; + int rc = 0; + + tfe_hw_irq_sof_cb = + tfe_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF]; + + switch (event_info->res_id) { + case CAM_ISP_HW_TFE_IN_CAMIF: + tfe_hw_mgr_ctx->sof_cnt[event_info->hw_idx]++; + rc = cam_tfe_hw_mgr_check_irq_for_dual_tfe(tfe_hw_mgr_ctx, + CAM_ISP_HW_EVENT_SOF); + if (!rc) { + cam_tfe_mgr_cmd_get_sof_timestamp(tfe_hw_mgr_ctx, + &sof_done_event_data.timestamp, + &sof_done_event_data.boot_time); + + if (atomic_read(&tfe_hw_mgr_ctx->overflow_pending)) + break; + + tfe_hw_irq_sof_cb(tfe_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); + } + break; + + case CAM_ISP_HW_TFE_IN_RDI0: + case CAM_ISP_HW_TFE_IN_RDI1: + case CAM_ISP_HW_TFE_IN_RDI2: + if (!tfe_hw_mgr_ctx->is_rdi_only_context) + break; + cam_tfe_mgr_cmd_get_sof_timestamp(tfe_hw_mgr_ctx, + &sof_done_event_data.timestamp, + &sof_done_event_data.boot_time); + if (atomic_read(&tfe_hw_mgr_ctx->overflow_pending)) + break; + tfe_hw_irq_sof_cb(tfe_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "SOF for TFE source %d", event_info->res_id); + + return 0; +} + +static int cam_tfe_hw_mgr_handle_hw_eof( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_tfe_hw_mgr_ctx *tfe_hw_mgr_ctx = ctx; + cam_hw_event_cb_func tfe_hw_irq_eof_cb; + struct cam_isp_hw_eof_event_data eof_done_event_data; + int rc = 0; + + tfe_hw_irq_eof_cb = + tfe_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EOF]; + + switch (event_info->res_id) { + case CAM_ISP_HW_TFE_IN_CAMIF: + tfe_hw_mgr_ctx->eof_cnt[event_info->hw_idx]++; + rc = cam_tfe_hw_mgr_check_irq_for_dual_tfe(tfe_hw_mgr_ctx, + CAM_ISP_HW_EVENT_EOF); + if (!rc) { + if (atomic_read(&tfe_hw_mgr_ctx->overflow_pending)) + break; + tfe_hw_irq_eof_cb(tfe_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EOF, &eof_done_event_data); + } + break; + + case CAM_ISP_HW_TFE_IN_RDI0: + case CAM_ISP_HW_TFE_IN_RDI1: + case CAM_ISP_HW_TFE_IN_RDI2: + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "EOF for out_res->res_id: 0x%x", + event_info->res_id); + + return 0; +} + +static int cam_tfe_hw_mgr_handle_hw_buf_done( + void *ctx, + void *evt_info) +{ + cam_hw_event_cb_func tfe_hwr_irq_wm_done_cb; + struct cam_tfe_hw_mgr_ctx *tfe_hw_mgr_ctx = ctx; + struct cam_isp_hw_done_event_data buf_done_event_data = {0}; + struct cam_isp_hw_event_info *event_info = evt_info; + + tfe_hwr_irq_wm_done_cb = + tfe_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_DONE]; + + buf_done_event_data.num_handles = 1; + buf_done_event_data.resource_handle[0] = event_info->res_id; + + if (atomic_read(&tfe_hw_mgr_ctx->overflow_pending)) + return 0; + + if (buf_done_event_data.num_handles > 0 && tfe_hwr_irq_wm_done_cb) { + CAM_DBG(CAM_ISP, "Notify ISP context"); + tfe_hwr_irq_wm_done_cb(tfe_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_DONE, &buf_done_event_data); + } + + CAM_DBG(CAM_ISP, "Buf done for out_res->res_id: 0x%x", + event_info->res_id); + + return 0; +} + +static int cam_tfe_hw_mgr_event_handler( + void *priv, + uint32_t evt_id, + void *evt_info) +{ + int rc = 0; + + if (!evt_info) + return -EINVAL; + + if (!priv) + if (evt_id != CAM_ISP_HW_EVENT_ERROR) + return -EINVAL; + + CAM_DBG(CAM_ISP, "Event ID 0x%x", evt_id); + + switch (evt_id) { + case CAM_ISP_HW_EVENT_SOF: + rc = cam_tfe_hw_mgr_handle_hw_sof(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_REG_UPDATE: + rc = cam_tfe_hw_mgr_handle_hw_rup(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_EPOCH: + rc = cam_tfe_hw_mgr_handle_hw_epoch(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_EOF: + rc = cam_tfe_hw_mgr_handle_hw_eof(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_DONE: + rc = cam_tfe_hw_mgr_handle_hw_buf_done(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_ERROR: + rc = cam_tfe_hw_mgr_handle_hw_err(evt_info); + break; + + default: + CAM_ERR(CAM_ISP, "Invalid event ID %d", evt_id); + break; + } + + return rc; +} + +static int cam_tfe_hw_mgr_sort_dev_with_caps( + struct cam_tfe_hw_mgr *tfe_hw_mgr) +{ + int i; + + /* get caps for csid devices */ + for (i = 0; i < CAM_TFE_CSID_HW_NUM_MAX; i++) { + if (!tfe_hw_mgr->csid_devices[i]) + continue; + if (tfe_hw_mgr->csid_devices[i]->hw_ops.get_hw_caps) { + tfe_hw_mgr->csid_devices[i]->hw_ops.get_hw_caps( + tfe_hw_mgr->csid_devices[i]->hw_priv, + &tfe_hw_mgr->tfe_csid_dev_caps[i], + sizeof(tfe_hw_mgr->tfe_csid_dev_caps[i])); + } + } + + /* get caps for tfe devices */ + for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) { + if (!tfe_hw_mgr->tfe_devices[i]) + continue; + if (tfe_hw_mgr->tfe_devices[i]->hw_ops.get_hw_caps) { + tfe_hw_mgr->tfe_devices[i]->hw_ops.get_hw_caps( + tfe_hw_mgr->tfe_devices[i]->hw_priv, + &tfe_hw_mgr->tfe_dev_caps[i], + sizeof(tfe_hw_mgr->tfe_dev_caps[i])); + } + } + + return 0; +} + +static int cam_tfe_set_csid_debug(void *data, u64 val) +{ + g_tfe_hw_mgr.debug_cfg.csid_debug = val; + CAM_DBG(CAM_ISP, "Set CSID Debug value :%lld", val); + return 0; +} + +static int cam_tfe_get_csid_debug(void *data, u64 *val) +{ + *val = g_tfe_hw_mgr.debug_cfg.csid_debug; + CAM_DBG(CAM_ISP, "Get CSID Debug value :%lld", + g_tfe_hw_mgr.debug_cfg.csid_debug); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(cam_tfe_csid_debug, + cam_tfe_get_csid_debug, + cam_tfe_set_csid_debug, "%16llu"); + +static int cam_tfe_set_camif_debug(void *data, u64 val) +{ + g_tfe_hw_mgr.debug_cfg.camif_debug = val; + CAM_DBG(CAM_ISP, + "Set camif enable_diag_sensor_status value :%lld", val); + return 0; +} + +static int cam_tfe_get_camif_debug(void *data, u64 *val) +{ + *val = g_tfe_hw_mgr.debug_cfg.camif_debug; + CAM_DBG(CAM_ISP, + "Set camif enable_diag_sensor_status value :%lld", + g_tfe_hw_mgr.debug_cfg.csid_debug); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(cam_tfe_camif_debug, + cam_tfe_get_camif_debug, + cam_tfe_set_camif_debug, "%16llu"); + +static int cam_tfe_hw_mgr_debug_register(void) +{ + g_tfe_hw_mgr.debug_cfg.dentry = debugfs_create_dir("camera_tfe", + NULL); + + if (!g_tfe_hw_mgr.debug_cfg.dentry) { + CAM_ERR(CAM_ISP, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_file("tfe_csid_debug", + 0644, + g_tfe_hw_mgr.debug_cfg.dentry, NULL, + &cam_tfe_csid_debug)) { + CAM_ERR(CAM_ISP, "failed to create cam_tfe_csid_debug"); + goto err; + } + + if (!debugfs_create_u32("enable_recovery", + 0644, + g_tfe_hw_mgr.debug_cfg.dentry, + &g_tfe_hw_mgr.debug_cfg.enable_recovery)) { + CAM_ERR(CAM_ISP, "failed to create enable_recovery"); + goto err; + } + + if (!debugfs_create_bool("enable_reg_dump", + 0644, + g_tfe_hw_mgr.debug_cfg.dentry, + &g_tfe_hw_mgr.debug_cfg.enable_reg_dump)) { + CAM_ERR(CAM_ISP, "failed to create enable_reg_dump"); + goto err; + } + + if (!debugfs_create_file("tfe_camif_debug", + 0644, + g_tfe_hw_mgr.debug_cfg.dentry, NULL, + &cam_tfe_camif_debug)) { + CAM_ERR(CAM_ISP, "failed to create cam_tfe_camif_debug"); + goto err; + } + + if (!debugfs_create_bool("per_req_reg_dump", + 0644, + g_tfe_hw_mgr.debug_cfg.dentry, + &g_tfe_hw_mgr.debug_cfg.per_req_reg_dump)) { + CAM_ERR(CAM_ISP, "failed to create per_req_reg_dump entry"); + goto err; + } + + + g_tfe_hw_mgr.debug_cfg.enable_recovery = 0; + + return 0; + +err: + debugfs_remove_recursive(g_tfe_hw_mgr.debug_cfg.dentry); + return -ENOMEM; +} + +int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) +{ + int rc = -EFAULT; + int i, j; + struct cam_iommu_handle cdm_handles; + struct cam_tfe_hw_mgr_ctx *ctx_pool; + struct cam_isp_hw_mgr_res *res_list_tfe_out; + + CAM_DBG(CAM_ISP, "Enter"); + + memset(&g_tfe_hw_mgr, 0, sizeof(g_tfe_hw_mgr)); + + mutex_init(&g_tfe_hw_mgr.ctx_mutex); + + if (CAM_TFE_HW_NUM_MAX != CAM_TFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, "CSID num is different then TFE num"); + return -EINVAL; + } + + /* fill tfe hw intf information */ + for (i = 0, j = 0; i < CAM_TFE_HW_NUM_MAX; i++) { + rc = cam_tfe_hw_init(&g_tfe_hw_mgr.tfe_devices[i], i); + if (!rc) { + struct cam_hw_info *tfe_hw = (struct cam_hw_info *) + g_tfe_hw_mgr.tfe_devices[i]->hw_priv; + struct cam_hw_soc_info *soc_info = &tfe_hw->soc_info; + + j++; + + g_tfe_hw_mgr.cdm_reg_map[i] = &soc_info->reg_map[0]; + CAM_DBG(CAM_ISP, + "reg_map: mem base = %pK cam_base = 0x%llx", + (void __iomem *)soc_info->reg_map[0].mem_base, + (uint64_t) soc_info->reg_map[0].mem_cam_base); + } else { + g_tfe_hw_mgr.cdm_reg_map[i] = NULL; + } + } + if (j == 0) { + CAM_ERR(CAM_ISP, "no valid TFE HW"); + return -EINVAL; + } + + /* fill csid hw intf information */ + for (i = 0, j = 0; i < CAM_TFE_CSID_HW_NUM_MAX; i++) { + rc = cam_tfe_csid_hw_init(&g_tfe_hw_mgr.csid_devices[i], i); + if (!rc) + j++; + } + if (!j) { + CAM_ERR(CAM_ISP, "no valid TFE CSID HW"); + return -EINVAL; + } + + /* fill tpg hw intf information */ + for (i = 0, j = 0; i < CAM_TOP_TPG_HW_NUM_MAX; i++) { + rc = cam_top_tpg_hw_init(&g_tfe_hw_mgr.tpg_devices[i], i); + if (!rc) + j++; + } + if (!j) { + CAM_ERR(CAM_ISP, "no valid TFE TPG HW"); + return -EINVAL; + } + + cam_tfe_hw_mgr_sort_dev_with_caps(&g_tfe_hw_mgr); + + /* setup tfe context list */ + INIT_LIST_HEAD(&g_tfe_hw_mgr.free_ctx_list); + INIT_LIST_HEAD(&g_tfe_hw_mgr.used_ctx_list); + + /* + * for now, we only support one iommu handle. later + * we will need to setup more iommu handle for other + * use cases. + * Also, we have to release them once we have the + * deinit support + */ + if (cam_smmu_get_handle("tfe", + &g_tfe_hw_mgr.mgr_common.img_iommu_hdl)) { + CAM_ERR(CAM_ISP, "Can not get iommu handle"); + return -EINVAL; + } + + if (cam_smmu_get_handle("cam-secure", + &g_tfe_hw_mgr.mgr_common.img_iommu_hdl_secure)) { + CAM_ERR(CAM_ISP, "Failed to get secure iommu handle"); + goto secure_fail; + } + + CAM_DBG(CAM_ISP, "iommu_handles: non-secure[0x%x], secure[0x%x]", + g_tfe_hw_mgr.mgr_common.img_iommu_hdl, + g_tfe_hw_mgr.mgr_common.img_iommu_hdl_secure); + + if (!cam_cdm_get_iommu_handle("tfe0", &cdm_handles)) { + CAM_DBG(CAM_ISP, "Successfully acquired the CDM iommu handles"); + g_tfe_hw_mgr.mgr_common.cmd_iommu_hdl = cdm_handles.non_secure; + g_tfe_hw_mgr.mgr_common.cmd_iommu_hdl_secure = + cdm_handles.secure; + } else { + CAM_DBG(CAM_ISP, "Failed to acquire the CDM iommu handles"); + g_tfe_hw_mgr.mgr_common.cmd_iommu_hdl = -1; + g_tfe_hw_mgr.mgr_common.cmd_iommu_hdl_secure = -1; + } + + atomic_set(&g_tfe_hw_mgr.active_ctx_cnt, 0); + for (i = 0; i < CAM_CTX_MAX; i++) { + memset(&g_tfe_hw_mgr.ctx_pool[i], 0, + sizeof(g_tfe_hw_mgr.ctx_pool[i])); + INIT_LIST_HEAD(&g_tfe_hw_mgr.ctx_pool[i].list); + INIT_LIST_HEAD(&g_tfe_hw_mgr.ctx_pool[i].res_list_tfe_csid); + INIT_LIST_HEAD(&g_tfe_hw_mgr.ctx_pool[i].res_list_tfe_in); + ctx_pool = &g_tfe_hw_mgr.ctx_pool[i]; + for (j = 0; j < CAM_TFE_HW_OUT_RES_MAX; j++) { + res_list_tfe_out = &ctx_pool->res_list_tfe_out[j]; + INIT_LIST_HEAD(&res_list_tfe_out->list); + } + + /* init context pool */ + INIT_LIST_HEAD(&g_tfe_hw_mgr.ctx_pool[i].free_res_list); + for (j = 0; j < CAM_TFE_HW_RES_POOL_MAX; j++) { + INIT_LIST_HEAD( + &g_tfe_hw_mgr.ctx_pool[i].res_pool[j].list); + list_add_tail( + &g_tfe_hw_mgr.ctx_pool[i].res_pool[j].list, + &g_tfe_hw_mgr.ctx_pool[i].free_res_list); + } + + g_tfe_hw_mgr.ctx_pool[i].cdm_cmd = + kzalloc(((sizeof(struct cam_cdm_bl_request)) + + ((CAM_TFE_HW_ENTRIES_MAX - 1) * + sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); + if (!g_tfe_hw_mgr.ctx_pool[i].cdm_cmd) { + rc = -ENOMEM; + CAM_ERR(CAM_ISP, "Allocation Failed for cdm command"); + goto end; + } + + g_tfe_hw_mgr.ctx_pool[i].ctx_index = i; + g_tfe_hw_mgr.ctx_pool[i].hw_mgr = &g_tfe_hw_mgr; + + cam_tasklet_init(&g_tfe_hw_mgr.mgr_common.tasklet_pool[i], + &g_tfe_hw_mgr.ctx_pool[i], i); + g_tfe_hw_mgr.ctx_pool[i].common.tasklet_info = + g_tfe_hw_mgr.mgr_common.tasklet_pool[i]; + + + init_completion(&g_tfe_hw_mgr.ctx_pool[i].config_done_complete); + list_add_tail(&g_tfe_hw_mgr.ctx_pool[i].list, + &g_tfe_hw_mgr.free_ctx_list); + } + + /* Create Worker for tfe_hw_mgr with 10 tasks */ + rc = cam_req_mgr_workq_create("cam_tfe_worker", 10, + &g_tfe_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Unable to create worker"); + goto end; + } + + /* fill return structure */ + hw_mgr_intf->hw_mgr_priv = &g_tfe_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_tfe_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_tfe_mgr_acquire; + hw_mgr_intf->hw_start = cam_tfe_mgr_start_hw; + hw_mgr_intf->hw_stop = cam_tfe_mgr_stop_hw; + hw_mgr_intf->hw_read = cam_tfe_mgr_read; + hw_mgr_intf->hw_write = cam_tfe_mgr_write; + hw_mgr_intf->hw_release = cam_tfe_mgr_release_hw; + hw_mgr_intf->hw_prepare_update = cam_tfe_mgr_prepare_hw_update; + 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; + + if (iommu_hdl) + *iommu_hdl = g_tfe_hw_mgr.mgr_common.img_iommu_hdl; + + cam_tfe_hw_mgr_debug_register(); + CAM_DBG(CAM_ISP, "Exit"); + + return 0; +end: + if (rc) { + for (i = 0; i < CAM_CTX_MAX; i++) { + cam_tasklet_deinit( + &g_tfe_hw_mgr.mgr_common.tasklet_pool[i]); + kfree(g_tfe_hw_mgr.ctx_pool[i].cdm_cmd); + g_tfe_hw_mgr.ctx_pool[i].cdm_cmd = NULL; + g_tfe_hw_mgr.ctx_pool[i].common.tasklet_info = NULL; + } + } + cam_smmu_destroy_handle( + g_tfe_hw_mgr.mgr_common.img_iommu_hdl_secure); + g_tfe_hw_mgr.mgr_common.img_iommu_hdl_secure = -1; +secure_fail: + cam_smmu_destroy_handle(g_tfe_hw_mgr.mgr_common.img_iommu_hdl); + g_tfe_hw_mgr.mgr_common.img_iommu_hdl = -1; + return rc; +} 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 new file mode 100644 index 000000000000..cd701b18d311 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_HW_MGR_H_ +#define _CAM_TFE_HW_MGR_H_ + +#include +#include +#include "cam_isp_hw_mgr.h" +#include "cam_tfe_hw_intf.h" +#include "cam_tfe_csid_hw_intf.h" +#include "cam_top_tpg_hw_intf.h" +#include "cam_tasklet_util.h" + + + +/* TFE resource constants */ +#define CAM_TFE_HW_IN_RES_MAX (CAM_ISP_TFE_IN_RES_MAX & 0xFF) +#define CAM_TFE_HW_OUT_RES_MAX (CAM_ISP_TFE_OUT_RES_MAX & 0xFF) +#define CAM_TFE_HW_RES_POOL_MAX 64 + +/** + * struct cam_tfe_hw_mgr_debug - contain the debug information + * + * @dentry: Debugfs entry + * @csid_debug: csid debug information + * @enable_recovery: enable recovery + * @camif_debug: enable sensor diagnosis status + * @enable_reg_dump: enable reg dump on error; + * @per_req_reg_dump: Enable per request reg dump + * + */ +struct cam_tfe_hw_mgr_debug { + struct dentry *dentry; + uint64_t csid_debug; + uint32_t enable_recovery; + uint32_t camif_debug; + bool enable_reg_dump; + bool per_req_reg_dump; +}; + +/** + * struct cam_tfe_hw_mgr_ctx - TFE HW manager Context object + * + * @list: used by the ctx list. + * @common: common acquired context data + * @ctx_index: acquired context id. + * @hw_mgr: tfe hw mgr which owns this context + * @ctx_in_use: flag to tell whether context is active + * @res_list_csid: csid resource list + * @res_list_tfe_in: tfe input resource list + * @res_list_tfe_out: tfe output resoruces array + * @free_res_list: free resources list for the branch node + * @res_pool: memory storage for the free resource list + * @base device base index array contain the all TFE HW + * instance associated with this context. + * @num_base number of valid base data in the base array + * @cdm_handle cdm hw acquire handle + * @cdm_ops cdm util operation pointer for building + * cdm commands + * @cdm_cmd cdm base and length request pointer + * @config_done_complete indicator for configuration complete + * @sof_cnt sof count value per core, used for dual TFE + * @epoch_cnt epoch count value per core, used for dual TFE + * @eof_cnt eof count value per core, used for dual TFE + * @overflow_pending flat to specify the overflow is pending for the + * context + * @cdm_done flag to indicate cdm has finished writing shadow + * registers + * @is_rdi_only_context flag to specify the context has only rdi resource + * @reg_dump_buf_desc: cmd buffer descriptors for reg dump + * @num_reg_dump_buf: count of descriptors in reg_dump_buf_desc + * @applied_req_id: last request id to be applied + * @last_dump_flush_req_id last req id for which reg dump on flush was called + * @last_dump_err_req_id last req id for which reg dump on error was called + * @init_done indicate whether init hw is done + * @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 + * @dual_tfe_irq_mismatch_cnt irq mismatch count value per core, used for + * dual TFE + */ +struct cam_tfe_hw_mgr_ctx { + struct list_head list; + struct cam_isp_hw_mgr_ctx common; + + uint32_t ctx_index; + struct cam_tfe_hw_mgr *hw_mgr; + uint32_t ctx_in_use; + + struct cam_isp_hw_mgr_res res_list_tpg; + struct list_head res_list_tfe_csid; + struct list_head res_list_tfe_in; + struct cam_isp_hw_mgr_res + res_list_tfe_out[CAM_TFE_HW_OUT_RES_MAX]; + + struct list_head free_res_list; + struct cam_isp_hw_mgr_res res_pool[CAM_TFE_HW_RES_POOL_MAX]; + + struct cam_isp_ctx_base_info base[CAM_TFE_HW_NUM_MAX]; + uint32_t num_base; + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; + struct cam_cdm_bl_request *cdm_cmd; + struct completion config_done_complete; + + uint32_t sof_cnt[CAM_TFE_HW_NUM_MAX]; + uint32_t epoch_cnt[CAM_TFE_HW_NUM_MAX]; + uint32_t eof_cnt[CAM_TFE_HW_NUM_MAX]; + atomic_t overflow_pending; + atomic_t cdm_done; + uint32_t is_rdi_only_context; + struct cam_cmd_buf_desc reg_dump_buf_desc[ + CAM_REG_DUMP_MAX_BUF_ENTRIES]; + uint32_t num_reg_dump_buf; + uint64_t applied_req_id; + uint64_t last_dump_flush_req_id; + uint64_t last_dump_err_req_id; + bool init_done; + bool is_dual; + bool is_tpg; + uint32_t master_hw_idx; + uint32_t dual_tfe_irq_mismatch_cnt; +}; + +/** + * struct cam_tfe_hw_mgr - TFE HW Manager + * + * @mgr_common: common data for all HW managers + * @tpg_devices: tpg devices instacnce array. This will be filled by + * HW manager during the initialization. + * @csid_devices: csid device instances array. This will be filled by + * HW manager during the initialization. + * @tfe_devices: TFE device instances array. This will be filled by + * HW layer during initialization + * @cdm_reg_map commands for register dump + * @ctx_mutex: mutex for the hw context pool + * @active_ctx_cnt active context count number + * @free_ctx_list: free hw context list + * @used_ctx_list: used hw context list + * @ctx_pool: context storage + * @tfe_csid_dev_caps csid device capability stored per core + * @tfe_dev_caps tfe device capability per core + * @work q work queue for TFE hw manager + * @debug_cfg debug configuration + */ +struct cam_tfe_hw_mgr { + struct cam_isp_hw_mgr mgr_common; + struct cam_hw_intf *tpg_devices[CAM_TOP_TPG_HW_NUM_MAX]; + struct cam_hw_intf *csid_devices[CAM_TFE_CSID_HW_NUM_MAX]; + struct cam_hw_intf *tfe_devices[CAM_TFE_HW_NUM_MAX]; + struct cam_soc_reg_map *cdm_reg_map[CAM_TFE_HW_NUM_MAX]; + struct mutex ctx_mutex; + atomic_t active_ctx_cnt; + struct list_head free_ctx_list; + struct list_head used_ctx_list; + struct cam_tfe_hw_mgr_ctx ctx_pool[CAM_CTX_MAX]; + + struct cam_tfe_csid_hw_caps tfe_csid_dev_caps[ + CAM_TFE_CSID_HW_NUM_MAX]; + struct cam_tfe_hw_get_hw_cap tfe_dev_caps[CAM_TFE_HW_NUM_MAX]; + struct cam_req_mgr_core_workq *workq; + struct cam_tfe_hw_mgr_debug debug_cfg; +}; + +/** + * struct cam_tfe_hw_event_recovery_data - Payload for the recovery procedure + * + * @error_type: Error type that causes the recovery + * @affected_core: Array of the hardware cores that are affected + * @affected_ctx: Array of the hardware contexts that are affected + * @no_of_context: Actual number of the affected context + * + */ +struct cam_tfe_hw_event_recovery_data { + uint32_t error_type; + uint32_t affected_core[CAM_TFE_HW_NUM_MAX]; + struct cam_tfe_hw_mgr_ctx *affected_ctx[CAM_CTX_MAX]; + uint32_t no_of_context; +}; + +/** + * cam_tfe_hw_mgr_init() + * + * @brief: Initialize the TFE hardware manger. This is the + * etnry functinon for the TFE HW manager. + * + * @hw_mgr_intf: TFE hardware manager object returned + * @iommu_hdl: Iommu handle to be returned + * + */ +int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl); + +#endif /* _CAM_TFE_HW_MGR_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index f83f392edc92..5cce370fd8df 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -17,6 +17,8 @@ #define CAM_IFE_RDI_NUM_MAX 4 #define CAM_ISP_BW_CONFIG_V1 1 #define CAM_ISP_BW_CONFIG_V2 2 +#define CAM_TFE_HW_NUM_MAX 3 +#define CAM_TFE_RDI_NUM_MAX 3 /* Appliacble vote paths for dual ife, based on no. of UAPI definitions */ #define CAM_ISP_MAX_PER_PATH_VOTES 30 @@ -252,12 +254,12 @@ struct cam_isp_hw_cmd_args { * * @brief: Initialization function for the ISP hardware manager * - * @of_node: Device node input + * @device_name_str: Device name string * @hw_mgr: Input/output structure for the ISP hardware manager * initialization * @iommu_hdl: Iommu handle to be returned */ -int cam_isp_hw_mgr_init(struct device_node *of_node, +int cam_isp_hw_mgr_init(const char *device_name_str, struct cam_hw_mgr_intf *hw_mgr, int *iommu_hdl); #endif /* __CAM_ISP_HW_MGR_INTF_H__ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile index 41c244c96572..20d61bede674 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_SPECTRA_CAMERA) += ife_csid_hw/ -obj-$(CONFIG_SPECTRA_CAMERA) += vfe_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += ife_csid_hw/ tfe_csid_hw/ top_tpg/ +obj-$(CONFIG_SPECTRA_CAMERA) += vfe_hw/ tfe_hw/ 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 29a414b71297..483f85bc241e 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 @@ -38,11 +38,14 @@ struct cam_isp_timestamp { void cam_isp_hw_get_timestamp(struct cam_isp_timestamp *time_stamp); enum cam_isp_hw_type { - CAM_ISP_HW_TYPE_CSID = 0, - CAM_ISP_HW_TYPE_ISPIF = 1, - CAM_ISP_HW_TYPE_VFE = 2, - CAM_ISP_HW_TYPE_IFE_CSID = 3, - CAM_ISP_HW_TYPE_MAX = 4, + CAM_ISP_HW_TYPE_CSID, + CAM_ISP_HW_TYPE_ISPIF, + CAM_ISP_HW_TYPE_VFE, + CAM_ISP_HW_TYPE_IFE_CSID, + CAM_ISP_HW_TYPE_TFE, + CAM_ISP_HW_TYPE_TFE_CSID, + CAM_ISP_HW_TYPE_TPG, + CAM_ISP_HW_TYPE_MAX, }; enum cam_isp_hw_split_id { @@ -74,6 +77,9 @@ enum cam_isp_resource_type { CAM_ISP_RESOURCE_VFE_IN, CAM_ISP_RESOURCE_VFE_OUT, CAM_ISP_RESOURCE_VFE_BUS_RD, + CAM_ISP_RESOURCE_TPG, + CAM_ISP_RESOURCE_TFE_IN, + CAM_ISP_RESOURCE_TFE_OUT, CAM_ISP_RESOURCE_MAX, }; @@ -91,6 +97,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_BW_UPDATE_V2, CAM_ISP_HW_CMD_BW_CONTROL, CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, + CAM_ISP_HW_CMD_GET_REG_DUMP, CAM_ISP_HW_CMD_UBWC_UPDATE, CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, @@ -102,6 +109,8 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, + CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h new file mode 100644 index 000000000000..75de9d3ea945 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_CSID_HW_INTF_H_ +#define _CAM_TFE_CSID_HW_INTF_H_ + +#include "cam_isp_hw.h" +#include "cam_hw_intf.h" + +/* MAX TFE CSID instance */ +#define CAM_TFE_CSID_HW_NUM_MAX 3 +#define CAM_TFE_CSID_RDI_MAX 3 + +/** + * enum cam_tfe_pix_path_res_id - Specify the csid patch + */ +enum cam_tfe_csid_path_res_id { + CAM_TFE_CSID_PATH_RES_RDI_0, + CAM_TFE_CSID_PATH_RES_RDI_1, + CAM_TFE_CSID_PATH_RES_RDI_2, + CAM_TFE_CSID_PATH_RES_IPP, + CAM_TFE_CSID_PATH_RES_MAX, +}; + +/** + * enum cam_tfe_csid_irq_reg + */ +enum cam_tfe_csid_irq_reg { + TFE_CSID_IRQ_REG_RDI0, + TFE_CSID_IRQ_REG_RDI1, + TFE_CSID_IRQ_REG_RDI2, + TFE_CSID_IRQ_REG_TOP, + TFE_CSID_IRQ_REG_RX, + TFE_CSID_IRQ_REG_IPP, + TFE_CSID_IRQ_REG_MAX, +}; + + +/** + * struct cam_tfe_csid_hw_caps- get the CSID hw capability + * @num_rdis: number of rdis supported by CSID HW device + * @num_pix: number of pxl paths supported by CSID HW device + * @major_version : major version + * @minor_version: minor version + * @version_incr: version increment + * + */ +struct cam_tfe_csid_hw_caps { + uint32_t num_rdis; + uint32_t num_pix; + uint32_t major_version; + uint32_t minor_version; + uint32_t version_incr; +}; + +/** + * struct cam_tfe_csid_hw_reserve_resource_args- hw reserve + * @res_type : Reource type ie PATH + * @res_id : Resource id to be reserved + * @in_port : Input port resource info + * @out_port: Output port resource info, used for RDI path only + * @sync_mode: Sync mode + * Sync mode could be master, slave or none + * @master_idx: Master device index to be configured in the slave path + * for master path, this value is not required. + * only slave need to configure the master index value + * @phy_sel: Phy selection number if tpg is enabled from userspace + * @event_cb_prv: Context data + * @event_cb: Callback function to hw mgr in case of hw events + * @node_res : Reserved resource structure pointer + * + */ +struct cam_tfe_csid_hw_reserve_resource_args { + enum cam_isp_resource_type res_type; + uint32_t res_id; + struct cam_isp_tfe_in_port_info *in_port; + struct cam_isp_tfe_out_port_info *out_port; + enum cam_isp_hw_sync_mode sync_mode; + uint32_t master_idx; + uint32_t phy_sel; + void *event_cb_prv; + cam_hw_mgr_event_cb_func event_cb; + struct cam_isp_resource_node *node_res; +}; + +/** + * enum cam_tfe_csid_halt_cmd - Specify the halt command type + */ +enum cam_tfe_csid_halt_cmd { + CAM_TFE_CSID_HALT_AT_FRAME_BOUNDARY, + CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY, + CAM_TFE_CSID_HALT_IMMEDIATELY, + CAM_TFE_CSID_HALT_MAX, +}; + +/** + * struct cam_csid_hw_stop- stop all resources + * @stop_cmd : Applicable only for PATH resources + * if stop command set to Halt immediately,driver will stop + * path immediately, manager need to reset the path after HI + * if stop command set to halt at frame boundary, driver will set + * halt at frame boundary and wait for frame boundary + * @num_res : Number of resources to be stopped + * @node_res : Reource pointer array( ie cid or CSID) + * + */ +struct cam_tfe_csid_hw_stop_args { + enum cam_tfe_csid_halt_cmd stop_cmd; + uint32_t num_res; + struct cam_isp_resource_node **node_res; +}; + +/** + * enum cam_tfe_csid_reset_type - Specify the reset type + */ +enum cam_tfe_csid_reset_type { + CAM_TFE_CSID_RESET_GLOBAL, + CAM_TFE_CSID_RESET_PATH, + CAM_TFE_CSID_RESET_MAX, +}; + +/** + * struct cam_tfe_csid_reset_cfg- Csid reset configuration + * @ reset_type : Global reset or path reset + * @res_node : Resource need to be reset + * + */ +struct cam_tfe_csid_reset_cfg_args { + enum cam_tfe_csid_reset_type reset_type; + struct cam_isp_resource_node *node_res; +}; + +/** + * struct cam_csid_get_time_stamp_args- time stamp capture arguments + * @res_node : Resource to get the time stamp + * @time_stamp_val : Captured time stamp + * @boot_timestamp : Boot time stamp + */ +struct cam_tfe_csid_get_time_stamp_args { + struct cam_isp_resource_node *node_res; + uint64_t time_stamp_val; + uint64_t boot_timestamp; +}; + +/** + * enum cam_tfe_csid_cmd_type - Specify the csid command + */ +enum cam_tfe_csid_cmd_type { + CAM_TFE_CSID_CMD_GET_TIME_STAMP, + CAM_TFE_CSID_SET_CSID_DEBUG, + CAM_TFE_CSID_SOF_IRQ_DEBUG, + CAM_TFE_CSID_CMD_GET_REG_DUMP, + CAM_TFE_CSID_CMD_MAX, +}; + +/** + * cam_tfe_csid_hw_init() + * + * @brief: Initialize function for the CSID hardware + * + * @tfe_csid_hw: CSID hardware instance returned + * @hw_idex: CSID hardware instance id + */ +int cam_tfe_csid_hw_init(struct cam_hw_intf **tfe_csid_hw, + uint32_t hw_idx); + +/* + * struct cam_tfe_csid_clock_update_args: + * + * @clk_rate: Clock rate requested + */ +struct cam_tfe_csid_clock_update_args { + uint64_t clk_rate; +}; + + +#endif /* _CAM_TFE_CSID_HW_INTF_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_hw_intf.h new file mode 100644 index 000000000000..0678a89d0264 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_hw_intf.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_HW_INTF_H_ +#define _CAM_TFE_HW_INTF_H_ + +#include "cam_isp_hw.h" +#include "cam_cpas_api.h" + +#define CAM_TFE_HW_NUM_MAX 3 +#define TFE_CORE_BASE_IDX 0 + + +enum cam_isp_hw_tfe_in { + CAM_ISP_HW_TFE_IN_CAMIF = 0, + CAM_ISP_HW_TFE_IN_RDI0 = 1, + CAM_ISP_HW_TFE_IN_RDI1 = 2, + CAM_ISP_HW_TFE_IN_RDI2 = 3, + CAM_ISP_HW_TFE_IN_MAX, +}; + +enum cam_isp_hw_tfe_core { + CAM_ISP_HW_TFE_CORE_0, + CAM_ISP_HW_TFE_CORE_1, + CAM_ISP_HW_TFE_CORE_2, + CAM_ISP_HW_TFE_CORE_MAX, +}; + +enum cam_tfe_hw_irq_status { + CAM_TFE_IRQ_STATUS_SUCCESS, + CAM_TFE_IRQ_STATUS_ERR, + CAM_TFE_IRQ_STATUS_OVERFLOW, + CAM_TFE_IRQ_STATUS_P2I_ERROR, + CAM_TFE_IRQ_STATUS_VIOLATION, + CAM_TFE_IRQ_STATUS_MAX, +}; + +enum cam_tfe_hw_irq_regs { + CAM_TFE_IRQ_CAMIF_REG_STATUS0 = 0, + CAM_TFE_IRQ_CAMIF_REG_STATUS1 = 1, + CAM_TFE_IRQ_CAMIF_REG_STATUS2 = 2, + CAM_TFE_IRQ_REGISTERS_MAX, +}; + +enum cam_tfe_bus_irq_regs { + CAM_TFE_IRQ_BUS_REG_STATUS0 = 0, + CAM_TFE_IRQ_BUS_REG_STATUS1 = 1, + CAM_TFE_BUS_IRQ_REGISTERS_MAX, +}; + +enum cam_tfe_reset_type { + CAM_TFE_HW_RESET_HW_AND_REG, + CAM_TFE_HW_RESET_HW, + CAM_TFE_HW_RESET_MAX, +}; + +enum cam_tfe_bw_control_action { + CAM_TFE_BW_CONTROL_EXCLUDE = 0, + CAM_TFE_BW_CONTROL_INCLUDE = 1 +}; + +/* + * struct cam_tfe_hw_get_hw_cap: + * + * @max_width: Max width supported by HW + * @max_height: Max height supported by HW + * @max_pixel_num: Max Pixel channels available + * @max_rdi_num: Max Raw channels available + */ +struct cam_tfe_hw_get_hw_cap { + uint32_t max_width; + uint32_t max_height; + uint32_t max_pixel_num; + uint32_t max_rdi_num; +}; + +/* + * struct cam_tfe_hw_tfe_out_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @out_port_info: Output Port details to acquire + * @unique_id: Unique Identity of Context to associate with this + * resource. Used for composite grouping of multiple + * resources in the same context + * @is_dual: Dual TFE or not + * @split_id: In case of Dual TFE, this is Left or Right. + * (Default is Left if Single TFE) + * @is_master: In case of Dual TFE, this is Master or Slave. + * (Default is Master in case of Single TFE) + * @cdm_ops: CDM operations + * @ctx: Context data + */ +struct cam_tfe_hw_tfe_out_acquire_args { + struct cam_isp_resource_node *rsrc_node; + struct cam_isp_tfe_out_port_info *out_port_info; + uint32_t unique_id; + uint32_t is_dual; + enum cam_isp_hw_split_id split_id; + uint32_t is_master; + struct cam_cdm_utils_ops *cdm_ops; + void *ctx; +}; + +/* + * struct cam_tfe_hw_tfe_in_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @res_id: Resource ID of resource to acquire if specific, + * else CAM_ISP_HW_TFE_IN_MAX + * @cdm_ops: CDM operations + * @sync_mode: In case of Dual TFE, this is Master or Slave. + * (Default is Master in case of Single TFE) + * @in_port: Input port details to acquire + * @camif_pd_enable Camif pd enable or disable + * @dual_tfe_sync_sel_idx Dual tfe master hardware index + */ +struct cam_tfe_hw_tfe_in_acquire_args { + struct cam_isp_resource_node *rsrc_node; + struct cam_isp_tfe_in_port_info *in_port; + uint32_t res_id; + void *cdm_ops; + enum cam_isp_hw_sync_mode sync_mode; + bool camif_pd_enable; + uint32_t dual_tfe_sync_sel_idx; +}; + +/* + * struct cam_tfe_acquire_args: + * + * @rsrc_type: Type of Resource (OUT/IN) to acquire + * @tasklet: Tasklet to associate with this resource. This is + * used to schedule bottom of IRQ events associated + * with this resource. + * @priv: Context data + * @event_cb: Callback function to hw mgr in case of hw events + * @tfe_out: Acquire args for TFE_OUT + * @tfe_in: Acquire args for TFE_IN + */ +struct cam_tfe_acquire_args { + enum cam_isp_resource_type rsrc_type; + void *tasklet; + void *priv; + cam_hw_mgr_event_cb_func event_cb; + union { + struct cam_tfe_hw_tfe_out_acquire_args tfe_out; + struct cam_tfe_hw_tfe_in_acquire_args tfe_in; + }; +}; + +/* + * struct cam_tfe_clock_update_args: + * + * @node_res: Resource to get the time stamp + * @clk_rate: Clock rate requested + */ +struct cam_tfe_clock_update_args { + struct cam_isp_resource_node *node_res; + uint64_t clk_rate; +}; + +/* + * struct cam_tfe_bw_update_args: + * + * @node_res: Resource to get the BW + * @isp_vote: Vote info according to usage data (left/right/rdi) + */ +struct cam_tfe_bw_update_args { + struct cam_isp_resource_node *node_res; + struct cam_axi_vote isp_vote; +}; + +/* + * struct cam_tfe_dual_update_args: + * + * @Brief: update the dual isp striping configuration. + * + * @ split_id: spilt id to inform left or rifht + * @ res: resource node + * @ stripe_config: stripe configuration for port + * + */ +struct cam_tfe_dual_update_args { + enum cam_isp_hw_split_id split_id; + struct cam_isp_resource_node *res; + struct cam_isp_tfe_dual_stripe_config *stripe_config; +}; + +/* + * struct cam_tfe_bw_control_args: + * + * @node_res: Resource to get the time stamp + * @action: Bandwidth control action + */ +struct cam_tfe_bw_control_args { + struct cam_isp_resource_node *node_res; + enum cam_tfe_bw_control_action action; +}; + +/* + * struct cam_tfe_irq_evt_payload: + * + * @Brief: This structure is used to save payload for IRQ + * related to TFE_TOP resources + * + * @list: list_head node for the payload + * @core_index: Index of TFE HW that generated this IRQ event + * @core_info: Private data of handler in bottom half context + * @evt_id: IRQ event + * @irq_reg_val: IRQ and Error register values, read when IRQ was + * handled + * @bus_irq_val Bus irq register status + * @debug_status_0: Value of debug status_0 register at time of IRQ + * @ccif_violation_status ccif violation status + * @overflow_status bus overflow status + * @image_size_violation_status image size violations status + + * @error_type: Identify different errors + * @enable_reg_dump: enable register dump on error + * @ts: Timestamp + */ +struct cam_tfe_irq_evt_payload { + struct list_head list; + uint32_t core_index; + void *core_info; + uint32_t evt_id; + uint32_t irq_reg_val[CAM_TFE_IRQ_REGISTERS_MAX]; + uint32_t bus_irq_val[CAM_TFE_BUS_IRQ_REGISTERS_MAX]; + uint32_t ccif_violation_status; + uint32_t overflow_status; + uint32_t image_size_violation_status; + uint32_t debug_status_0; + + uint32_t error_type; + bool enable_reg_dump; + struct cam_isp_timestamp ts; +}; + +/* + * cam_tfe_hw_init() + * + * @Brief: Initialize TFE HW device + * + * @tfe_hw: tfe_hw interface to fill in and return on + * successful initialization + * @hw_idx: Index of TFE HW + */ +int cam_tfe_hw_init(struct cam_hw_intf **tfe_hw, uint32_t hw_idx); + +#endif /* _CAM_TFE_HW_INTF_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_top_tpg_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_top_tpg_hw_intf.h new file mode 100644 index 000000000000..a773a23dfda4 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_top_tpg_hw_intf.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TOP_TPG_HW_INTF_H_ +#define _CAM_TOP_TPG_HW_INTF_H_ + +#include "cam_isp_hw.h" +#include "cam_hw_intf.h" + +/* Max top tpg instance */ +#define CAM_TOP_TPG_HW_NUM_MAX 2 +/* Max supported number of DT for TPG */ +#define CAM_TOP_TPG_MAX_SUPPORTED_DT 4 + +/** + * enum cam_top_tpg_id - top tpg hw instance id + */ +enum cam_top_tpg_id { + CAM_TOP_TPG_ID_0, + CAM_TOP_TPG_ID_1, + CAM_TFE_TPG_ID_MAX, +}; + +/** + * struct cam_top_tpg_hw_caps- Get the top tpg hw capability + * @major_version : Major version + * @minor_version: Minor version + * @version_incr: Version increment + * + */ +struct cam_top_tpg_hw_caps { + uint32_t major_version; + uint32_t minor_version; + uint32_t version_incr; +}; + +/** + * struct cam_tfe_csid_hw_reserve_resource_args- hw reserve + * @num_inport: number of inport + * TPG support 4 dt types, each different dt comes in different + * in port. + * @in_port : Input port resource info structure pointer + * @node_res : Reserved resource structure pointer + * + */ +struct cam_top_tpg_hw_reserve_resource_args { + uint32_t num_inport; + struct cam_isp_tfe_in_port_info *in_port[CAM_TOP_TPG_MAX_SUPPORTED_DT]; + struct cam_isp_resource_node *node_res; +}; + +/** + * cam_top_tpg_hw_init() + * + * @brief: Initialize function for the tpg hardware + * + * @top_tpg_hw: TPG hardware instance returned + * @hw_idex: TPG hardware instance id + */ +int cam_top_tpg_hw_init(struct cam_hw_intf **top_tpg_hw, + uint32_t hw_idx); + +/* + * struct cam_top_tpg_clock_update_args: + * + * @clk_rate: phy rate requested + */ +struct cam_top_tpg_clock_update_args { + uint64_t clk_rate; +}; + +#endif /* _CAM_TOP_TPG_HW_INTF_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile new file mode 100644 index 000000000000..dcb41c82af58 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_tfe_csid_dev.o cam_tfe_csid_soc.o cam_tfe_csid_core.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_tfe_csid530.o diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.c new file mode 100644 index 000000000000..488431771b2a --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#include +#include "cam_tfe_csid_core.h" +#include "cam_tfe_csid530.h" +#include "cam_tfe_csid_dev.h" + +#define CAM_TFE_CSID_DRV_NAME "csid_530" +#define CAM_TFE_CSID_VERSION_V530 0x50030000 + +static struct cam_tfe_csid_hw_info cam_tfe_csid530_hw_info = { + .csid_reg = &cam_tfe_csid_530_reg_offset, + .hw_dts_version = CAM_TFE_CSID_VERSION_V530, +}; + +static const struct of_device_id cam_tfe_csid530_dt_match[] = { + { + .compatible = "qcom,csid530", + .data = &cam_tfe_csid530_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_tfe_csid530_dt_match); + +static struct platform_driver cam_tfe_csid530_driver = { + .probe = cam_tfe_csid_probe, + .remove = cam_tfe_csid_remove, + .driver = { + .name = CAM_TFE_CSID_DRV_NAME, + .of_match_table = cam_tfe_csid530_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_tfe_csid530_init_module(void) +{ + return platform_driver_register(&cam_tfe_csid530_driver); +} + +static void __exit cam_tfe_csid530_exit_module(void) +{ + platform_driver_unregister(&cam_tfe_csid530_driver); +} + +module_init(cam_tfe_csid530_init_module); +module_exit(cam_tfe_csid530_exit_module); +MODULE_DESCRIPTION("CAM TFE_CSID530 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h new file mode 100644 index 000000000000..7486a35af33e --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h @@ -0,0 +1,222 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_CSID_530_H_ +#define _CAM_TFE_CSID_530_H_ + +#include "cam_tfe_csid_core.h" + +static struct cam_tfe_csid_pxl_reg_offset cam_tfe_csid_530_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + .csid_pxl_err_recovery_cfg0_addr = 0x2d0, + .csid_pxl_err_recovery_cfg1_addr = 0x2d4, + .csid_pxl_err_recovery_cfg2_addr = 0x2d8, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .halt_master_sel_shift = 4, + .halt_mode_shift = 2, + .halt_master_sel_master_val = 3, + .halt_master_sel_slave_val = 0, +}; + +static struct cam_tfe_csid_rdi_reg_offset cam_tfe_csid_530_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_err_recovery_cfg0_addr = 0x3b0, + .csid_rdi_err_recovery_cfg1_addr = 0x3b4, + .csid_rdi_err_recovery_cfg2_addr = 0x3b8, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, +}; + +static struct cam_tfe_csid_rdi_reg_offset cam_tfe_csid_530_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_err_recovery_cfg0_addr = 0x4b0, + .csid_rdi_err_recovery_cfg1_addr = 0x4b4, + .csid_rdi_err_recovery_cfg2_addr = 0x4b8, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, +}; + +static struct cam_tfe_csid_rdi_reg_offset cam_tfe_csid_530_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_err_recovery_cfg0_addr = 0x5b0, + .csid_rdi_err_recovery_cfg1_addr = 0x5b4, + .csid_rdi_err_recovery_cfg2_addr = 0x5b8, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, +}; + +static struct cam_tfe_csid_csi2_rx_reg_offset + cam_tfe_csid_530_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 12, + .csi2_capture_cphy_pkt_dt_shift = 14, + .csi2_capture_cphy_pkt_vc_shift = 20, + .csi2_rx_phy_num_mask = 0x3, + .csi2_rx_long_pkt_hdr_rst_stb_shift = 0x1, + .csi2_rx_short_pkt_hdr_rst_stb_shift = 0x2, +}; + +static struct cam_tfe_csid_common_reg_offset + cam_tfe_csid_530_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 5, + .minor_version = 3, + .version_incr = 0, + .num_rdis = 3, + .num_pix = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .ipp_path_rst_stb_all = 0x17, + .rdi_path_rst_stb_all = 0x97, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0x3FFFF, + .rdi_irq_mask_all = 0x3FFFF, + .top_tfe2_pix_pipe_fuse_reg = 0xFE4, + .top_tfe2_fuse_reg = 0xFE8, +}; + +static struct cam_tfe_csid_reg_offset cam_tfe_csid_530_reg_offset = { + .cmn_reg = &cam_tfe_csid_530_cmn_reg_offset, + .csi2_reg = &cam_tfe_csid_530_csi2_reg_offset, + .ipp_reg = &cam_tfe_csid_530_ipp_reg_offset, + .rdi_reg = { + &cam_tfe_csid_530_rdi_0_reg_offset, + &cam_tfe_csid_530_rdi_1_reg_offset, + &cam_tfe_csid_530_rdi_2_reg_offset, + }, +}; + +#endif /*_CAM_TFE_CSID_530_H_ */ 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 new file mode 100644 index 000000000000..e4348a4c097e --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c @@ -0,0 +1,2822 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "cam_tfe_csid_core.h" +#include "cam_isp_hw.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" +#include "cam_isp_hw_mgr_intf.h" + +/* Timeout value in msec */ +#define TFE_CSID_TIMEOUT 1000 + +/* Timeout values in usec */ +#define CAM_TFE_CSID_TIMEOUT_SLEEP_US 1000 +#define CAM_TFE_CSID_TIMEOUT_ALL_US 100000 + +/* + * Constant Factors needed to change QTimer ticks to nanoseconds + * QTimer Freq = 19.2 MHz + * Time(us) = ticks/19.2 + * Time(ns) = ticks/19.2 * 1000 + */ +#define CAM_TFE_CSID_QTIMER_MUL_FACTOR 10000 +#define CAM_TFE_CSID_QTIMER_DIV_FACTOR 192 + +/* Max number of sof irq's triggered in case of SOF freeze */ +#define CAM_TFE_CSID_IRQ_SOF_DEBUG_CNT_MAX 12 + +/* Max CSI Rx irq error count threshold value */ +#define CAM_TFE_CSID_MAX_IRQ_ERROR_COUNT 5 + +static int cam_tfe_csid_is_ipp_format_supported( + uint32_t in_format) +{ + int rc = -EINVAL; + + switch (in_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: + rc = 0; + break; + default: + break; + } + return rc; +} + +static int cam_tfe_csid_get_format_rdi( + uint32_t in_format, uint32_t out_format, + uint32_t *decode_fmt, uint32_t *plain_fmt) +{ + int rc = 0; + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_6: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN8: + *decode_fmt = 0x0; + *plain_fmt = 0x0; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_8: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_PLAIN128: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN8: + *decode_fmt = 0x1; + *plain_fmt = 0x0; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_10: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_PLAIN128: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN16_10: + *decode_fmt = 0x2; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_12: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_12: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN16_12: + *decode_fmt = 0x3; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_14: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_14: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN16_14: + *decode_fmt = 0x4; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_16: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_16: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN16_16: + *decode_fmt = 0x5; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + default: + rc = -EINVAL; + break; + } + + if (rc) + CAM_ERR(CAM_ISP, "Unsupported format pair in %d out %d", + in_format, out_format); + + return rc; +} + +static int cam_tfe_csid_get_format_ipp( + uint32_t in_format, + uint32_t *decode_fmt, uint32_t *plain_fmt) +{ + int rc = 0; + + CAM_DBG(CAM_ISP, "input format:%d", + in_format); + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + *decode_fmt = 0; + *plain_fmt = 0; + break; + case CAM_FORMAT_MIPI_RAW_8: + *decode_fmt = 0x1; + *plain_fmt = 0; + break; + case CAM_FORMAT_MIPI_RAW_10: + *decode_fmt = 0x2; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_12: + *decode_fmt = 0x3; + *plain_fmt = 0x1; + break; + default: + CAM_ERR(CAM_ISP, "Unsupported format %d", + in_format); + rc = -EINVAL; + } + + CAM_DBG(CAM_ISP, "decode_fmt:%d plain_fmt:%d", + *decode_fmt, *plain_fmt); + + return rc; +} + +static int cam_tfe_csid_cid_get(struct cam_tfe_csid_hw *csid_hw, + int32_t vc, uint32_t dt, uint32_t *cid) +{ + uint32_t i = 0; + + /* Return already reserved CID if the VC/DT matches */ + for (i = 0; i < CAM_TFE_CSID_CID_MAX; i++) { + if (csid_hw->cid_res[i].cnt >= 1) { + if (csid_hw->cid_res[i].vc == vc && + csid_hw->cid_res[i].dt == dt) { + csid_hw->cid_res[i].cnt++; + *cid = i; + CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", + csid_hw->hw_intf->hw_idx, i); + return 0; + } + } + } + + for (i = 0; i < CAM_TFE_CSID_CID_MAX; i++) { + if (!csid_hw->cid_res[i].cnt) { + csid_hw->cid_res[i].vc = vc; + csid_hw->cid_res[i].dt = dt; + csid_hw->cid_res[i].cnt = 1; + *cid = i; + CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", + csid_hw->hw_intf->hw_idx, i); + return 0; + } + } + + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Free cid is not available", + csid_hw->hw_intf->hw_idx); + /* Dump CID values */ + for (i = 0; i < CAM_TFE_CSID_CID_MAX; i++) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CID:%d vc:%d dt:%d cnt:%d", + csid_hw->hw_intf->hw_idx, i, csid_hw->cid_res[i].vc, + csid_hw->cid_res[i].dt, csid_hw->cid_res[i].cnt); + } + return -EINVAL; +} + +static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw) +{ + struct cam_hw_soc_info *soc_info; + const struct cam_tfe_csid_reg_offset *csid_reg; + int rc = 0; + uint32_t val = 0, i; + uint32_t status; + + soc_info = &csid_hw->hw_info->soc_info; + csid_reg = csid_hw->csid_info->csid_reg; + + 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); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d Csid reset", csid_hw->hw_intf->hw_idx); + + /* Mask all interrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + if (csid_hw->pxl_pipe_enable) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + + /* clear all interrupts */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + + cam_io_w_mb(csid_reg->csi2_reg->csi2_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); + + if (csid_hw->pxl_pipe_enable) + cam_io_w_mb(csid_reg->cmn_reg->ipp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); + + for (i = 0 ; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(csid_reg->cmn_reg->rdi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + cam_io_w_mb(0x80, soc_info->reg_map[0].mem_base + + csid_hw->csid_info->csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + + /* perform the top CSID HW registers reset */ + cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_TFE_CSID_TIMEOUT_SLEEP_US, CAM_TFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; + } + + /* perform the SW registers reset */ + reinit_completion(&csid_hw->csid_top_complete); + cam_io_w_mb(csid_reg->cmn_reg->csid_reg_rst_stb, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + + rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, + msecs_to_jiffies(TFE_CSID_TIMEOUT)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, "CSID:%d soft reg reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + if (rc == 0) + rc = -ETIMEDOUT; + } else + rc = 0; + + usleep_range(3000, 3010); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + if (val != 0) + CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d", + csid_hw->hw_intf->hw_idx, val); + csid_hw->error_irq_count = 0; + + return rc; +} + +static int cam_tfe_csid_path_reset(struct cam_tfe_csid_hw *csid_hw, + struct cam_tfe_csid_reset_cfg_args *reset) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info; + struct cam_isp_resource_node *res; + const struct cam_tfe_csid_reg_offset *csid_reg; + uint32_t reset_strb_addr, reset_strb_val, val, id; + struct completion *complete; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + res = reset->node_res; + + 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); + return -EINVAL; + } + + if (res->res_id >= CAM_TFE_CSID_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "CSID:%d resource:%d", + csid_hw->hw_intf->hw_idx, res->res_id); + + if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) { + if (!csid_reg->ipp_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = csid_reg->ipp_reg->csid_pxl_rst_strobes_addr; + complete = &csid_hw->csid_ipp_complete; + reset_strb_val = csid_reg->cmn_reg->ipp_path_rst_stb_all; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + val |= TFE_CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + } else { + id = res->res_id; + if (!csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d RDI res not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = + csid_reg->rdi_reg[id]->csid_rdi_rst_strobes_addr; + complete = + &csid_hw->csid_rdin_complete[id]; + reset_strb_val = csid_reg->cmn_reg->rdi_path_rst_stb_all; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + val |= TFE_CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + } + + reinit_completion(complete); + + /* Reset the corresponding tfe csid path */ + cam_io_w_mb(reset_strb_val, soc_info->reg_map[0].mem_base + + reset_strb_addr); + + rc = wait_for_completion_timeout(complete, + msecs_to_jiffies(TFE_CSID_TIMEOUT)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, "CSID:%d Res id %d fail rc = %d", + csid_hw->hw_intf->hw_idx, + res->res_id, rc); + if (rc == 0) + rc = -ETIMEDOUT; + } + +end: + return rc; +} + +static int cam_tfe_csid_cid_reserve(struct cam_tfe_csid_hw *csid_hw, + struct cam_tfe_csid_hw_reserve_resource_args *cid_reserv, + uint32_t *cid_value) +{ + int rc = 0; + + CAM_DBG(CAM_ISP, + "CSID:%d res_id:0x%x Lane type:%d lane_num:%d dt:%d vc:%d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_id, + cid_reserv->in_port->lane_type, + cid_reserv->in_port->lane_num, + cid_reserv->in_port->dt, + cid_reserv->in_port->vc); + + if (cid_reserv->in_port->res_id >= CAM_ISP_TFE_IN_RES_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid phy sel %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_id); + rc = -EINVAL; + goto end; + } + + if (cid_reserv->in_port->lane_type >= CAM_ISP_LANE_TYPE_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid lane type %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->lane_type); + rc = -EINVAL; + goto end; + } + + if ((cid_reserv->in_port->lane_type == CAM_ISP_LANE_TYPE_DPHY && + cid_reserv->in_port->lane_num > 4)) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid lane num %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->lane_num); + rc = -EINVAL; + goto end; + } + + if (cid_reserv->in_port->lane_type == CAM_ISP_LANE_TYPE_CPHY && + cid_reserv->in_port->lane_num > 3) { + CAM_ERR(CAM_ISP, " CSID:%d Invalid lane type %d & num %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->lane_type, + cid_reserv->in_port->lane_num); + rc = -EINVAL; + goto end; + } + + /* CSID CSI2 v1.1 supports 4 vc */ + if (cid_reserv->in_port->dt > 0x3f || + cid_reserv->in_port->vc > 0x3) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d dt %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->vc, cid_reserv->in_port->dt); + rc = -EINVAL; + goto end; + } + + if (csid_hw->csi2_reserve_cnt == UINT_MAX) { + CAM_ERR(CAM_ISP, + "CSID%d reserve cnt reached max", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "Reserve_cnt %u", csid_hw->csi2_reserve_cnt); + + if (csid_hw->csi2_reserve_cnt) { + /* current configure res type should match requested res type */ + if (csid_hw->in_res_id != cid_reserv->in_port->res_id) { + rc = -EINVAL; + goto end; + } + + if (csid_hw->csi2_rx_cfg.lane_cfg != + cid_reserv->in_port->lane_cfg || + csid_hw->csi2_rx_cfg.lane_type != + cid_reserv->in_port->lane_type || + csid_hw->csi2_rx_cfg.lane_num != + cid_reserv->in_port->lane_num) { + rc = -EINVAL; + goto end; + } + } + + rc = cam_tfe_csid_cid_get(csid_hw, + cid_reserv->in_port->vc, + cid_reserv->in_port->dt, + cid_value); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d CID Reserve failed res_id %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_id); + goto end; + } + + if (!csid_hw->csi2_reserve_cnt) { + csid_hw->in_res_id = cid_reserv->in_port->res_id; + + csid_hw->csi2_rx_cfg.lane_cfg = + cid_reserv->in_port->lane_cfg; + csid_hw->csi2_rx_cfg.lane_type = + cid_reserv->in_port->lane_type; + csid_hw->csi2_rx_cfg.lane_num = + cid_reserv->in_port->lane_num; + + if (cid_reserv->in_port->res_id != CAM_ISP_TFE_IN_RES_TPG) + csid_hw->csi2_rx_cfg.phy_sel = + (cid_reserv->in_port->res_id & 0xFF) - 1; + else + csid_hw->csi2_rx_cfg.phy_sel = + (cid_reserv->phy_sel & 0xFF) - 1; + } + + csid_hw->csi2_reserve_cnt++; + CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired reserv cnt:%d", + csid_hw->hw_intf->hw_idx, *cid_value, + csid_hw->csi2_reserve_cnt); + +end: + return rc; +} + +static int cam_tfe_csid_path_reserve(struct cam_tfe_csid_hw *csid_hw, + struct cam_tfe_csid_hw_reserve_resource_args *reserve) +{ + int rc = 0; + struct cam_tfe_csid_path_cfg *path_data; + struct cam_isp_resource_node *res; + uint32_t cid_value; + + /* CSID CSI2 v2.0 supports 4 vc */ + if (reserve->in_port->dt > 0x3f || reserve->in_port->vc > 0x3 || + (reserve->sync_mode >= CAM_ISP_HW_SYNC_MAX)) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d dt %d mode:%d", + csid_hw->hw_intf->hw_idx, + reserve->in_port->vc, reserve->in_port->dt, + reserve->sync_mode); + rc = -EINVAL; + goto end; + } + + switch (reserve->res_id) { + case CAM_TFE_CSID_PATH_RES_IPP: + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_DBG(CAM_ISP, + "CSID:%d IPP resource not available %d", + csid_hw->hw_intf->hw_idx, + csid_hw->ipp_res.res_state); + rc = -EINVAL; + goto end; + } + + if (cam_tfe_csid_is_ipp_format_supported( + reserve->in_port->format)) { + CAM_ERR(CAM_ISP, + "CSID:%d res id:%d un support format %d", + csid_hw->hw_intf->hw_idx, reserve->res_id, + reserve->in_port->format); + rc = -EINVAL; + goto end; + } + rc = cam_tfe_csid_cid_reserve(csid_hw, reserve, &cid_value); + if (rc) + goto end; + + /* assign the IPP resource */ + res = &csid_hw->ipp_res; + CAM_DBG(CAM_ISP, + "CSID:%d IPP resource:%d acquired successfully", + csid_hw->hw_intf->hw_idx, res->res_id); + + break; + + 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 (csid_hw->rdi_res[reserve->res_id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d RDI:%d resource not available %d", + csid_hw->hw_intf->hw_idx, + reserve->res_id, + csid_hw->rdi_res[reserve->res_id].res_state); + rc = -EINVAL; + goto end; + } + + rc = cam_tfe_csid_cid_reserve(csid_hw, reserve, &cid_value); + if (rc) + goto end; + + res = &csid_hw->rdi_res[reserve->res_id]; + CAM_DBG(CAM_ISP, + "CSID:%d RDI resource:%d acquire success", + csid_hw->hw_intf->hw_idx, + res->res_id); + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id:%d", + csid_hw->hw_intf->hw_idx, reserve->res_id); + rc = -EINVAL; + goto end; + } + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + path_data = (struct cam_tfe_csid_path_cfg *)res->res_priv; + + CAM_DBG(CAM_ISP, "sensor width:%d height:%d fps:%d vbi:%d hbi:%d", + reserve->in_port->sensor_width, + reserve->in_port->sensor_height, + reserve->in_port->sensor_fps, + reserve->in_port->sensor_vbi, + reserve->in_port->sensor_hbi); + path_data->sensor_width = reserve->in_port->sensor_width; + path_data->sensor_height = reserve->in_port->sensor_height; + path_data->sensor_fps = reserve->in_port->sensor_fps; + path_data->sensor_hbi = reserve->in_port->sensor_vbi; + path_data->sensor_vbi = reserve->in_port->sensor_hbi; + + path_data->cid = cid_value; + path_data->in_format = reserve->in_port->format; + path_data->out_format = reserve->out_port->format; + path_data->sync_mode = reserve->sync_mode; + path_data->height = reserve->in_port->height; + path_data->start_line = reserve->in_port->line_start; + path_data->end_line = reserve->in_port->line_end; + + csid_hw->event_cb = reserve->event_cb; + csid_hw->event_cb_priv = reserve->event_cb_prv; + + /* Enable crop only for ipp */ + if (reserve->res_id == CAM_TFE_CSID_PATH_RES_IPP) + path_data->crop_enable = true; + + CAM_DBG(CAM_ISP, + "Res id: %d height:%d line_start %d line_end %d crop_en %d", + reserve->res_id, reserve->in_port->height, + reserve->in_port->line_start, reserve->in_port->line_end, + path_data->crop_enable); + + path_data->dt = reserve->in_port->dt; + path_data->vc = reserve->in_port->vc; + + if (reserve->sync_mode == CAM_ISP_HW_SYNC_MASTER) { + path_data->start_pixel = reserve->in_port->left_start; + path_data->end_pixel = reserve->in_port->left_end; + path_data->width = reserve->in_port->left_width; + CAM_DBG(CAM_ISP, "CSID:%d master:startpixel 0x%x endpixel:0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_pixel, + path_data->end_pixel); + CAM_DBG(CAM_ISP, "CSID:%d master:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_line, + path_data->end_line); + } else if (reserve->sync_mode == CAM_ISP_HW_SYNC_SLAVE) { + path_data->master_idx = reserve->master_idx; + CAM_DBG(CAM_ISP, "CSID:%d master_idx=%d", + csid_hw->hw_intf->hw_idx, path_data->master_idx); + path_data->start_pixel = reserve->in_port->right_start; + path_data->end_pixel = reserve->in_port->right_end; + path_data->width = reserve->in_port->right_width; + CAM_DBG(CAM_ISP, "CSID:%d slave:start:0x%x end:0x%x width 0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_pixel, + path_data->end_pixel, path_data->width); + CAM_DBG(CAM_ISP, "CSID:%d slave:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_line, + path_data->end_line); + } else { + path_data->width = reserve->in_port->left_width; + path_data->start_pixel = reserve->in_port->left_start; + path_data->end_pixel = reserve->in_port->left_end; + CAM_DBG(CAM_ISP, "Res id: %d left width %d start: %d stop:%d", + reserve->res_id, reserve->in_port->left_width, + reserve->in_port->left_start, + reserve->in_port->left_end); + } + + CAM_DBG(CAM_ISP, "Res %d width %d height %d", reserve->res_id, + path_data->width, path_data->height); + reserve->node_res = res; + +end: + return rc; +} + +static int cam_tfe_csid_enable_csi2( + struct cam_tfe_csid_hw *csid_hw) +{ + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t val = 0; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + CAM_DBG(CAM_ISP, "CSID:%d config csi2 rx", + csid_hw->hw_intf->hw_idx); + + /* rx cfg0 */ + val = 0; + val = (csid_hw->csi2_rx_cfg.lane_num - 1) | + (csid_hw->csi2_rx_cfg.lane_cfg << 4) | + (csid_hw->csi2_rx_cfg.lane_type << 24); + val |= (csid_hw->csi2_rx_cfg.phy_sel & + csid_reg->csi2_reg->csi2_rx_phy_num_mask) << 20; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + + /* rx cfg1 */ + val = (1 << csid_reg->csi2_reg->csi2_misr_enable_shift_val); + + /* enable packet ecc correction */ + val |= 1; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + + /* Enable the CSI2 rx inerrupts */ + val = TFE_CSID_CSI2_RX_INFO_RST_DONE | + TFE_CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW | + TFE_CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW | + TFE_CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW | + TFE_CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW | + TFE_CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION | + TFE_CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION | + TFE_CSID_CSI2_RX_ERROR_CRC | + TFE_CSID_CSI2_RX_ERROR_ECC | + TFE_CSID_CSI2_RX_ERROR_MMAPPED_VC_DT | + TFE_CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW | + TFE_CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME | + TFE_CSID_CSI2_RX_ERROR_CPHY_PH_CRC; + + /* Enable the interrupt based on csid debug info set */ + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOT_IRQ) + val |= TFE_CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED | + TFE_CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED | + TFE_CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED | + TFE_CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED; + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOT_IRQ) + val |= TFE_CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED | + TFE_CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED | + TFE_CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED | + TFE_CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED; + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val |= TFE_CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED; + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= TFE_CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED; + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= TFE_CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + return 0; +} + +static int cam_tfe_csid_disable_csi2( + struct cam_tfe_csid_hw *csid_hw) +{ + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + CAM_DBG(CAM_ISP, "CSID:%d Disable csi2 rx", + csid_hw->hw_intf->hw_idx); + + /* Disable the CSI2 rx inerrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + /* Reset the Rx CFG registers */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + + return 0; +} + +static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw *csid_hw) +{ + int rc = 0; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t i, val, clk_lvl; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + /* overflow check before increment */ + if (csid_hw->hw_info->open_count == UINT_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Open count reached max", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + + /* Increment ref Count */ + csid_hw->hw_info->open_count++; + if (csid_hw->hw_info->open_count > 1) { + CAM_DBG(CAM_ISP, "CSID hw has already been enabled"); + return rc; + } + + CAM_DBG(CAM_ISP, "CSID:%d init CSID HW", + csid_hw->hw_intf->hw_idx); + + rc = cam_soc_util_get_clk_level(soc_info, csid_hw->clk_rate, + soc_info->src_clk_idx, &clk_lvl); + CAM_DBG(CAM_ISP, "CSID clock lvl %u", clk_lvl); + + rc = cam_tfe_csid_enable_soc_resources(soc_info, clk_lvl); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d Enable SOC failed", + csid_hw->hw_intf->hw_idx); + goto err; + } + + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_UP; + /* Disable the top IRQ interrupt */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + /* Reset CSID top */ + rc = cam_tfe_csid_global_reset(csid_hw); + if (rc) + goto disable_soc; + + /* clear all interrupts */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + + cam_io_w_mb(csid_reg->csi2_reg->csi2_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); + + if (csid_hw->pxl_pipe_enable) + cam_io_w_mb(csid_reg->cmn_reg->ipp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(csid_reg->cmn_reg->rdi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_hw_version_addr); + CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + /* enable the csi2 rx */ + rc = cam_tfe_csid_enable_csi2(csid_hw); + if (rc) + goto disable_soc; + + return rc; + +disable_soc: + cam_tfe_csid_disable_soc_resources(soc_info); + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; +err: + csid_hw->hw_info->open_count--; + return rc; +} + +static int cam_tfe_csid_disable_hw(struct cam_tfe_csid_hw *csid_hw) +{ + int rc = -EINVAL; + struct cam_hw_soc_info *soc_info; + const struct cam_tfe_csid_reg_offset *csid_reg; + unsigned long flags; + + /* Check for refcount */ + if (!csid_hw->hw_info->open_count) { + CAM_WARN(CAM_ISP, "Unbalanced disable_hw"); + return rc; + } + + /* Decrement ref Count */ + csid_hw->hw_info->open_count--; + + if (csid_hw->hw_info->open_count) { + rc = 0; + return rc; + } + + soc_info = &csid_hw->hw_info->soc_info; + csid_reg = csid_hw->csid_info->csid_reg; + + /* Disable the csi2 */ + cam_tfe_csid_disable_csi2(csid_hw); + + CAM_DBG(CAM_ISP, "%s:Calling Global Reset", __func__); + cam_tfe_csid_global_reset(csid_hw); + CAM_DBG(CAM_ISP, "%s:Global Reset Done", __func__); + + CAM_DBG(CAM_ISP, "CSID:%d De-init CSID HW", + csid_hw->hw_intf->hw_idx); + + /* Disable the top IRQ interrupt */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + + rc = cam_tfe_csid_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", + csid_hw->hw_intf->hw_idx); + + spin_lock_irqsave(&csid_hw->spin_lock, flags); + csid_hw->device_enabled = 0; + spin_unlock_irqrestore(&csid_hw->spin_lock, flags); + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + csid_hw->error_irq_count = 0; + + return rc; +} + +static int cam_tfe_csid_init_config_pxl_path( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_tfe_csid_path_cfg *path_data; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + const struct cam_tfe_csid_pxl_reg_offset *pxl_reg = NULL; + uint32_t decode_format = 0, plain_format = 0, val = 0; + + path_data = (struct cam_tfe_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + pxl_reg = csid_reg->ipp_reg; + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP :%d is not supported on HW", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Config IPP Path"); + rc = cam_tfe_csid_get_format_ipp(path_data->in_format, + &decode_format, &plain_format); + if (rc) + return rc; + + /* + * configure Pxl path and enable the time stamp capture. + * enable the HW measrurement blocks + */ + val = (path_data->vc << csid_reg->cmn_reg->vc_shift_val) | + (path_data->dt << csid_reg->cmn_reg->dt_shift_val) | + (path_data->cid << csid_reg->cmn_reg->dt_id_shift_val) | + (decode_format << csid_reg->cmn_reg->fmt_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_h_en_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_v_en_shift_val) | + (1 << 1); + + val |= (1 << pxl_reg->pix_store_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg1_addr); + + /* select the post irq sub sample strobe for time stamp capture */ + val |= TFE_CSID_TIMESTAMP_STB_POST_IRQ; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg1_addr); + + if (path_data->crop_enable) { + val = (((path_data->end_pixel & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_pixel & 0xFFFF)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_hcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Horizontal crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + val = (((path_data->end_line & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_line & 0xFFFF)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_vcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Vertical Crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + /* Enable generating early eof strobe based on crop config */ + if (!(csid_hw->csid_debug & TFE_CSID_DEBUG_DISABLE_EARLY_EOF)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + val |= (1 << pxl_reg->early_eof_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + } + } + + /* Enable the Pxl path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + val |= (1 << csid_reg->cmn_reg->path_en_shift_val); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + + /* Enable Error Detection Overflow ctrl mode: 2 -> Detect overflow */ + val = 0x9; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_err_recovery_cfg0_addr); + + /* configure the rx packet capture based on csid debug set */ + val = 0; + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val = ((1 << + csid_reg->csi2_reg->csi2_capture_short_pkt_en_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_short_pkt_vc_shift)); + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_long_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_long_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_long_pkt_vc_shift)); + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_vc_shift)); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_capture_ctrl_addr); + CAM_DBG(CAM_ISP, "rx capture control value 0x%x", val); + + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + + return rc; +} + +static int cam_tfe_csid_deinit_pxl_path( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + const struct cam_tfe_csid_pxl_reg_offset *pxl_reg = NULL; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + pxl_reg = csid_reg->ipp_reg; + if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) { + CAM_ERR(CAM_ISP, + "CSID:%d IPP Res type %d res_id:%d in wrong state %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + rc = -EINVAL; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP %d is not supported on HW", + csid_hw->hw_intf->hw_idx, res->res_id); + rc = -EINVAL; + goto end; + } + + /* Disable Error Recovery */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_err_recovery_cfg0_addr); + +end: + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_tfe_csid_enable_pxl_path( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_tfe_csid_path_cfg *path_data; + const struct cam_tfe_csid_pxl_reg_offset *pxl_reg = NULL; + uint32_t val = 0; + + path_data = (struct cam_tfe_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + pxl_reg = csid_reg->ipp_reg; + + if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) { + CAM_ERR(CAM_ISP, + "CSID:%d IPP path res type:%d res_id:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + return -EINVAL; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP resid: %d not supported on HW", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enable IPP path"); + + /* Set master or slave path */ + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) + /* Set halt mode as master */ + val = (TFE_CSID_HALT_MODE_MASTER << + pxl_reg->halt_mode_shift) | + (pxl_reg->halt_master_sel_master_val << + pxl_reg->halt_master_sel_shift); + else if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + /* Set halt mode as slave and set master idx */ + val = (TFE_CSID_HALT_MODE_SLAVE << pxl_reg->halt_mode_shift); + else + /* Default is internal halt mode */ + val = 0; + + /* + * Resume at frame boundary if Master or No Sync. + * Slave will get resume command from Master. + */ + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) + val |= CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + CAM_DBG(CAM_ISP, "CSID:%d IPP Ctrl val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + /* Enable the required pxl path interrupts */ + val = TFE_CSID_PATH_INFO_RST_DONE | + TFE_CSID_PATH_ERROR_FIFO_OVERFLOW | + TFE_CSID_PATH_IPP_ERROR_CCIF_VIOLATION | + TFE_CSID_PATH_IPP_OVERFLOW_IRQ; + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ) + val |= TFE_CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOF_IRQ) + val |= TFE_CSID_PATH_INFO_INPUT_EOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + + CAM_DBG(CAM_ISP, "Enable IPP IRQ mask 0x%x", val); + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_tfe_csid_disable_pxl_path( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_tfe_csid_halt_cmd stop_cmd) +{ + int rc = 0; + uint32_t val = 0; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_tfe_csid_path_cfg *path_data; + const struct cam_tfe_csid_pxl_reg_offset *pxl_reg; + + path_data = (struct cam_tfe_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id >= CAM_TFE_CSID_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, res->res_state); + return rc; + } + + pxl_reg = csid_reg->ipp_reg; + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_DBG(CAM_ISP, "CSID:%d IPP path Res:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, res->res_id, res->res_state); + return -EINVAL; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP %d is not supported on HW", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + if (stop_cmd != CAM_TFE_CSID_HALT_AT_FRAME_BOUNDARY && + stop_cmd != CAM_TFE_CSID_HALT_IMMEDIATELY) { + CAM_ERR(CAM_ISP, + "CSID:%d IPP path un supported stop command:%d", + csid_hw->hw_intf->hw_idx, stop_cmd); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id:%d IPP path", + csid_hw->hw_intf->hw_idx, res->res_id); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) { + /* configure Halt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + return rc; +} + +static int cam_tfe_csid_init_config_rdi_path( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_tfe_csid_path_cfg *path_data; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t path_format = 0, plain_fmt = 0, val = 0, id; + + path_data = (struct cam_tfe_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + id = res->res_id; + if (!csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d RDI:%d is not supported on HW", + csid_hw->hw_intf->hw_idx, id); + return -EINVAL; + } + + rc = cam_tfe_csid_get_format_rdi(path_data->in_format, + path_data->out_format, &path_format, &plain_fmt); + if (rc) + return rc; + + /* + * RDI path config and enable the time stamp capture + * Enable the measurement blocks + */ + val = (path_data->vc << csid_reg->cmn_reg->vc_shift_val) | + (path_data->dt << csid_reg->cmn_reg->dt_shift_val) | + (path_data->cid << csid_reg->cmn_reg->dt_id_shift_val) | + (path_format << csid_reg->cmn_reg->fmt_shift_val) | + (plain_fmt << csid_reg->cmn_reg->plain_fmt_shit_val) | + (1 << 2) | 1; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + + /* select the post irq sub sample strobe for time stamp capture */ + cam_io_w_mb(TFE_CSID_TIMESTAMP_STB_POST_IRQ, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg1_addr); + + /* Enable Error Detection, Overflow ctrl mode: 2 -> Detect overflow */ + val = 0x9; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_err_recovery_cfg0_addr); + + /* Configure the halt mode */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + /* Enable the RPP path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + val |= (1 << csid_reg->cmn_reg->path_en_shift_val); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + + /* configure the rx packet capture based on csid debug set */ + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val = ((1 << + csid_reg->csi2_reg->csi2_capture_short_pkt_en_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_short_pkt_vc_shift)); + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_long_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_long_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_long_pkt_vc_shift)); + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_vc_shift)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_capture_ctrl_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + + return rc; +} + +static int cam_tfe_csid_deinit_rdi_path( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t id; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; + + if (res->res_id > CAM_TFE_CSID_PATH_RES_RDI_2 || + res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW || + !csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id%d state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + /* Disable Error Recovery */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_err_recovery_cfg0_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_tfe_csid_enable_rdi_path( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t id, val; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; + + if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_id > CAM_TFE_CSID_PATH_RES_RDI_2 || + !csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, + "CSID:%d invalid res type:%d res_id:%d state%d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + return -EINVAL; + } + + /* resume at frame boundary */ + cam_io_w_mb(CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + /* Enable the required RDI interrupts */ + val = TFE_CSID_PATH_INFO_RST_DONE | TFE_CSID_PATH_ERROR_FIFO_OVERFLOW | + TFE_CSID_PATH_RDI_ERROR_CCIF_VIOLATION | + TFE_CSID_PATH_RDI_OVERFLOW_IRQ; + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ) + val |= TFE_CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOF_IRQ) + val |= TFE_CSID_PATH_INFO_INPUT_EOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_tfe_csid_disable_rdi_path( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_tfe_csid_halt_cmd stop_cmd) +{ + int rc = 0; + uint32_t id, val = 0; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; + + if ((res->res_id > CAM_TFE_CSID_PATH_RES_RDI_2) || + (!csid_reg->rdi_reg[res->res_id])) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, + res->res_id, res->res_state); + return rc; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d Invalid res_state%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + if (stop_cmd != CAM_TFE_CSID_HALT_AT_FRAME_BOUNDARY && + stop_cmd != CAM_TFE_CSID_HALT_IMMEDIATELY) { + CAM_ERR(CAM_ISP, "CSID:%d un supported stop command:%d", + csid_hw->hw_intf->hw_idx, stop_cmd); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_id); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + + /* Halt the RDI path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + return rc; +} + +static int cam_tfe_csid_poll_stop_status( + struct cam_tfe_csid_hw *csid_hw, + uint32_t res_mask) +{ + int rc = 0; + uint32_t csid_status_addr = 0, val = 0, res_id = 0; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + for (; res_id < CAM_TFE_CSID_PATH_RES_MAX; res_id++, res_mask >>= 1) { + if ((res_mask & 0x1) == 0) + continue; + val = 0; + + if (res_id == CAM_TFE_CSID_PATH_RES_IPP) { + csid_status_addr = + csid_reg->ipp_reg->csid_pxl_status_addr; + + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_STREAMING) + continue; + + } else { + csid_status_addr = + csid_reg->rdi_reg[res_id]->csid_rdi_status_addr; + + if (csid_hw->rdi_res[res_id].res_state != + CAM_ISP_RESOURCE_STATE_STREAMING) + continue; + + } + + CAM_DBG(CAM_ISP, "start polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_status_addr, val, (val & 0x1) == 0x1, + CAM_TFE_CSID_TIMEOUT_SLEEP_US, + CAM_TFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d res:%d halt failed rc %d", + csid_hw->hw_intf->hw_idx, res_id, rc); + rc = -ETIMEDOUT; + break; + } + CAM_DBG(CAM_ISP, "End polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + } + + return rc; +} + +static int cam_tfe_csid_get_time_stamp( + struct cam_tfe_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_tfe_csid_get_time_stamp_args *time_stamp; + struct cam_isp_resource_node *res; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + const struct cam_tfe_csid_rdi_reg_offset *rdi_reg; + struct timespec64 ts; + uint32_t time_32, id; + + time_stamp = (struct cam_tfe_csid_get_time_stamp_args *)cmd_args; + res = time_stamp->node_res; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH || + res->res_id >= CAM_TFE_CSID_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res_type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid dev state :%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) { + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_timestamp_curr0_sof_addr); + } else { + id = res->res_id; + rdi_reg = csid_reg->rdi_reg[id]; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_timestamp_curr0_sof_addr); + } + + time_stamp->time_stamp_val |= (uint64_t) time_32; + time_stamp->time_stamp_val = mul_u64_u32_div( + time_stamp->time_stamp_val, + CAM_TFE_CSID_QTIMER_MUL_FACTOR, + CAM_TFE_CSID_QTIMER_DIV_FACTOR); + + get_monotonic_boottime64(&ts); + time_stamp->boot_timestamp = (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + + return 0; +} + +static int cam_tfe_csid_set_csid_debug(struct cam_tfe_csid_hw *csid_hw, + void *cmd_args) +{ + uint32_t *csid_debug; + + csid_debug = (uint32_t *) cmd_args; + csid_hw->csid_debug = *csid_debug; + CAM_DBG(CAM_ISP, "CSID:%d set csid debug value:%d", + csid_hw->hw_intf->hw_idx, csid_hw->csid_debug); + + return 0; +} + +static int cam_tfe_csid_get_hw_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_tfe_csid_hw_caps *hw_caps; + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + const struct cam_tfe_csid_reg_offset *csid_reg; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_tfe_csid_hw *)csid_hw_info->core_info; + csid_reg = csid_hw->csid_info->csid_reg; + hw_caps = (struct cam_tfe_csid_hw_caps *) get_hw_cap_args; + + hw_caps->num_rdis = csid_reg->cmn_reg->num_rdis; + hw_caps->num_pix = csid_hw->pxl_pipe_enable; + hw_caps->major_version = csid_reg->cmn_reg->major_version; + hw_caps->minor_version = csid_reg->cmn_reg->minor_version; + hw_caps->version_incr = csid_reg->cmn_reg->version_incr; + + CAM_DBG(CAM_ISP, + "CSID:%d No rdis:%d, no pix:%d, major:%d minor:%d ver :%d", + csid_hw->hw_intf->hw_idx, hw_caps->num_rdis, + hw_caps->num_pix, hw_caps->major_version, + hw_caps->minor_version, hw_caps->version_incr); + + return rc; +} + +static int cam_tfe_csid_reset(void *hw_priv, + void *reset_args, uint32_t arg_size) +{ + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_tfe_csid_reset_cfg_args *reset; + int rc = 0; + + if (!hw_priv || !reset_args || (arg_size != + sizeof(struct cam_tfe_csid_reset_cfg_args))) { + CAM_ERR(CAM_ISP, "CSID:Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_tfe_csid_hw *)csid_hw_info->core_info; + reset = (struct cam_tfe_csid_reset_cfg_args *)reset_args; + + switch (reset->reset_type) { + case CAM_TFE_CSID_RESET_GLOBAL: + rc = cam_tfe_csid_global_reset(csid_hw); + break; + case CAM_TFE_CSID_RESET_PATH: + rc = cam_tfe_csid_path_reset(csid_hw, reset); + break; + default: + CAM_ERR(CAM_ISP, "CSID:Invalid reset type :%d", + reset->reset_type); + rc = -EINVAL; + break; + } + + return rc; +} + +static int cam_tfe_csid_reserve(void *hw_priv, + void *reserve_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_tfe_csid_hw_reserve_resource_args *reserv; + + if (!hw_priv || !reserve_args || (arg_size != + sizeof(struct cam_tfe_csid_hw_reserve_resource_args))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_tfe_csid_hw *)csid_hw_info->core_info; + reserv = (struct cam_tfe_csid_hw_reserve_resource_args *)reserve_args; + + if (reserv->res_type != CAM_ISP_RESOURCE_PIX_PATH) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type :%d", + csid_hw->hw_intf->hw_idx, reserv->res_type); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "res_type %d, CSID: %u", + reserv->res_type, csid_hw->hw_intf->hw_idx); + + mutex_lock(&csid_hw->hw_info->hw_mutex); + rc = cam_tfe_csid_path_reserve(csid_hw, reserv); + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_tfe_csid_release(void *hw_priv, + void *release_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + struct cam_tfe_csid_path_cfg *path_data; + + if (!hw_priv || !release_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + 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 *)release_args; + + 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)) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + goto end; + } + + if ((res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE) || + (res->res_state >= CAM_ISP_RESOURCE_STATE_STREAMING)) { + CAM_WARN(CAM_ISP, + "CSID:%d res type:%d Res %d in state %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, + res->res_state); + goto end; + } + + CAM_DBG(CAM_ISP, "CSID:%d res type :%d Resource id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); + + path_data = (struct cam_tfe_csid_path_cfg *)res->res_priv; + if (csid_hw->cid_res[path_data->cid].cnt) + csid_hw->cid_res[path_data->cid].cnt--; + + if (csid_hw->csi2_reserve_cnt) + csid_hw->csi2_reserve_cnt--; + + if (!csid_hw->csi2_reserve_cnt) + memset(&csid_hw->csi2_rx_cfg, 0, + sizeof(struct cam_tfe_csid_csi2_rx_cfg)); + + CAM_DBG(CAM_ISP, "CSID:%d res id :%d cnt:%d reserv cnt:%d", + csid_hw->hw_intf->hw_idx, + res->res_id, csid_hw->cid_res[path_data->cid].cnt, + csid_hw->csi2_reserve_cnt); + + res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_tfe_csid_reset_retain_sw_reg( + struct cam_tfe_csid_hw *csid_hw) +{ + int rc = 0; + uint32_t status; + const struct cam_tfe_csid_reg_offset *csid_reg = + csid_hw->csid_info->csid_reg; + struct cam_hw_soc_info *soc_info; + + soc_info = &csid_hw->hw_info->soc_info; + /* 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); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_TFE_CSID_TIMEOUT_SLEEP_US, CAM_TFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; + } else { + CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d", + csid_hw->hw_intf->hw_idx, rc); + rc = 0; + } + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + return rc; +} + +static int cam_tfe_csid_init_hw(void *hw_priv, + void *init_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + const struct cam_tfe_csid_reg_offset *csid_reg; + unsigned long flags; + + if (!hw_priv || !init_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type state %d", + csid_hw->hw_intf->hw_idx, + res->res_type); + return -EINVAL; + } + + 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; + + 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) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res tpe:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + goto end; + } + + if ((res->res_type == CAM_ISP_RESOURCE_PIX_PATH) && + (res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED)) { + CAM_ERR(CAM_ISP, + "CSID:%d res type:%d res_id:%dInvalid state %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "CSID:%d res type :%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); + + /* Initialize the csid hardware */ + rc = cam_tfe_csid_enable_hw(csid_hw); + if (rc) + goto end; + + if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) + rc = cam_tfe_csid_init_config_pxl_path(csid_hw, res); + else + rc = cam_tfe_csid_init_config_rdi_path(csid_hw, res); + + rc = cam_tfe_csid_reset_retain_sw_reg(csid_hw); + if (rc < 0) + CAM_ERR(CAM_ISP, "CSID: Failed in SW reset"); + + if (rc) + cam_tfe_csid_disable_hw(csid_hw); + + spin_lock_irqsave(&csid_hw->spin_lock, flags); + csid_hw->device_enabled = 1; + spin_unlock_irqrestore(&csid_hw->spin_lock, flags); +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_tfe_csid_deinit_hw(void *hw_priv, + void *deinit_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + + if (!hw_priv || !deinit_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID:Invalid arguments"); + return -EINVAL; + } + + 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"); + 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; + + 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", + csid_hw->hw_intf->hw_idx, + res->res_id); + goto end; + } + + CAM_DBG(CAM_ISP, "De-Init IPP Path: %d", res->res_id); + + if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) + rc = cam_tfe_csid_deinit_pxl_path(csid_hw, res); + else + rc = cam_tfe_csid_deinit_rdi_path(csid_hw, res); + + /* Disable CSID HW */ + CAM_DBG(CAM_ISP, "Disabling CSID Hw"); + cam_tfe_csid_disable_hw(csid_hw); + CAM_DBG(CAM_ISP, "%s: Exit", __func__); + +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_tfe_csid_start(void *hw_priv, void *start_args, + uint32_t arg_size) +{ + int rc = 0; + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + const struct cam_tfe_csid_reg_offset *csid_reg; + + if (!hw_priv || !start_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + 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 *)start_args; + csid_reg = csid_hw->csid_info->csid_reg; + + if (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && + res->res_id >= CAM_TFE_CSID_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res tpe:%d res id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + goto end; + } + + /* Reset sof irq debug fields */ + csid_hw->sof_irq_triggered = false; + csid_hw->irq_debug_cnt = 0; + + CAM_DBG(CAM_ISP, "CSID:%d res_type :%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); + + switch (res->res_type) { + case CAM_ISP_RESOURCE_PIX_PATH: + if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) + rc = cam_tfe_csid_enable_pxl_path(csid_hw, res); + else + rc = cam_tfe_csid_enable_rdi_path(csid_hw, res); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", + csid_hw->hw_intf->hw_idx, res->res_type); + break; + } +end: + return rc; +} + +static int cam_tfe_csid_stop(void *hw_priv, + void *stop_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + struct cam_tfe_csid_hw_stop_args *csid_stop; + uint32_t i; + uint32_t res_mask = 0; + + if (!hw_priv || !stop_args || + (arg_size != sizeof(struct cam_tfe_csid_hw_stop_args))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + csid_stop = (struct cam_tfe_csid_hw_stop_args *) stop_args; + + if (!csid_stop->num_res) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_tfe_csid_hw *)csid_hw_info->core_info; + CAM_DBG(CAM_ISP, "CSID:%d num_res %d", + csid_hw->hw_intf->hw_idx, + csid_stop->num_res); + + /* Stop the resource first */ + for (i = 0; i < csid_stop->num_res; i++) { + res = csid_stop->node_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id); + switch (res->res_type) { + case CAM_ISP_RESOURCE_PIX_PATH: + res_mask |= (1 << res->res_id); + if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) + rc = cam_tfe_csid_disable_pxl_path(csid_hw, + res, csid_stop->stop_cmd); + else + rc = cam_tfe_csid_disable_rdi_path(csid_hw, + res, csid_stop->stop_cmd); + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } + } + + if (res_mask) + rc = cam_tfe_csid_poll_stop_status(csid_hw, res_mask); + + for (i = 0; i < csid_stop->num_res; i++) { + res = csid_stop->node_res[i]; + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + } + + CAM_DBG(CAM_ISP, "%s: Exit", __func__); + return rc; +} + +static int cam_tfe_csid_read(void *hw_priv, + void *read_args, uint32_t arg_size) +{ + CAM_ERR(CAM_ISP, "CSID: un supported"); + return -EINVAL; +} + +static int cam_tfe_csid_write(void *hw_priv, + void *write_args, uint32_t arg_size) +{ + CAM_ERR(CAM_ISP, "CSID: un supported"); + return -EINVAL; +} + +static int cam_tfe_csid_sof_irq_debug( + struct cam_tfe_csid_hw *csid_hw, void *cmd_args) +{ + int i = 0; + uint32_t val = 0; + bool sof_irq_enable = false; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (*((uint32_t *)cmd_args) == 1) + sof_irq_enable = true; + + if (csid_hw->hw_info->hw_state == + CAM_HW_STATE_POWER_DOWN) { + CAM_WARN(CAM_ISP, + "CSID powered down unable to %s sof irq", + sof_irq_enable ? "enable" : "disable"); + return 0; + } + + if (csid_reg->ipp_reg) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + + if (val) { + if (sof_irq_enable) + val |= TFE_CSID_PATH_INFO_INPUT_SOF; + else + val &= ~TFE_CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + val = 0; + } + } + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + if (val) { + if (sof_irq_enable) + val |= TFE_CSID_PATH_INFO_INPUT_SOF; + else + val &= ~TFE_CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + val = 0; + } + } + + if (sof_irq_enable) { + csid_hw->csid_debug |= TFE_CSID_DEBUG_ENABLE_SOF_IRQ; + csid_hw->sof_irq_triggered = true; + } else { + csid_hw->csid_debug &= ~TFE_CSID_DEBUG_ENABLE_SOF_IRQ; + csid_hw->sof_irq_triggered = false; + } + + CAM_INFO(CAM_ISP, "SOF freeze: CSID SOF irq %s", + sof_irq_enable ? "enabled" : "disabled"); + + return 0; +} + +static int cam_tfe_csid_set_csid_clock( + struct cam_tfe_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_tfe_csid_clock_update_args *clk_update = NULL; + + if (!csid_hw) + return -EINVAL; + + clk_update = + (struct cam_tfe_csid_clock_update_args *)cmd_args; + + csid_hw->clk_rate = clk_update->clk_rate; + CAM_DBG(CAM_ISP, "CSID clock rate %llu", csid_hw->clk_rate); + + return 0; +} + +static int cam_tfe_csid_get_regdump(struct cam_tfe_csid_hw *csid_hw, + void *cmd_args) +{ + struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_isp_resource_node *res; + struct cam_tfe_csid_path_cfg *path_data; + uint32_t id; + int val; + + csid_reg = (struct cam_tfe_csid_reg_offset *) + csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + res = (struct cam_isp_resource_node *)cmd_args; + path_data = (struct cam_tfe_csid_path_cfg *)res->res_priv; + + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH || + res->res_id >= CAM_TFE_CSID_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res_type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid dev state :%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) { + CAM_INFO(CAM_ISP, "Dumping CSID:%d IPP registers ", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_cfg0_addr); + CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x", + csid_reg->ipp_reg->csid_pxl_cfg0_addr, val); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_cfg1_addr); + CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x", + csid_reg->ipp_reg->csid_pxl_cfg1_addr, val); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_ctrl_addr); + CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x", + csid_reg->ipp_reg->csid_pxl_ctrl_addr, val); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_hcrop_addr); + CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x", + csid_reg->ipp_reg->csid_pxl_hcrop_addr, val); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_vcrop_addr); + CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x", + csid_reg->ipp_reg->csid_pxl_vcrop_addr, val); + } else { + id = res->res_id; + CAM_INFO(CAM_ISP, "Dumping CSID:%d RDI:%d registers ", + csid_hw->hw_intf->hw_idx, id); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x", + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr, val); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg1_addr); + CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x", + csid_reg->rdi_reg[id]->csid_rdi_cfg1_addr, val); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + CAM_INFO(CAM_ISP, "offset 0x%x=0x08%x", + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr, val); + } + CAM_INFO(CAM_ISP, + "start pix:%d end pix:%d start line:%d end line:%d w:%d h:%d", + path_data->start_pixel, path_data->end_pixel, + path_data->start_line, path_data->end_line, + path_data->width, path_data->height); + CAM_INFO(CAM_ISP, + "clock:%d crop_enable:%d vc:%d dt:%d informat:%d outformat:%d", + path_data->clk_rate, path_data->crop_enable, + path_data->vc, path_data->dt, + path_data->in_format, path_data->out_format); + + return 0; +} + +static int cam_tfe_csid_process_cmd(void *hw_priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + + if (!hw_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "CSID: Invalid arguments"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_tfe_csid_hw *)csid_hw_info->core_info; + + switch (cmd_type) { + case CAM_TFE_CSID_CMD_GET_TIME_STAMP: + rc = cam_tfe_csid_get_time_stamp(csid_hw, cmd_args); + break; + case CAM_TFE_CSID_SET_CSID_DEBUG: + rc = cam_tfe_csid_set_csid_debug(csid_hw, cmd_args); + break; + case CAM_TFE_CSID_SOF_IRQ_DEBUG: + rc = cam_tfe_csid_sof_irq_debug(csid_hw, cmd_args); + break; + case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE: + rc = cam_tfe_csid_set_csid_clock(csid_hw, cmd_args); + break; + case CAM_TFE_CSID_CMD_GET_REG_DUMP: + rc = cam_tfe_csid_get_regdump(csid_hw, cmd_args); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", + csid_hw->hw_intf->hw_idx, cmd_type); + rc = -EINVAL; + break; + } + + return rc; +} + +irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) +{ + struct cam_tfe_csid_hw *csid_hw; + struct cam_hw_soc_info *soc_info; + 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; + uint32_t sof_irq_debug_en = 0; + unsigned long flags; + uint32_t i, val; + + csid_hw = (struct cam_tfe_csid_hw *)data; + + if (!data) { + CAM_ERR(CAM_ISP, "CSID: Invalid arguments"); + return IRQ_HANDLED; + } + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + csi2_reg = csid_reg->csi2_reg; + + /* read */ + irq_status[TFE_CSID_IRQ_REG_TOP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr); + + irq_status[TFE_CSID_IRQ_REG_RX] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_status_addr); + + if (csid_hw->pxl_pipe_enable) + irq_status[TFE_CSID_IRQ_REG_IPP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_status_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + irq_status[i] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); + + /* clear */ + cam_io_w_mb(irq_status[TFE_CSID_IRQ_REG_TOP], + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + + cam_io_w_mb(irq_status[TFE_CSID_IRQ_REG_RX], + soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); + + if (csid_hw->pxl_pipe_enable) + cam_io_w_mb(irq_status[TFE_CSID_IRQ_REG_IPP], + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + cam_io_w_mb(irq_status[i], + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + } + 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]) + complete(&csid_hw->csid_top_complete); + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) + complete(&csid_hw->csid_csi2_complete); + + spin_lock_irqsave(&csid_hw->spin_lock, flags); + if (csid_hw->device_enabled == 1) { + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { + fatal_err_detected = true; + } + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { + fatal_err_detected = true; + } + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { + fatal_err_detected = true; + } + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { + fatal_err_detected = true; + } + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) + csid_hw->error_irq_count++; + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) + csid_hw->error_irq_count++; + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) + csid_hw->error_irq_count++; + + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) + csid_hw->error_irq_count++; + + } + spin_unlock_irqrestore(&csid_hw->spin_lock, flags); + + 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 + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + } + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOT_IRQ) { + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL0_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL1_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL2_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL3_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + } + + if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOT_IRQ) { + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL0_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL1_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL2_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL3_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + } + + if ((csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) && + (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d LONG_PKT_CAPTURED", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_0_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d long packet VC :%d DT:%d WC:%d", + csid_hw->hw_intf->hw_idx, + (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_1_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d long packet ECC :%d", + csid_hw->hw_intf->hw_idx, val); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_ftr_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d long pkt cal CRC:%d expected CRC:%d", + csid_hw->hw_intf->hw_idx, (val >> 16), (val & 0xFFFF)); + } + if ((csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) && + (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d SHORT_PKT_CAPTURED", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_short_pkt_0_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d short pkt VC :%d DT:%d LC:%d", + csid_hw->hw_intf->hw_idx, + (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_short_pkt_1_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d short packet ECC :%d", + csid_hw->hw_intf->hw_idx, val); + } + + if ((csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) && + (irq_status[TFE_CSID_IRQ_REG_RX] & + TFE_CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PKT_HDR_CAPTURED", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_cphy_pkt_hdr_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d cphy packet VC :%d DT:%d WC:%d", + csid_hw->hw_intf->hw_idx, + (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + } + + /* read the IPP errors */ + if (csid_hw->pxl_pipe_enable) { + /* IPP reset done bit */ + if (irq_status[TFE_CSID_IRQ_REG_IPP] & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "CSID IPP reset complete"); + complete(&csid_hw->csid_ipp_complete); + } + + if ((irq_status[TFE_CSID_IRQ_REG_IPP] & + TFE_CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP SOF received", + csid_hw->hw_intf->hw_idx); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status[TFE_CSID_IRQ_REG_IPP] & + TFE_CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", + csid_hw->hw_intf->hw_idx); + } + + if (irq_status[TFE_CSID_IRQ_REG_IPP] & + TFE_CSID_PATH_ERROR_FIFO_OVERFLOW) { + /* Stop IPP path immediately */ + cam_io_w_mb(CAM_TFE_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_ctrl_addr); + } + } + + 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)) { + CAM_DBG(CAM_ISP, "CSID RDI%d reset complete", i); + complete(&csid_hw->csid_rdin_complete[i]); + } + + if ((irq_status[i] & TFE_CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI:%d SOF received", i); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status[i] & TFE_CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI:%d EOF received", i); + } + + if (irq_status[i] & TFE_CSID_PATH_ERROR_FIFO_OVERFLOW) { + /* Stop RDI path immediately */ + 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 (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; + } + + CAM_DBG(CAM_ISP, "IRQ Handling exit"); + return IRQ_HANDLED; +} + +int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, + uint32_t csid_idx) +{ + int rc = -EINVAL; + uint32_t i, val, clk_lvl; + struct cam_tfe_csid_path_cfg *path_data; + struct cam_hw_info *csid_hw_info; + struct cam_tfe_csid_hw *tfe_csid_hw = NULL; + const struct cam_tfe_csid_reg_offset *csid_reg; + + if (csid_idx >= CAM_TFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid csid index:%d", csid_idx); + return rc; + } + + csid_hw_info = (struct cam_hw_info *) csid_hw_intf->hw_priv; + tfe_csid_hw = (struct cam_tfe_csid_hw *) csid_hw_info->core_info; + + tfe_csid_hw->hw_intf = csid_hw_intf; + tfe_csid_hw->hw_info = csid_hw_info; + csid_reg = tfe_csid_hw->csid_info->csid_reg; + + CAM_DBG(CAM_ISP, "type %d index %d", + tfe_csid_hw->hw_intf->hw_type, csid_idx); + + tfe_csid_hw->device_enabled = 0; + tfe_csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&tfe_csid_hw->hw_info->hw_mutex); + spin_lock_init(&tfe_csid_hw->hw_info->hw_lock); + spin_lock_init(&tfe_csid_hw->spin_lock); + init_completion(&tfe_csid_hw->hw_info->hw_complete); + + init_completion(&tfe_csid_hw->csid_top_complete); + init_completion(&tfe_csid_hw->csid_csi2_complete); + init_completion(&tfe_csid_hw->csid_ipp_complete); + for (i = 0; i < CAM_TFE_CSID_RDI_MAX; i++) + init_completion(&tfe_csid_hw->csid_rdin_complete[i]); + + rc = cam_tfe_csid_init_soc_resources(&tfe_csid_hw->hw_info->soc_info, + cam_tfe_csid_irq, tfe_csid_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d Failed to init_soc", csid_idx); + goto err; + } + rc = cam_soc_util_get_clk_level(&tfe_csid_hw->hw_info->soc_info, + tfe_csid_hw->clk_rate, + tfe_csid_hw->hw_info->soc_info.src_clk_idx, &clk_lvl); + CAM_DBG(CAM_ISP, "CSID clock lvl %u", clk_lvl); + + rc = cam_tfe_csid_enable_soc_resources(&tfe_csid_hw->hw_info->soc_info, + clk_lvl); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d Enable SOC failed", + tfe_csid_hw->hw_intf->hw_idx); + goto err; + } + + tfe_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_tfe_csid_get_hw_caps; + tfe_csid_hw->hw_intf->hw_ops.init = cam_tfe_csid_init_hw; + tfe_csid_hw->hw_intf->hw_ops.deinit = cam_tfe_csid_deinit_hw; + tfe_csid_hw->hw_intf->hw_ops.reset = cam_tfe_csid_reset; + tfe_csid_hw->hw_intf->hw_ops.reserve = cam_tfe_csid_reserve; + tfe_csid_hw->hw_intf->hw_ops.release = cam_tfe_csid_release; + tfe_csid_hw->hw_intf->hw_ops.start = cam_tfe_csid_start; + tfe_csid_hw->hw_intf->hw_ops.stop = cam_tfe_csid_stop; + tfe_csid_hw->hw_intf->hw_ops.read = cam_tfe_csid_read; + tfe_csid_hw->hw_intf->hw_ops.write = cam_tfe_csid_write; + tfe_csid_hw->hw_intf->hw_ops.process_cmd = cam_tfe_csid_process_cmd; + + /* reset the cid values */ + for (i = 0; i < CAM_TFE_CSID_CID_MAX; i++) { + tfe_csid_hw->cid_res[i].vc = 0; + tfe_csid_hw->cid_res[i].dt = 0; + tfe_csid_hw->cid_res[i].cnt = 0; + } + + if (tfe_csid_hw->hw_intf->hw_idx == 2) { + val = cam_io_r_mb( + tfe_csid_hw->hw_info->soc_info.reg_map[1].mem_base + + csid_reg->cmn_reg->top_tfe2_fuse_reg); + if (val) { + CAM_INFO(CAM_ISP, "TFE 2 is not supported by hardware"); + rc = -EINVAL; + goto err; + } + } + + val = cam_io_r_mb( + tfe_csid_hw->hw_info->soc_info.reg_map[1].mem_base + + csid_reg->cmn_reg->top_tfe2_pix_pipe_fuse_reg); + + /* Initialize the IPP resources */ + if (!(val && (tfe_csid_hw->hw_intf->hw_idx == 2))) { + CAM_DBG(CAM_ISP, "initializing the pix path"); + + tfe_csid_hw->ipp_res.res_type = CAM_ISP_RESOURCE_PIX_PATH; + tfe_csid_hw->ipp_res.res_id = CAM_TFE_CSID_PATH_RES_IPP; + tfe_csid_hw->ipp_res.res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + tfe_csid_hw->ipp_res.hw_intf = tfe_csid_hw->hw_intf; + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + tfe_csid_hw->ipp_res.res_priv = path_data; + tfe_csid_hw->pxl_pipe_enable = 1; + } + + /* Initialize the RDI resource */ + for (i = 0; i < tfe_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + i++) { + /* res type is from RDI 0 to RDI2 */ + tfe_csid_hw->rdi_res[i].res_type = + CAM_ISP_RESOURCE_PIX_PATH; + tfe_csid_hw->rdi_res[i].res_id = i; + tfe_csid_hw->rdi_res[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + tfe_csid_hw->rdi_res[i].hw_intf = tfe_csid_hw->hw_intf; + + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + tfe_csid_hw->rdi_res[i].res_priv = path_data; + } + + tfe_csid_hw->csid_debug = 0; + tfe_csid_hw->error_irq_count = 0; + + 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); + goto err; + } + + return 0; +err: + if (rc) { + kfree(tfe_csid_hw->ipp_res.res_priv); + for (i = 0; i < + tfe_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + i++) + kfree(tfe_csid_hw->rdi_res[i].res_priv); + } + + return rc; +} + + +int cam_tfe_csid_hw_deinit(struct cam_tfe_csid_hw *tfe_csid_hw) +{ + int rc = -EINVAL; + uint32_t i; + + if (!tfe_csid_hw) { + CAM_ERR(CAM_ISP, "Invalid param"); + return rc; + } + + /* release the privdate data memory from resources */ + kfree(tfe_csid_hw->ipp_res.res_priv); + + for (i = 0; i < + tfe_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + i++) { + kfree(tfe_csid_hw->rdi_res[i].res_priv); + } + + cam_tfe_csid_deinit_soc_resources(&tfe_csid_hw->hw_info->soc_info); + + return 0; +} 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 new file mode 100644 index 000000000000..f706bbaefd05 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h @@ -0,0 +1,412 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_CSID_HW_H_ +#define _CAM_TFE_CSID_HW_H_ + +#include "cam_hw.h" +#include "cam_tfe_csid_hw_intf.h" +#include "cam_tfe_csid_soc.h" + +#define CAM_TFE_CSID_CID_MAX 4 + +#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) +#define TFE_CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED BIT(3) +#define TFE_CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED BIT(4) +#define TFE_CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED BIT(5) +#define TFE_CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED BIT(6) +#define TFE_CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED BIT(7) +#define TFE_CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED BIT(8) +#define TFE_CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED BIT(9) +#define TFE_CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED BIT(10) +#define TFE_CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION BIT(11) +#define TFE_CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION BIT(12) +#define TFE_CSID_CSI2_RX_ERROR_CPHY_PH_CRC BIT(13) +#define TFE_CSID_CSI2_RX_WARNING_ECC BIT(14) +#define TFE_CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW BIT(15) +#define TFE_CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW BIT(16) +#define TFE_CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW BIT(17) +#define TFE_CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW BIT(18) +#define TFE_CSID_CSI2_RX_ERROR_CRC BIT(19) +#define TFE_CSID_CSI2_RX_ERROR_ECC BIT(20) +#define TFE_CSID_CSI2_RX_ERROR_MMAPPED_VC_DT BIT(21) +#define TFE_CSID_CSI2_RX_ERROR_UNMAPPED_VC_DT BIT(22) +#define TFE_CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW BIT(23) +#define TFE_CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME BIT(24) +#define TFE_CSID_CSI2_RX_INFO_RST_DONE BIT(27) + +#define TFE_CSID_PATH_INFO_RST_DONE BIT(1) +#define TFE_CSID_PATH_ERROR_FIFO_OVERFLOW BIT(2) +#define TFE_CSID_PATH_INFO_INPUT_EOF BIT(9) +#define TFE_CSID_PATH_INFO_INPUT_EOL BIT(10) +#define TFE_CSID_PATH_INFO_INPUT_SOL BIT(11) +#define TFE_CSID_PATH_INFO_INPUT_SOF BIT(12) +#define TFE_CSID_PATH_IPP_ERROR_CCIF_VIOLATION BIT(15) +#define TFE_CSID_PATH_IPP_OVERFLOW_IRQ BIT(16) +#define TFE_CSID_PATH_IPP_FRAME_DROP BIT(17) +#define TFE_CSID_PATH_RDI_FRAME_DROP BIT(16) +#define TFE_CSID_PATH_RDI_OVERFLOW_IRQ BIT(17) +#define TFE_CSID_PATH_RDI_ERROR_CCIF_VIOLATION BIT(18) + +/* + * Debug values enable the corresponding interrupts and debug logs provide + * necessary information + */ +#define TFE_CSID_DEBUG_ENABLE_SOF_IRQ BIT(0) +#define TFE_CSID_DEBUG_ENABLE_EOF_IRQ BIT(1) +#define TFE_CSID_DEBUG_ENABLE_SOT_IRQ BIT(2) +#define TFE_CSID_DEBUG_ENABLE_EOT_IRQ BIT(3) +#define TFE_CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE BIT(4) +#define TFE_CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE BIT(5) +#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) + +/* enum cam_csid_path_halt_mode select the path halt mode control */ +enum cam_tfe_csid_path_halt_mode { + TFE_CSID_HALT_MODE_INTERNAL, + TFE_CSID_HALT_MODE_GLOBAL, + TFE_CSID_HALT_MODE_MASTER, + TFE_CSID_HALT_MODE_SLAVE, +}; + +/** + *enum cam_csid_path_timestamp_stb_sel - select the sof/eof strobes used to + * capture the timestamp + */ +enum cam_tfe_csid_path_timestamp_stb_sel { + TFE_CSID_TIMESTAMP_STB_PRE_HALT, + TFE_CSID_TIMESTAMP_STB_POST_HALT, + TFE_CSID_TIMESTAMP_STB_POST_IRQ, + TFE_CSID_TIMESTAMP_STB_MAX, +}; + +struct cam_tfe_csid_pxl_reg_offset { + /* Pxl path register offsets*/ + uint32_t csid_pxl_irq_status_addr; + uint32_t csid_pxl_irq_mask_addr; + uint32_t csid_pxl_irq_clear_addr; + uint32_t csid_pxl_irq_set_addr; + + uint32_t csid_pxl_cfg0_addr; + uint32_t csid_pxl_cfg1_addr; + uint32_t csid_pxl_ctrl_addr; + uint32_t csid_pxl_hcrop_addr; + uint32_t csid_pxl_vcrop_addr; + uint32_t csid_pxl_rst_strobes_addr; + uint32_t csid_pxl_status_addr; + uint32_t csid_pxl_misr_val_addr; + uint32_t csid_pxl_timestamp_curr0_sof_addr; + uint32_t csid_pxl_timestamp_curr1_sof_addr; + uint32_t csid_pxl_timestamp_perv0_sof_addr; + uint32_t csid_pxl_timestamp_perv1_sof_addr; + uint32_t csid_pxl_timestamp_curr0_eof_addr; + uint32_t csid_pxl_timestamp_curr1_eof_addr; + uint32_t csid_pxl_timestamp_perv0_eof_addr; + uint32_t csid_pxl_timestamp_perv1_eof_addr; + uint32_t csid_pxl_err_recovery_cfg0_addr; + uint32_t csid_pxl_err_recovery_cfg1_addr; + uint32_t csid_pxl_err_recovery_cfg2_addr; + + /* configuration */ + uint32_t pix_store_en_shift_val; + uint32_t early_eof_en_shift_val; + uint32_t halt_master_sel_shift; + uint32_t halt_mode_shift; + uint32_t halt_master_sel_master_val; + uint32_t halt_master_sel_slave_val; +}; + +struct cam_tfe_csid_rdi_reg_offset { + uint32_t csid_rdi_irq_status_addr; + uint32_t csid_rdi_irq_mask_addr; + uint32_t csid_rdi_irq_clear_addr; + uint32_t csid_rdi_irq_set_addr; + + /*RDI N register address */ + uint32_t csid_rdi_cfg0_addr; + uint32_t csid_rdi_cfg1_addr; + uint32_t csid_rdi_ctrl_addr; + uint32_t csid_rdi_rst_strobes_addr; + uint32_t csid_rdi_status_addr; + uint32_t csid_rdi_misr_val0_addr; + uint32_t csid_rdi_misr_val1_addr; + uint32_t csid_rdi_timestamp_curr0_sof_addr; + uint32_t csid_rdi_timestamp_curr1_sof_addr; + uint32_t csid_rdi_timestamp_prev0_sof_addr; + uint32_t csid_rdi_timestamp_prev1_sof_addr; + uint32_t csid_rdi_timestamp_curr0_eof_addr; + uint32_t csid_rdi_timestamp_curr1_eof_addr; + uint32_t csid_rdi_timestamp_prev0_eof_addr; + uint32_t csid_rdi_timestamp_prev1_eof_addr; + uint32_t csid_rdi_err_recovery_cfg0_addr; + uint32_t csid_rdi_err_recovery_cfg1_addr; + uint32_t csid_rdi_err_recovery_cfg2_addr; + uint32_t csid_rdi_byte_cntr_ping_addr; + uint32_t csid_rdi_byte_cntr_pong_addr; + + /* configuration */ + uint32_t packing_format; +}; + +struct cam_tfe_csid_csi2_rx_reg_offset { + uint32_t csid_csi2_rx_irq_status_addr; + uint32_t csid_csi2_rx_irq_mask_addr; + uint32_t csid_csi2_rx_irq_clear_addr; + uint32_t csid_csi2_rx_irq_set_addr; + uint32_t csid_csi2_rx_cfg0_addr; + uint32_t csid_csi2_rx_cfg1_addr; + uint32_t csid_csi2_rx_capture_ctrl_addr; + uint32_t csid_csi2_rx_rst_strobes_addr; + uint32_t csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr; + uint32_t csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr; + uint32_t csid_csi2_rx_captured_short_pkt_0_addr; + uint32_t csid_csi2_rx_captured_short_pkt_1_addr; + uint32_t csid_csi2_rx_captured_long_pkt_0_addr; + uint32_t csid_csi2_rx_captured_long_pkt_1_addr; + uint32_t csid_csi2_rx_captured_long_pkt_ftr_addr; + uint32_t csid_csi2_rx_captured_cphy_pkt_hdr_addr; + uint32_t csid_csi2_rx_total_pkts_rcvd_addr; + uint32_t csid_csi2_rx_stats_ecc_addr; //no + uint32_t csid_csi2_rx_total_crc_err_addr; + + /*configurations */ + uint32_t csi2_rst_srb_all; + uint32_t csi2_rst_done_shift_val; + uint32_t csi2_irq_mask_all; + uint32_t csi2_misr_enable_shift_val; + uint32_t csi2_vc_mode_shift_val; + uint32_t csi2_capture_long_pkt_en_shift; + uint32_t csi2_capture_short_pkt_en_shift; + uint32_t csi2_capture_cphy_pkt_en_shift; + uint32_t csi2_capture_long_pkt_dt_shift; + uint32_t csi2_capture_long_pkt_vc_shift; + uint32_t csi2_capture_short_pkt_vc_shift; + uint32_t csi2_capture_cphy_pkt_dt_shift; + uint32_t csi2_capture_cphy_pkt_vc_shift; + uint32_t csi2_rx_phy_num_mask; + uint32_t csi2_rx_long_pkt_hdr_rst_stb_shift; + uint32_t csi2_rx_short_pkt_hdr_rst_stb_shift; +}; + +struct cam_tfe_csid_common_reg_offset { + /* MIPI CSID registers */ + uint32_t csid_hw_version_addr; + uint32_t csid_cfg0_addr; + uint32_t csid_ctrl_addr; + uint32_t csid_rst_strobes_addr; + + uint32_t csid_test_bus_ctrl_addr; + uint32_t csid_top_irq_status_addr; + uint32_t csid_top_irq_mask_addr; + uint32_t csid_top_irq_clear_addr; + uint32_t csid_top_irq_set_addr; + uint32_t csid_irq_cmd_addr; + + /*configurations */ + uint32_t major_version; + uint32_t minor_version; + uint32_t version_incr; + uint32_t num_rdis; + uint32_t num_pix; + uint32_t csid_reg_rst_stb; + uint32_t csid_rst_stb; + uint32_t csid_rst_stb_sw_all; + uint32_t ipp_path_rst_stb_all; + uint32_t rdi_path_rst_stb_all; + uint32_t path_rst_done_shift_val; + uint32_t path_en_shift_val; + uint32_t dt_id_shift_val; + uint32_t vc_shift_val; + uint32_t dt_shift_val; + uint32_t fmt_shift_val; + uint32_t plain_fmt_shit_val; + uint32_t crop_v_en_shift_val; + uint32_t crop_h_en_shift_val; + uint32_t crop_shift; + uint32_t ipp_irq_mask_all; + uint32_t rdi_irq_mask_all; + uint32_t top_tfe2_pix_pipe_fuse_reg; + uint32_t top_tfe2_fuse_reg; +}; + +/** + * struct cam_tfe_csid_reg_offset- CSID instance register info + * + * @cmn_reg: csid common registers info + * @ipp_reg: ipp register offset information + * @ppp_reg: ppp register offset information + * @rdi_reg: rdi register offser information + * + */ +struct cam_tfe_csid_reg_offset { + const struct cam_tfe_csid_common_reg_offset *cmn_reg; + const struct cam_tfe_csid_csi2_rx_reg_offset *csi2_reg; + const struct cam_tfe_csid_pxl_reg_offset *ipp_reg; + const struct cam_tfe_csid_rdi_reg_offset *rdi_reg[CAM_TFE_CSID_RDI_MAX]; +}; + +/** + * struct cam_tfe_csid_hw_info- CSID HW info + * + * @csid_reg: csid register offsets + * @hw_dts_version: HW DTS version + * @csid_max_clk: maximim csid clock + * + */ +struct cam_tfe_csid_hw_info { + const struct cam_tfe_csid_reg_offset *csid_reg; + uint32_t hw_dts_version; + uint32_t csid_max_clk; +}; + +/** + * struct cam_tfe_csid_csi2_rx_cfg- csid csi2 rx configuration data + * @phy_sel: input resource type for sensor only + * @lane_type: lane type: c-phy or d-phy + * @lane_num : active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * + */ +struct cam_tfe_csid_csi2_rx_cfg { + uint32_t phy_sel; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; +}; + +/** + * struct cam_tfe_csid_cid_data- cid configuration private data + * + * @vc: Virtual channel + * @dt: Data type + * @cnt: Cid resource reference count. + * + */ +struct cam_tfe_csid_cid_data { + uint32_t vc; + uint32_t dt; + uint32_t cnt; +}; + +/** + * struct cam_tfe_csid_path_cfg- csid path configuration details. It is stored + * as private data for IPP/ RDI paths + * @vc : Virtual channel number + * @dt : Data type number + * @cid cid number, it is same as DT_ID number in HW + * @in_format: input decode format + * @out_format: output format + * @crop_enable: crop is enable or disabled, if enabled + * then remaining parameters are valid. + * @start_pixel: start pixel + * @end_pixel: end_pixel + * @width: width + * @start_line: start line + * @end_line: end_line + * @height: heigth + * @sync_mode: Applicable for IPP/RDI path reservation + * Reserving the path for master IPP or slave IPP + * master (set value 1), Slave ( set value 2) + * for RDI, set mode to none + * @master_idx: For Slave reservation, Give master TFE instance Index. + * Slave will synchronize with master Start and stop operations + * @clk_rate Clock rate + * @sensor_width Sensor width in pixel + * @sensor_height Sensor height in pixel + * @sensor_fps Sensor fps + * @sensor_hbi Sensor horizontal blanking interval + * @sensor_vbi Sensor vertical blanking interval + * + */ +struct cam_tfe_csid_path_cfg { + uint32_t vc; + uint32_t dt; + uint32_t cid; + uint32_t in_format; + uint32_t out_format; + bool crop_enable; + uint32_t start_pixel; + uint32_t end_pixel; + uint32_t width; + uint32_t start_line; + uint32_t end_line; + uint32_t height; + enum cam_isp_hw_sync_mode sync_mode; + uint32_t master_idx; + uint64_t clk_rate; + uint32_t sensor_width; + uint32_t sensor_height; + uint32_t sensor_fps; + uint32_t sensor_hbi; + uint32_t sensor_vbi; +}; + +/** + * struct cam_tfe_csid_hw- csid hw device resources data + * + * @hw_intf: contain the csid hw interface information + * @hw_info: csid hw device information + * @csid_info: csid hw specific information + * @in_res_id: csid in resource type + * @csi2_rx_cfg: csi2 rx decoder configuration for csid + * @csi2_rx_reserve_cnt: csi2 reservations count value + * @ipp_res: image pixel path resource + * @rdi_res: raw dump image path resources + * @cid_res: cid resources values + * @csid_top_reset_complete: csid top reset completion + * @csid_csi2_reset_complete: csi2 reset completion + * @csid_ipp_reset_complete: ipp reset completion + * @csid_ppp_complete: ppp reset completion + * @csid_rdin_reset_complete: rdi n completion + * @csid_debug: csid debug information to enable the SOT, EOT, + * SOF, EOF, measure etc in the csid hw + * @clk_rate Clock rate + * @sof_irq_triggered: Flag is set on receiving event to enable sof irq + * incase of SOF freeze. + * @irq_debug_cnt: Counter to track sof irq's when above flag is set. + * @error_irq_count Error IRQ count, if continuous error irq comes + * need to stop the CSID and mask interrupts. + * @device_enabled Device enabled will set once CSID powered on and + * initial configuration are done. + * @lock_state csid spin lock + * @event_cb: Callback function to hw mgr in case of hw events + * @event_cb_priv: Context data + * + */ +struct cam_tfe_csid_hw { + struct cam_hw_intf *hw_intf; + struct cam_hw_info *hw_info; + struct cam_tfe_csid_hw_info *csid_info; + uint32_t in_res_id; + struct cam_tfe_csid_csi2_rx_cfg csi2_rx_cfg; + uint32_t csi2_reserve_cnt; + uint32_t pxl_pipe_enable; + struct cam_isp_resource_node ipp_res; + struct cam_isp_resource_node rdi_res[CAM_TFE_CSID_RDI_MAX]; + struct cam_tfe_csid_cid_data cid_res[CAM_TFE_CSID_CID_MAX]; + struct completion csid_top_complete; + struct completion csid_csi2_complete; + struct completion csid_ipp_complete; + struct completion csid_rdin_complete[CAM_TFE_CSID_RDI_MAX]; + uint64_t csid_debug; + uint64_t clk_rate; + bool sof_irq_triggered; + uint32_t irq_debug_cnt; + uint32_t error_irq_count; + uint32_t device_enabled; + spinlock_t spin_lock; + cam_hw_mgr_event_cb_func event_cb; + void *event_cb_priv; +}; + +int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, + uint32_t csid_idx); + +int cam_tfe_csid_hw_deinit(struct cam_tfe_csid_hw *tfe_csid_hw); + +#endif /* _CAM_TFE_CSID_HW_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_dev.c new file mode 100644 index 000000000000..edd391ae9781 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_dev.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include "cam_tfe_csid_core.h" +#include "cam_tfe_csid_dev.h" +#include "cam_tfe_csid_hw_intf.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_tfe_csid_hw_list[CAM_TFE_CSID_HW_NUM_MAX] = { + 0, 0, 0}; + +static char csid_dev_name[8]; + +int cam_tfe_csid_probe(struct platform_device *pdev) +{ + + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + struct cam_tfe_csid_hw *csid_dev = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_tfe_csid_hw_info *csid_hw_data = NULL; + uint32_t csid_dev_idx; + int rc = 0; + + CAM_DBG(CAM_ISP, "probe called"); + + csid_hw_intf = kzalloc(sizeof(*csid_hw_intf), GFP_KERNEL); + if (!csid_hw_intf) { + rc = -ENOMEM; + goto err; + } + + csid_hw_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!csid_hw_info) { + rc = -ENOMEM; + goto free_hw_intf; + } + + csid_dev = kzalloc(sizeof(struct cam_tfe_csid_hw), GFP_KERNEL); + if (!csid_dev) { + rc = -ENOMEM; + goto free_hw_info; + } + + /* get tfe csid hw index */ + of_property_read_u32(pdev->dev.of_node, "cell-index", &csid_dev_idx); + /* get tfe csid hw information */ + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ISP, "No matching table for the tfe csid hw"); + rc = -EINVAL; + goto free_dev; + } + + memset(csid_dev_name, 0, sizeof(csid_dev_name)); + snprintf(csid_dev_name, sizeof(csid_dev_name), + "csid%1u", csid_dev_idx); + + csid_hw_intf->hw_idx = csid_dev_idx; + csid_hw_intf->hw_type = CAM_ISP_HW_TYPE_TFE_CSID; + csid_hw_intf->hw_priv = csid_hw_info; + + csid_hw_info->core_info = csid_dev; + csid_hw_info->soc_info.pdev = pdev; + csid_hw_info->soc_info.dev = &pdev->dev; + csid_hw_info->soc_info.dev_name = csid_dev_name; + csid_hw_info->soc_info.index = csid_dev_idx; + + csid_hw_data = (struct cam_tfe_csid_hw_info *)match_dev->data; + /* need to setup the pdev before call the tfe hw probe init */ + csid_dev->csid_info = csid_hw_data; + + rc = cam_tfe_csid_hw_probe_init(csid_hw_intf, csid_dev_idx); + if (rc) + goto free_dev; + + platform_set_drvdata(pdev, csid_dev); + CAM_DBG(CAM_ISP, "CSID:%d probe successful", + csid_hw_intf->hw_idx); + + if (csid_hw_intf->hw_idx < CAM_TFE_CSID_HW_NUM_MAX) + cam_tfe_csid_hw_list[csid_hw_intf->hw_idx] = csid_hw_intf; + else + goto free_dev; + + return 0; + +free_dev: + kfree(csid_dev); +free_hw_info: + kfree(csid_hw_info); +free_hw_intf: + kfree(csid_hw_intf); +err: + return rc; +} + +int cam_tfe_csid_remove(struct platform_device *pdev) +{ + struct cam_tfe_csid_hw *csid_dev = NULL; + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + + csid_dev = (struct cam_tfe_csid_hw *)platform_get_drvdata(pdev); + csid_hw_intf = csid_dev->hw_intf; + csid_hw_info = csid_dev->hw_info; + + CAM_DBG(CAM_ISP, "CSID:%d remove", + csid_dev->hw_intf->hw_idx); + + cam_tfe_csid_hw_deinit(csid_dev); + + /*release the csid device memory */ + kfree(csid_dev); + kfree(csid_hw_info); + kfree(csid_hw_intf); + return 0; +} + +int cam_tfe_csid_hw_init(struct cam_hw_intf **tfe_csid_hw, + uint32_t hw_idx) +{ + int rc = 0; + + if (cam_tfe_csid_hw_list[hw_idx]) { + *tfe_csid_hw = cam_tfe_csid_hw_list[hw_idx]; + } else { + *tfe_csid_hw = NULL; + rc = -1; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_dev.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_dev.h new file mode 100644 index 000000000000..cca3108fb450 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_dev.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_CSID_DEV_H_ +#define _CAM_TFE_CSID_DEV_H_ + +#include "cam_isp_hw.h" + +irqreturn_t cam_tfe_csid_irq(int irq_num, void *data); + +int cam_tfe_csid_probe(struct platform_device *pdev); +int cam_tfe_csid_remove(struct platform_device *pdev); + +#endif /*_CAM_TFE_CSID_DEV_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c new file mode 100644 index 000000000000..f7d776a7cb5e --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ +#include +#include "cam_tfe_csid_soc.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + + +int cam_tfe_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t csid_irq_handler, void *irq_data) +{ + int rc = 0; + struct cam_cpas_register_params cpas_register_param; + struct cam_tfe_csid_soc_private *soc_private; + + soc_private = kzalloc(sizeof(struct cam_tfe_csid_soc_private), + GFP_KERNEL); + if (!soc_private) + return -ENOMEM; + + soc_info->soc_private = soc_private; + + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + /* Need to see if we want post process the clock list */ + rc = cam_soc_util_request_platform_resource(soc_info, csid_irq_handler, + irq_data); + + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Error Request platform resources failed rc=%d", rc); + goto free_soc_private; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "csid", + CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = soc_info->dev; + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc); + goto release_soc; + } else { + soc_private->cpas_handle = cpas_register_param.client_handle; + } + + return rc; + +release_soc: + cam_soc_util_release_platform_resource(soc_info); +free_soc_private: + kfree(soc_private); + + return rc; +} + +int cam_tfe_csid_deinit_soc_resources( + struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_tfe_csid_soc_private *soc_private; + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -ENODEV; + } + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + + return rc; +} + +int cam_tfe_csid_enable_soc_resources( + struct cam_hw_soc_info *soc_info, enum cam_vote_level clk_level) +{ + int rc = 0; + struct cam_tfe_csid_soc_private *soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + soc_private = soc_info->soc_private; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + + CAM_DBG(CAM_ISP, "csid camnoc_bw:%lld mnoc_ab_bw:%lld mnoc_ib_bw:%lld ", + axi_vote.axi_path[0].camnoc_bw, + axi_vote.axi_path[0].mnoc_ab_bw, + axi_vote.axi_path[0].mnoc_ib_bw); + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_ISP, "Error CPAS start failed"); + rc = -EFAULT; + goto end; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + clk_level, true); + if (rc) { + CAM_ERR(CAM_ISP, "enable platform failed"); + goto stop_cpas; + } + + return rc; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); +end: + return rc; +} + +int cam_tfe_csid_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_tfe_csid_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_ISP, "Disable platform failed"); + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Error CPAS stop failed rc=%d", rc); + return rc; + } + + return rc; +} + +int cam_tfe_csid_enable_tfe_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_tfe_base_offset) +{ + int rc = 0; + struct cam_tfe_csid_soc_private *soc_private; + uint32_t cpass_tfe_force_clk_offset; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + + soc_private = soc_info->soc_private; + cpass_tfe_force_clk_offset = + cpas_tfe_base_offset + (0x4 * soc_info->index); + rc = cam_cpas_reg_write(soc_private->cpas_handle, CAM_CPAS_REG_CPASTOP, + cpass_tfe_force_clk_offset, 1, 1); + + if (rc) + CAM_ERR(CAM_ISP, "CPASS set TFE:%d Force clock On failed", + soc_info->index); + else + CAM_DBG(CAM_ISP, "CPASS set TFE:%d Force clock On", + soc_info->index); + + return rc; +} + +int cam_tfe_csid_disable_tfe_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_tfe_base_offset) +{ + int rc = 0; + struct cam_tfe_csid_soc_private *soc_private; + uint32_t cpass_tfe_force_clk_offset; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + + soc_private = soc_info->soc_private; + cpass_tfe_force_clk_offset = + cpas_tfe_base_offset + (0x4 * soc_info->index); + rc = cam_cpas_reg_write(soc_private->cpas_handle, CAM_CPAS_REG_CPASTOP, + cpass_tfe_force_clk_offset, 1, 0); + + if (rc) + CAM_ERR(CAM_ISP, "CPASS set TFE:%d Force clock Off failed", + soc_info->index); + else + CAM_DBG(CAM_ISP, "CPASS set TFE:%d Force clock off", + soc_info->index); + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.h new file mode 100644 index 000000000000..5da1ff713343 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_CSID_SOC_H_ +#define _CAM_TFE_CSID_SOC_H_ + +#include "cam_isp_hw.h" + +/* + * struct cam_csid_soc_private: + * + * @Brief: Private SOC data specific to CSID HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver. + * This handle is used for all further interface + * with CPAS. + */ +struct cam_tfe_csid_soc_private { + uint32_t cpas_handle; +}; + +/** + * struct csid_device_soc_info - CSID SOC info object + * + * @csi_vdd_voltage: Csi vdd voltage value + * + */ +struct cam_tfe_csid_device_soc_info { + int csi_vdd_voltage; +}; + +/** + * cam_tfe_csid_init_soc_resources() + * + * @brief: Csid initialization function for the soc info + * + * @soc_info: Soc info structure pointer + * @csid_irq_handler: Irq handler function to be registered + * @irq_data: Irq data for the callback function + * + */ +int cam_tfe_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t csid_irq_handler, void *irq_data); + + +/** + * cam_tfe_csid_deinit_soc_resources() + * + * @brief: Csid de initialization function for the soc info + * + * @soc_info: Soc info structure pointer + * + */ +int cam_tfe_csid_deinit_soc_resources(struct cam_hw_soc_info *soc_info); + +/** + * cam_tfe_csid_enable_soc_resources() + * + * @brief: Csid soc resource enable function + * + * @soc_info: Soc info structure pointer + * @clk_lvl: Vote level to start with + * + */ +int cam_tfe_csid_enable_soc_resources(struct cam_hw_soc_info *soc_info, + uint32_t clk_lvl); + +/** + * cam_tfe_csid_disable_soc_resources() + * + * @brief: Csid soc resource disable function + * + * @soc_info: Soc info structure pointer + * + */ +int cam_tfe_csid_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +/** + * cam_tfe_csid_enable_tfe_force_clock() + * + * @brief: If csid testgen used for dual isp case, before + * starting csid test gen, enable tfe force clock on + * through cpas + * + * @soc_info: Soc info structure pointer + * @cpas_tfe_base_offset: Cpas tfe force clock base reg offset value + * + */ +int cam_tfe_csid_enable_tfe_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_tfe_base_offset); + +/** + * cam_tfe_csid_disable_tfe_force_clock_on() + * + * @brief: Disable the TFE force clock on after dual ISP + * CSID test gen stop + * + * @soc_info: Soc info structure pointer + * @cpas_tfe_base_offset: Cpas tfe force clock base reg offset value + * + */ +int cam_tfe_csid_disable_tfe_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_tfe_base_offset); + +/** + * cam_tfe_csid_get_vote_level() + * + * @brief: Get the vote level from clock rate + * + * @soc_info: Soc info structure pointer + * @clock_rate Clock rate + * + */ +uint32_t cam_tfe_csid_get_vote_level(struct cam_hw_soc_info *soc_info, + uint64_t clock_rate); + +#endif /* _CAM_TFE_CSID_SOC_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/Makefile new file mode 100644 index 000000000000..777b5e7fda6a --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_tfe_soc.o cam_tfe_dev.o cam_tfe_core.o cam_tfe_bus.o cam_tfe.o diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe.c new file mode 100644 index 000000000000..4bafa35e905c --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_tfe530.h" +#include "cam_tfe_hw_intf.h" +#include "cam_tfe_core.h" +#include "cam_tfe_dev.h" + +static const struct of_device_id cam_tfe_dt_match[] = { + { + .compatible = "qcom,tfe530", + .data = &cam_tfe530, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_tfe_dt_match); + +static struct platform_driver cam_tfe_driver = { + .probe = cam_tfe_probe, + .remove = cam_tfe_remove, + .driver = { + .name = "cam_tfe", + .of_match_table = cam_tfe_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_tfe_init_module(void) +{ + return platform_driver_register(&cam_tfe_driver); +} + +static void __exit cam_tfe_exit_module(void) +{ + platform_driver_unregister(&cam_tfe_driver); +} + +module_init(cam_tfe_init_module); +module_exit(cam_tfe_exit_module); +MODULE_DESCRIPTION("CAM TFE driver"); +MODULE_LICENSE("GPL v2"); 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 new file mode 100644 index 000000000000..2deb3dd6b835 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe530.h @@ -0,0 +1,813 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_TFE530_H_ +#define _CAM_TFE530_H_ +#include "cam_tfe_core.h" +#include "cam_tfe_bus.h" + + +static struct cam_tfe_top_reg_offset_common tfe530_top_commong_reg = { + .hw_version = 0x00001000, + .hw_capability = 0x00001004, + .lens_feature = 0x00001008, + .stats_feature = 0x0000100C, + .zoom_feature = 0x00001010, + .global_reset_cmd = 0x00001014, + .core_cgc_ctrl = 0x00001018, + .ahb_cgc_ctrl = 0x0000101C, + .core_cfg_0 = 0x00001024, + .core_cfg_1 = 0x00001028, + .reg_update_cmd = 0x0000102C, + .diag_config = 0x00001060, + .diag_sensor_status_0 = 0x00001064, + .diag_sensor_status_1 = 0x00001068, + .diag_sensor_frame_cnt_status = 0x0000106C, + .violation_status = 0x00001070, + .stats_throttle_cnt_cfg_0 = 0x00001074, + .stats_throttle_cnt_cfg_1 = 0x00001078, + .debug_0 = 0x000010A0, + .debug_1 = 0x000010A4, + .debug_2 = 0x000010A8, + .debug_3 = 0x000010AC, + .debug_cfg = 0x000010DC, + .perf_cnt_cfg = 0x000010E0, + .perf_pixel_count = 0x000010E4, + .perf_line_count = 0x000010E8, + .perf_stall_count = 0x000010EC, + .perf_always_count = 0x000010F0, + .perf_count_status = 0x000010F4, +}; + +static struct cam_tfe_camif_reg tfe530_camif_reg = { + .hw_version = 0x00001200, + .hw_status = 0x00001204, + .module_cfg = 0x00001260, + .pdaf_raw_crop_width_cfg = 0x00001268, + .pdaf_raw_crop_height_cfg = 0x0000126C, + .line_skip_pattern = 0x00001270, + .pixel_skip_pattern = 0x00001274, + .period_cfg = 0x00001278, + .irq_subsample_pattern = 0x0000127C, + .epoch_irq_cfg = 0x00001280, + .debug_1 = 0x000013F0, + .debug_0 = 0x000013F4, + .test_bus_ctrl = 0x000013F8, + .spare = 0x000013F8, + .reg_update_cmd = 0x0000102C, +}; + +static struct cam_tfe_camif_reg_data tfe530_camif_reg_data = { + .extern_reg_update_mask = 0x00000001, + .dual_tfe_pix_en_shift = 0x00000001, + .extern_reg_update_shift = 0x0, + .camif_pd_rdi2_src_sel_shift = 0x2, + .dual_tfe_sync_sel_shift = 18, + .pixel_pattern_shift = 24, + .pixel_pattern_mask = 0x7000000, + .module_enable_shift = 0, + .pix_out_enable_shift = 8, + .pdaf_output_enable_shift = 9, + .dsp_mode_shift = 0, + .dsp_mode_mask = 0, + .dsp_en_shift = 0, + .dsp_en_mask = 0, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .epoch1_irq_mask = 0x00000008, + .eof_irq_mask = 0x00000002, + .reg_update_irq_mask = 0x00000001, + .error_irq_mask0 = 0x00010100, + .error_irq_mask2 = 0x00000023, + .subscribe_irq_mask = { + 0x00000000, + 0x00000007, + 0x00000000, + }, + .enable_diagnostic_hw = 0x1, + .perf_cnt_start_cmd_shift = 0, + .perf_cnt_continuous_shift = 2, + .perf_client_sel_shift = 8, + .perf_window_start_shift = 16, + .perf_window_end_shift = 20, +}; + +static struct cam_tfe_rdi_reg tfe530_rdi0_reg = { + .rdi_hw_version = 0x00001400, + .rdi_hw_status = 0x00001404, + .rdi_module_config = 0x00001460, + .rdi_skip_period = 0x00001468, + .rdi_irq_subsample_pattern = 0x0000146C, + .rdi_epoch_irq = 0x00001470, + .rdi_debug_1 = 0x000015F0, + .rdi_debug_0 = 0x000015F4, + .rdi_test_bus_ctrl = 0x000015F8, + .rdi_spare = 0x000015FC, + .reg_update_cmd = 0x0000102C, +}; + +static struct cam_tfe_rdi_reg_data tfe530_rdi0_reg_data = { + .reg_update_cmd_data = 0x2, + .epoch_line_cfg = 0x00140014, + .pixel_pattern_shift = 24, + .pixel_pattern_mask = 0x07000000, + .rdi_out_enable_shift = 0, + + .sof_irq_mask = 0x00000010, + .epoch0_irq_mask = 0x00000040, + .epoch1_irq_mask = 0x00000080, + .eof_irq_mask = 0x00000020, + .error_irq_mask0 = 0x00020200, + .error_irq_mask2 = 0x00000004, + .subscribe_irq_mask = { + 0x00000000, + 0x00000030, + 0x00000000, + }, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_tfe_rdi_reg tfe530_rdi1_reg = { + .rdi_hw_version = 0x00001600, + .rdi_hw_status = 0x00001604, + .rdi_module_config = 0x00001660, + .rdi_skip_period = 0x00001668, + .rdi_irq_subsample_pattern = 0x0000166C, + .rdi_epoch_irq = 0x00001670, + .rdi_debug_1 = 0x000017F0, + .rdi_debug_0 = 0x000017F4, + .rdi_test_bus_ctrl = 0x000017F8, + .rdi_spare = 0x000017FC, + .reg_update_cmd = 0x0000102C, +}; + +static struct cam_tfe_rdi_reg_data tfe530_rdi1_reg_data = { + .reg_update_cmd_data = 0x4, + .epoch_line_cfg = 0x00140014, + .pixel_pattern_shift = 24, + .pixel_pattern_mask = 0x07000000, + .rdi_out_enable_shift = 0, + + .sof_irq_mask = 0x00000100, + .epoch0_irq_mask = 0x00000400, + .epoch1_irq_mask = 0x00000800, + .eof_irq_mask = 0x00000200, + .error_irq_mask0 = 0x00040400, + .error_irq_mask2 = 0x00000008, + .subscribe_irq_mask = { + 0x00000000, + 0x00000300, + 0x00000000, + }, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_tfe_rdi_reg tfe530_rdi2_reg = { + .rdi_hw_version = 0x00001800, + .rdi_hw_status = 0x00001804, + .rdi_module_config = 0x00001860, + .rdi_skip_period = 0x00001868, + .rdi_irq_subsample_pattern = 0x0000186C, + .rdi_epoch_irq = 0x00001870, + .rdi_debug_1 = 0x000019F0, + .rdi_debug_0 = 0x000019F4, + .rdi_test_bus_ctrl = 0x000019F8, + .rdi_spare = 0x000019FC, + .reg_update_cmd = 0x0000102C, +}; + +static struct cam_tfe_rdi_reg_data tfe530_rdi2_reg_data = { + .reg_update_cmd_data = 0x8, + .epoch_line_cfg = 0x00140014, + .pixel_pattern_shift = 24, + .pixel_pattern_mask = 0x07000000, + .rdi_out_enable_shift = 0, + + .sof_irq_mask = 0x00001000, + .epoch0_irq_mask = 0x00004000, + .epoch1_irq_mask = 0x00008000, + .eof_irq_mask = 0x00002000, + .error_irq_mask0 = 0x00080800, + .error_irq_mask2 = 0x00000004, + .subscribe_irq_mask = { + 0x00000000, + 0x00003000, + 0x00000000, + }, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_tfe_top_hw_info tfe530_top_hw_info = { + .common_reg = &tfe530_top_commong_reg, + .camif_hw_info = { + .camif_reg = &tfe530_camif_reg, + .reg_data = &tfe530_camif_reg_data, + }, + .rdi_hw_info = { + { + .rdi_reg = &tfe530_rdi0_reg, + .reg_data = &tfe530_rdi0_reg_data, + }, + { + .rdi_reg = &tfe530_rdi1_reg, + .reg_data = &tfe530_rdi1_reg_data, + }, + { + .rdi_reg = &tfe530_rdi2_reg, + .reg_data = &tfe530_rdi2_reg_data, + }, + }, + .in_port = { + CAM_TFE_CAMIF_VER_1_0, + CAM_TFE_RDI_VER_1_0, + CAM_TFE_RDI_VER_1_0, + CAM_TFE_RDI_VER_1_0 + }, + .reg_dump_data = { + .num_reg_dump_entries = 19, + .num_lut_dump_entries = 0, + .bus_start_addr = 0x2000, + .bus_write_top_end_addr = 0x2120, + .bus_client_start_addr = 0x2200, + .bus_client_offset = 0x100, + .num_bus_clients = 10, + .reg_entry = { + { + .start_offset = 0x1000, + .end_offset = 0x10F4, + }, + { + .start_offset = 0x1260, + .end_offset = 0x1280, + }, + { + .start_offset = 0x13F0, + .end_offset = 0x13FC, + }, + { + .start_offset = 0x1460, + .end_offset = 0x1470, + }, + { + .start_offset = 0x15F0, + .end_offset = 0x15FC, + }, + { + .start_offset = 0x1660, + .end_offset = 0x1670, + }, + { + .start_offset = 0x17F0, + .end_offset = 0x17FC, + }, + { + .start_offset = 0x1860, + .end_offset = 0x1870, + }, + { + .start_offset = 0x19F0, + .end_offset = 0x19FC, + }, + { + .start_offset = 0x2660, + .end_offset = 0x2694, + }, + { + .start_offset = 0x2860, + .end_offset = 0x2884, + }, + { + .start_offset = 0x2A60, + .end_offset = 0X2B34, + }, + { + .start_offset = 0x2C60, + .end_offset = 0X2C80, + }, + { + .start_offset = 0x2E60, + .end_offset = 0X2E7C, + }, + { + .start_offset = 0x3060, + .end_offset = 0X3110, + }, + { + .start_offset = 0x3260, + .end_offset = 0X3278, + }, + { + .start_offset = 0x3460, + .end_offset = 0X3478, + }, + { + .start_offset = 0x3660, + .end_offset = 0X3684, + }, + { + .start_offset = 0x3860, + .end_offset = 0X3884, + }, + }, + .lut_entry = { + { + .lut_word_size = 1, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + .dmi_reg_offset = 0x2800, + }, + { + .lut_word_size = 1, + .lut_bank_sel = 0x41, + .lut_addr_size = 180, + .dmi_reg_offset = 0x3000, + }, + }, + }, +}; + +static struct cam_tfe_bus_hw_info tfe530_bus_hw_info = { + .common_reg = { + .hw_version = 0x00001A00, + .cgc_ovd = 0x00001A08, + .comp_cfg_0 = 0x00001A0C, + .comp_cfg_1 = 0x00001A10, + .frameheader_cfg = { + 0x00001A34, + 0x00001A38, + 0x00001A3C, + 0x00001A40, + }, + .pwr_iso_cfg = 0x00001A5C, + .overflow_status_clear = 0x00001A60, + .ccif_violation_status = 0x00001A64, + .overflow_status = 0x00001A68, + .image_size_violation_status = 0x00001A70, + .perf_count_cfg = { + 0x00001A74, + 0x00001A78, + 0x00001A7C, + 0x00001A80, + 0x00001A84, + 0x00001A88, + 0x00001A8C, + 0x00001A90, + }, + .perf_count_val = { + 0x00001A94, + 0x00001A98, + 0x00001A9C, + 0x00001AA0, + 0x00001AA4, + 0x00001AA8, + 0x00001AAC, + 0x00001AB0, + }, + .perf_count_status = 0x00001AB4, + .debug_status_top_cfg = 0x00001AD4, + .debug_status_top = 0x00001AD8, + .test_bus_ctrl = 0x00001ADC, + .irq_mask = { + 0x00001A18, + 0x00001A1C, + }, + .irq_clear = { + 0x00001A20, + 0x00001A24, + }, + .irq_status = { + 0x00001A28, + 0x00001A2C, + }, + .irq_cmd = 0x00001A30, + }, + .num_client = CAM_TFE_BUS_MAX_CLIENTS, + .bus_client_reg = { + /* BUS Client 0 BAYER */ + { + .cfg = 0x00001C00, + .image_addr = 0x00001C04, + .frame_incr = 0x00001C08, + .image_cfg_0 = 0x00001C0C, + .image_cfg_1 = 0x00001C10, + .image_cfg_2 = 0x00001C14, + .packer_cfg = 0x00001C18, + .bw_limit = 0x00001C1C, + .frame_header_addr = 0x00001C20, + .frame_header_incr = 0x00001C24, + .frame_header_cfg = 0x00001C28, + .line_done_cfg = 0x00000000, + .irq_subsample_period = 0x00001C30, + .irq_subsample_pattern = 0x00001C34, + .framedrop_period = 0x00001C38, + .framedrop_pattern = 0x00001C3C, + .addr_status_0 = 0x00001C68, + .addr_status_1 = 0x00001C6C, + .addr_status_2 = 0x00001C70, + .addr_status_3 = 0x00001C74, + .debug_status_cfg = 0x00001C78, + .debug_status_0 = 0x00001C7C, + .debug_status_1 = 0x00001C80, + .comp_group = CAM_TFE_BUS_COMP_GRP_0, + }, + /* BUS Client 1 IDEAL RAW*/ + { + .cfg = 0x00001D00, + .image_addr = 0x00001D04, + .frame_incr = 0x00001D08, + .image_cfg_0 = 0x00001D0C, + .image_cfg_1 = 0x00001D10, + .image_cfg_2 = 0x00001D14, + .packer_cfg = 0x00001D18, + .bw_limit = 0x00001D1C, + .frame_header_addr = 0x00001D20, + .frame_header_incr = 0x00001D24, + .frame_header_cfg = 0x00001D28, + .line_done_cfg = 0x00000000, + .irq_subsample_period = 0x00001D30, + .irq_subsample_pattern = 0x00001D34, + .framedrop_period = 0x00001D38, + .framedrop_pattern = 0x00001D3C, + .addr_status_0 = 0x00001D68, + .addr_status_1 = 0x00001D6C, + .addr_status_2 = 0x00001D70, + .addr_status_3 = 0x00001D74, + .debug_status_cfg = 0x00001D78, + .debug_status_0 = 0x00001D7C, + .debug_status_1 = 0x00001D80, + .comp_group = CAM_TFE_BUS_COMP_GRP_1, + }, + /* BUS Client 2 Stats BE Tintless */ + { + .cfg = 0x00001E00, + .image_addr = 0x00001E04, + .frame_incr = 0x00001E08, + .image_cfg_0 = 0x00001E0C, + .image_cfg_1 = 0x00001E10, + .image_cfg_2 = 0x00001E14, + .packer_cfg = 0x00001E18, + .bw_limit = 0x00001E1C, + .frame_header_addr = 0x00001E20, + .frame_header_incr = 0x00001E24, + .frame_header_cfg = 0x00001E28, + .line_done_cfg = 0x00001E00, + .irq_subsample_period = 0x00001E30, + .irq_subsample_pattern = 0x00000E34, + .framedrop_period = 0x00001E38, + .framedrop_pattern = 0x00001E3C, + .addr_status_0 = 0x00001E68, + .addr_status_1 = 0x00001E6C, + .addr_status_2 = 0x00001E70, + .addr_status_3 = 0x00001E74, + .debug_status_cfg = 0x00001E78, + .debug_status_0 = 0x00001E7C, + .debug_status_1 = 0x00001E80, + .comp_group = CAM_TFE_BUS_COMP_GRP_2, + }, + /* BUS Client 3 Stats Bhist */ + { + .cfg = 0x00001F00, + .image_addr = 0x00001F04, + .frame_incr = 0x00001F08, + .image_cfg_0 = 0x00001F0C, + .image_cfg_1 = 0x00001F10, + .image_cfg_2 = 0x00001F14, + .packer_cfg = 0x00001F18, + .bw_limit = 0x00001F1C, + .frame_header_addr = 0x00001F20, + .frame_header_incr = 0x00001F24, + .frame_header_cfg = 0x00001F28, + .line_done_cfg = 0x00000000, + .irq_subsample_period = 0x00001F30, + .irq_subsample_pattern = 0x00001F34, + .framedrop_period = 0x00001F38, + .framedrop_pattern = 0x00001F3C, + .addr_status_0 = 0x00001F68, + .addr_status_1 = 0x00001F6C, + .addr_status_2 = 0x00001F70, + .addr_status_3 = 0x00001F74, + .debug_status_cfg = 0x00001F78, + .debug_status_0 = 0x00001F7C, + .debug_status_1 = 0x00001F80, + .comp_group = CAM_TFE_BUS_COMP_GRP_2, + }, + /* BUS Client 4 Stats AWB BG */ + { + .cfg = 0x00002000, + .image_addr = 0x00002004, + .frame_incr = 0x00002008, + .image_cfg_0 = 0x0000200C, + .image_cfg_1 = 0x00002010, + .image_cfg_2 = 0x00002014, + .packer_cfg = 0x00002018, + .bw_limit = 0x0000201C, + .frame_header_addr = 0x00002020, + .frame_header_incr = 0x00002024, + .frame_header_cfg = 0x00002028, + .line_done_cfg = 0x00000000, + .irq_subsample_period = 0x00002030, + .irq_subsample_pattern = 0x00002034, + .framedrop_period = 0x00002038, + .framedrop_pattern = 0x0000203C, + .addr_status_0 = 0x00002068, + .addr_status_1 = 0x0000206C, + .addr_status_2 = 0x00002070, + .addr_status_3 = 0x00002074, + .debug_status_cfg = 0x00002078, + .debug_status_0 = 0x0000207C, + .debug_status_1 = 0x00002080, + .comp_group = CAM_TFE_BUS_COMP_GRP_3, + }, + /* BUS Client 5 Stats AEC BG */ + { + .cfg = 0x00002100, + .image_addr = 0x00002104, + .frame_incr = 0x00002108, + .image_cfg_0 = 0x0000210C, + .image_cfg_1 = 0x00002110, + .image_cfg_2 = 0x00002114, + .packer_cfg = 0x00002118, + .bw_limit = 0x0000211C, + .frame_header_addr = 0x00002120, + .frame_header_incr = 0x00002124, + .frame_header_cfg = 0x00002128, + .line_done_cfg = 0x00000000, + .irq_subsample_period = 0x00002130, + .irq_subsample_pattern = 0x00002134, + .framedrop_period = 0x00002138, + .framedrop_pattern = 0x0000213C, + .addr_status_0 = 0x00002168, + .addr_status_1 = 0x0000216C, + .addr_status_2 = 0x00002170, + .addr_status_3 = 0x00002174, + .debug_status_cfg = 0x00002178, + .debug_status_0 = 0x0000217C, + .debug_status_1 = 0x00002180, + .comp_group = CAM_TFE_BUS_COMP_GRP_3, + }, + /* BUS Client 6 Stats BAF */ + { + .cfg = 0x00002200, + .image_addr = 0x00002204, + .frame_incr = 0x00002208, + .image_cfg_0 = 0x0000220C, + .image_cfg_1 = 0x00002210, + .image_cfg_2 = 0x00002214, + .packer_cfg = 0x00002218, + .bw_limit = 0x0000221C, + .frame_header_addr = 0x00002220, + .frame_header_incr = 0x00002224, + .frame_header_cfg = 0x00002228, + .line_done_cfg = 0x00000000, + .irq_subsample_period = 0x00002230, + .irq_subsample_pattern = 0x00002234, + .framedrop_period = 0x00002238, + .framedrop_pattern = 0x0000223C, + .addr_status_0 = 0x00002268, + .addr_status_1 = 0x0000226C, + .addr_status_2 = 0x00002270, + .addr_status_3 = 0x00002274, + .debug_status_cfg = 0x00002278, + .debug_status_0 = 0x0000227C, + .debug_status_1 = 0x00002280, + .comp_group = CAM_TFE_BUS_COMP_GRP_4, + }, + /* BUS Client 7 RDI0 */ + { + .cfg = 0x00002300, + .image_addr = 0x00002304, + .frame_incr = 0x00002308, + .image_cfg_0 = 0x0000230C, + .image_cfg_1 = 0x00002310, + .image_cfg_2 = 0x00002314, + .packer_cfg = 0x00002318, + .bw_limit = 0x0000231C, + .frame_header_addr = 0x00002320, + .frame_header_incr = 0x00002324, + .frame_header_cfg = 0x00002328, + .line_done_cfg = 0x00000000, + .irq_subsample_period = 0x00002330, + .irq_subsample_pattern = 0x00002334, + .framedrop_period = 0x00002338, + .framedrop_pattern = 0x0000233C, + .addr_status_0 = 0x00002368, + .addr_status_1 = 0x0000236C, + .addr_status_2 = 0x00002370, + .addr_status_3 = 0x00002374, + .debug_status_cfg = 0x00002378, + .debug_status_0 = 0x0000237C, + .debug_status_1 = 0x00002380, + .comp_group = CAM_TFE_BUS_COMP_GRP_5, + }, + /* BUS Client 8 RDI1 */ + { + .cfg = 0x00002400, + .image_addr = 0x00002404, + .frame_incr = 0x00002408, + .image_cfg_0 = 0x0000240C, + .image_cfg_1 = 0x00002410, + .image_cfg_2 = 0x00002414, + .packer_cfg = 0x00002418, + .bw_limit = 0x0000241C, + .frame_header_addr = 0x00002420, + .frame_header_incr = 0x00002424, + .frame_header_cfg = 0x00002428, + .line_done_cfg = 0x00000000, + .irq_subsample_period = 0x00002430, + .irq_subsample_pattern = 0x00002434, + .framedrop_period = 0x00002438, + .framedrop_pattern = 0x0000243C, + .addr_status_0 = 0x00002468, + .addr_status_1 = 0x0000246C, + .addr_status_2 = 0x00002470, + .addr_status_3 = 0x00002474, + .debug_status_cfg = 0x00002478, + .debug_status_0 = 0x0000247C, + .debug_status_1 = 0x00002480, + .comp_group = CAM_TFE_BUS_COMP_GRP_6, + }, + /* BUS Client 9 PDAF/RDI2*/ + { + .cfg = 0x00002500, + .image_addr = 0x00002504, + .frame_incr = 0x00002508, + .image_cfg_0 = 0x0000250C, + .image_cfg_1 = 0x00002510, + .image_cfg_2 = 0x00002514, + .packer_cfg = 0x00002518, + .bw_limit = 0x0000251C, + .frame_header_addr = 0x00002520, + .frame_header_incr = 0x00002524, + .frame_header_cfg = 0x00002528, + .line_done_cfg = 0x00000000, + .irq_subsample_period = 0x00002530, + .irq_subsample_pattern = 0x00002534, + .framedrop_period = 0x00002538, + .framedrop_pattern = 0x0000253C, + .addr_status_0 = 0x00002568, + .addr_status_1 = 0x0000256C, + .addr_status_2 = 0x00002570, + .addr_status_3 = 0x00002574, + .debug_status_cfg = 0x00002578, + .debug_status_0 = 0x0000257C, + .debug_status_1 = 0x00002580, + .comp_group = CAM_TFE_BUS_COMP_GRP_7, + }, + }, + .num_out = CAM_TFE_BUS_TFE_OUT_MAX, + .tfe_out_hw_info = { + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + .composite_group = CAM_TFE_BUS_COMP_GRP_5, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_1, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + .composite_group = CAM_TFE_BUS_COMP_GRP_6, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_2, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + .composite_group = CAM_TFE_BUS_COMP_GRP_7, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_3, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + .composite_group = CAM_TFE_BUS_COMP_GRP_0, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_0, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_RAW_DUMP, + .max_width = 4096, + .max_height = 4096, + .composite_group = CAM_TFE_BUS_COMP_GRP_1, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_0, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_PDAF, + .max_width = 4096, + .max_height = 4096, + .composite_group = CAM_TFE_BUS_COMP_GRP_7, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_3, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + .composite_group = CAM_TFE_BUS_COMP_GRP_3, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_0, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_STATS_HDR_BHIST, + .max_width = -1, + .max_height = -1, + .composite_group = CAM_TFE_BUS_COMP_GRP_2, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_0, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + .composite_group = CAM_TFE_BUS_COMP_GRP_2, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_0, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + .composite_group = CAM_TFE_BUS_COMP_GRP_3, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_0, + }, + { + .tfe_out_id = CAM_TFE_BUS_TFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + .composite_group = CAM_TFE_BUS_COMP_GRP_4, + .rup_group_id = CAM_TFE_BUS_RUP_GRP_0, + }, + }, + .comp_done_shift = 8, + .top_bus_wr_irq_shift = 1, + .comp_buf_done_mask = 0xFF00, + .comp_rup_done_mask = 0xF, + .bus_irq_error_mask = { + 0xD0000000, + 0x00000000, + }, +}; + +struct cam_tfe_hw_info cam_tfe530 = { + .top_irq_mask = { + 0x00001034, + 0x00001038, + 0x0000103C, + }, + .top_irq_clear = { + 0x00001040, + 0x00001044, + 0x00001048, + }, + .top_irq_status = { + 0x0000104C, + 0x00001050, + 0x00001054, + }, + .top_irq_cmd = 0x00001030, + .global_clear_bitmask = 0x00000001, + + .bus_irq_mask = { + 0x00001A18, + 0x00001A1C, + }, + .bus_irq_clear = { + 0x00001A20, + 0x00001A24, + }, + .bus_irq_status = { + 0x00001A28, + 0x00001A2C, + }, + .bus_irq_cmd = 0x00001A30, + .bus_violation_reg = 0x00001A64, + .bus_overflow_reg = 0x00001A68, + .bus_image_size_vilation_reg = 0x1A70, + .bus_overflow_clear_cmd = 0x1A60, + .debug_status_top = 0x1AD8, + + .reset_irq_mask = { + 0x00000001, + 0x00000000, + 0x00000000, + }, + .error_irq_mask = { + 0x000F0F00, + 0x00000000, + 0x0000003F, + }, + .bus_reg_irq_mask = { + 0x00000002, + 0x00000000, + 0x00000000, + }, + + .bus_version = CAM_TFE_BUS_1_0, + .bus_hw_info = &tfe530_bus_hw_info, + + .top_version = CAM_TFE_TOP_1_0, + .top_hw_info = &tfe530_top_hw_info, +}; + +#endif /* _CAM_TFE530_H_ */ 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 new file mode 100644 index 000000000000..fdb7ed7eb12d --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c @@ -0,0 +1,2149 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_hw_intf.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_tfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_tfe_bus.h" +#include "cam_tfe_irq.h" +#include "cam_tfe_soc.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + + +static const char drv_name[] = "tfe_bus"; + +#define CAM_TFE_BUS_IRQ_REG0 0 +#define CAM_TFE_BUS_IRQ_REG1 1 + +#define CAM_TFE_BUS_PAYLOAD_MAX 256 + +#define CAM_TFE_RDI_BUS_DEFAULT_WIDTH 0xFFFF +#define CAM_TFE_RDI_BUS_DEFAULT_STRIDE 0xFFFF + +#define CAM_TFE_MAX_OUT_RES_PER_COMP_GRP 2 + +#define MAX_BUF_UPDATE_REG_NUM \ + (sizeof(struct cam_tfe_bus_reg_offset_bus_client) / 4) +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +enum cam_tfe_bus_packer_format { + PACKER_FMT_PLAIN_128, + PACKER_FMT_PLAIN_8, + PACKER_FMT_PLAIN_8_ODD_EVEN, + PACKER_FMT_PLAIN_8_LSB_MSB_10, + PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN, + PACKER_FMT_PLAIN_16_10BPP, + PACKER_FMT_PLAIN_16_12BPP, + PACKER_FMT_PLAIN_16_14BPP, + PACKER_FMT_PLAIN_16_16BPP, + PACKER_FMT_PLAIN_32, + PACKER_FMT_PLAIN_64, + PACKER_FMT_TP_10, + PACKET_FMT_MIPI10, + PACKET_FMT_MIPI12, + PACKER_FMT_MAX, +}; + +struct cam_tfe_bus_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *tfe_core_data; + struct cam_tfe_bus_reg_offset_common *common_reg; + uint32_t io_buf_update[MAX_REG_VAL_PAIR_SIZE]; + + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t comp_done_shift; + bool is_lite; + cam_hw_mgr_event_cb_func event_cb; + bool rup_irq_enable[CAM_TFE_BUS_RUP_GRP_MAX]; +}; + +struct cam_tfe_bus_wm_resource_data { + uint32_t index; + struct cam_tfe_bus_common_data *common_data; + struct cam_tfe_bus_reg_offset_bus_client *hw_regs; + + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t pack_fmt; + uint32_t burst_len; + + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + + uint32_t en_cfg; + uint32_t is_dual; +}; + +struct cam_tfe_bus_comp_grp_data { + enum cam_tfe_bus_comp_grp_id comp_grp_id; + struct cam_tfe_bus_common_data *common_data; + + uint32_t is_master; + uint32_t is_dual; + uint32_t addr_sync_mode; + uint32_t composite_mask; + + uint32_t acquire_dev_cnt; + uint32_t source_grp; + + struct cam_isp_resource_node + *out_rsrc[CAM_TFE_MAX_OUT_RES_PER_COMP_GRP]; +}; + +struct cam_tfe_bus_tfe_out_data { + uint32_t out_id; + uint32_t composite_group; + uint32_t rup_group_id; + uint32_t source_group; + struct cam_tfe_bus_common_data *common_data; + + uint32_t num_wm; + struct cam_isp_resource_node *wm_res[PLANE_MAX]; + + struct cam_isp_resource_node *comp_grp; + struct list_head tfe_out_list; + + uint32_t is_master; + uint32_t is_dual; + + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + uint32_t secure_mode; + void *priv; + cam_hw_mgr_event_cb_func event_cb; +}; + +struct cam_tfe_bus_priv { + struct cam_tfe_bus_common_data common_data; + uint32_t num_client; + uint32_t num_out; + uint32_t top_bus_wr_irq_shift; + + struct cam_isp_resource_node bus_client[CAM_TFE_BUS_MAX_CLIENTS]; + struct cam_isp_resource_node comp_grp[CAM_TFE_BUS_COMP_GRP_MAX]; + struct cam_isp_resource_node tfe_out[CAM_TFE_BUS_TFE_OUT_MAX]; + + struct list_head free_comp_grp; + struct list_head used_comp_grp; + + void *tasklet_info; + uint32_t comp_buf_done_mask; + uint32_t comp_rup_done_mask; + uint32_t bus_irq_error_mask[CAM_TFE_BUS_IRQ_REGISTERS_MAX]; +}; + +static bool cam_tfe_bus_can_be_secure(uint32_t out_id) +{ + switch (out_id) { + case CAM_TFE_BUS_TFE_OUT_FULL: + case CAM_TFE_BUS_TFE_OUT_RAW_DUMP: + case CAM_TFE_BUS_TFE_OUT_RDI0: + case CAM_TFE_BUS_TFE_OUT_RDI1: + case CAM_TFE_BUS_TFE_OUT_RDI2: + return true; + + case CAM_TFE_BUS_TFE_OUT_STATS_HDR_BE: + case CAM_TFE_BUS_TFE_OUT_STATS_HDR_BHIST: + case CAM_TFE_BUS_TFE_OUT_STATS_TL_BG: + case CAM_TFE_BUS_TFE_OUT_STATS_BF: + case CAM_TFE_BUS_TFE_OUT_STATS_AWB_BG: + default: + return false; + } +} + +static enum cam_tfe_bus_tfe_out_id + cam_tfe_bus_get_out_res_id(uint32_t out_res_id) +{ + switch (out_res_id) { + case CAM_ISP_TFE_OUT_RES_FULL: + return CAM_TFE_BUS_TFE_OUT_FULL; + case CAM_ISP_TFE_OUT_RES_RAW_DUMP: + return CAM_TFE_BUS_TFE_OUT_RAW_DUMP; + case CAM_ISP_TFE_OUT_RES_PDAF: + return CAM_TFE_BUS_TFE_OUT_PDAF; + case CAM_ISP_TFE_OUT_RES_RDI_0: + return CAM_TFE_BUS_TFE_OUT_RDI0; + case CAM_ISP_TFE_OUT_RES_RDI_1: + return CAM_TFE_BUS_TFE_OUT_RDI1; + case CAM_ISP_TFE_OUT_RES_RDI_2: + return CAM_TFE_BUS_TFE_OUT_RDI2; + case CAM_ISP_TFE_OUT_RES_STATS_HDR_BE: + return CAM_TFE_BUS_TFE_OUT_STATS_HDR_BE; + case CAM_ISP_TFE_OUT_RES_STATS_HDR_BHIST: + return CAM_TFE_BUS_TFE_OUT_STATS_HDR_BHIST; + case CAM_ISP_TFE_OUT_RES_STATS_TL_BG: + return CAM_TFE_BUS_TFE_OUT_STATS_TL_BG; + case CAM_ISP_TFE_OUT_RES_STATS_BF: + return CAM_TFE_BUS_TFE_OUT_STATS_BF; + case CAM_ISP_TFE_OUT_RES_STATS_AWB_BG: + return CAM_TFE_BUS_TFE_OUT_STATS_AWB_BG; + default: + return CAM_TFE_BUS_TFE_OUT_MAX; + } +} + +static int cam_tfe_bus_get_num_wm( + enum cam_tfe_bus_tfe_out_id out_res_id, + uint32_t format) +{ + switch (out_res_id) { + case CAM_TFE_BUS_TFE_OUT_RDI0: + case CAM_TFE_BUS_TFE_OUT_RDI1: + case CAM_TFE_BUS_TFE_OUT_RDI2: + switch (format) { + 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_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN128: + return 1; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_PDAF: + switch (format) { + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + return 1; + default: + break; + } + break; + + case CAM_TFE_BUS_TFE_OUT_FULL: + switch (format) { + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + return 1; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_RAW_DUMP: + switch (format) { + case CAM_FORMAT_ARGB_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + return 1; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_STATS_HDR_BE: + case CAM_TFE_BUS_TFE_OUT_STATS_HDR_BHIST: + case CAM_TFE_BUS_TFE_OUT_STATS_TL_BG: + case CAM_TFE_BUS_TFE_OUT_STATS_BF: + case CAM_TFE_BUS_TFE_OUT_STATS_AWB_BG: + switch (format) { + case CAM_FORMAT_PLAIN64: + return 1; + default: + break; + } + break; + default: + break; + } + + CAM_ERR(CAM_ISP, "Unsupported format %u for resource id %u", + format, out_res_id); + + return -EINVAL; +} + +static int cam_tfe_bus_get_wm_idx( + enum cam_tfe_bus_tfe_out_id tfe_out_res_id, + enum cam_tfe_bus_plane_type plane) +{ + int wm_idx = -1; + + switch (tfe_out_res_id) { + case CAM_TFE_BUS_TFE_OUT_RDI0: + switch (plane) { + case PLANE_Y: + wm_idx = 7; + break; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_RDI1: + switch (plane) { + case PLANE_Y: + wm_idx = 8; + break; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_RDI2: + switch (plane) { + case PLANE_Y: + wm_idx = 9; + break; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_PDAF: + switch (plane) { + case PLANE_Y: + wm_idx = 9; + break; + default: + break; + } + break; + + case CAM_TFE_BUS_TFE_OUT_FULL: + switch (plane) { + case PLANE_Y: + wm_idx = 0; + break; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_RAW_DUMP: + switch (plane) { + case PLANE_Y: + wm_idx = 1; + break; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_STATS_HDR_BE: + switch (plane) { + case PLANE_Y: + wm_idx = 5; + break; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_STATS_HDR_BHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 3; + break; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_STATS_AWB_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 4; + break; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_STATS_TL_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 2; + break; + default: + break; + } + break; + case CAM_TFE_BUS_TFE_OUT_STATS_BF: + switch (plane) { + case PLANE_Y: + wm_idx = 6; + break; + default: + break; + } + break; + + default: + break; + } + + return wm_idx; +} + +static enum cam_tfe_bus_packer_format + cam_tfe_bus_get_packer_fmt(uint32_t out_fmt, int wm_index) +{ + switch (out_fmt) { + 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_MIPI_RAW_20: + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PD8: + return PACKER_FMT_PLAIN_128; + case CAM_FORMAT_PLAIN8: + return PACKER_FMT_PLAIN_8; + case CAM_FORMAT_Y_ONLY: + return PACKER_FMT_PLAIN_8_LSB_MSB_10; + case CAM_FORMAT_PLAIN16_10: + return PACKER_FMT_PLAIN_16_10BPP; + case CAM_FORMAT_PLAIN16_12: + return PACKER_FMT_PLAIN_16_12BPP; + case CAM_FORMAT_PLAIN16_14: + return PACKER_FMT_PLAIN_16_14BPP; + case CAM_FORMAT_PLAIN16_16: + return PACKER_FMT_PLAIN_16_16BPP; + case CAM_FORMAT_ARGB: + return PACKER_FMT_PLAIN_32; + case CAM_FORMAT_PLAIN64: + case CAM_FORMAT_PD10: + return PACKER_FMT_PLAIN_64; + case CAM_FORMAT_TP10: + return PACKER_FMT_TP_10; + default: + return PACKER_FMT_MAX; + } +} + +static int cam_tfe_bus_acquire_wm( + struct cam_tfe_bus_priv *bus_priv, + struct cam_isp_tfe_out_port_info *out_port_info, + struct cam_isp_resource_node **wm_res, + void *tasklet, + enum cam_tfe_bus_tfe_out_id tfe_out_res_id, + enum cam_tfe_bus_plane_type plane, + uint32_t *client_done_mask, + uint32_t is_dual, + enum cam_tfe_bus_comp_grp_id *comp_grp_id) +{ + struct cam_isp_resource_node *wm_res_local = NULL; + struct cam_tfe_bus_wm_resource_data *rsrc_data = NULL; + uint32_t wm_idx = 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) { + CAM_ERR(CAM_ISP, "Unsupported TFE out %d plane %d", + tfe_out_res_id, plane); + return -EINVAL; + } + + wm_res_local = &bus_priv->bus_client[wm_idx]; + if (wm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "WM:%d not available state:%d", + wm_idx, wm_res_local->res_state); + return -EALREADY; + } + wm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + wm_res_local->tasklet_info = tasklet; + + rsrc_data = wm_res_local->res_priv; + rsrc_data->format = out_port_info->format; + rsrc_data->pack_fmt = cam_tfe_bus_get_packer_fmt(rsrc_data->format, + wm_idx); + + rsrc_data->width = out_port_info->width; + rsrc_data->height = out_port_info->height; + rsrc_data->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; + } + } else if (rsrc_data->index == 0) { + /* WM 0 FULL_OUT */ + switch (rsrc_data->format) { + case CAM_FORMAT_MIPI_RAW_8: + rsrc_data->pack_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_10: + rsrc_data->pack_fmt = 0xc; + break; + case CAM_FORMAT_MIPI_RAW_12: + rsrc_data->pack_fmt = 0xd; + break; + case CAM_FORMAT_PLAIN8: + rsrc_data->pack_fmt = 0x1; + break; + case CAM_FORMAT_PLAIN16_10: + rsrc_data->pack_fmt = 0x5; + rsrc_data->pack_fmt |= 0x10; + break; + case CAM_FORMAT_PLAIN16_12: + rsrc_data->pack_fmt = 0x6; + rsrc_data->pack_fmt |= 0x10; + break; + default: + CAM_ERR(CAM_ISP, "Invalid format %d", + rsrc_data->format); + return -EINVAL; + } + + rsrc_data->en_cfg = 0x1; + } else if (rsrc_data->index >= 2 && rsrc_data->index <= 6) { + /* WM 2-6 stats */ + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } else if (rsrc_data->index == 1) { + /* WM 1 Raw dump */ + rsrc_data->stride = rsrc_data->width; + rsrc_data->en_cfg = 0x1; + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x10; + } else { + CAM_ERR(CAM_ISP, "Invalid WM:%d requested", rsrc_data->index); + return -EINVAL; + } + + *wm_res = wm_res_local; + *comp_grp_id = rsrc_data->hw_regs->comp_group; + *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", + rsrc_data->index, rsrc_data->width, rsrc_data->height, + rsrc_data->format, *comp_grp_id, rsrc_data->pack_fmt); + return 0; +} + +static int cam_tfe_bus_release_wm(void *bus_priv, + struct cam_isp_resource_node *wm_res) +{ + struct cam_tfe_bus_wm_resource_data *rsrc_data = wm_res->res_priv; + + rsrc_data->offset = 0; + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 0; + rsrc_data->format = 0; + rsrc_data->pack_fmt = 0; + rsrc_data->burst_len = 0; + rsrc_data->irq_subsample_period = 0; + rsrc_data->irq_subsample_pattern = 0; + rsrc_data->framedrop_period = 0; + rsrc_data->framedrop_pattern = 0; + rsrc_data->en_cfg = 0; + rsrc_data->is_dual = 0; + + wm_res->tasklet_info = NULL; + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + CAM_DBG(CAM_ISP, "TFE:%dRelease WM:%d", + rsrc_data->common_data->core_index, rsrc_data->index); + + return 0; +} + +static int cam_tfe_bus_start_wm(struct cam_isp_resource_node *wm_res) +{ + struct cam_tfe_bus_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_tfe_bus_common_data *common_data = + rsrc_data->common_data; + + cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->bw_limit); + + cam_io_w((rsrc_data->height << 16) | rsrc_data->width, + common_data->mem_base + rsrc_data->hw_regs->image_cfg_0); + cam_io_w(rsrc_data->pack_fmt, + 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) + cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + + rsrc_data->hw_regs->image_cfg_2)); + + /* Enable WM */ + cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + + rsrc_data->hw_regs->cfg); + + CAM_DBG(CAM_ISP, "TFE:%d WM:%d width = %d, height = %d", + common_data->core_index, rsrc_data->index, + rsrc_data->width, rsrc_data->height); + CAM_DBG(CAM_ISP, "WM:%d pk_fmt = %d", rsrc_data->index, + rsrc_data->pack_fmt); + CAM_DBG(CAM_ISP, "WM:%d stride = %d, burst len = %d", + rsrc_data->index, rsrc_data->stride, 0xf); + CAM_DBG(CAM_ISP, "TFE:%d Start WM:%d offset 0x%x val 0x%x", + common_data->core_index, rsrc_data->index, + (uint32_t) rsrc_data->hw_regs->cfg, rsrc_data->en_cfg); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_tfe_bus_stop_wm(struct cam_isp_resource_node *wm_res) +{ + struct cam_tfe_bus_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_tfe_bus_common_data *common_data = + rsrc_data->common_data; + + /* Disable WM */ + cam_io_w_mb(0x0, common_data->mem_base + rsrc_data->hw_regs->cfg); + CAM_DBG(CAM_ISP, "TFE:%d Stop WM:%d", + rsrc_data->common_data->core_index, rsrc_data->index); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return 0; +} + +static int cam_tfe_bus_init_wm_resource(uint32_t index, + struct cam_tfe_bus_priv *bus_priv, + struct cam_tfe_bus_hw_info *hw_info, + struct cam_isp_resource_node *wm_res) +{ + struct cam_tfe_bus_wm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_tfe_bus_wm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_ISP, "Failed to alloc for WM res priv"); + return -ENOMEM; + } + wm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &hw_info->bus_client_reg[index]; + rsrc_data->common_data = &bus_priv->common_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = cam_tfe_bus_start_wm; + wm_res->stop = cam_tfe_bus_stop_wm; + wm_res->hw_intf = bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_tfe_bus_deinit_wm_resource( + struct cam_isp_resource_node *wm_res) +{ + struct cam_tfe_bus_wm_resource_data *rsrc_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = NULL; + wm_res->stop = NULL; + wm_res->top_half_handler = NULL; + wm_res->bottom_half_handler = NULL; + wm_res->hw_intf = NULL; + + rsrc_data = wm_res->res_priv; + wm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static void cam_tfe_bus_add_wm_to_comp_grp( + struct cam_isp_resource_node *comp_grp, + uint32_t composite_mask) +{ + struct cam_tfe_bus_comp_grp_data *rsrc_data = comp_grp->res_priv; + + rsrc_data->composite_mask |= composite_mask; +} + +static bool cam_tfe_bus_match_comp_grp( + struct cam_tfe_bus_priv *bus_priv, + struct cam_isp_resource_node **comp_grp, + uint32_t comp_grp_id) +{ + struct cam_tfe_bus_comp_grp_data *rsrc_data = NULL; + struct cam_isp_resource_node *comp_grp_local = NULL; + + list_for_each_entry(comp_grp_local, + &bus_priv->used_comp_grp, list) { + rsrc_data = comp_grp_local->res_priv; + if (rsrc_data->comp_grp_id == comp_grp_id) { + /* Match found */ + *comp_grp = comp_grp_local; + return true; + } + } + + list_for_each_entry(comp_grp_local, + &bus_priv->free_comp_grp, list) { + rsrc_data = comp_grp_local->res_priv; + if (rsrc_data->comp_grp_id == comp_grp_id) { + /* Match found */ + *comp_grp = comp_grp_local; + list_del(&comp_grp_local->list); + list_add_tail(&comp_grp_local->list, + &bus_priv->used_comp_grp); + return false; + } + } + + *comp_grp = NULL; + return false; +} + +static int cam_tfe_bus_acquire_comp_grp( + struct cam_tfe_bus_priv *bus_priv, + struct cam_isp_tfe_out_port_info *out_port_info, + void *tasklet, + uint32_t is_dual, + uint32_t is_master, + struct cam_isp_resource_node **comp_grp, + enum cam_tfe_bus_comp_grp_id comp_grp_id, + struct cam_isp_resource_node *out_rsrc, + uint32_t source_group) +{ + int rc = 0; + struct cam_isp_resource_node *comp_grp_local = NULL; + struct cam_tfe_bus_comp_grp_data *rsrc_data = NULL; + bool previously_acquired = false; + + if (comp_grp_id >= CAM_TFE_BUS_COMP_GRP_0 && + comp_grp_id <= CAM_TFE_BUS_COMP_GRP_7) { + /* Check if matching comp_grp has already been acquired */ + previously_acquired = cam_tfe_bus_match_comp_grp( + bus_priv, &comp_grp_local, comp_grp_id); + } + + if (!comp_grp_local) { + CAM_ERR(CAM_ISP, "Invalid comp_grp_id:%d", comp_grp_id); + return -ENODEV; + } + + rsrc_data = comp_grp_local->res_priv; + if (rsrc_data->acquire_dev_cnt > CAM_TFE_MAX_OUT_RES_PER_COMP_GRP) { + CAM_ERR(CAM_ISP, "Many acquires comp_grp_id:%d", comp_grp_id); + return -ENODEV; + } + + if (!previously_acquired) { + comp_grp_local->tasklet_info = tasklet; + comp_grp_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + rsrc_data->is_master = is_master; + rsrc_data->is_dual = is_dual; + + if (is_master) + rsrc_data->addr_sync_mode = 0; + else + rsrc_data->addr_sync_mode = 1; + } else { + rsrc_data = comp_grp_local->res_priv; + /* Do not support runtime change in composite mask */ + if (comp_grp_local->res_state == + CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d Comp Grp %u", + comp_grp_local->res_state, + rsrc_data->comp_grp_id); + return -EBUSY; + } + } + + CAM_DBG(CAM_ISP, "Acquire comp_grp id:%u", rsrc_data->comp_grp_id); + rsrc_data->source_grp = source_group; + rsrc_data->out_rsrc[rsrc_data->acquire_dev_cnt] = out_rsrc; + rsrc_data->acquire_dev_cnt++; + *comp_grp = comp_grp_local; + + return rc; +} + +static int cam_tfe_bus_release_comp_grp( + struct cam_tfe_bus_priv *bus_priv, + struct cam_isp_resource_node *comp_grp) +{ + struct cam_isp_resource_node *comp_grp_local = NULL; + struct cam_tfe_bus_comp_grp_data *comp_rsrc_data = NULL; + int match_found = 0; + + if (!comp_grp) { + CAM_ERR(CAM_ISP, "Invalid Params Comp Grp %pK", comp_grp); + return -EINVAL; + } + + if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Already released Comp Grp"); + return 0; + } + + if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d", + comp_grp->res_state); + return -EBUSY; + } + + comp_rsrc_data = comp_grp->res_priv; + CAM_DBG(CAM_ISP, "Comp Grp id %u", comp_rsrc_data->comp_grp_id); + + list_for_each_entry(comp_grp_local, &bus_priv->used_comp_grp, list) { + if (comp_grp_local == comp_grp) { + match_found = 1; + break; + } + } + + if (!match_found) { + CAM_ERR(CAM_ISP, "Could not find comp_grp_id:%u", + comp_rsrc_data->comp_grp_id); + return -ENODEV; + } + + comp_rsrc_data->acquire_dev_cnt--; + if (comp_rsrc_data->acquire_dev_cnt == 0) { + list_del(&comp_grp_local->list); + + comp_rsrc_data->addr_sync_mode = 0; + comp_rsrc_data->composite_mask = 0; + + comp_grp_local->tasklet_info = NULL; + comp_grp_local->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + list_add_tail(&comp_grp_local->list, &bus_priv->free_comp_grp); + CAM_DBG(CAM_ISP, "Comp Grp id %u released", + comp_rsrc_data->comp_grp_id); + } + + return 0; +} + +static int cam_tfe_bus_start_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + int rc = 0; + uint32_t val; + struct cam_tfe_bus_comp_grp_data *rsrc_data = NULL; + struct cam_tfe_bus_common_data *common_data = NULL; + uint32_t bus_irq_reg_mask_0 = 0; + + rsrc_data = comp_grp->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_ISP, "TFE:%d comp_grp_id:%d streaming state:%d mask:0x%x", + common_data->core_index, rsrc_data->comp_grp_id, + comp_grp->res_state, rsrc_data->composite_mask); + + if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + return 0; + + if (rsrc_data->is_dual) { + if (rsrc_data->is_master) { + val = cam_io_r(common_data->mem_base + + common_data->common_reg->comp_cfg_0); + val |= (0x1 << (rsrc_data->comp_grp_id + 16)); + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val = cam_io_r(common_data->mem_base + + common_data->common_reg->comp_cfg_1); + val |= (0x1 << rsrc_data->comp_grp_id); + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_1); + } else { + val = cam_io_r(common_data->mem_base + + common_data->common_reg->comp_cfg_0); + val |= (0x1 << rsrc_data->comp_grp_id); + cam_io_w(val, common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val = cam_io_r(common_data->mem_base + + common_data->common_reg->comp_cfg_1); + val |= (0x1 << rsrc_data->comp_grp_id); + cam_io_w(val, common_data->mem_base + + common_data->common_reg->comp_cfg_1); + } + } + + if (rsrc_data->is_dual && !rsrc_data->is_master) + goto end; + + /* Update the composite done mask in bus irq mask*/ + bus_irq_reg_mask_0 = cam_io_r(common_data->mem_base + + common_data->common_reg->irq_mask[CAM_TFE_BUS_IRQ_REG0]); + bus_irq_reg_mask_0 |= (0x1 << (rsrc_data->comp_grp_id + + rsrc_data->common_data->comp_done_shift)); + cam_io_w_mb(bus_irq_reg_mask_0, common_data->mem_base + + common_data->common_reg->irq_mask[CAM_TFE_BUS_IRQ_REG0]); + + CAM_DBG(CAM_ISP, "TFE:%d start COMP_GRP:%d bus_irq_mask_0 0x%x", + common_data->core_index, rsrc_data->comp_grp_id, + bus_irq_reg_mask_0); + +end: + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return rc; +} + +static int cam_tfe_bus_stop_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + struct cam_tfe_bus_comp_grp_data *rsrc_data = NULL; + struct cam_tfe_bus_common_data *common_data = NULL; + uint32_t bus_irq_reg_mask_0 = 0; + + if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + return 0; + + rsrc_data = (struct cam_tfe_bus_comp_grp_data *)comp_grp->res_priv; + common_data = rsrc_data->common_data; + + /* Update the composite done mask in bus irq mask*/ + bus_irq_reg_mask_0 = cam_io_r(common_data->mem_base + + common_data->common_reg->irq_mask[CAM_TFE_BUS_IRQ_REG0]); + bus_irq_reg_mask_0 &= ~(0x1 << (rsrc_data->comp_grp_id + + rsrc_data->common_data->comp_done_shift)); + cam_io_w_mb(bus_irq_reg_mask_0, common_data->mem_base + + common_data->common_reg->irq_mask[CAM_TFE_BUS_IRQ_REG0]); + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return 0; +} + +static int cam_tfe_bus_init_comp_grp(uint32_t index, + struct cam_hw_soc_info *soc_info, + struct cam_tfe_bus_priv *bus_priv, + struct cam_tfe_bus_hw_info *hw_info, + struct cam_isp_resource_node *comp_grp) +{ + struct cam_tfe_bus_comp_grp_data *rsrc_data = NULL; + + rsrc_data = kzalloc(sizeof(struct cam_tfe_bus_comp_grp_data), + GFP_KERNEL); + if (!rsrc_data) + return -ENOMEM; + + comp_grp->res_priv = rsrc_data; + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&comp_grp->list); + + comp_grp->res_id = index; + rsrc_data->comp_grp_id = index; + rsrc_data->common_data = &bus_priv->common_data; + + list_add_tail(&comp_grp->list, &bus_priv->free_comp_grp); + + comp_grp->hw_intf = bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_tfe_bus_deinit_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + struct cam_tfe_bus_comp_grp_data *rsrc_data = + comp_grp->res_priv; + + comp_grp->start = NULL; + comp_grp->stop = NULL; + comp_grp->top_half_handler = NULL; + comp_grp->bottom_half_handler = NULL; + comp_grp->hw_intf = NULL; + + list_del_init(&comp_grp->list); + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + + comp_grp->res_priv = NULL; + + if (!rsrc_data) { + CAM_ERR(CAM_ISP, "comp_grp_priv is NULL"); + return -ENODEV; + } + kfree(rsrc_data); + + return 0; +} + +static int cam_tfe_bus_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + bool *mode = cmd_args; + struct cam_isp_resource_node *res = + (struct cam_isp_resource_node *) priv; + struct cam_tfe_bus_tfe_out_data *rsrc_data = + (struct cam_tfe_bus_tfe_out_data *)res->res_priv; + + *mode = (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? + true : false; + + return 0; +} + +static int cam_tfe_bus_acquire_tfe_out(void *priv, void *acquire_args, + uint32_t args_size) +{ + struct cam_tfe_bus_priv *bus_priv = priv; + struct cam_tfe_acquire_args *acq_args = acquire_args; + struct cam_tfe_hw_tfe_out_acquire_args *out_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_tfe_bus_tfe_out_data *rsrc_data = NULL; + enum cam_tfe_bus_tfe_out_id tfe_out_res_id; + enum cam_tfe_bus_comp_grp_id comp_grp_id; + int rc = -ENODEV; + uint32_t secure_caps = 0, mode; + uint32_t i, format, num_wm, client_done_mask = 0; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_ISP, "Invalid Param"); + return -EINVAL; + } + + out_acquire_args = &acq_args->tfe_out; + format = out_acquire_args->out_port_info->format; + + CAM_DBG(CAM_ISP, "resid 0x%x fmt:%d, sec mode:%d wm mode:%d", + out_acquire_args->out_port_info->res_id, format, + out_acquire_args->out_port_info->secure_mode, + out_acquire_args->out_port_info->wm_mode); + CAM_DBG(CAM_ISP, "width:%d, height:%d stride:%d", + out_acquire_args->out_port_info->width, + out_acquire_args->out_port_info->height, + out_acquire_args->out_port_info->stride); + + tfe_out_res_id = cam_tfe_bus_get_out_res_id( + out_acquire_args->out_port_info->res_id); + if (tfe_out_res_id == CAM_TFE_BUS_TFE_OUT_MAX) + return -ENODEV; + + num_wm = cam_tfe_bus_get_num_wm(tfe_out_res_id, format); + if (num_wm < 1) + return -EINVAL; + + rsrc_node = &bus_priv->tfe_out[tfe_out_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Resource not available: Res_id %d state:%d", + tfe_out_res_id, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_data = rsrc_node->res_priv; + rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->event_cb = acq_args->event_cb; + rsrc_data->priv = acq_args->priv; + + secure_caps = cam_tfe_bus_can_be_secure(rsrc_data->out_id); + mode = out_acquire_args->out_port_info->secure_mode; + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (!rsrc_data->common_data->num_sec_out) { + rsrc_data->secure_mode = mode; + rsrc_data->common_data->secure_mode = mode; + } else { + if (mode == rsrc_data->common_data->secure_mode) { + rsrc_data->secure_mode = + rsrc_data->common_data->secure_mode; + } else { + rc = -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return -EINVAL; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + bus_priv->tasklet_info = acq_args->tasklet; + rsrc_data->num_wm = num_wm; + rsrc_node->rdi_only_ctx = 0; + rsrc_node->res_id = out_acquire_args->out_port_info->res_id; + rsrc_node->cdm_ops = out_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = out_acquire_args->cdm_ops; + + /* Acquire WM and retrieve COMP GRP ID */ + for (i = 0; i < num_wm; i++) { + rc = cam_tfe_bus_acquire_wm(bus_priv, + out_acquire_args->out_port_info, + &rsrc_data->wm_res[i], + acq_args->tasklet, + tfe_out_res_id, + i, + &client_done_mask, + out_acquire_args->is_dual, + &comp_grp_id); + if (rc) { + CAM_ERR(CAM_ISP, + "TFE:%d WM acquire failed for Out %d rc=%d", + rsrc_data->common_data->core_index, + tfe_out_res_id, rc); + goto release_wm; + } + } + + /* Acquire composite group using COMP GRP ID */ + rc = cam_tfe_bus_acquire_comp_grp(bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + out_acquire_args->is_dual, + out_acquire_args->is_master, + &rsrc_data->comp_grp, + comp_grp_id, + rsrc_node, + rsrc_data->source_group); + if (rc) { + CAM_ERR(CAM_ISP, + "TFE%d Comp_Grp acquire fail for Out %d rc=%d", + rsrc_data->common_data->core_index, + tfe_out_res_id, rc); + return rc; + } + + rsrc_data->is_dual = out_acquire_args->is_dual; + rsrc_data->is_master = out_acquire_args->is_master; + + cam_tfe_bus_add_wm_to_comp_grp(rsrc_data->comp_grp, + client_done_mask); + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + out_acquire_args->rsrc_node = rsrc_node; + + return rc; + +release_wm: + for (i--; i >= 0; i--) + cam_tfe_bus_release_wm(bus_priv, + rsrc_data->wm_res[i]); + + cam_tfe_bus_release_comp_grp(bus_priv, rsrc_data->comp_grp); + + return rc; +} + +static int cam_tfe_bus_release_tfe_out(void *priv, void *release_args, + uint32_t args_size) +{ + struct cam_tfe_bus_priv *bus_priv = priv; + struct cam_isp_resource_node *tfe_out = NULL; + struct cam_tfe_bus_tfe_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + uint32_t i; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + tfe_out = (struct cam_isp_resource_node *)release_args; + rsrc_data = (struct cam_tfe_bus_tfe_out_data *)tfe_out->res_priv; + + if (tfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d res id:%d", + tfe_out->res_state, tfe_out->res_id); + } + + for (i = 0; i < rsrc_data->num_wm; i++) + cam_tfe_bus_release_wm(bus_priv, rsrc_data->wm_res[i]); + + rsrc_data->num_wm = 0; + + if (rsrc_data->comp_grp) + cam_tfe_bus_release_comp_grp(bus_priv, rsrc_data->comp_grp); + + rsrc_data->comp_grp = NULL; + + tfe_out->tasklet_info = NULL; + tfe_out->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_tfe_bus_can_be_secure(rsrc_data->out_id); + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (rsrc_data->secure_mode == + rsrc_data->common_data->secure_mode) { + rsrc_data->common_data->num_sec_out--; + rsrc_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } else { + /* + * The validity of the mode is properly + * checked while acquiring the output port. + * not expected to reach here, unless there is + * some corruption. + */ + CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", + rsrc_data->common_data->secure_mode, + rsrc_data->secure_mode); + } + + if (!rsrc_data->common_data->num_sec_out) + rsrc_data->common_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + if (tfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + tfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_tfe_bus_start_tfe_out(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + struct cam_isp_resource_node *tfe_out = hw_priv; + struct cam_tfe_bus_tfe_out_data *rsrc_data = NULL; + struct cam_tfe_bus_common_data *common_data = NULL; + uint32_t bus_irq_reg_mask_0 = 0; + uint32_t rup_group_id = 0; + int rc = 0, i; + + if (!tfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = tfe_out->res_priv; + common_data = rsrc_data->common_data; + rup_group_id = rsrc_data->rup_group_id; + + CAM_DBG(CAM_ISP, "TFE:%d Start resource index %d", + common_data->core_index, rsrc_data->out_id); + + if (tfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "TFE:%d Invalid resource state:%d", + common_data->core_index, tfe_out->res_state); + return -EACCES; + } + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_tfe_bus_start_wm(rsrc_data->wm_res[i]); + + rc = cam_tfe_bus_start_comp_grp(rsrc_data->comp_grp); + + if (rsrc_data->is_dual && !rsrc_data->is_master && + !tfe_out->rdi_only_ctx) + goto end; + + if (common_data->rup_irq_enable[rup_group_id]) + goto end; + + /* Update the composite regupdate mask in bus irq mask*/ + bus_irq_reg_mask_0 = cam_io_r(common_data->mem_base + + common_data->common_reg->irq_mask[CAM_TFE_BUS_IRQ_REG0]); + bus_irq_reg_mask_0 |= (0x1 << rup_group_id); + cam_io_w_mb(bus_irq_reg_mask_0, common_data->mem_base + + common_data->common_reg->irq_mask[CAM_TFE_BUS_IRQ_REG0]); + common_data->rup_irq_enable[rup_group_id] = true; + +end: + tfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_tfe_bus_stop_tfe_out(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + struct cam_isp_resource_node *tfe_out = hw_priv; + struct cam_tfe_bus_tfe_out_data *rsrc_data = NULL; + struct cam_tfe_bus_common_data *common_data = NULL; + uint32_t bus_irq_reg_mask_0 = 0, rup_group = 0; + int rc = 0, i; + + if (!tfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = tfe_out->res_priv; + common_data = rsrc_data->common_data; + rup_group = rsrc_data->rup_group_id; + + if (tfe_out->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + tfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "tfe_out res_state is %d", tfe_out->res_state); + return rc; + } + + rc = cam_tfe_bus_stop_comp_grp(rsrc_data->comp_grp); + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_tfe_bus_stop_wm(rsrc_data->wm_res[i]); + + + if (!common_data->rup_irq_enable[rup_group]) + goto end; + + /* disable composite regupdate mask in bus irq mask register*/ + bus_irq_reg_mask_0 = cam_io_r(common_data->mem_base + + common_data->common_reg->irq_mask[CAM_TFE_BUS_IRQ_REG0]); + bus_irq_reg_mask_0 &= ~(0x1 << rup_group); + cam_io_w_mb(bus_irq_reg_mask_0, common_data->mem_base + + common_data->common_reg->irq_mask[CAM_TFE_BUS_IRQ_REG0]); + common_data->rup_irq_enable[rup_group] = false; + +end: + tfe_out->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_tfe_bus_init_tfe_out_resource(uint32_t index, + struct cam_tfe_bus_priv *bus_priv, + struct cam_tfe_bus_hw_info *hw_info) +{ + struct cam_isp_resource_node *tfe_out = NULL; + struct cam_tfe_bus_tfe_out_data *rsrc_data = NULL; + int rc = 0; + int32_t tfe_out_id = hw_info->tfe_out_hw_info[index].tfe_out_id; + + if (tfe_out_id < 0 || + tfe_out_id >= CAM_TFE_BUS_TFE_OUT_MAX) { + CAM_ERR(CAM_ISP, "Init TFE Out failed, Invalid type=%d", + tfe_out_id); + return -EINVAL; + } + + tfe_out = &bus_priv->tfe_out[tfe_out_id]; + if (tfe_out->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + tfe_out->res_priv) { + CAM_ERR(CAM_ISP, "tfe_out_id %d has already been initialized", + tfe_out_id); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_tfe_bus_tfe_out_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + tfe_out->res_priv = rsrc_data; + + tfe_out->res_type = CAM_ISP_RESOURCE_TFE_OUT; + tfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&tfe_out->list); + + rsrc_data->composite_group = + hw_info->tfe_out_hw_info[index].composite_group; + rsrc_data->rup_group_id = + hw_info->tfe_out_hw_info[index].rup_group_id; + rsrc_data->out_id = + hw_info->tfe_out_hw_info[index].tfe_out_id; + rsrc_data->common_data = &bus_priv->common_data; + rsrc_data->max_width = + hw_info->tfe_out_hw_info[index].max_width; + rsrc_data->max_height = + hw_info->tfe_out_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + tfe_out->hw_intf = bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_tfe_bus_deinit_tfe_out_resource( + struct cam_isp_resource_node *tfe_out) +{ + struct cam_tfe_bus_tfe_out_data *rsrc_data = tfe_out->res_priv; + + if (tfe_out->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + CAM_DBG(CAM_ISP, "HW%d Res %d already deinitialized"); + return 0; + } + + tfe_out->start = NULL; + tfe_out->stop = NULL; + tfe_out->top_half_handler = NULL; + tfe_out->bottom_half_handler = NULL; + tfe_out->hw_intf = NULL; + + tfe_out->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&tfe_out->list); + tfe_out->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static const char *cam_tfe_bus_rup_type( + uint32_t group_id) +{ + switch (group_id) { + case CAM_ISP_HW_TFE_IN_CAMIF: + return "CAMIF RUP"; + case CAM_ISP_HW_TFE_IN_RDI0: + return "RDI0 RUP"; + case CAM_ISP_HW_TFE_IN_RDI1: + return "RDI1 RUP"; + case CAM_ISP_HW_TFE_IN_RDI2: + return "RDI2 RUP"; + default: + return "invalid rup group"; + } +} +static int cam_tfe_bus_rup_bottom_half( + struct cam_tfe_bus_priv *bus_priv, + struct cam_tfe_irq_evt_payload *evt_payload) +{ + struct cam_tfe_bus_common_data *common_data; + struct cam_tfe_bus_tfe_out_data *out_rsrc_data; + struct cam_isp_hw_event_info evt_info; + uint32_t i, j; + + common_data = &bus_priv->common_data; + evt_info.hw_idx = bus_priv->common_data.core_index; + evt_info.res_type = CAM_ISP_RESOURCE_TFE_OUT; + + for (i = 0; i < CAM_TFE_BUS_RUP_GRP_MAX; i++) { + if (!(evt_payload->bus_irq_val[0] & + bus_priv->comp_rup_done_mask)) + break; + + if (evt_payload->bus_irq_val[0] & BIT(i)) { + for (j = 0; j < CAM_TFE_BUS_TFE_OUT_MAX; j++) { + out_rsrc_data = + (struct cam_tfe_bus_tfe_out_data *) + bus_priv->tfe_out[j].res_priv; + if ((out_rsrc_data->rup_group_id == i) && + (bus_priv->tfe_out[j].res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) + break; + } + + if (j == CAM_TFE_BUS_TFE_OUT_MAX) { + CAM_ERR(CAM_ISP, + "TFE:%d out rsc active status[0]:0x%x", + bus_priv->common_data.core_index, + evt_payload->bus_irq_val[0]); + continue; + } + + CAM_DBG(CAM_ISP, "TFE:%d Received %s", + bus_priv->common_data.core_index, + cam_tfe_bus_rup_type(i)); + evt_info.res_id = i; + if (out_rsrc_data->event_cb) { + out_rsrc_data->event_cb( + out_rsrc_data->priv, + CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + /* reset the rup bit */ + evt_payload->bus_irq_val[0] &= ~BIT(i); + } else + CAM_ERR(CAM_ISP, + "TFE:%d No event cb id:%lld evt id:%d", + bus_priv->common_data.core_index, + out_rsrc_data->out_id, evt_info.res_id); + } + } + + return 0; +} + +static int cam_tfe_bus_bufdone_bottom_half( + struct cam_tfe_bus_priv *bus_priv, + struct cam_tfe_irq_evt_payload *evt_payload) +{ + struct cam_tfe_bus_common_data *common_data; + struct cam_tfe_bus_tfe_out_data *out_rsrc_data; + struct cam_isp_hw_event_info evt_info; + struct cam_isp_resource_node *out_rsrc = NULL; + struct cam_tfe_bus_comp_grp_data *comp_rsrc_data; + uint32_t i, j; + + common_data = &bus_priv->common_data; + + for (i = 0; i < CAM_TFE_BUS_COMP_GRP_MAX; i++) { + if (!(evt_payload->bus_irq_val[0] & + bus_priv->comp_buf_done_mask)) + break; + + comp_rsrc_data = (struct cam_tfe_bus_comp_grp_data *) + bus_priv->comp_grp[i].res_priv; + + if (evt_payload->bus_irq_val[0] & + BIT(comp_rsrc_data->comp_grp_id + + bus_priv->common_data.comp_done_shift)) { + for (j = 0; j < comp_rsrc_data->acquire_dev_cnt; j++) { + out_rsrc = comp_rsrc_data->out_rsrc[j]; + out_rsrc_data = out_rsrc->res_priv; + evt_info.res_type = out_rsrc->res_type; + evt_info.hw_idx = out_rsrc->hw_intf->hw_idx; + evt_info.res_id = out_rsrc->res_id; + out_rsrc_data->event_cb(out_rsrc_data->priv, + CAM_ISP_HW_EVENT_DONE, + (void *)&evt_info); + } + + evt_payload->bus_irq_val[0] &= + ~BIT(comp_rsrc_data->comp_grp_id + + bus_priv->common_data.comp_done_shift); + } + } + + return 0; +} + +static int cam_tfe_bus_bottom_half(void *priv, + bool rup_process, struct cam_tfe_irq_evt_payload *evt_payload) +{ + struct cam_tfe_bus_priv *bus_priv; + uint32_t val; + + if (!priv || !evt_payload) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid priv param"); + return -EINVAL; + } + bus_priv = (struct cam_tfe_bus_priv *) priv; + + /* 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 + + bus_priv->common_data.common_reg->irq_mask[0]); + 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) { + if (evt_payload->bus_irq_val[0] & + bus_priv->comp_rup_done_mask) + cam_tfe_bus_rup_bottom_half(bus_priv, evt_payload); + } else { + if (evt_payload->bus_irq_val[0] & + bus_priv->comp_buf_done_mask) + cam_tfe_bus_bufdone_bottom_half(bus_priv, evt_payload); + } + + return 0; + +} + +static int cam_tfe_bus_update_wm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_tfe_bus_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg; + struct cam_tfe_bus_tfe_out_data *tfe_out_data = NULL; + struct cam_tfe_bus_wm_resource_data *wm_data = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + uint32_t frame_inc = 0, val; + + bus_priv = (struct cam_tfe_bus_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + tfe_out_data = (struct cam_tfe_bus_tfe_out_data *) + update_buf->res->res_priv; + + if (!tfe_out_data || !tfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + if (update_buf->wm_update->num_buf != tfe_out_data->num_wm) { + CAM_ERR(CAM_ISP, + "Failed! Invalid number buffers:%d required:%d", + update_buf->wm_update->num_buf, tfe_out_data->num_wm); + return -EINVAL; + } + + reg_val_pair = &tfe_out_data->common_data->io_buf_update[0]; + io_cfg = update_buf->wm_update->io_cfg; + + for (i = 0, j = 0; i < tfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = tfe_out_data->wm_res[i]->res_priv; + /* update width register */ + val = cam_io_r_mb(wm_data->common_data->mem_base + + wm_data->hw_regs->image_cfg_0); + /* mask previously written width but preserve height */ + val = val & 0xFFFF0000; + val |= wm_data->width; + CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_0, val); + 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 %d", 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) { + CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_2, + io_cfg->planes[i].plane_stride); + wm_data->stride = val; + CAM_DBG(CAM_ISP, "WM %d image stride 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + frame_inc = io_cfg->planes[i].plane_stride * + io_cfg->planes[i].slice_height; + + CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i]); + CAM_DBG(CAM_ISP, "WM %d image address 0x%x", + wm_data->index, reg_val_pair[j-1]); + + CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->frame_incr, frame_inc); + CAM_DBG(CAM_ISP, "WM %d frame_inc %d", + wm_data->index, reg_val_pair[j-1]); + + /* enable the WM */ + CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->cfg, + wm_data->en_cfg); + } + + size = tfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_buf->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + tfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_buf->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_buf->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_tfe_bus_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_tfe_bus_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_hfr; + struct cam_tfe_bus_tfe_out_data *tfe_out_data = NULL; + struct cam_tfe_bus_wm_resource_data *wm_data = NULL; + struct cam_isp_tfe_port_hfr_config *hfr_cfg = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + + bus_priv = (struct cam_tfe_bus_priv *) priv; + update_hfr = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + tfe_out_data = (struct cam_tfe_bus_tfe_out_data *) + update_hfr->res->res_priv; + + if (!tfe_out_data || !tfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + reg_val_pair = &tfe_out_data->common_data->io_buf_update[0]; + hfr_cfg = (struct cam_isp_tfe_port_hfr_config *)update_hfr->data; + + for (i = 0, j = 0; i < tfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = tfe_out_data->wm_res[i]->res_priv; + CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_pattern, + hfr_cfg->framedrop_pattern); + wm_data->framedrop_pattern = hfr_cfg->framedrop_pattern; + CAM_DBG(CAM_ISP, "WM:%d framedrop pattern 0x%x", + wm_data->index, wm_data->framedrop_pattern); + + CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_period, + hfr_cfg->framedrop_period); + wm_data->framedrop_period = hfr_cfg->framedrop_period; + CAM_DBG(CAM_ISP, "WM:%d framedrop period 0x%x", + wm_data->index, wm_data->framedrop_period); + + CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_period, + hfr_cfg->subsample_period); + wm_data->irq_subsample_period = hfr_cfg->subsample_period; + CAM_DBG(CAM_ISP, "WM:%d irq subsample period 0x%x", + wm_data->index, wm_data->irq_subsample_period); + + CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_pattern, + hfr_cfg->subsample_pattern); + wm_data->irq_subsample_pattern = hfr_cfg->subsample_pattern; + CAM_DBG(CAM_ISP, "WM:%d irq subsample pattern 0x%x", + wm_data->index, wm_data->irq_subsample_pattern); + } + + size = tfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_hfr->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_hfr->cmd.size, size); + return -ENOMEM; + } + + tfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_hfr->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_hfr->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_tfe_bus_update_stripe_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_tfe_bus_priv *bus_priv; + struct cam_tfe_dual_update_args *stripe_args; + struct cam_tfe_bus_tfe_out_data *tfe_out_data = NULL; + struct cam_tfe_bus_wm_resource_data *wm_data = NULL; + struct cam_isp_tfe_dual_stripe_config *stripe_config; + uint32_t i; + + bus_priv = (struct cam_tfe_bus_priv *) priv; + stripe_args = (struct cam_tfe_dual_update_args *)cmd_args; + + tfe_out_data = (struct cam_tfe_bus_tfe_out_data *) + stripe_args->res->res_priv; + + if (!tfe_out_data) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + if (stripe_args->res->res_id < CAM_ISP_TFE_OUT_RES_BASE || + stripe_args->res->res_id >= CAM_ISP_TFE_OUT_RES_MAX) + return 0; + + stripe_config = (struct cam_isp_tfe_dual_stripe_config *) + stripe_args->stripe_config; + + for (i = 0; i < tfe_out_data->num_wm; i++) { + stripe_config = &stripe_args->stripe_config[i]; + wm_data = tfe_out_data->wm_res[i]->res_priv; + wm_data->width = stripe_config->width; + wm_data->offset = stripe_config->offset; + CAM_DBG(CAM_ISP, "id:%x WM:%d width:0x%x offset:%x", + stripe_args->res->res_id, wm_data->index, + wm_data->width, wm_data->offset); + } + + return 0; +} + +static int cam_tfe_bus_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_tfe_bus_priv *bus_priv = hw_priv; + uint32_t i, top_irq_reg_mask[3] = {0}; + int rc = -EINVAL; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + top_irq_reg_mask[0] = (1 << bus_priv->top_bus_wr_irq_shift); + + rc = cam_tfe_irq_config(bus_priv->common_data.tfe_core_data, + top_irq_reg_mask, CAM_TFE_TOP_IRQ_REG_NUM, true); + if (rc) + return rc; + + /* configure the error irq */ + for (i = 0; i < CAM_TFE_BUS_IRQ_REGISTERS_MAX; i++) + cam_io_w(bus_priv->bus_irq_error_mask[i], + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->irq_mask[i]); + + return 0; +} + +static int cam_tfe_bus_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_tfe_bus_priv *bus_priv = hw_priv; + uint32_t top_irq_reg_mask[3] = {0}; + int rc = 0; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Error: Invalid args"); + return -EINVAL; + } + top_irq_reg_mask[0] = (1 << bus_priv->top_bus_wr_irq_shift); + rc = cam_tfe_irq_config(bus_priv->common_data.tfe_core_data, + top_irq_reg_mask, CAM_TFE_TOP_IRQ_REG_NUM, false); + if (rc) + return rc; + + /* configure the error irq */ + cam_io_w(0, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->irq_mask[0]); + + cam_io_w_mb(0, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->irq_mask[1]); + + return rc; +} + +static int cam_tfe_bus_process_cmd(void *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + struct cam_tfe_bus_priv *bus_priv; + int rc = -EINVAL; + uint32_t i, val; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + rc = cam_tfe_bus_update_wm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE: + rc = cam_tfe_bus_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_tfe_bus_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STRIPE_UPDATE: + rc = cam_tfe_bus_update_stripe_cfg(priv, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + bus_priv = (struct cam_tfe_bus_priv *) priv; + /* disable the bus error interrupts */ + for (i = 0; i < CAM_TFE_BUS_IRQ_REGISTERS_MAX; i++) { + val = cam_io_r(bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->irq_mask[i]); + val &= ~bus_priv->bus_irq_error_mask[i]; + cam_io_w(val, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->irq_mask[i]); + } + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_tfe_bus_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *core_data, + struct cam_tfe_bus **tfe_bus) +{ + int i, rc = 0; + struct cam_tfe_bus_priv *bus_priv = NULL; + struct cam_tfe_bus *tfe_bus_local; + struct cam_tfe_bus_hw_info *hw_info = bus_hw_info; + + if (!soc_info || !hw_intf || !bus_hw_info) { + CAM_ERR(CAM_ISP, + "Invalid params soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_hw_info); + rc = -EINVAL; + goto end; + } + + tfe_bus_local = kzalloc(sizeof(struct cam_tfe_bus), GFP_KERNEL); + if (!tfe_bus_local) { + CAM_DBG(CAM_ISP, "Failed to alloc for tfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_tfe_bus_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_ISP, "Failed to alloc for tfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + tfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = hw_info->num_client; + bus_priv->num_out = hw_info->num_out; + bus_priv->top_bus_wr_irq_shift = hw_info->top_bus_wr_irq_shift; + bus_priv->common_data.comp_done_shift = hw_info->comp_done_shift; + + bus_priv->common_data.num_sec_out = 0; + bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, TFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.tfe_core_data = core_data; + bus_priv->common_data.common_reg = &hw_info->common_reg; + bus_priv->comp_buf_done_mask = hw_info->comp_buf_done_mask; + bus_priv->comp_rup_done_mask = hw_info->comp_rup_done_mask; + + for (i = 0; i < CAM_TFE_BUS_IRQ_REGISTERS_MAX; i++) + bus_priv->bus_irq_error_mask[i] = + hw_info->bus_irq_error_mask[i]; + + if (strnstr(soc_info->compatible, "lite", + strlen(soc_info->compatible)) != NULL) + bus_priv->common_data.is_lite = true; + else + bus_priv->common_data.is_lite = false; + + for (i = 0; i < CAM_TFE_BUS_RUP_GRP_MAX; i++) + bus_priv->common_data.rup_irq_enable[i] = false; + + mutex_init(&bus_priv->common_data.bus_mutex); + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_tfe_bus_init_wm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init WM failed rc=%d", rc); + goto deinit_wm; + } + } + + for (i = 0; i < CAM_TFE_BUS_COMP_GRP_MAX; i++) { + rc = cam_tfe_bus_init_comp_grp(i, soc_info, + bus_priv, bus_hw_info, + &bus_priv->comp_grp[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init Comp Grp failed rc=%d", rc); + goto deinit_comp_grp; + } + } + + for (i = 0; i < bus_priv->num_out; i++) { + rc = cam_tfe_bus_init_tfe_out_resource(i, bus_priv, + bus_hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init TFE Out failed rc=%d", rc); + goto deinit_tfe_out; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + + tfe_bus_local->hw_ops.reserve = cam_tfe_bus_acquire_tfe_out; + tfe_bus_local->hw_ops.release = cam_tfe_bus_release_tfe_out; + tfe_bus_local->hw_ops.start = cam_tfe_bus_start_tfe_out; + tfe_bus_local->hw_ops.stop = cam_tfe_bus_stop_tfe_out; + tfe_bus_local->hw_ops.init = cam_tfe_bus_init_hw; + tfe_bus_local->hw_ops.deinit = cam_tfe_bus_deinit_hw; + tfe_bus_local->bottom_half_handler = cam_tfe_bus_bottom_half; + tfe_bus_local->hw_ops.process_cmd = cam_tfe_bus_process_cmd; + + *tfe_bus = tfe_bus_local; + + return rc; + +deinit_tfe_out: + if (i < 0) + i = CAM_TFE_BUS_TFE_OUT_MAX; + for (--i; i >= 0; i--) + cam_tfe_bus_deinit_tfe_out_resource(&bus_priv->tfe_out[i]); + +deinit_comp_grp: + if (i < 0) + i = CAM_TFE_BUS_COMP_GRP_MAX; + for (--i; i >= 0; i--) + cam_tfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]); + +deinit_wm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_tfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]); + + kfree(tfe_bus_local->bus_priv); + +free_bus_local: + kfree(tfe_bus_local); + +end: + return rc; +} + +int cam_tfe_bus_deinit( + struct cam_tfe_bus **tfe_bus) +{ + int i, rc = 0; + struct cam_tfe_bus_priv *bus_priv = NULL; + struct cam_tfe_bus *tfe_bus_local; + + if (!tfe_bus || !*tfe_bus) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + tfe_bus_local = *tfe_bus; + bus_priv = tfe_bus_local->bus_priv; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_tfe_bus_deinit_wm_resource( + &bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit WM failed rc=%d", rc); + } + + for (i = 0; i < CAM_TFE_BUS_COMP_GRP_MAX; i++) { + rc = cam_tfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit Comp Grp failed rc=%d", rc); + } + + for (i = 0; i < CAM_TFE_BUS_TFE_OUT_MAX; i++) { + rc = cam_tfe_bus_deinit_tfe_out_resource( + &bus_priv->tfe_out[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit TFE Out failed rc=%d", rc); + } + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + mutex_destroy(&bus_priv->common_data.bus_mutex); + kfree(tfe_bus_local->bus_priv); + +free_bus_local: + kfree(tfe_bus_local); + + *tfe_bus = NULL; + + return rc; +} 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 new file mode 100644 index 000000000000..e5736c6f97c4 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.h @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_TFE_BUS_H_ +#define _CAM_TFE_BUS_H_ + +#include "cam_soc_util.h" +#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_1_0 0x1000 + + +#define CAM_TFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ + do { \ + buf_array[(index)++] = offset; \ + buf_array[(index)++] = val; \ + } while (0) + +#define ALIGNUP(value, alignment) \ + ((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); + +enum cam_tfe_bus_plane_type { + PLANE_Y, + PLANE_C, + PLANE_MAX, +}; + + +enum cam_tfe_bus_tfe_core_id { + CAM_TFE_BUS_TFE_CORE_0, + CAM_TFE_BUS_TFE_CORE_1, + CAM_TFE_BUS_TFE_CORE_2, + CAM_TFE_BUS_TFE_CORE_MAX, +}; + +enum cam_tfe_bus_comp_grp_id { + CAM_TFE_BUS_COMP_GRP_0, + CAM_TFE_BUS_COMP_GRP_1, + CAM_TFE_BUS_COMP_GRP_2, + CAM_TFE_BUS_COMP_GRP_3, + CAM_TFE_BUS_COMP_GRP_4, + CAM_TFE_BUS_COMP_GRP_5, + CAM_TFE_BUS_COMP_GRP_6, + CAM_TFE_BUS_COMP_GRP_7, + CAM_TFE_BUS_COMP_GRP_MAX, +}; + +enum cam_tfe_bus_rup_grp_id { + CAM_TFE_BUS_RUP_GRP_0, + CAM_TFE_BUS_RUP_GRP_1, + CAM_TFE_BUS_RUP_GRP_2, + CAM_TFE_BUS_RUP_GRP_3, + CAM_TFE_BUS_RUP_GRP_MAX, +}; + +enum cam_tfe_bus_tfe_out_id { + CAM_TFE_BUS_TFE_OUT_RDI0, + CAM_TFE_BUS_TFE_OUT_RDI1, + CAM_TFE_BUS_TFE_OUT_RDI2, + CAM_TFE_BUS_TFE_OUT_FULL, + CAM_TFE_BUS_TFE_OUT_RAW_DUMP, + CAM_TFE_BUS_TFE_OUT_PDAF, + CAM_TFE_BUS_TFE_OUT_STATS_HDR_BE, + CAM_TFE_BUS_TFE_OUT_STATS_HDR_BHIST, + CAM_TFE_BUS_TFE_OUT_STATS_TL_BG, + CAM_TFE_BUS_TFE_OUT_STATS_AWB_BG, + CAM_TFE_BUS_TFE_OUT_STATS_BF, + CAM_TFE_BUS_TFE_OUT_MAX, +}; + +/* + * struct cam_tfe_bus_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_tfe_bus_reg_offset_common { + uint32_t hw_version; + uint32_t cgc_ovd; + uint32_t comp_cfg_0; + uint32_t comp_cfg_1; + uint32_t frameheader_cfg[4]; + uint32_t pwr_iso_cfg; + uint32_t overflow_status_clear; + uint32_t ccif_violation_status; + uint32_t overflow_status; + uint32_t image_size_violation_status; + uint32_t perf_count_cfg[CAM_TFE_BUS_MAX_PERF_CNT_REG]; + uint32_t perf_count_val[CAM_TFE_BUS_MAX_PERF_CNT_REG]; + uint32_t perf_count_status; + uint32_t debug_status_top_cfg; + uint32_t debug_status_top; + uint32_t test_bus_ctrl; + uint32_t irq_mask[CAM_TFE_BUS_IRQ_REGISTERS_MAX]; + uint32_t irq_clear[CAM_TFE_BUS_IRQ_REGISTERS_MAX]; + uint32_t irq_status[CAM_TFE_BUS_IRQ_REGISTERS_MAX]; + uint32_t irq_cmd; +}; + +/* + * struct cam_tfe_bus_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_tfe_bus_reg_offset_bus_client { + uint32_t cfg; + uint32_t image_addr; + uint32_t frame_incr; + uint32_t image_cfg_0; + uint32_t image_cfg_1; + uint32_t image_cfg_2; + uint32_t packer_cfg; + uint32_t bw_limit; + uint32_t frame_header_addr; + uint32_t frame_header_incr; + uint32_t frame_header_cfg; + uint32_t line_done_cfg; + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + uint32_t addr_status_0; + uint32_t addr_status_1; + uint32_t addr_status_2; + uint32_t addr_status_3; + uint32_t debug_status_cfg; + uint32_t debug_status_0; + uint32_t debug_status_1; + uint32_t comp_group; +}; + +/* + * struct cam_tfe_bus_tfe_out_hw_info: + * + * @Brief: HW capability of TFE Bus Client + * tfe_out_id Tfe out port id + * max_width Max width supported by the outport + * max_height Max height supported by outport + * composite_group Out port composite group id + * rup_group_id Reg update group of outport id + */ +struct cam_tfe_bus_tfe_out_hw_info { + enum cam_tfe_bus_tfe_out_id tfe_out_id; + uint32_t max_width; + uint32_t max_height; + uint32_t composite_group; + uint32_t rup_group_id; +}; + +/* + * struct cam_tfe_bus_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @num_client: Total number of write clients + * @bus_client_reg: Bus client register info + * @tfe_out_hw_info: TFE output capability + * @comp_done_shift: Mask shift for comp done mask + * @top_bus_wr_irq_shift: Mask shift for top level BUS WR irq + * @comp_buf_done_mask: Composite buf done bits mask + * @comp_rup_done_mask: Reg update done mask + * @bus_irq_error_mask: Bus irq error mask bits + */ +struct cam_tfe_bus_hw_info { + struct cam_tfe_bus_reg_offset_common common_reg; + uint32_t num_client; + struct cam_tfe_bus_reg_offset_bus_client + bus_client_reg[CAM_TFE_BUS_MAX_CLIENTS]; + uint32_t num_out; + struct cam_tfe_bus_tfe_out_hw_info + tfe_out_hw_info[CAM_TFE_BUS_TFE_OUT_MAX]; + uint32_t comp_done_shift; + uint32_t top_bus_wr_irq_shift; + uint32_t comp_buf_done_mask; + uint32_t comp_rup_done_mask; + uint32_t bus_irq_error_mask[CAM_TFE_BUS_IRQ_REGISTERS_MAX]; +}; + +/* + * struct cam_tfe_bus: + * + * @Brief: Bus interface structure + * + * @bus_priv: Private data of bus + * @hw_ops: Hardware interface functions + * @bottom_half_handler: Bottom Half handler function + */ +struct cam_tfe_bus { + void *bus_priv; + struct cam_hw_ops hw_ops; + CAM_BUS_HANDLER_BOTTOM_HALF bottom_half_handler; +}; + +/* + * cam_tfe_bus_init() + * + * @Brief: Initialize Bus layer + * + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @core_data: Core data pointer used for top irq config + * @tfe_bus: Pointer to tfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_bus_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *core_data, + struct cam_tfe_bus **tfe_bus); + +/* + * cam_tfe_bus_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @tfe_bus: Pointer to tfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_bus_deinit(struct cam_tfe_bus **tfe_bus); + +#endif /* _CAM_TFE_BUS_H_ */ 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 new file mode 100644 index 000000000000..793558cc2931 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c @@ -0,0 +1,2529 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "cam_cdm_util.h" +#include "cam_tasklet_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_tfe_soc.h" +#include "cam_tfe_core.h" +#include "cam_tfe_bus.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "tfe"; + +#define CAM_TFE_HW_RESET_HW_AND_REG_VAL 0x1 +#define CAM_TFE_HW_RESET_HW_VAL 0x10000 +#define CAM_TFE_DELAY_BW_REDUCTION_NUM_FRAMES 3 +#define CAM_TFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 +#define CAM_TFE_DELAY_BW_REDUCTION_NUM_FRAMES 3 + +struct cam_tfe_top_common_data { + struct cam_hw_soc_info *soc_info; + struct cam_hw_intf *hw_intf; + struct cam_tfe_top_reg_offset_common *common_reg; + struct cam_tfe_reg_dump_data *reg_dump_data; +}; + +struct cam_tfe_top_priv { + struct cam_tfe_top_common_data common_data; + struct cam_isp_resource_node in_rsrc[CAM_TFE_TOP_IN_PORT_MAX]; + unsigned long hw_clk_rate; + struct cam_axi_vote applied_axi_vote; + struct cam_axi_vote req_axi_vote[CAM_TFE_TOP_IN_PORT_MAX]; + unsigned long req_clk_rate[CAM_TFE_TOP_IN_PORT_MAX]; + struct cam_axi_vote last_vote[CAM_TFE_TOP_IN_PORT_MAX * + CAM_TFE_DELAY_BW_REDUCTION_NUM_FRAMES]; + uint32_t last_counter; + uint64_t total_bw_applied; + enum cam_tfe_bw_control_action + axi_vote_control[CAM_TFE_TOP_IN_PORT_MAX]; + uint32_t irq_prepared_mask[3]; + void *tasklet_info; +}; + +struct cam_tfe_camif_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_tfe_top_reg_offset_common *common_reg; + struct cam_tfe_camif_reg *camif_reg; + struct cam_tfe_camif_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + enum cam_isp_hw_sync_mode sync_mode; + uint32_t dsp_mode; + uint32_t pix_pattern; + uint32_t first_pixel; + uint32_t first_line; + uint32_t last_pixel; + uint32_t last_line; + bool enable_sof_irq_debug; + uint32_t irq_debug_cnt; + uint32_t camif_debug; + uint32_t camif_pd_enable; + uint32_t dual_tfe_sync_sel; +}; + +struct cam_tfe_rdi_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_tfe_top_reg_offset_common *common_reg; + struct cam_tfe_rdi_reg *rdi_reg; + struct cam_tfe_rdi_reg_data *reg_data; + cam_hw_mgr_event_cb_func event_cb; + void *priv; + enum cam_isp_hw_sync_mode sync_mode; + uint32_t pix_pattern; +}; + +static int cam_tfe_validate_pix_pattern(uint32_t pattern) +{ + int rc; + + switch (pattern) { + case CAM_ISP_TFE_PATTERN_BAYER_RGRGRG: + case CAM_ISP_TFE_PATTERN_BAYER_GRGRGR: + case CAM_ISP_TFE_PATTERN_BAYER_BGBGBG: + case CAM_ISP_TFE_PATTERN_BAYER_GBGBGB: + case CAM_ISP_TFE_PATTERN_YUV_YCBYCR: + case CAM_ISP_TFE_PATTERN_YUV_YCRYCB: + case CAM_ISP_TFE_PATTERN_YUV_CBYCRY: + case CAM_ISP_TFE_PATTERN_YUV_CRYCBY: + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, "Error Invalid pix pattern:%d", pattern); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_tfe_get_evt_payload(struct cam_tfe_hw_core_info *core_info, + struct cam_tfe_irq_evt_payload **evt_payload) +{ + spin_lock(&core_info->spin_lock); + if (list_empty(&core_info->free_payload_list)) { + *evt_payload = NULL; + spin_unlock(&core_info->spin_lock); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload, core id 0x%x", + core_info->core_index); + return -ENODEV; + } + + *evt_payload = list_first_entry(&core_info->free_payload_list, + struct cam_tfe_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + spin_unlock(&core_info->spin_lock); + + return 0; +} + +int cam_tfe_put_evt_payload(void *core_info, + struct cam_tfe_irq_evt_payload **evt_payload) +{ + struct cam_tfe_hw_core_info *tfe_core_info = core_info; + unsigned long flags; + + if (!core_info) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&tfe_core_info->spin_lock, flags); + (*evt_payload)->error_type = 0; + list_add_tail(&(*evt_payload)->list, &tfe_core_info->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&tfe_core_info->spin_lock, flags); + + return 0; +} + +int cam_tfe_get_hw_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size) +{ + return -EPERM; +} + +void cam_tfe_get_timestamp(struct cam_isp_timestamp *time_stamp) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + time_stamp->mono_time.tv_sec = ts.tv_sec; + time_stamp->mono_time.tv_usec = ts.tv_nsec/1000; +} + +int cam_tfe_irq_config(void *tfe_core_data, + uint32_t *irq_mask, uint32_t num_reg, bool enable) +{ + struct cam_tfe_hw_core_info *core_info; + struct cam_tfe_top_priv *top_priv; + struct cam_hw_soc_info *soc_info; + void __iomem *mem_base; + bool need_lock; + unsigned long flags = 0; + uint32_t i, val; + + if (!tfe_core_data) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Invalid core data"); + return -EINVAL; + } + + core_info = (struct cam_tfe_hw_core_info *)tfe_core_data; + top_priv = (struct cam_tfe_top_priv *)core_info->top_priv; + soc_info = (struct cam_hw_soc_info *)top_priv->common_data.soc_info; + mem_base = soc_info->reg_map[TFE_CORE_BASE_IDX].mem_base; + + need_lock = !in_irq(); + if (need_lock) + spin_lock_irqsave(&core_info->spin_lock, flags); + + for (i = 0; i < num_reg; i++) { + val = cam_io_r_mb(mem_base + + core_info->tfe_hw_info->top_irq_mask[i]); + if (enable) + val |= irq_mask[i]; + else + val &= ~irq_mask[i]; + cam_io_w_mb(val, mem_base + + core_info->tfe_hw_info->top_irq_mask[i]); + } + if (need_lock) + spin_unlock_irqrestore(&core_info->spin_lock, flags); + + 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) +{ + 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; + + 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 != + CAM_ISP_RESOURCE_STATE_STREAMING)) + continue; + + if (top_priv->in_rsrc[i].res_id == CAM_ISP_HW_TFE_IN_CAMIF) { + camif_data = (struct cam_tfe_camif_data *) + top_priv->in_rsrc[i].res_priv; + val_0 = cam_io_r(mem_base + + camif_data->camif_reg->debug_0); + val_1 = cam_io_r(mem_base + + camif_data->camif_reg->debug_1); + CAM_INFO(CAM_ISP, + "camif debug1:0x%x Height:0x%x, width:0x%x", + val_1, + ((val_0 >> 16) & 0x1FFF), + (val_0 & 0x1FFF)); + } else if ((top_priv->in_rsrc[i].res_id >= + CAM_ISP_HW_TFE_IN_RDI0) || + (top_priv->in_rsrc[i].res_id <= + CAM_ISP_HW_TFE_IN_RDI2)) { + rdi_data = (struct cam_tfe_rdi_data *) + top_priv->in_rsrc[i].res_priv; + val_0 = cam_io_r(mem_base + + rdi_data->rdi_reg->rdi_debug_0); + val_1 = cam_io_r(mem_base + + rdi_data->rdi_reg->rdi_debug_1); + CAM_INFO(CAM_ISP, + "RDI res id:%d debug1:0x%x Height:0x%x, width:0x%x", + top_priv->in_rsrc[i].res_id, + val_1, ((val_0 >> 16) & 0x1FFF), + (val_0 & 0x1FFF)); + } + } + val_0 = cam_io_r(mem_base + + top_priv->common_data.common_reg->perf_stall_count); + + /* 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)) + CAM_INFO(CAM_ISP, "PP_FRAME_DROP"); + + if (evt_payload->irq_reg_val[0] & BIT(9)) + CAM_INFO(CAM_ISP, "RDI0_FRAME_DROP"); + + if (evt_payload->irq_reg_val[0] & BIT(10)) + CAM_INFO(CAM_ISP, "RDI1_FRAME_DROP"); + + if (evt_payload->irq_reg_val[0] & BIT(11)) + CAM_INFO(CAM_ISP, "RDI2_FRAME_DROP"); + + if (evt_payload->irq_reg_val[0] & BIT(16)) + CAM_INFO(CAM_ISP, "PP_OVERFLOW"); + + if (evt_payload->irq_reg_val[0] & BIT(17)) + CAM_INFO(CAM_ISP, "RDI0_OVERFLOW"); + + if (evt_payload->irq_reg_val[0] & BIT(18)) + CAM_INFO(CAM_ISP, "RDI1_OVERFLOW"); + + if (evt_payload->irq_reg_val[0] & BIT(19)) + CAM_INFO(CAM_ISP, "RDI2_OVERFLOW"); + } + + /* Check the violation errors */ + if (evt_payload->irq_reg_val[2] & hw_info->error_irq_mask[2]) { + if (evt_payload->irq_reg_val[2] & BIT(0)) + CAM_INFO(CAM_ISP, "PP_CAMIF_VIOLATION"); + + if (evt_payload->irq_reg_val[2] & BIT(1)) + CAM_INFO(CAM_ISP, "PP_VIOLATION"); + + if (evt_payload->irq_reg_val[2] & BIT(2)) + CAM_INFO(CAM_ISP, "RDI0_CAMIF_VIOLATION"); + + if (evt_payload->irq_reg_val[2] & BIT(3)) + CAM_INFO(CAM_ISP, "RDI1_CAMIF_VIOLATION"); + + if (evt_payload->irq_reg_val[2] & BIT(4)) + CAM_INFO(CAM_ISP, "RDI2_CAMIF_VIOLATION"); + + if (evt_payload->irq_reg_val[2] & BIT(5)) + CAM_INFO(CAM_ISP, "DIAG_VIOLATION"); + + val_0 = cam_io_r(mem_base + + top_priv->common_data.common_reg->violation_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"); + + 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); + +} + +static int cam_tfe_error_irq_bottom_half( + struct cam_tfe_hw_core_info *core_info, + struct cam_tfe_top_priv *top_priv, + struct cam_tfe_irq_evt_payload *evt_payload, + cam_hw_mgr_event_cb_func event_cb, + void *event_cb_priv) +{ + struct cam_isp_hw_event_info evt_info; + struct cam_tfe_hw_info *hw_info; + + 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); + } + + 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]); + + evt_info.err_type = CAM_TFE_IRQ_STATUS_VIOLATION; + 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); + } + + return 0; +} + +static int cam_tfe_rdi_irq_bottom_half( + struct cam_isp_resource_node *rdi_node, + bool epoch_process, + struct cam_tfe_irq_evt_payload *evt_payload) +{ + struct cam_tfe_rdi_data *rdi_priv; + struct cam_isp_hw_event_info evt_info; + struct cam_hw_info *hw_info; + + rdi_priv = (struct cam_tfe_rdi_data *)rdi_node->res_priv; + hw_info = rdi_node->hw_intf->hw_priv; + + evt_info.hw_idx = rdi_node->hw_intf->hw_idx; + evt_info.res_id = rdi_node->res_id; + evt_info.res_type = rdi_node->res_type; + + if ((!epoch_process) && (evt_payload->irq_reg_val[1] & + rdi_priv->reg_data->eof_irq_mask)) { + CAM_DBG(CAM_ISP, "Received EOF"); + if (rdi_priv->event_cb) + rdi_priv->event_cb(rdi_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + } + + if ((!epoch_process) && (evt_payload->irq_reg_val[1] & + rdi_priv->reg_data->sof_irq_mask)) { + CAM_DBG(CAM_ISP, "Received SOF"); + if (rdi_priv->event_cb) + rdi_priv->event_cb(rdi_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + } + + if (epoch_process && (evt_payload->irq_reg_val[1] & + rdi_priv->reg_data->epoch0_irq_mask)) { + CAM_DBG(CAM_ISP, "Received EPOCH0"); + + if (rdi_priv->event_cb) + rdi_priv->event_cb(rdi_priv->priv, + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); + } + + return 0; +} + +static int cam_tfe_camif_irq_bottom_half( + struct cam_isp_resource_node *camif_node, + bool epoch_process, + struct cam_tfe_irq_evt_payload *evt_payload) +{ + struct cam_tfe_camif_data *camif_priv; + struct cam_isp_hw_event_info evt_info; + struct cam_hw_info *hw_info; + uint32_t val; + + camif_priv = camif_node->res_priv; + hw_info = camif_node->hw_intf->hw_priv; + evt_info.hw_idx = camif_node->hw_intf->hw_idx; + evt_info.res_id = camif_node->res_id; + evt_info.res_type = camif_node->res_type; + + if ((!epoch_process) && (evt_payload->irq_reg_val[1] & + camif_priv->reg_data->eof_irq_mask)) { + CAM_DBG(CAM_ISP, "Received EOF"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + } + + if ((!epoch_process) && (evt_payload->irq_reg_val[1] & + camif_priv->reg_data->sof_irq_mask)) { + if ((camif_priv->enable_sof_irq_debug) && + (camif_priv->irq_debug_cnt <= + CAM_TFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "Received SOF"); + + camif_priv->irq_debug_cnt++; + if (camif_priv->irq_debug_cnt == + CAM_TFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX) { + camif_priv->enable_sof_irq_debug = + false; + camif_priv->irq_debug_cnt = 0; + } + } else + CAM_DBG(CAM_ISP, "Received SOF"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + } + + if (epoch_process && (evt_payload->irq_reg_val[1] & + camif_priv->reg_data->epoch0_irq_mask)) { + CAM_DBG(CAM_ISP, "Received EPOCH"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); + } + + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + val = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->diag_sensor_status_0); + CAM_DBG(CAM_ISP, "TFE_DIAG_SENSOR_STATUS: 0x%x", + camif_priv->mem_base, val); + } + + return 0; +} + +static int cam_tfe_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + 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_camif_data *camif_priv; + struct cam_tfe_rdi_data *rdi_priv; + cam_hw_mgr_event_cb_func event_cb = NULL; + void *event_cb_priv = NULL; + uint32_t i; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, + "Invalid params handle_priv:%pK, evt_payload_priv:%pK", + handler_priv, evt_payload_priv); + return 0; + } + + core_info = (struct cam_tfe_hw_core_info *)handler_priv; + top_priv = (struct cam_tfe_top_priv *)core_info->top_priv; + evt_payload = evt_payload_priv; + + /* process sof and eof */ + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + if ((top_priv->in_rsrc[i].res_id == + CAM_ISP_HW_TFE_IN_CAMIF) && + (top_priv->in_rsrc[i].res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + camif_priv = (struct cam_tfe_camif_data *) + top_priv->in_rsrc[i].res_priv; + event_cb = camif_priv->event_cb; + event_cb_priv = camif_priv->priv; + + if (camif_priv->reg_data->subscribe_irq_mask[1] & + evt_payload->irq_reg_val[1]) + cam_tfe_camif_irq_bottom_half( + &top_priv->in_rsrc[i], false, + evt_payload); + + } else if ((top_priv->in_rsrc[i].res_id >= + CAM_ISP_HW_TFE_IN_RDI0) && + (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)) { + rdi_priv = (struct cam_tfe_rdi_data *) + top_priv->in_rsrc[i].res_priv; + event_cb = rdi_priv->event_cb; + event_cb_priv = rdi_priv->priv; + + if (rdi_priv->reg_data->subscribe_irq_mask[1] & + evt_payload->irq_reg_val[1]) + cam_tfe_rdi_irq_bottom_half( + &top_priv->in_rsrc[i], false, + evt_payload); + } + } + + /* process the irq errors */ + cam_tfe_error_irq_bottom_half(core_info, top_priv, evt_payload, + event_cb, event_cb_priv); + + /* process the reg update in the bus */ + 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); + } + + /* process the epoch */ + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + if ((top_priv->in_rsrc[i].res_id == + CAM_ISP_HW_TFE_IN_CAMIF) && + (top_priv->in_rsrc[i].res_state == + CAM_ISP_RESOURCE_STATE_STREAMING)) { + camif_priv = (struct cam_tfe_camif_data *) + 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( + &top_priv->in_rsrc[i], true, + evt_payload); + } else if ((top_priv->in_rsrc[i].res_id >= + CAM_ISP_HW_TFE_IN_RDI0) && + (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)) { + rdi_priv = (struct cam_tfe_rdi_data *) + 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( + &top_priv->in_rsrc[i], true, + evt_payload); + } + } + + /* process the bufone */ + 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); + } + + cam_tfe_put_evt_payload(core_info, &evt_payload); + + return 0; +} + +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 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]) { + 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]); + 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]); + + cam_io_w_mb(core_info->tfe_hw_info->global_clear_bitmask, + mem_base + core_info->tfe_hw_info->top_irq_cmd); + } + + return 0; +} + +irqreturn_t cam_tfe_irq(int irq_num, void *data) +{ + struct cam_hw_info *tfe_hw; + struct cam_tfe_hw_core_info *core_info; + struct cam_tfe_top_priv *top_priv; + void __iomem *mem_base; + struct cam_tfe_irq_evt_payload *evt_payload; + uint32_t top_irq_status[CAM_TFE_TOP_IRQ_REG_NUM] = {0}; + uint32_t bus_irq_status[CAM_TFE_BUS_MAX_IRQ_REGISTERS] = {0}; + uint32_t i, ccif_violation = 0, overflow_status = 0; + uint32_t image_sz_violation = 0; + void *bh_cmd = NULL; + int rc = -EINVAL; + + if (!data) + return IRQ_NONE; + + tfe_hw = (struct cam_hw_info *)data; + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + top_priv = (struct cam_tfe_top_priv *)core_info->top_priv; + mem_base = top_priv->common_data.soc_info->reg_map[0].mem_base; + + if (tfe_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_ISP, "TFE:%d hw is not powered up", + core_info->core_index); + return IRQ_HANDLED; + } + + for (i = 0; i < CAM_TFE_TOP_IRQ_REG_NUM; i++) + top_irq_status[i] = cam_io_r(mem_base + + core_info->tfe_hw_info->top_irq_status[i]); + + for (i = 0; i < CAM_TFE_TOP_IRQ_REG_NUM; i++) + cam_io_w(top_irq_status[i], mem_base + + core_info->tfe_hw_info->top_irq_clear[i]); + + CAM_DBG(CAM_ISP, "TFE:%d IRQ status_0:0x%x status_1:0x%x status_2:0x%x", + core_info->core_index, top_irq_status[0], + top_irq_status[1], top_irq_status[2]); + + if (top_irq_status[0] & core_info->tfe_hw_info->bus_reg_irq_mask[0]) { + for (i = 0; i < CAM_TFE_BUS_MAX_IRQ_REGISTERS; i++) + bus_irq_status[i] = cam_io_r(mem_base + + core_info->tfe_hw_info->bus_irq_status[i]); + + for (i = 0; i < CAM_TFE_BUS_MAX_IRQ_REGISTERS; i++) + cam_io_w(bus_irq_status[i], mem_base + + core_info->tfe_hw_info->bus_irq_clear[i]); + + ccif_violation = cam_io_r(mem_base + + core_info->tfe_hw_info->bus_violation_reg); + overflow_status = cam_io_r(mem_base + + core_info->tfe_hw_info->bus_overflow_reg); + image_sz_violation = cam_io_r(mem_base + + core_info->tfe_hw_info->bus_image_size_vilation_reg); + + cam_io_w(core_info->tfe_hw_info->global_clear_bitmask, + mem_base + core_info->tfe_hw_info->bus_irq_cmd); + + CAM_DBG(CAM_ISP, "TFE:%d BUS IRQ status_0:0x%x status_1:0x%x", + core_info->core_index, bus_irq_status[0], + bus_irq_status[1]); + } + + cam_io_w_mb(core_info->tfe_hw_info->global_clear_bitmask, + mem_base + core_info->tfe_hw_info->top_irq_cmd); + + /* check reset */ + if ((top_irq_status[0] & core_info->tfe_hw_info->reset_irq_mask[0]) || + (top_irq_status[1] & + core_info->tfe_hw_info->reset_irq_mask[1]) || + (top_irq_status[2] & + core_info->tfe_hw_info->reset_irq_mask[2])) { + /* Reset ack */ + complete(&core_info->reset_complete); + return IRQ_HANDLED; + } + + /* Check the irq errors */ + cam_tfe_irq_err_top_half(core_info, mem_base, top_irq_status); + + rc = cam_tfe_get_evt_payload(core_info, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ status0=0x%x status2=0x%x", + top_irq_status[0], top_irq_status[1]); + goto end; + } + + cam_tfe_get_timestamp(&evt_payload->ts); + + for (i = 0; i < CAM_TFE_TOP_IRQ_REG_NUM; i++) + evt_payload->irq_reg_val[i] = top_irq_status[i]; + + for (i = 0; i < CAM_TFE_BUS_MAX_IRQ_REGISTERS; i++) + evt_payload->bus_irq_val[i] = bus_irq_status[i]; + + evt_payload->ccif_violation_status = ccif_violation; + evt_payload->overflow_status = overflow_status; + evt_payload->image_size_violation_status = image_sz_violation; + + evt_payload->core_index = core_info->core_index; + evt_payload->core_info = core_info; + + rc = tasklet_bh_api.get_bh_payload_func( + top_priv->tasklet_info, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No payload, IRQ handling frozen"); + cam_tfe_put_evt_payload(core_info, &evt_payload); + goto end; + } + + tasklet_bh_api.bottom_half_enqueue_func( + top_priv->tasklet_info, + bh_cmd, + core_info, + evt_payload, + cam_tfe_irq_bottom_half); + +end: + return IRQ_HANDLED; + +} + +static int cam_tfe_top_set_hw_clk_rate( + struct cam_tfe_top_priv *top_priv) +{ + struct cam_hw_soc_info *soc_info = NULL; + int i, rc = 0; + unsigned long max_clk_rate = 0; + + soc_info = top_priv->common_data.soc_info; + + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + if (top_priv->req_clk_rate[i] > max_clk_rate) + max_clk_rate = top_priv->req_clk_rate[i]; + } + if (max_clk_rate == top_priv->hw_clk_rate) + return 0; + + CAM_DBG(CAM_ISP, "TFE:%d Clock name=%s idx=%d clk=%llu", + top_priv->common_data.soc_info->index, + soc_info->clk_name[soc_info->src_clk_idx], + soc_info->src_clk_idx, max_clk_rate); + + rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); + + if (!rc) + top_priv->hw_clk_rate = max_clk_rate; + else + CAM_ERR(CAM_ISP, "TFE:%d set src clock rate:%lld failed, rc=%d", + top_priv->common_data.soc_info->index, max_clk_rate, rc); + + return rc; +} + +static struct cam_axi_vote *cam_tfe_top_delay_bw_reduction( + struct cam_tfe_top_priv *top_priv, + uint64_t *to_be_applied_bw) +{ + uint32_t i, j; + int vote_idx = -1; + uint64_t max_bw = 0; + uint64_t total_bw; + struct cam_axi_vote *curr_l_vote; + + for (i = 0; i < (CAM_TFE_TOP_IN_PORT_MAX * + CAM_TFE_DELAY_BW_REDUCTION_NUM_FRAMES); i++) { + total_bw = 0; + curr_l_vote = &top_priv->last_vote[i]; + for (j = 0; j < curr_l_vote->num_paths; j++) { + if (total_bw > + (U64_MAX - + curr_l_vote->axi_path[j].camnoc_bw)) { + CAM_ERR(CAM_ISP, "Overflow at idx: %d", j); + return NULL; + } + + total_bw += curr_l_vote->axi_path[j].camnoc_bw; + } + + if (total_bw > max_bw) { + vote_idx = i; + max_bw = total_bw; + } + } + + if (vote_idx < 0) + return NULL; + + *to_be_applied_bw = max_bw; + + return &top_priv->last_vote[vote_idx]; +} + +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 *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; + int rc = 0; + uint32_t i; + uint32_t num_paths = 0; + uint64_t total_bw_new_vote = 0; + bool bw_unchanged = true; + bool apply_bw_update = false; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + if (top_priv->axi_vote_control[i] == + CAM_TFE_BW_CONTROL_INCLUDE) { + if (num_paths + + top_priv->req_axi_vote[i].num_paths > + CAM_CPAS_MAX_PATHS_PER_CLIENT) { + CAM_ERR(CAM_ISP, + "Required paths(%d) more than max(%d)", + num_paths + + top_priv->req_axi_vote[i].num_paths, + CAM_CPAS_MAX_PATHS_PER_CLIENT); + return -EINVAL; + } + + 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( + struct cam_axi_per_path_bw_vote)); + num_paths += top_priv->req_axi_vote[i].num_paths; + } + } + + agg_vote.num_paths = num_paths; + + 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), + 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); + + total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw; + } + + 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) || + (total_bw_new_vote != top_priv->total_bw_applied)) + bw_unchanged = false; + + CAM_DBG(CAM_PERF, + "tfe[%d] : applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d", + top_priv->common_data.hw_intf->hw_idx, + top_priv->total_bw_applied, total_bw_new_vote, + bw_unchanged, start_stop); + + if (bw_unchanged) { + CAM_DBG(CAM_ISP, "BW config unchanged"); + return 0; + } + + if (start_stop) { + /* need to vote current request immediately */ + 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_counter = (top_priv->last_counter + 1) % + (CAM_TFE_TOP_IN_PORT_MAX * + CAM_TFE_DELAY_BW_REDUCTION_NUM_FRAMES); + } else { + /* + * Find max bw request in last few frames. This will the bw + * that we want to vote to CPAS now. + */ + to_be_applied_axi_vote = + cam_tfe_top_delay_bw_reduction(top_priv, + &total_bw_new_vote); + if (!to_be_applied_axi_vote) { + CAM_ERR(CAM_ISP, "to_be_applied_axi_vote is NULL"); + return -EINVAL; + } + } + + for (i = 0; i < to_be_applied_axi_vote->num_paths; i++) { + CAM_DBG(CAM_PERF, + "tfe[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]", + top_priv->common_data.hw_intf->hw_idx, + cam_cpas_axi_util_path_type_to_string( + to_be_applied_axi_vote->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + to_be_applied_axi_vote->axi_path[i].transac_type), + to_be_applied_axi_vote->axi_path[i].camnoc_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ab_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ib_bw); + } + + if ((to_be_applied_axi_vote->num_paths != + top_priv->applied_axi_vote.num_paths) || + (total_bw_new_vote != top_priv->total_bw_applied)) + apply_bw_update = true; + + CAM_DBG(CAM_PERF, + "tfe[%d] : Delayed update: applied_total=%lld, new_total=%lld apply_bw_update=%d, start_stop=%d", + top_priv->common_data.hw_intf->hw_idx, + top_priv->total_bw_applied, total_bw_new_vote, + apply_bw_update, start_stop); + + if (apply_bw_update) { + rc = cam_cpas_update_axi_vote(soc_private->cpas_handle, + to_be_applied_axi_vote); + if (!rc) { + memcpy(&top_priv->applied_axi_vote, + to_be_applied_axi_vote, + sizeof(struct cam_axi_vote)); + top_priv->total_bw_applied = total_bw_new_vote; + } else { + CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); + } + } + + return rc; +} + +static int cam_tfe_top_get_base(struct cam_tfe_top_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t mem_base = 0; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Error Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res || !top_priv || + !top_priv->common_data.soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid args"); + return -EINVAL; + } + + cdm_util_ops = + (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_changebase(); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE( + top_priv->common_data.soc_info, TFE_CORE_BASE_IDX); + + cdm_util_ops->cdm_write_changebase( + cdm_args->cmd.cmd_buf_addr, mem_base); + cdm_args->cmd.used_bytes = (size * 4); + + return 0; +} + +static int cam_tfe_top_get_reg_update( + struct cam_tfe_top_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_tfe_camif_data *camif_rsrc_data = NULL; + struct cam_tfe_rdi_data *rdi_rsrc_data = NULL; + struct cam_isp_resource_node *in_res; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + in_res = cdm_args->res; + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + if (in_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) { + camif_rsrc_data = in_res->res_priv; + reg_val_pair[0] = camif_rsrc_data->camif_reg->reg_update_cmd; + reg_val_pair[1] = + camif_rsrc_data->reg_data->reg_update_cmd_data; + } else if ((in_res->res_id >= CAM_ISP_HW_TFE_IN_RDI0) && + (in_res->res_id <= CAM_ISP_HW_TFE_IN_RDI2)) { + rdi_rsrc_data = in_res->res_priv; + reg_val_pair[0] = rdi_rsrc_data->rdi_reg->reg_update_cmd; + reg_val_pair[1] = rdi_rsrc_data->reg_data->reg_update_cmd_data; + } + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_tfe_top_clock_update( + struct cam_tfe_top_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_tfe_clock_update_args *clk_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int i, rc = 0; + + clk_update = + (struct cam_tfe_clock_update_args *)cmd_args; + res = clk_update->node_res; + + if (!res || !res->hw_intf->hw_priv) { + CAM_ERR(CAM_ISP, "Invalid input res %pK", res); + return -EINVAL; + } + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_TFE_IN || + res->res_id >= CAM_ISP_HW_TFE_IN_MAX) { + CAM_ERR(CAM_ISP, "TFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + if (top_priv->in_rsrc[i].res_id == res->res_id) { + top_priv->req_clk_rate[i] = clk_update->clk_rate; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_DBG(CAM_ISP, + "TFE:%d Not ready to set clocks yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else + rc = cam_tfe_top_set_hw_clk_rate(top_priv); + + return rc; +} + +static int cam_tfe_top_bw_update( + struct cam_tfe_top_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_tfe_bw_update_args *bw_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_update = (struct cam_tfe_bw_update_args *)cmd_args; + res = bw_update->node_res; + + if (!res || !res->hw_intf || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_TFE_IN || + res->res_id >= CAM_ISP_HW_TFE_IN_MAX) { + CAM_ERR(CAM_ISP, "TFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_ISP_HW_TFE_IN_MAX; i++) { + if (top_priv->in_rsrc[i].res_id == res->res_id) { + memcpy(&top_priv->req_axi_vote[i], &bw_update->isp_vote, + sizeof(struct cam_axi_vote)); + top_priv->axi_vote_control[i] = + CAM_TFE_BW_CONTROL_INCLUDE; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "TFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_tfe_top_set_axi_bw_vote(top_priv, false); + } + + return rc; +} + +static int cam_tfe_top_bw_control( + struct cam_tfe_top_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_tfe_bw_control_args *bw_ctrl = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_ctrl = (struct cam_tfe_bw_control_args *)cmd_args; + res = bw_ctrl->node_res; + + if (!res || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_TFE_IN || + res->res_id >= CAM_ISP_HW_TFE_IN_MAX) { + CAM_ERR(CAM_ISP, "TFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + if (top_priv->in_rsrc[i].res_id == res->res_id) { + top_priv->axi_vote_control[i] = bw_ctrl->action; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "TFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_tfe_top_set_axi_bw_vote(top_priv, true); + } + + return rc; +} + +static int cam_tfe_top_get_reg_dump( + struct cam_tfe_top_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *reg_dump_cmd = cmd_args; + struct cam_tfe_soc_private *soc_private; + struct cam_tfe_reg_dump_data *reg_dump_data; + struct cam_hw_soc_info *soc_info; + void __iomem *mem_base; + int i, j, num_reg_dump_entries; + uint32_t val_0, val_1, val_2, val_3, wm_offset, start_offset; + uint32_t end_offset, lut_word_size, lut_size, lut_bank_sel, lut_dmi_reg; + + if (!reg_dump_cmd) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((reg_dump_cmd->res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (reg_dump_cmd->res->res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + 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; + CAM_INFO(CAM_ISP, "dump tfe:%d registers", + top_priv->common_data.hw_intf->hw_idx); + + reg_dump_data = top_priv->common_data.reg_dump_data; + num_reg_dump_entries = reg_dump_data->num_reg_dump_entries; + for (i = 0; i < num_reg_dump_entries; i++) { + start_offset = reg_dump_data->reg_entry[i].start_offset; + end_offset = reg_dump_data->reg_entry[i].end_offset; + + for (j = start_offset; (j + 0xc) <= end_offset; j += 0x10) { + val_0 = cam_io_r_mb(mem_base + j); + val_1 = cam_io_r_mb(mem_base + j + 4); + val_2 = cam_io_r_mb(mem_base + j + 0x8); + val_3 = cam_io_r_mb(mem_base + j + 0xc); + CAM_INFO(CAM_ISP, "0x%04x=0x%08x 0x%08x 0x%08x 0x%08x", + j, val_0, val_1, val_2, val_3); + } + } + + num_reg_dump_entries = reg_dump_data->num_lut_dump_entries; + for (i = 0; i < num_reg_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; + + 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++) { + val_0 = cam_io_r_mb(mem_base + 0xC30); + CAM_INFO(CAM_ISP, "Bank%d:0x%x LO: 0x%x", + lut_bank_sel, j, val_0); + } + } + /* No mem selected */ + cam_io_w_mb(0, mem_base + 0xC24); + cam_io_w_mb(0, mem_base + 0xC28); + + start_offset = reg_dump_data->bus_start_addr; + end_offset = reg_dump_data->bus_write_top_end_addr; + + CAM_INFO(CAM_ISP, "bus start addr:0x%x end_offset:0x%x", + start_offset, end_offset); + + for (i = start_offset; (i + 0xc) <= end_offset; i += 0x10) { + val_0 = cam_io_r_mb(mem_base + i); + val_1 = cam_io_r_mb(mem_base + i + 4); + val_2 = cam_io_r_mb(mem_base + i + 0x8); + val_3 = cam_io_r_mb(mem_base + i + 0xc); + CAM_INFO(CAM_ISP, "0x%04x=0x%08x 0x%08x 0x%08x 0x%08x", + i, val_0, val_1, val_2, val_3); + } + + wm_offset = reg_dump_data->bus_client_start_addr; + + CAM_INFO(CAM_ISP, "bus wm offset:0x%x", + wm_offset); + + for (j = 0; j < reg_dump_data->num_bus_clients; j++) { + for (i = 0x0; (i + 0xc) <= 0x3C; i += 0x10) { + val_0 = cam_io_r_mb(mem_base + wm_offset + i); + val_1 = cam_io_r_mb(mem_base + wm_offset + i + 4); + val_2 = cam_io_r_mb(mem_base + wm_offset + i + 0x8); + val_3 = cam_io_r_mb(mem_base + wm_offset + i + 0xc); + CAM_INFO(CAM_ISP, "0x%04x=0x%08x 0x%08x 0x%08x 0x%08x", + (wm_offset + i), val_0, val_1, val_2, val_3); + } + for (i = 0x60; (i + 0xc) <= 0x80; i += 0x10) { + val_0 = cam_io_r_mb(mem_base + wm_offset + i); + val_1 = cam_io_r_mb(mem_base + wm_offset + i + 4); + val_2 = cam_io_r_mb(mem_base + wm_offset + i + 0x8); + val_3 = cam_io_r_mb(mem_base + wm_offset + i + 0xc); + CAM_INFO(CAM_ISP, "0x%04x=0x%08x 0x%08x 0x%08x 0x%08x", + (wm_offset + i), val_0, val_1, val_2, val_3); + } + wm_offset += reg_dump_data->bus_client_offset; + } + + 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); + + /* dump the clock votings */ + CAM_INFO(CAM_ISP, "TFE:%d clk=%ld", + top_priv->common_data.hw_intf->hw_idx, + top_priv->hw_clk_rate); + + 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) +{ + struct cam_tfe_top_priv *top_priv; + struct cam_isp_hw_get_cmd_update *cmd_update; + struct cam_isp_resource_node *camif_res = NULL; + void __iomem *mem_base; + uint32_t i; + + int rc = 0; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments\n"); + return -EINVAL; + } + top_priv = (struct cam_tfe_top_priv *)core_info->top_priv; + cmd_update = (struct cam_isp_hw_get_cmd_update *)cmd_args; + camif_res = cmd_update->res; + mem_base = top_priv->common_data.soc_info->reg_map[0].mem_base; + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) { + CAM_ERR(CAM_ISP, "Error! Invalid state\n"); + return 0; + } + + for (i = 0; i < CAM_TFE_TOP_IRQ_REG_NUM; i++) { + CAM_INFO(CAM_ISP, + "Core Id =%d TOP IRQ status[%d ] val 0x%x", + core_info->core_index, i, + cam_io_r_mb(mem_base + + core_info->tfe_hw_info->top_irq_status[i])); + } + + for (i = 0; i < CAM_TFE_BUS_MAX_IRQ_REGISTERS; i++) { + CAM_INFO(CAM_ISP, + "Core Id =%d BUS IRQ status[%d ] val:0x%x", + core_info->core_index, i, + cam_io_r_mb(mem_base + + core_info->tfe_hw_info->bus_irq_status[i])); + } + + return rc; +} + +int cam_tfe_top_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size) +{ + struct cam_tfe_top_priv *top_priv; + struct cam_tfe_acquire_args *args; + struct cam_tfe_hw_tfe_in_acquire_args *acquire_args; + struct cam_tfe_camif_data *camif_data; + struct cam_tfe_rdi_data *rdi_data; + uint32_t i; + int rc = -EINVAL; + + if (!device_priv || !reserve_args) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_tfe_top_priv *)device_priv; + args = (struct cam_tfe_acquire_args *)reserve_args; + acquire_args = &args->tfe_in; + + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + CAM_DBG(CAM_ISP, "i :%d res_id:%d state:%d", i, + acquire_args->res_id, top_priv->in_rsrc[i].res_state); + + if ((top_priv->in_rsrc[i].res_id == acquire_args->res_id) && + (top_priv->in_rsrc[i].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE)) { + rc = cam_tfe_validate_pix_pattern( + acquire_args->in_port->pix_pattern); + if (rc) + return rc; + + if (acquire_args->res_id == CAM_ISP_HW_TFE_IN_CAMIF) { + camif_data = (struct cam_tfe_camif_data *) + top_priv->in_rsrc[i].res_priv; + camif_data->pix_pattern = + acquire_args->in_port->pix_pattern; + camif_data->dsp_mode = + acquire_args->in_port->dsp_mode; + camif_data->first_pixel = + acquire_args->in_port->left_start; + camif_data->last_pixel = + acquire_args->in_port->left_end; + camif_data->first_line = + acquire_args->in_port->line_start; + camif_data->last_line = + acquire_args->in_port->line_end; + camif_data->camif_pd_enable = + acquire_args->camif_pd_enable; + camif_data->dual_tfe_sync_sel = + acquire_args->dual_tfe_sync_sel_idx; + camif_data->sync_mode = acquire_args->sync_mode; + camif_data->event_cb = args->event_cb; + camif_data->priv = args->priv; + + CAM_DBG(CAM_ISP, + "TFE:%d pix_pattern:%d dsp_mode=%d", + top_priv->in_rsrc[i].hw_intf->hw_idx, + camif_data->pix_pattern, + camif_data->dsp_mode); + } else { + rdi_data = (struct cam_tfe_rdi_data *) + top_priv->in_rsrc[i].res_priv; + rdi_data->pix_pattern = + acquire_args->in_port->pix_pattern; + rdi_data->sync_mode = acquire_args->sync_mode; + rdi_data->event_cb = args->event_cb; + rdi_data->priv = args->priv; + } + + top_priv->in_rsrc[i].cdm_ops = acquire_args->cdm_ops; + top_priv->in_rsrc[i].tasklet_info = args->tasklet; + top_priv->in_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + top_priv->tasklet_info = args->tasklet; + acquire_args->rsrc_node = + &top_priv->in_rsrc[i]; + rc = 0; + break; + } + } + + return rc; +} + +int cam_tfe_top_release(void *device_priv, + void *release_args, uint32_t arg_size) +{ + struct cam_tfe_top_priv *top_priv; + struct cam_isp_resource_node *in_res; + + if (!device_priv || !release_args) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_tfe_top_priv *)device_priv; + in_res = (struct cam_isp_resource_node *)release_args; + + CAM_DBG(CAM_ISP, "TFE:%d resource id:%d in state %d", + in_res->hw_intf->hw_idx, in_res->res_id, + in_res->res_state); + if (in_res->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "TFE:%d Error Resource Invalid res_state :%d", + in_res->hw_intf->hw_idx, in_res->res_state); + return -EINVAL; + } + in_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + in_res->cdm_ops = NULL; + in_res->tasklet_info = NULL; + in_res->rdi_only_ctx = 0; + + return 0; +} + +static int cam_tfe_camif_resource_start( + struct cam_tfe_hw_core_info *core_info, + struct cam_isp_resource_node *camif_res) +{ + struct cam_tfe_camif_data *rsrc_data; + struct cam_tfe_soc_private *soc_private; + uint32_t val = 0; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t computed_epoch_line_cfg; + + if (!camif_res || !core_info) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + if (camif_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "TFE:%d Error Invalid camif res res_state:%d", + core_info->core_index, camif_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_tfe_camif_data *)camif_res->res_priv; + soc_private = rsrc_data->soc_info->soc_private; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "TFE:%d Error soc_private NULL", + core_info->core_index); + return -ENODEV; + } + + /* Camif module config */ + val = cam_io_r(rsrc_data->mem_base + + rsrc_data->camif_reg->module_cfg); + val &= ~(rsrc_data->reg_data->pixel_pattern_mask); + val |= (rsrc_data->pix_pattern << + rsrc_data->reg_data->pixel_pattern_shift); + val |= (1 << rsrc_data->reg_data->module_enable_shift); + val |= (1 << rsrc_data->reg_data->pix_out_enable_shift); + if (rsrc_data->camif_pd_enable) + val |= (1 << rsrc_data->reg_data->pdaf_output_enable_shift); + + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->camif_reg->module_cfg); + + CAM_DBG(CAM_ISP, "TFE:%d camif module config val:%d", + core_info->core_index, val); + + /* Config tfe core*/ + val = 0; + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val = (1 << rsrc_data->reg_data->extern_reg_update_shift); + + if ((rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) || + (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_MASTER)) { + val |= (1 << rsrc_data->reg_data->dual_tfe_pix_en_shift); + val |= ((rsrc_data->dual_tfe_sync_sel + 1) << + rsrc_data->reg_data->dual_tfe_sync_sel_shift); + } + + if (!rsrc_data->camif_pd_enable) + val |= (1 << rsrc_data->reg_data->camif_pd_rdi2_src_sel_shift); + + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_0); + + CAM_DBG(CAM_ISP, "TFE:%d core_cfg 0 val:0x%x", core_info->core_index, + val); + + val = cam_io_r(rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_1); + val &= ~BIT(0); + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_1); + CAM_DBG(CAM_ISP, "TFE:%d core_cfg 1 val:0x%x", core_info->core_index, + val); + + /* Epoch config */ + epoch0_irq_mask = ((rsrc_data->last_line - + rsrc_data->first_line) / 2) + + rsrc_data->first_line; + epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & + 0xFFFF; + computed_epoch_line_cfg = (epoch0_irq_mask << 16) | + epoch1_irq_mask; + cam_io_w_mb(computed_epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_reg->epoch_irq_cfg); + CAM_DBG(CAM_ISP, "TFE:%d first_line: %u\n" + "last_line: %u\n" + "epoch_line_cfg: 0x%x", + core_info->core_index, + rsrc_data->first_line, + rsrc_data->last_line, + computed_epoch_line_cfg); + + camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->camif_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP val:%d", camif_res->hw_intf->hw_idx, + rsrc_data->reg_data->reg_update_cmd_data); + + /* Disable sof irq debug flag */ + rsrc_data->enable_sof_irq_debug = false; + rsrc_data->irq_debug_cnt = 0; + + if (rsrc_data->camif_debug & CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->common_reg->diag_config); + val |= rsrc_data->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->diag_config); + } + + /* Enable the irq */ + cam_tfe_irq_config(core_info, rsrc_data->reg_data->subscribe_irq_mask, + CAM_TFE_TOP_IRQ_REG_NUM, true); + + /* Program perf counters */ + val = (1 << rsrc_data->reg_data->perf_cnt_start_cmd_shift) | + (1 << rsrc_data->reg_data->perf_cnt_continuous_shift) | + (1 << rsrc_data->reg_data->perf_client_sel_shift) | + (1 << rsrc_data->reg_data->perf_window_start_shift) | + (2 << rsrc_data->reg_data->perf_window_end_shift); + cam_io_w_mb(val, + rsrc_data->mem_base + rsrc_data->common_reg->perf_cnt_cfg); + CAM_DBG(CAM_ISP, "TFE:%d perf_cfg val:%d", core_info->core_index, + val); + + /* Enable the top debug registers */ + cam_io_w_mb(0x1, + rsrc_data->mem_base + rsrc_data->common_reg->debug_cfg); + + CAM_DBG(CAM_ISP, "Start Camif TFE %d Done", core_info->core_index); + return 0; +} + +int cam_tfe_top_start(struct cam_tfe_hw_core_info *core_info, + void *start_args, uint32_t arg_size) +{ + struct cam_tfe_top_priv *top_priv; + struct cam_isp_resource_node *in_res; + struct cam_hw_info *hw_info = NULL; + struct cam_tfe_rdi_data *rsrc_rdi_data; + uint32_t val; + int rc = 0; + + if (!start_args) { + CAM_ERR(CAM_ISP, "TFE:%d Error Invalid input arguments", + core_info->core_index); + return -EINVAL; + } + + top_priv = (struct cam_tfe_top_priv *)core_info->top_priv; + in_res = (struct cam_isp_resource_node *)start_args; + hw_info = (struct cam_hw_info *)in_res->hw_intf->hw_priv; + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "TFE:%d HW not powered up", + core_info->core_index); + rc = -EPERM; + goto end; + } + + rc = cam_tfe_top_set_hw_clk_rate(top_priv); + if (rc) { + CAM_ERR(CAM_ISP, "TFE:%d set_hw_clk_rate failed, rc=%d", + hw_info->soc_info.index, rc); + return rc; + } + + rc = cam_tfe_top_set_axi_bw_vote(top_priv, true); + if (rc) { + CAM_ERR(CAM_ISP, "TFE:%d set_axi_bw_vote failed, rc=%d", + core_info->core_index, rc); + return rc; + } + + if (in_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) { + cam_tfe_camif_resource_start(core_info, in_res); + } else if (in_res->res_id >= CAM_ISP_HW_TFE_IN_RDI0 || + in_res->res_id <= CAM_ISP_HW_TFE_IN_RDI2) { + rsrc_rdi_data = (struct cam_tfe_rdi_data *) in_res->res_priv; + val = (rsrc_rdi_data->pix_pattern << + rsrc_rdi_data->reg_data->pixel_pattern_shift); + + val |= (1 << rsrc_rdi_data->reg_data->rdi_out_enable_shift); + cam_io_w_mb(val, rsrc_rdi_data->mem_base + + rsrc_rdi_data->rdi_reg->rdi_module_config); + + /* Epoch config */ + cam_io_w_mb(rsrc_rdi_data->reg_data->epoch_line_cfg, + rsrc_rdi_data->mem_base + + rsrc_rdi_data->rdi_reg->rdi_epoch_irq); + + /* Reg Update */ + cam_io_w_mb(rsrc_rdi_data->reg_data->reg_update_cmd_data, + rsrc_rdi_data->mem_base + + rsrc_rdi_data->rdi_reg->reg_update_cmd); + in_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Enable the irq */ + if (in_res->rdi_only_ctx) + cam_tfe_irq_config(core_info, + rsrc_rdi_data->reg_data->subscribe_irq_mask, + CAM_TFE_TOP_IRQ_REG_NUM, true); + + CAM_DBG(CAM_ISP, "TFE:%d Start RDI %d", core_info->core_index, + in_res->res_id - CAM_ISP_HW_TFE_IN_RDI0); + } + + core_info->irq_err_config_cnt++; + 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); + +end: + return rc; +} + +int cam_tfe_top_stop(struct cam_tfe_hw_core_info *core_info, + void *stop_args, uint32_t arg_size) +{ + struct cam_tfe_top_priv *top_priv; + struct cam_isp_resource_node *in_res; + struct cam_hw_info *hw_info = NULL; + struct cam_tfe_camif_data *camif_data; + struct cam_tfe_rdi_data *rsrc_rdi_data; + uint32_t val = 0; + int i, rc = 0; + + if (!stop_args) { + CAM_ERR(CAM_ISP, "TFE:%d Error Invalid input arguments", + core_info->core_index); + return -EINVAL; + } + + top_priv = (struct cam_tfe_top_priv *)core_info->top_priv; + in_res = (struct cam_isp_resource_node *)stop_args; + hw_info = (struct cam_hw_info *)in_res->hw_intf->hw_priv; + + if (in_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + in_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + if (in_res->res_id == CAM_ISP_HW_TFE_IN_CAMIF) { + camif_data = (struct cam_tfe_camif_data *)in_res->res_priv; + + cam_io_w_mb(0, camif_data->mem_base + + camif_data->camif_reg->module_cfg); + + cam_tfe_irq_config(core_info, + camif_data->reg_data->subscribe_irq_mask, + CAM_TFE_TOP_IRQ_REG_NUM, false); + + if (in_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + in_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + val = cam_io_r_mb(camif_data->mem_base + + camif_data->common_reg->diag_config); + if (val & camif_data->reg_data->enable_diagnostic_hw) { + val &= ~camif_data->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, camif_data->mem_base + + camif_data->common_reg->diag_config); + } + } else if ((in_res->res_id >= CAM_ISP_HW_TFE_IN_RDI0) && + (in_res->res_id <= CAM_ISP_HW_TFE_IN_RDI2)) { + rsrc_rdi_data = (struct cam_tfe_rdi_data *) in_res->res_priv; + cam_io_w_mb(0x0, rsrc_rdi_data->mem_base + + rsrc_rdi_data->rdi_reg->rdi_module_config); + + if (in_res->rdi_only_ctx) + cam_tfe_irq_config(core_info, + rsrc_rdi_data->reg_data->subscribe_irq_mask, + CAM_TFE_TOP_IRQ_REG_NUM, false); + + if (in_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + in_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + } else { + CAM_ERR(CAM_ISP, "TFE:%d Invalid res id:%d", + core_info->core_index, in_res->res_id); + return -EINVAL; + } + + if (!rc) { + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + if (top_priv->in_rsrc[i].res_id == in_res->res_id) { + top_priv->req_clk_rate[i] = 0; + memset(&top_priv->req_axi_vote[i], 0, + sizeof(struct cam_axi_vote)); + top_priv->axi_vote_control[i] = + CAM_TFE_BW_CONTROL_EXCLUDE; + break; + } + } + } + + core_info->irq_err_config_cnt--; + if (!core_info->irq_err_config_cnt) + cam_tfe_irq_config(core_info, + core_info->tfe_hw_info->error_irq_mask, + CAM_TFE_TOP_IRQ_REG_NUM, false); + + return rc; +} + +int cam_tfe_top_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + struct cam_tfe_hw_core_info *core_info) +{ + struct cam_tfe_top_priv *top_priv = NULL; + struct cam_tfe_top_hw_info *hw_info = top_hw_info; + struct cam_tfe_soc_private *soc_private = NULL; + struct cam_tfe_camif_data *camif_priv = NULL; + struct cam_tfe_rdi_data *rdi_priv = NULL; + int i, j, rc = 0; + + top_priv = kzalloc(sizeof(struct cam_tfe_top_priv), + GFP_KERNEL); + if (!top_priv) { + CAM_DBG(CAM_ISP, "TFE:%DError Failed to alloc for tfe_top_priv", + core_info->core_index); + rc = -ENOMEM; + goto end; + } + core_info->top_priv = top_priv; + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "TFE:%d Error soc_private NULL", + core_info->core_index); + rc = -ENODEV; + goto free_tfe_top_priv; + } + + top_priv->hw_clk_rate = 0; + 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; + + for (i = 0, j = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + top_priv->in_rsrc[i].res_type = CAM_ISP_RESOURCE_TFE_IN; + top_priv->in_rsrc[i].hw_intf = hw_intf; + top_priv->in_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + top_priv->req_clk_rate[i] = 0; + memset(&top_priv->req_axi_vote[i], 0, + sizeof(struct cam_axi_vote)); + top_priv->axi_vote_control[i] = + CAM_TFE_BW_CONTROL_EXCLUDE; + + if (hw_info->in_port[i] == CAM_TFE_CAMIF_VER_1_0) { + top_priv->in_rsrc[i].res_id = + CAM_ISP_HW_TFE_IN_CAMIF; + + camif_priv = kzalloc(sizeof(struct cam_tfe_camif_data), + GFP_KERNEL); + if (!camif_priv) { + CAM_DBG(CAM_ISP, + "TFE:%dError Failed to alloc for camif_priv", + core_info->core_index); + goto free_tfe_top_priv; + } + + top_priv->in_rsrc[i].res_priv = camif_priv; + + camif_priv->mem_base = + soc_info->reg_map[TFE_CORE_BASE_IDX].mem_base; + camif_priv->camif_reg = + hw_info->camif_hw_info.camif_reg; + camif_priv->common_reg = hw_info->common_reg; + camif_priv->reg_data = + hw_info->camif_hw_info.reg_data; + camif_priv->hw_intf = hw_intf; + camif_priv->soc_info = soc_info; + + } else if (hw_info->in_port[i] == + CAM_TFE_RDI_VER_1_0) { + top_priv->in_rsrc[i].res_id = + CAM_ISP_HW_TFE_IN_RDI0 + j; + + rdi_priv = kzalloc(sizeof(struct cam_tfe_rdi_data), + GFP_KERNEL); + if (!rdi_priv) { + CAM_DBG(CAM_ISP, + "TFE:%d Error Failed to alloc for rdi_priv", + core_info->core_index); + goto deinit_resources; + } + + top_priv->in_rsrc[i].res_priv = rdi_priv; + + rdi_priv->mem_base = + soc_info->reg_map[TFE_CORE_BASE_IDX].mem_base; + rdi_priv->hw_intf = hw_intf; + rdi_priv->common_reg = hw_info->common_reg; + rdi_priv->rdi_reg = + hw_info->rdi_hw_info[j].rdi_reg; + rdi_priv->reg_data = + hw_info->rdi_hw_info[j++].reg_data; + } else { + CAM_WARN(CAM_ISP, "TFE:%d Invalid inport type: %u", + core_info->core_index, hw_info->in_port[i]); + } + } + + top_priv->common_data.soc_info = soc_info; + top_priv->common_data.hw_intf = hw_intf; + top_priv->common_data.common_reg = hw_info->common_reg; + top_priv->common_data.reg_dump_data = &hw_info->reg_dump_data; + + return rc; + +deinit_resources: + for (--i; i >= 0; i--) { + + top_priv->in_rsrc[i].start = NULL; + top_priv->in_rsrc[i].stop = NULL; + top_priv->in_rsrc[i].process_cmd = NULL; + top_priv->in_rsrc[i].top_half_handler = NULL; + top_priv->in_rsrc[i].bottom_half_handler = NULL; + + if (!top_priv->in_rsrc[i].res_priv) + continue; + + kfree(top_priv->in_rsrc[i].res_priv); + top_priv->in_rsrc[i].res_priv = NULL; + top_priv->in_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + } +free_tfe_top_priv: + kfree(core_info->top_priv); + core_info->top_priv = NULL; +end: + return rc; +} + + +int cam_tfe_top_deinit(struct cam_tfe_top_priv *top_priv) +{ + int i, rc = 0; + + if (!top_priv) { + CAM_ERR(CAM_ISP, "Error Invalid input"); + return -EINVAL; + } + + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + top_priv->in_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + + top_priv->in_rsrc[i].start = NULL; + top_priv->in_rsrc[i].stop = NULL; + top_priv->in_rsrc[i].process_cmd = NULL; + top_priv->in_rsrc[i].top_half_handler = NULL; + top_priv->in_rsrc[i].bottom_half_handler = NULL; + + if (!top_priv->in_rsrc[i].res_priv) { + CAM_ERR(CAM_ISP, "Error res_priv is NULL"); + return -ENODEV; + } + + kfree(top_priv->in_rsrc[i].res_priv); + top_priv->in_rsrc[i].res_priv = NULL; + } + + return rc; +} + +int cam_tfe_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) +{ + struct cam_hw_info *tfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_tfe_hw_core_info *core_info = NULL; + struct cam_tfe_top_priv *top_priv = NULL; + struct cam_tfe_hw_info *hw_info = NULL; + void __iomem *mem_base; + uint32_t *reset_reg_args = reset_core_args; + uint32_t i, reset_reg_val, irq_status[3]; + int rc; + + CAM_DBG(CAM_ISP, "Enter"); + + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + soc_info = &tfe_hw->soc_info; + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + top_priv = core_info->top_priv; + hw_info = core_info->tfe_hw_info; + mem_base = tfe_hw->soc_info.reg_map[TFE_CORE_BASE_IDX].mem_base; + + for (i = 0; i < CAM_TFE_TOP_IRQ_REG_NUM; i++) + irq_status[i] = cam_io_r(mem_base + + core_info->tfe_hw_info->top_irq_status[i]); + + for (i = 0; i < CAM_TFE_TOP_IRQ_REG_NUM; i++) + cam_io_w(irq_status[i], mem_base + + core_info->tfe_hw_info->top_irq_clear[i]); + + cam_io_w_mb(core_info->tfe_hw_info->global_clear_bitmask, + mem_base + core_info->tfe_hw_info->top_irq_cmd); + + /* Mask all irq registers */ + 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]); + + cam_tfe_irq_config(core_info, hw_info->reset_irq_mask, + CAM_TFE_TOP_IRQ_REG_NUM, true); + + reinit_completion(&core_info->reset_complete); + + CAM_DBG(CAM_ISP, "calling RESET on tfe %d", soc_info->index); + + switch (*reset_reg_args) { + case CAM_TFE_HW_RESET_HW_AND_REG: + reset_reg_val = CAM_TFE_HW_RESET_HW_AND_REG_VAL; + break; + default: + reset_reg_val = CAM_TFE_HW_RESET_HW_VAL; + break; + } + + cam_io_w_mb(reset_reg_val, mem_base + + top_priv->common_data.common_reg->global_reset_cmd); + + 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); + if (rc <= 0) { + CAM_ERR(CAM_ISP, "TFE:%d Error Reset Timeout", + core_info->core_index); + rc = -ETIMEDOUT; + } else { + rc = 0; + CAM_DBG(CAM_ISP, "TFE:%d reset complete done (%d)", + core_info->core_index, rc); + } + + CAM_DBG(CAM_ISP, "TFE:%d reset complete done (%d)", + core_info->core_index, rc); + + cam_tfe_irq_config(core_info, hw_info->reset_irq_mask, + CAM_TFE_TOP_IRQ_REG_NUM, false); + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +int cam_tfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *tfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_tfe_hw_core_info *core_info = NULL; + struct cam_tfe_top_priv *top_priv; + void __iomem *mem_base; + int rc = 0; + uint32_t reset_core_args = + CAM_TFE_HW_RESET_HW_AND_REG; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + soc_info = &tfe_hw->soc_info; + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + top_priv = (struct cam_tfe_top_priv *)core_info->top_priv; + + mutex_lock(&tfe_hw->hw_mutex); + tfe_hw->open_count++; + if (tfe_hw->open_count > 1) { + mutex_unlock(&tfe_hw->hw_mutex); + CAM_DBG(CAM_ISP, "TFE:%d has already been initialized cnt %d", + core_info->core_index, tfe_hw->open_count); + return 0; + } + mutex_unlock(&tfe_hw->hw_mutex); + + /* Turn ON Regulators, Clocks and other SOC resources */ + rc = cam_tfe_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ISP, "Enable SOC failed"); + rc = -EFAULT; + goto decrement_open_cnt; + } + tfe_hw->hw_state = CAM_HW_STATE_POWER_UP; + + mem_base = tfe_hw->soc_info.reg_map[TFE_CORE_BASE_IDX].mem_base; + CAM_DBG(CAM_ISP, "TFE:%d Enable soc done", core_info->core_index); + + /* Do HW Reset */ + rc = cam_tfe_reset(hw_priv, &reset_core_args, sizeof(uint32_t)); + if (rc) { + CAM_ERR(CAM_ISP, "TFE:%d Reset Failed rc=%d", + core_info->core_index, rc); + goto disable_soc; + } + + top_priv->hw_clk_rate = 0; + core_info->irq_err_config_cnt = 0; + core_info->irq_err_config = false; + rc = core_info->tfe_bus->hw_ops.init(core_info->tfe_bus->bus_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "TFE:%d Top HW init Failed rc=%d", + core_info->core_index, rc); + goto disable_soc; + } + + return rc; + +disable_soc: + cam_tfe_disable_soc_resources(soc_info); + tfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + +decrement_open_cnt: + mutex_lock(&tfe_hw->hw_mutex); + tfe_hw->open_count--; + mutex_unlock(&tfe_hw->hw_mutex); + return rc; +} + +int cam_tfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *tfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_tfe_hw_core_info *core_info = NULL; + int rc = 0; + uint32_t reset_core_args = + CAM_TFE_HW_RESET_HW_AND_REG; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + soc_info = &tfe_hw->soc_info; + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + + mutex_lock(&tfe_hw->hw_mutex); + if (!tfe_hw->open_count) { + mutex_unlock(&tfe_hw->hw_mutex); + CAM_ERR_RATE_LIMIT(CAM_ISP, "TFE:%d Error Unbalanced deinit", + core_info->core_index); + return -EFAULT; + } + tfe_hw->open_count--; + if (tfe_hw->open_count) { + mutex_unlock(&tfe_hw->hw_mutex); + CAM_DBG(CAM_ISP, "TFE:%d open_cnt non-zero =%d", + core_info->core_index, tfe_hw->open_count); + return 0; + } + mutex_unlock(&tfe_hw->hw_mutex); + + rc = core_info->tfe_bus->hw_ops.deinit(core_info->tfe_bus->bus_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "TFE:%d Bus HW deinit Failed rc=%d", + core_info->core_index, rc); + + rc = cam_tfe_reset(hw_priv, &reset_core_args, sizeof(uint32_t)); + + /* Turn OFF Regulators, Clocks and other SOC resources */ + CAM_DBG(CAM_ISP, "TFE:%d Disable SOC resource", core_info->core_index); + rc = cam_tfe_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_ISP, " TFE:%d Disable SOC failed", + core_info->core_index); + + tfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +int cam_tfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size) +{ + struct cam_tfe_hw_core_info *core_info = NULL; + struct cam_hw_info *tfe_hw = hw_priv; + struct cam_tfe_acquire_args *acquire; + int rc = -ENODEV; + + if (!hw_priv || !reserve_args || (arg_size != + sizeof(struct cam_tfe_acquire_args))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + acquire = (struct cam_tfe_acquire_args *)reserve_args; + + CAM_DBG(CAM_ISP, "TFE:%d acquire res type: %d", + core_info->core_index, acquire->rsrc_type); + mutex_lock(&tfe_hw->hw_mutex); + if (acquire->rsrc_type == CAM_ISP_RESOURCE_TFE_IN) { + rc = cam_tfe_top_reserve(core_info->top_priv, + reserve_args, arg_size); + } else if (acquire->rsrc_type == CAM_ISP_RESOURCE_TFE_OUT) { + rc = core_info->tfe_bus->hw_ops.reserve( + core_info->tfe_bus->bus_priv, acquire, + sizeof(*acquire)); + } else { + CAM_ERR(CAM_ISP, "TFE:%d Invalid res type:%d", + core_info->core_index, acquire->rsrc_type); + } + + mutex_unlock(&tfe_hw->hw_mutex); + + return rc; +} + + +int cam_tfe_release(void *hw_priv, void *release_args, uint32_t arg_size) +{ + struct cam_tfe_hw_core_info *core_info = NULL; + struct cam_hw_info *tfe_hw = hw_priv; + struct cam_isp_resource_node *isp_res; + int rc = -ENODEV; + + if (!hw_priv || !release_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + isp_res = (struct cam_isp_resource_node *) release_args; + + mutex_lock(&tfe_hw->hw_mutex); + if (isp_res->res_type == CAM_ISP_RESOURCE_TFE_IN) + rc = cam_tfe_top_release(core_info->top_priv, isp_res, + sizeof(*isp_res)); + else if (isp_res->res_type == CAM_ISP_RESOURCE_TFE_OUT) { + rc = core_info->tfe_bus->hw_ops.release( + core_info->tfe_bus->bus_priv, isp_res, + sizeof(*isp_res)); + } else { + CAM_ERR(CAM_ISP, "TFE:%d Invalid res type:%d", + core_info->core_index, isp_res->res_type); + } + + mutex_unlock(&tfe_hw->hw_mutex); + + return rc; +} + +int cam_tfe_start(void *hw_priv, void *start_args, uint32_t arg_size) +{ + struct cam_tfe_hw_core_info *core_info = NULL; + struct cam_hw_info *tfe_hw = hw_priv; + struct cam_isp_resource_node *start_res; + + int rc = 0; + + if (!hw_priv || !start_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + start_res = (struct cam_isp_resource_node *)start_args; + core_info->tasklet_info = start_res->tasklet_info; + + mutex_lock(&tfe_hw->hw_mutex); + if (start_res->res_type == CAM_ISP_RESOURCE_TFE_IN) { + rc = cam_tfe_top_start(core_info, start_args, + arg_size); + if (rc) + CAM_ERR(CAM_ISP, "TFE:%d Start failed. type:%d", + core_info->core_index, start_res->res_type); + + } else if (start_res->res_type == CAM_ISP_RESOURCE_TFE_OUT) { + rc = core_info->tfe_bus->hw_ops.start(start_res, NULL, 0); + } else { + CAM_ERR(CAM_ISP, "TFE:%d Invalid res type:%d", + core_info->core_index, start_res->res_type); + rc = -EFAULT; + } + + mutex_unlock(&tfe_hw->hw_mutex); + + return rc; +} + +int cam_tfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) +{ + struct cam_tfe_hw_core_info *core_info = NULL; + struct cam_hw_info *tfe_hw = hw_priv; + struct cam_isp_resource_node *isp_res; + int rc = -EINVAL; + + if (!hw_priv || !stop_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + isp_res = (struct cam_isp_resource_node *)stop_args; + + mutex_lock(&tfe_hw->hw_mutex); + if (isp_res->res_type == CAM_ISP_RESOURCE_TFE_IN) { + rc = cam_tfe_top_stop(core_info, isp_res, + sizeof(struct cam_isp_resource_node)); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_TFE_OUT) { + rc = core_info->tfe_bus->hw_ops.stop(isp_res, NULL, 0); + } else { + CAM_ERR(CAM_ISP, "TFE:%d Invalid res type:%d", + core_info->core_index, isp_res->res_type); + } + + CAM_DBG(CAM_ISP, "TFE:%d stopped res type:%d res id:%d res_state:%d ", + core_info->core_index, isp_res->res_type, + isp_res->res_id, isp_res->res_state); + + mutex_unlock(&tfe_hw->hw_mutex); + + return rc; +} + +int cam_tfe_read(void *hw_priv, void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_tfe_write(void *hw_priv, void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_tfe_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *tfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_tfe_hw_core_info *core_info = NULL; + struct cam_tfe_hw_info *hw_info = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + soc_info = &tfe_hw->soc_info; + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + hw_info = core_info->tfe_hw_info; + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_CHANGE_BASE: + rc = cam_tfe_top_get_base(core_info->top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_tfe_top_get_reg_update(core_info->top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_CLOCK_UPDATE: + rc = cam_tfe_top_clock_update(core_info->top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE_V2: + rc = cam_tfe_top_bw_update(core_info->top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_CONTROL: + rc = cam_tfe_top_bw_control(core_info->top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_GET_REG_DUMP: + rc = cam_tfe_top_get_reg_dump(core_info->top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + rc = cam_tfe_camif_irq_reg_dump(core_info, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA: + *((struct cam_hw_soc_info **)cmd_args) = soc_info; + break; + case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + case CAM_ISP_HW_CMD_GET_HFR_UPDATE: + case CAM_ISP_HW_CMD_STRIPE_UPDATE: + case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = core_info->tfe_bus->hw_ops.process_cmd( + core_info->tfe_bus->bus_priv, cmd_type, cmd_args, + arg_size); + break; + default: + CAM_ERR(CAM_ISP, "TFE:%d Invalid cmd type:%d", + core_info->core_index, cmd_type); + rc = -EINVAL; + break; + } + return rc; +} + +int cam_tfe_core_init(struct cam_tfe_hw_core_info *core_info, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + struct cam_tfe_hw_info *tfe_hw_info) +{ + int rc = -EINVAL; + int i; + + rc = cam_tfe_top_init(soc_info, hw_intf, tfe_hw_info->top_hw_info, + core_info); + if (rc) { + CAM_ERR(CAM_ISP, "TFE:%d Error cam_tfe_top_init failed", + core_info->core_index); + goto end; + } + + rc = cam_tfe_bus_init(soc_info, hw_intf, + tfe_hw_info->bus_hw_info, core_info, + &core_info->tfe_bus); + if (rc) { + CAM_ERR(CAM_ISP, "TFE:%d Error cam_tfe_bus_init failed", + core_info->core_index); + goto deinit_top; + } + + INIT_LIST_HEAD(&core_info->free_payload_list); + for (i = 0; i < CAM_TFE_EVT_MAX; i++) { + INIT_LIST_HEAD(&core_info->evt_payload[i].list); + list_add_tail(&core_info->evt_payload[i].list, + &core_info->free_payload_list); + } + + core_info->irq_err_config = false; + core_info->irq_err_config_cnt = 0; + spin_lock_init(&core_info->spin_lock); + init_completion(&core_info->reset_complete); + + return rc; + +deinit_top: + cam_tfe_top_deinit(core_info->top_priv); + +end: + return rc; +} + +int cam_tfe_core_deinit(struct cam_tfe_hw_core_info *core_info, + struct cam_tfe_hw_info *tfe_hw_info) +{ + int rc = -EINVAL; + int i; + unsigned long flags; + + spin_lock_irqsave(&core_info->spin_lock, flags); + + INIT_LIST_HEAD(&core_info->free_payload_list); + for (i = 0; i < CAM_TFE_EVT_MAX; i++) + INIT_LIST_HEAD(&core_info->evt_payload[i].list); + + rc = cam_tfe_bus_deinit(&core_info->tfe_bus); + if (rc) + CAM_ERR(CAM_ISP, "TFE:%d Error cam_tfe_bus_deinit failed rc=%d", + core_info->core_index, rc); + + rc = cam_tfe_top_deinit(core_info->top_priv); + kfree(core_info->top_priv); + core_info->top_priv = NULL; + + if (rc) + CAM_ERR(CAM_ISP, "Error cam_tfe_top_deinit failed rc=%d", rc); + + spin_unlock_irqrestore(&core_info->spin_lock, flags); + + return rc; +} 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 new file mode 100644 index 000000000000..71170d1e27e3 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h @@ -0,0 +1,272 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_TFE_CORE_H_ +#define _CAM_TFE_CORE_H_ + +#include +#include "cam_hw_intf.h" +#include "cam_tfe_bus.h" +#include "cam_tfe_hw_intf.h" +#include "cam_tfe_irq.h" + +#define CAM_TFE_CAMIF_VER_1_0 0x10 +#define CAM_TFE_RDI_VER_1_0 0x1000 +#define CAM_TFE_TOP_1_0 0x1000 +#define CAM_TFE_TOP_IN_PORT_MAX 4 +#define CAM_TFE_RDI_MAX 4 + +#define CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS BIT(0) +#define CAM_TFE_EVT_MAX 256 + +#define CAM_TFE_MAX_REG_DUMP_ENTRIES 20 +#define CAM_TFE_MAX_LUT_DUMP_ENTRIES 10 + +enum cam_tfe_lut_word_size { + CAM_TFE_LUT_WORD_SIZE_32, + CAM_TFE_LUT_WORD_SIZE_64, + CAM_TFE_LUT_WORD_SIZE_MAX, +}; + +struct cam_tfe_reg_dump_entry { + uint32_t start_offset; + uint32_t end_offset; +}; + +struct cam_tfe_lut_dump_entry { + enum cam_tfe_lut_word_size lut_word_size; + uint32_t lut_bank_sel; + uint32_t lut_addr_size; + uint32_t dmi_reg_offset; +}; +struct cam_tfe_reg_dump_data { + uint32_t num_reg_dump_entries; + uint32_t num_lut_dump_entries; + uint32_t bus_start_addr; + uint32_t bus_write_top_end_addr; + uint32_t bus_client_start_addr; + uint32_t bus_client_offset; + uint32_t num_bus_clients; + struct cam_tfe_reg_dump_entry + reg_entry[CAM_TFE_MAX_REG_DUMP_ENTRIES]; + struct cam_tfe_lut_dump_entry + lut_entry[CAM_TFE_MAX_LUT_DUMP_ENTRIES]; +}; + +struct cam_tfe_top_reg_offset_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t lens_feature; + uint32_t stats_feature; + uint32_t zoom_feature; + uint32_t global_reset_cmd; + uint32_t core_cgc_ctrl; + uint32_t ahb_cgc_ctrl; + uint32_t core_cfg_0; + uint32_t core_cfg_1; + uint32_t reg_update_cmd; + uint32_t diag_config; + uint32_t diag_sensor_status_0; + uint32_t diag_sensor_status_1; + uint32_t diag_sensor_frame_cnt_status; + uint32_t violation_status; + uint32_t stats_throttle_cnt_cfg_0; + uint32_t stats_throttle_cnt_cfg_1; + uint32_t debug_0; + uint32_t debug_1; + uint32_t debug_2; + uint32_t debug_3; + uint32_t debug_cfg; + uint32_t perf_cnt_cfg; + uint32_t perf_pixel_count; + uint32_t perf_line_count; + uint32_t perf_stall_count; + uint32_t perf_always_count; + uint32_t perf_count_status; +}; + +struct cam_tfe_camif_reg { + uint32_t hw_version; + uint32_t hw_status; + uint32_t module_cfg; + uint32_t pdaf_raw_crop_width_cfg; + uint32_t pdaf_raw_crop_height_cfg; + uint32_t line_skip_pattern; + uint32_t pixel_skip_pattern; + uint32_t period_cfg; + uint32_t irq_subsample_pattern; + uint32_t epoch_irq_cfg; + uint32_t debug_1; + uint32_t debug_0; + uint32_t test_bus_ctrl; + uint32_t spare; + uint32_t reg_update_cmd; +}; + +struct cam_tfe_camif_reg_data { + uint32_t extern_reg_update_mask; + uint32_t dual_tfe_pix_en_shift; + uint32_t extern_reg_update_shift; + uint32_t camif_pd_rdi2_src_sel_shift; + uint32_t dual_tfe_sync_sel_shift; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + uint32_t module_enable_shift; + uint32_t pix_out_enable_shift; + uint32_t pdaf_output_enable_shift; + + uint32_t dsp_mode_shift; + uint32_t dsp_mode_mask; + uint32_t dsp_en_shift; + uint32_t dsp_en_mask; + + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t eof_irq_mask; + uint32_t reg_update_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask2; + uint32_t subscribe_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM]; + + uint32_t enable_diagnostic_hw; + uint32_t perf_cnt_start_cmd_shift; + uint32_t perf_cnt_continuous_shift; + uint32_t perf_client_sel_shift; + uint32_t perf_window_start_shift; + uint32_t perf_window_end_shift; +}; + +struct cam_tfe_camif_hw_info { + struct cam_tfe_camif_reg *camif_reg; + struct cam_tfe_camif_reg_data *reg_data; +}; + +struct cam_tfe_rdi_reg { + uint32_t rdi_hw_version; + uint32_t rdi_hw_status; + uint32_t rdi_module_config; + uint32_t rdi_skip_period; + uint32_t rdi_irq_subsample_pattern; + uint32_t rdi_epoch_irq; + uint32_t rdi_debug_1; + uint32_t rdi_debug_0; + uint32_t rdi_test_bus_ctrl; + uint32_t rdi_spare; + uint32_t reg_update_cmd; +}; + +struct cam_tfe_rdi_reg_data { + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + uint32_t rdi_out_enable_shift; + + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask2; + uint32_t subscribe_irq_mask[CAM_TFE_TOP_IRQ_REG_NUM]; + uint32_t enable_diagnostic_hw; +}; + +struct cam_tfe_rdi_hw_info { + struct cam_tfe_rdi_reg *rdi_reg; + struct cam_tfe_rdi_reg_data *reg_data; +}; + +struct cam_tfe_top_hw_info { + struct cam_tfe_top_reg_offset_common *common_reg; + struct cam_tfe_camif_hw_info camif_hw_info; + struct cam_tfe_rdi_hw_info rdi_hw_info[CAM_TFE_RDI_MAX]; + uint32_t in_port[CAM_TFE_TOP_IN_PORT_MAX]; + struct cam_tfe_reg_dump_data reg_dump_data; +}; + +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 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 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 top_version; + void *top_hw_info; + + uint32_t bus_version; + void *bus_hw_info; +}; + +struct cam_tfe_hw_core_info { + uint32_t core_index; + struct cam_tfe_hw_info *tfe_hw_info; + void *top_priv; + struct cam_tfe_bus *tfe_bus; + void *tasklet_info; + struct cam_tfe_irq_evt_payload evt_payload[CAM_TFE_EVT_MAX]; + struct list_head free_payload_list; + bool irq_err_config; + uint32_t irq_err_config_cnt; + spinlock_t spin_lock; + struct completion reset_complete; +}; + +int cam_tfe_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size); +int cam_tfe_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_tfe_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size); +int cam_tfe_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size); +int cam_tfe_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size); +int cam_tfe_release(void *device_priv, + void *reserve_args, uint32_t arg_size); +int cam_tfe_start(void *device_priv, + void *start_args, uint32_t arg_size); +int cam_tfe_stop(void *device_priv, + void *stop_args, uint32_t arg_size); +int cam_tfe_read(void *device_priv, + void *read_args, uint32_t arg_size); +int cam_tfe_write(void *device_priv, + void *write_args, uint32_t arg_size); +int cam_tfe_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +irqreturn_t cam_tfe_irq(int irq_num, void *data); + +int cam_tfe_core_init(struct cam_tfe_hw_core_info *core_info, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + struct cam_tfe_hw_info *tfe_hw_info); + +int cam_tfe_core_deinit(struct cam_tfe_hw_core_info *core_info, + struct cam_tfe_hw_info *tfe_hw_info); + +#endif /* _CAM_TFE_CORE_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.c new file mode 100644 index 000000000000..6666e2955523 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include "cam_tfe_dev.h" +#include "cam_tfe_core.h" +#include "cam_tfe_soc.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_tfe_hw_list[CAM_TFE_HW_NUM_MAX] = {0, 0, 0}; + +static char tfe_dev_name[8]; + +int cam_tfe_probe(struct platform_device *pdev) +{ + struct cam_hw_info *tfe_hw = NULL; + struct cam_hw_intf *tfe_hw_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_tfe_hw_core_info *core_info = NULL; + struct cam_tfe_hw_info *hw_info = NULL; + int rc = 0; + + tfe_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!tfe_hw_intf) { + rc = -ENOMEM; + goto end; + } + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &tfe_hw_intf->hw_idx); + + tfe_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!tfe_hw) { + rc = -ENOMEM; + goto free_tfe_hw_intf; + } + + memset(tfe_dev_name, 0, sizeof(tfe_dev_name)); + snprintf(tfe_dev_name, sizeof(tfe_dev_name), + "tfe%1u", tfe_hw_intf->hw_idx); + + tfe_hw->soc_info.pdev = pdev; + tfe_hw->soc_info.dev = &pdev->dev; + tfe_hw->soc_info.dev_name = tfe_dev_name; + tfe_hw_intf->hw_priv = tfe_hw; + tfe_hw_intf->hw_ops.get_hw_caps = cam_tfe_get_hw_caps; + tfe_hw_intf->hw_ops.init = cam_tfe_init_hw; + tfe_hw_intf->hw_ops.deinit = cam_tfe_deinit_hw; + tfe_hw_intf->hw_ops.reset = cam_tfe_reset; + tfe_hw_intf->hw_ops.reserve = cam_tfe_reserve; + tfe_hw_intf->hw_ops.release = cam_tfe_release; + tfe_hw_intf->hw_ops.start = cam_tfe_start; + tfe_hw_intf->hw_ops.stop = cam_tfe_stop; + tfe_hw_intf->hw_ops.read = cam_tfe_read; + tfe_hw_intf->hw_ops.write = cam_tfe_write; + tfe_hw_intf->hw_ops.process_cmd = cam_tfe_process_cmd; + tfe_hw_intf->hw_type = CAM_ISP_HW_TYPE_TFE; + + CAM_DBG(CAM_ISP, "type %d index %d", + tfe_hw_intf->hw_type, tfe_hw_intf->hw_idx); + + platform_set_drvdata(pdev, tfe_hw_intf); + + tfe_hw->core_info = kzalloc(sizeof(struct cam_tfe_hw_core_info), + GFP_KERNEL); + if (!tfe_hw->core_info) { + CAM_DBG(CAM_ISP, "Failed to alloc for core"); + rc = -ENOMEM; + goto free_tfe_hw; + } + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ISP, "Of_match Failed"); + rc = -EINVAL; + goto free_core_info; + } + hw_info = (struct cam_tfe_hw_info *)match_dev->data; + core_info->tfe_hw_info = hw_info; + core_info->core_index = tfe_hw_intf->hw_idx; + + rc = cam_tfe_init_soc_resources(&tfe_hw->soc_info, cam_tfe_irq, + tfe_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Failed to init soc rc=%d", rc); + goto free_core_info; + } + + rc = cam_tfe_core_init(core_info, &tfe_hw->soc_info, + tfe_hw_intf, hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Failed to init core rc=%d", rc); + goto deinit_soc; + } + + tfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&tfe_hw->hw_mutex); + spin_lock_init(&tfe_hw->hw_lock); + init_completion(&tfe_hw->hw_complete); + + if (tfe_hw_intf->hw_idx < CAM_TFE_HW_NUM_MAX) + cam_tfe_hw_list[tfe_hw_intf->hw_idx] = tfe_hw_intf; + + cam_tfe_init_hw(tfe_hw, NULL, 0); + cam_tfe_deinit_hw(tfe_hw, NULL, 0); + + CAM_DBG(CAM_ISP, "TFE%d probe successful", tfe_hw_intf->hw_idx); + + return rc; + +deinit_soc: + if (cam_tfe_deinit_soc_resources(&tfe_hw->soc_info)) + CAM_ERR(CAM_ISP, "Failed to deinit soc"); +free_core_info: + kfree(tfe_hw->core_info); +free_tfe_hw: + kfree(tfe_hw); +free_tfe_hw_intf: + kfree(tfe_hw_intf); +end: + return rc; +} + +int cam_tfe_remove(struct platform_device *pdev) +{ + struct cam_hw_info *tfe_hw = NULL; + struct cam_hw_intf *tfe_hw_intf = NULL; + struct cam_tfe_hw_core_info *core_info = NULL; + int rc = 0; + + tfe_hw_intf = platform_get_drvdata(pdev); + if (!tfe_hw_intf) { + CAM_ERR(CAM_ISP, "Error! No data in pdev"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "type %d index %d", + tfe_hw_intf->hw_type, tfe_hw_intf->hw_idx); + + if (tfe_hw_intf->hw_idx < CAM_TFE_HW_NUM_MAX) + cam_tfe_hw_list[tfe_hw_intf->hw_idx] = NULL; + + tfe_hw = tfe_hw_intf->hw_priv; + if (!tfe_hw) { + CAM_ERR(CAM_ISP, "Error! HW data is NULL"); + rc = -ENODEV; + goto free_tfe_hw_intf; + } + + core_info = (struct cam_tfe_hw_core_info *)tfe_hw->core_info; + if (!core_info) { + CAM_ERR(CAM_ISP, "Error! core data NULL"); + rc = -EINVAL; + goto deinit_soc; + } + + rc = cam_tfe_core_deinit(core_info, core_info->tfe_hw_info); + if (rc < 0) + CAM_ERR(CAM_ISP, "Failed to deinit core rc=%d", rc); + + kfree(tfe_hw->core_info); + +deinit_soc: + rc = cam_tfe_deinit_soc_resources(&tfe_hw->soc_info); + if (rc < 0) + CAM_ERR(CAM_ISP, "Failed to deinit soc rc=%d", rc); + + mutex_destroy(&tfe_hw->hw_mutex); + kfree(tfe_hw); + + CAM_DBG(CAM_ISP, "TFE%d remove successful", tfe_hw_intf->hw_idx); + +free_tfe_hw_intf: + kfree(tfe_hw_intf); + + return rc; +} + +int cam_tfe_hw_init(struct cam_hw_intf **tfe_hw, uint32_t hw_idx) +{ + int rc = 0; + + if (cam_tfe_hw_list[hw_idx]) { + *tfe_hw = cam_tfe_hw_list[hw_idx]; + rc = 0; + } else { + *tfe_hw = NULL; + rc = -ENODEV; + } + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.h new file mode 100644 index 000000000000..41816285a611 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_dev.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_DEV_H_ +#define _CAM_TFE_DEV_H_ + +#include + +/* + * cam_tfe_probe() + * + * @brief: Driver probe function called on Boot + * + * @pdev: Platform Device pointer + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_probe(struct platform_device *pdev); + +/* + * cam_tfe_remove() + * + * @brief: Driver remove function + * + * @pdev: Platform Device pointer + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_remove(struct platform_device *pdev); + +#endif /* _CAM_TFE_DEV_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_irq.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_irq.h new file mode 100644 index 000000000000..4b77f0eb2a25 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_irq.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_IRQ_H_ +#define _CAM_TFE_IRQ_H_ + +#include + +#define CAM_TFE_TOP_IRQ_REG_NUM 3 + +/* + * cam_tfe_irq_config() + * + * @brief: Tfe hw irq configuration + * + * @tfe_core_data: tfe core pointer + * @irq_mask: Irq mask for enable interrupts or disable + * @num_reg: Number irq mask registers + * @enable: enable = 1, enable the given irq mask interrupts + * enable = 0 disable the given irq mask interrupts + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_irq_config(void *tfe_core_data, + uint32_t *irq_mask, uint32_t num_reg, bool enable); + + +#endif /* _CAM_TFE_IRQ_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c new file mode 100644 index 000000000000..267c2c0755ad --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_cpas_api.h" +#include "cam_tfe_soc.h" +#include "cam_debug_util.h" + +static bool cam_tfe_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + bool error_handled = false; + + if (!irq_data) + return error_handled; + + CAM_DBG(CAM_ISP, "CPSS error type=%d ", + irq_data->irq_type); + + return error_handled; +} + +int cam_tfe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t tfe_irq_handler, void *irq_data) +{ + int rc = 0; + struct cam_tfe_soc_private *soc_private; + struct cam_cpas_register_params cpas_register_param; + + soc_private = kzalloc(sizeof(struct cam_tfe_soc_private), + GFP_KERNEL); + if (!soc_private) { + CAM_DBG(CAM_ISP, "Error! soc_private Alloc Failed"); + return -ENOMEM; + } + soc_info->soc_private = soc_private; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_ISP, "Error! get DT properties failed rc=%d", rc); + goto free_soc_private; + } + + rc = cam_soc_util_get_option_clk_by_name(soc_info, + CAM_TFE_DSP_CLK_NAME, &soc_private->dsp_clk, + &soc_private->dsp_clk_index, &soc_private->dsp_clk_rate); + if (rc) + CAM_WARN(CAM_ISP, "Option clk get failed with rc %d", rc); + + rc = cam_soc_util_request_platform_resource(soc_info, tfe_irq_handler, + irq_data); + + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Error! Request platform resources failed rc=%d", rc); + goto free_soc_private; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "tfe", + CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = soc_info->dev; + cpas_register_param.cam_cpas_client_cb = cam_tfe_cpas_cb; + cpas_register_param.userdata = soc_info; + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc); + goto release_soc; + } + + soc_private->cpas_handle = cpas_register_param.client_handle; + + return rc; + +release_soc: + cam_soc_util_release_platform_resource(soc_info); +free_soc_private: + kfree(soc_private); + + return rc; +} + +int cam_tfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_tfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error! soc_info NULL"); + return -ENODEV; + } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error! soc_private NULL"); + return -ENODEV; + } + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_ISP, "CPAS0 unregistration failed rc=%d", rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_ISP, + "Error! Release platform resource failed rc=%d", rc); + + + rc = cam_soc_util_clk_put(&soc_private->dsp_clk); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Error Put dsp clk failed rc=%d", rc); + + kfree(soc_private); + + return rc; +} + +int cam_tfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_tfe_soc_private *soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error! Invalid params"); + rc = -EINVAL; + goto end; + } + soc_private = soc_info->soc_private; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_IFE_VID; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[0].camnoc_bw = 10640000000L; + axi_vote.axi_path[0].mnoc_ab_bw = 10640000000L; + axi_vote.axi_path[0].mnoc_ib_bw = 10640000000L; + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_ISP, "Error! CPAS0 start failed rc=%d", rc); + rc = -EFAULT; + goto end; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_TURBO_VOTE, true); + if (rc) { + CAM_ERR(CAM_ISP, "Error! enable platform failed rc=%d", rc); + goto stop_cpas; + } + + return rc; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); +end: + return rc; +} + +int cam_tfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name) +{ + int rc = 0; + struct cam_tfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + if (strcmp(clk_name, CAM_TFE_DSP_CLK_NAME) == 0) { + rc = cam_soc_util_clk_enable(soc_private->dsp_clk, + CAM_TFE_DSP_CLK_NAME, soc_private->dsp_clk_rate); + if (rc) + CAM_ERR(CAM_ISP, + "Error enable dsp clk failed rc=%d", rc); + } + + return rc; +} + +int cam_tfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name) +{ + int rc = 0; + struct cam_tfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + if (strcmp(clk_name, CAM_TFE_DSP_CLK_NAME) == 0) { + rc = cam_soc_util_clk_disable(soc_private->dsp_clk, + CAM_TFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, + "Error enable dsp clk failed rc=%d", rc); + } + + return rc; +} + + +int cam_tfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_tfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error! Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_ISP, "Disable platform failed rc=%d", rc); + return rc; + } + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Error! CPAS stop failed rc=%d", rc); + return rc; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.h new file mode 100644 index 000000000000..2e6e47d8561d --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TFE_SOC_H_ +#define _CAM_TFE_SOC_H_ + +#include "cam_soc_util.h" +#include "cam_isp_hw.h" + +#define CAM_TFE_DSP_CLK_NAME "tfe_dsp_clk" + +enum cam_cpas_handle_id { + CAM_CPAS_HANDLE_CAMIF, + CAM_CPAS_HANDLE_RAW, + CAM_CPAS_HANDLE_MAX, +}; + +/* + * struct cam_tfe_soc_private: + * + * @Brief: Private SOC data specific to TFE HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver. + * This handle is used for all further interface + * with CPAS. + * @cpas_version: Has cpas version read from Hardware + */ +struct cam_tfe_soc_private { + uint32_t cpas_handle; + uint32_t cpas_version; + struct clk *dsp_clk; + int32_t dsp_clk_index; + int32_t dsp_clk_rate; +}; + +/* + * cam_tfe_init_soc_resources() + * + * @Brief: Initialize SOC resources including private data + * + * @soc_info: Device soc information + * @handler: Irq handler function pointer + * @irq_data: Irq handler function Callback data + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t tfe_irq_handler, void *irq_data); + +/* + * cam_tfe_deinit_soc_resources() + * + * @Brief: Deinitialize SOC resources including private data + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_tfe_enable_soc_resources() + * + * @brief: Enable regulator, irq resources, start CPAS + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_tfe_disable_soc_resources() + * + * @brief: Disable regulator, irq resources, stop CPAS + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_tfe_soc_enable_clk() + * + * @brief: Enable clock with given name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to enable + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name); + +/* + * cam_tfe_soc_disable_dsp_clk() + * + * @brief: Disable clock with given name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to enable + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_tfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name); + +#endif /* _CAM_TFE_SOC_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/Makefile new file mode 100644 index 000000000000..f08acab1e1dc --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_top_tpg_dev.o cam_top_tpg_soc.o cam_top_tpg_core.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_top_tpg_v1.o \ No newline at end of file diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c new file mode 100644 index 000000000000..1ab170c9b2d5 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c @@ -0,0 +1,671 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "cam_top_tpg_core.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + + +static uint32_t tpg_num_dt_map[CAM_TOP_TPG_MAX_SUPPORTED_DT] = { + 0, + 3, + 1, + 2 +}; + +static int cam_top_tpg_get_format(uint32_t in_format, + uint32_t *tpg_encode_format) +{ + int rc = 0; + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + *tpg_encode_format = 0; + break; + case CAM_FORMAT_MIPI_RAW_8: + *tpg_encode_format = 1; + break; + case CAM_FORMAT_MIPI_RAW_10: + *tpg_encode_format = 2; + break; + case CAM_FORMAT_MIPI_RAW_12: + *tpg_encode_format = 3; + break; + case CAM_FORMAT_MIPI_RAW_14: + *tpg_encode_format = 4; + break; + case CAM_FORMAT_MIPI_RAW_16: + *tpg_encode_format = 4; + break; + default: + CAM_ERR(CAM_ISP, "Unsupported input encode format %d", + in_format); + rc = -EINVAL; + } + return rc; +} + +static int cam_top_tpg_get_hw_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_top_tpg_hw_caps *hw_caps; + struct cam_top_tpg_hw *tpg_hw; + struct cam_hw_info *tpg_hw_info; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_ISP, "TPG: Invalid args"); + return -EINVAL; + } + + tpg_hw_info = (struct cam_hw_info *)hw_priv; + tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info; + hw_caps = (struct cam_top_tpg_hw_caps *) get_hw_cap_args; + + hw_caps->major_version = tpg_hw->tpg_info->tpg_reg->major_version; + hw_caps->minor_version = tpg_hw->tpg_info->tpg_reg->minor_version; + hw_caps->version_incr = tpg_hw->tpg_info->tpg_reg->version_incr; + + CAM_DBG(CAM_ISP, + "TPG:%d major:%d minor:%d ver :%d", + tpg_hw->hw_intf->hw_idx, hw_caps->major_version, + hw_caps->minor_version, hw_caps->version_incr); + + return rc; +} + +static int cam_top_tpg_reserve(void *hw_priv, + void *reserve_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_top_tpg_hw *tpg_hw; + struct cam_hw_info *tpg_hw_info; + struct cam_top_tpg_hw_reserve_resource_args *reserv; + struct cam_top_tpg_cfg *tpg_data; + uint32_t encode_format = 0; + uint32_t i; + + if (!hw_priv || !reserve_args || (arg_size != + sizeof(struct cam_top_tpg_hw_reserve_resource_args))) { + CAM_ERR(CAM_ISP, "TPG: Invalid args"); + return -EINVAL; + } + + tpg_hw_info = (struct cam_hw_info *)hw_priv; + tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info; + reserv = (struct cam_top_tpg_hw_reserve_resource_args *)reserve_args; + + if (reserv->num_inport <= 0 || + reserv->num_inport > CAM_TOP_TPG_MAX_SUPPORTED_DT) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "TPG: %u invalid input num port:%d", + tpg_hw->hw_intf->hw_idx, reserv->num_inport); + return -EINVAL; + } + + mutex_lock(&tpg_hw->hw_info->hw_mutex); + if (tpg_hw->tpg_res.res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + mutex_unlock(&tpg_hw->hw_info->hw_mutex); + return -EINVAL; + } + + if ((reserv->in_port[0]->vc > 0xF) || + (reserv->in_port[0]->lane_num <= 0 || + reserv->in_port[0]->lane_num > 4) || + (reserv->in_port[0]->pix_pattern > 4) || + (reserv->in_port[0]->lane_type >= 2)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "TPG:%u invalid input %d %d %d %d", + tpg_hw->hw_intf->hw_idx, reserv->in_port[0]->vc, + reserv->in_port[0]->lane_num, + reserv->in_port[0]->pix_pattern, + reserv->in_port[0]->lane_type); + mutex_unlock(&tpg_hw->hw_info->hw_mutex); + return -EINVAL; + } + rc = cam_top_tpg_get_format(reserv->in_port[0]->format, + &encode_format); + if (rc) + return rc; + + CAM_DBG(CAM_ISP, "TPG: %u enter", tpg_hw->hw_intf->hw_idx); + + tpg_data = (struct cam_top_tpg_cfg *)tpg_hw->tpg_res.res_priv; + tpg_data->vc_num = reserv->in_port[0]->vc; + tpg_data->phy_sel = reserv->in_port[0]->lane_type; + tpg_data->num_active_lanes = reserv->in_port[0]->lane_num; + tpg_data->h_blank_count = reserv->in_port[0]->sensor_hbi; + tpg_data->v_blank_count = reserv->in_port[0]->sensor_vbi; + tpg_data->pix_pattern = reserv->in_port[0]->pix_pattern; + tpg_data->dt_cfg[0].data_type = reserv->in_port[0]->dt; + tpg_data->dt_cfg[0].frame_height = reserv->in_port[0]->height; + if (reserv->in_port[0]->usage_type) + tpg_data->dt_cfg[0].frame_width = + ((reserv->in_port[0]->right_end - + reserv->in_port[0]->left_start) + 1); + else + tpg_data->dt_cfg[0].frame_width = + reserv->in_port[0]->left_width; + tpg_data->dt_cfg[0].encode_format = encode_format; + tpg_data->num_active_dts = 1; + + CAM_DBG(CAM_ISP, + "TPG:%u vc_num:%d dt:%d phy:%d lines:%d pattern:%d format:%d", + tpg_hw->hw_intf->hw_idx, + tpg_data->vc_num, tpg_data->dt_cfg[0].data_type, + tpg_data->phy_sel, tpg_data->num_active_lanes, + tpg_data->pix_pattern, + tpg_data->dt_cfg[0].encode_format); + + CAM_DBG(CAM_ISP, "TPG:%u height:%d width:%d h blank:%d v blank:%d", + tpg_hw->hw_intf->hw_idx, + tpg_data->dt_cfg[0].frame_height, + tpg_data->dt_cfg[0].frame_width, + tpg_data->h_blank_count, + tpg_data->v_blank_count); + + if (reserv->num_inport == 1) + goto end; + + for (i = 1; i < reserv->num_inport; i++) { + if ((tpg_data->vc_num != reserv->in_port[i]->vc) || + (tpg_data->phy_sel != reserv->in_port[i]->lane_type) || + (tpg_data->num_active_lanes != + reserv->in_port[i]->lane_num) || + (tpg_data->pix_pattern != + reserv->in_port[i]->pix_pattern)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "TPG: %u invalid DT config for tpg", + tpg_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto error; + } + rc = cam_top_tpg_get_format(reserv->in_port[0]->format, + &encode_format); + if (rc) + return rc; + + tpg_data->dt_cfg[i].data_type = reserv->in_port[i]->dt; + tpg_data->dt_cfg[i].frame_height = + reserv->in_port[i]->height; + tpg_data->dt_cfg[i].frame_width = + reserv->in_port[i]->left_width; + tpg_data->dt_cfg[i].encode_format = encode_format; + tpg_data->num_active_dts++; + + CAM_DBG(CAM_ISP, "TPG:%u height:%d width:%d dt:%d format:%d", + tpg_hw->hw_intf->hw_idx, + tpg_data->dt_cfg[i].frame_height, + tpg_data->dt_cfg[i].frame_width, + tpg_data->dt_cfg[i].data_type, + tpg_data->dt_cfg[i].encode_format); + + } +end: + reserv->node_res = &tpg_hw->tpg_res; + tpg_hw->tpg_res.res_state = CAM_ISP_RESOURCE_STATE_RESERVED; +error: + mutex_unlock(&tpg_hw->hw_info->hw_mutex); + CAM_DBG(CAM_ISP, "exit rc %u", rc); + + return rc; +} + +static int cam_top_tpg_release(void *hw_priv, + void *release_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_top_tpg_hw *tpg_hw; + struct cam_hw_info *tpg_hw_info; + struct cam_top_tpg_cfg *tpg_data; + struct cam_isp_resource_node *tpg_res; + + if (!hw_priv || !release_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "TPG: Invalid args"); + return -EINVAL; + } + + tpg_hw_info = (struct cam_hw_info *)hw_priv; + tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info; + tpg_res = (struct cam_isp_resource_node *)release_args; + + mutex_lock(&tpg_hw->hw_info->hw_mutex); + if ((tpg_res->res_type != CAM_ISP_RESOURCE_TPG) || + (tpg_res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE)) { + CAM_ERR(CAM_ISP, "TPG:%d Invalid res type:%d res_state:%d", + tpg_hw->hw_intf->hw_idx, tpg_res->res_type, + tpg_res->res_state); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "TPG:%d res type :%d", + tpg_hw->hw_intf->hw_idx, tpg_res->res_type); + + tpg_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + tpg_data = (struct cam_top_tpg_cfg *)tpg_res->res_priv; + memset(tpg_data, 0, sizeof(struct cam_top_tpg_cfg)); + +end: + mutex_unlock(&tpg_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_top_tpg_init_hw(void *hw_priv, + void *init_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_top_tpg_hw *tpg_hw; + struct cam_hw_info *tpg_hw_info; + struct cam_isp_resource_node *tpg_res; + const struct cam_top_tpg_reg_offset *tpg_reg; + struct cam_hw_soc_info *soc_info; + uint32_t val, clk_lvl; + + if (!hw_priv || !init_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "TPG: Invalid args"); + return -EINVAL; + } + + tpg_hw_info = (struct cam_hw_info *)hw_priv; + tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info; + tpg_res = (struct cam_isp_resource_node *)init_args; + tpg_reg = tpg_hw->tpg_info->tpg_reg; + soc_info = &tpg_hw->hw_info->soc_info; + + if (tpg_res->res_type != CAM_ISP_RESOURCE_TPG) { + CAM_ERR(CAM_ISP, "TPG:%d Invalid res type state %d", + tpg_hw->hw_intf->hw_idx, + tpg_res->res_type); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "TPG:%d init HW res type :%d", + tpg_hw->hw_intf->hw_idx, tpg_res->res_type); + mutex_lock(&tpg_hw->hw_info->hw_mutex); + /* overflow check before increment */ + if (tpg_hw->hw_info->open_count == UINT_MAX) { + CAM_ERR(CAM_ISP, "TPG:%d Open count reached max", + tpg_hw->hw_intf->hw_idx); + mutex_unlock(&tpg_hw->hw_info->hw_mutex); + return -EINVAL; + } + + /* Increment ref Count */ + tpg_hw->hw_info->open_count++; + if (tpg_hw->hw_info->open_count > 1) { + CAM_DBG(CAM_ISP, "TPG hw has already been enabled"); + mutex_unlock(&tpg_hw->hw_info->hw_mutex); + return rc; + } + + rc = cam_soc_util_get_clk_level(soc_info, tpg_hw->clk_rate, + soc_info->src_clk_idx, &clk_lvl); + CAM_DBG(CAM_ISP, "TPG phy clock level %u", clk_lvl); + + rc = cam_top_tpg_enable_soc_resources(soc_info, clk_lvl); + if (rc) { + CAM_ERR(CAM_ISP, "TPG:%d Enable SOC failed", + tpg_hw->hw_intf->hw_idx); + goto err; + } + + tpg_hw->hw_info->hw_state = CAM_HW_STATE_POWER_UP; + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + tpg_reg->tpg_hw_version); + CAM_DBG(CAM_ISP, "TPG:%d TPG HW version: 0x%x", + tpg_hw->hw_intf->hw_idx, val); + + mutex_unlock(&tpg_hw->hw_info->hw_mutex); + return rc; + +err: + tpg_hw->hw_info->open_count--; + mutex_unlock(&tpg_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_top_tpg_deinit_hw(void *hw_priv, + void *deinit_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_top_tpg_hw *tpg_hw; + struct cam_hw_info *tpg_hw_info; + struct cam_isp_resource_node *tpg_res; + struct cam_hw_soc_info *soc_info; + + if (!hw_priv || !deinit_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "TPG:Invalid arguments"); + return -EINVAL; + } + + tpg_res = (struct cam_isp_resource_node *)deinit_args; + tpg_hw_info = (struct cam_hw_info *)hw_priv; + tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info; + + if (tpg_res->res_type != CAM_ISP_RESOURCE_TPG) { + CAM_ERR(CAM_ISP, "TPG:%d Invalid Res type %d", + tpg_hw->hw_intf->hw_idx, + tpg_res->res_type); + return -EINVAL; + } + + mutex_lock(&tpg_hw->hw_info->hw_mutex); + /* Check for refcount */ + if (!tpg_hw->hw_info->open_count) { + CAM_WARN(CAM_ISP, "Unbalanced disable_hw"); + goto end; + } + + /* Decrement ref Count */ + tpg_hw->hw_info->open_count--; + if (tpg_hw->hw_info->open_count) { + rc = 0; + goto end; + } + + soc_info = &tpg_hw->hw_info->soc_info; + rc = cam_top_tpg_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_ISP, "TPG:%d Disable SOC failed", + tpg_hw->hw_intf->hw_idx); + + tpg_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + CAM_DBG(CAM_ISP, "TPG:%d deint completed", tpg_hw->hw_intf->hw_idx); + +end: + mutex_unlock(&tpg_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_top_tpg_start(void *hw_priv, void *start_args, + uint32_t arg_size) +{ + int rc = 0; + struct cam_top_tpg_hw *tpg_hw; + struct cam_hw_info *tpg_hw_info; + struct cam_hw_soc_info *soc_info; + struct cam_isp_resource_node *tpg_res; + const struct cam_top_tpg_reg_offset *tpg_reg; + struct cam_top_tpg_cfg *tpg_data; + uint32_t i, val; + + if (!hw_priv || !start_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "TPG: Invalid args"); + return -EINVAL; + } + + tpg_hw_info = (struct cam_hw_info *)hw_priv; + tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info; + tpg_reg = tpg_hw->tpg_info->tpg_reg; + tpg_res = (struct cam_isp_resource_node *)start_args; + tpg_data = (struct cam_top_tpg_cfg *)tpg_res->res_priv; + soc_info = &tpg_hw->hw_info->soc_info; + + if ((tpg_res->res_type != CAM_ISP_RESOURCE_TPG) || + (tpg_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED)) { + CAM_ERR(CAM_ISP, "TPG:%d Invalid Res type:%d res_state:%d", + tpg_hw->hw_intf->hw_idx, + tpg_res->res_type, tpg_res->res_state); + rc = -EINVAL; + goto end; + } + cam_io_w_mb(0x12345678, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_lfsr_seed); + + for (i = 0; i < tpg_data->num_active_dts; i++) { + val = (((tpg_data->dt_cfg[i].frame_width & 0xFFFF) << 16) | + (tpg_data->dt_cfg[i].frame_height & 0x3FFF)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_dt_0_cfg_0 + 0x10 * i); + cam_io_w_mb(tpg_data->dt_cfg[i].data_type, + soc_info->reg_map[0].mem_base + + tpg_reg->tpg_dt_0_cfg_1 + 0x10 * i); + val = ((tpg_data->dt_cfg[i].encode_format & 0xF) << + tpg_reg->tpg_dt_encode_format_shift) | + tpg_reg->tpg_payload_mode_color; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_dt_0_cfg_2 + 0x10 * i); + } + + val = (tpg_num_dt_map[tpg_data->num_active_dts-1] << + tpg_reg->tpg_num_dts_shift_val) | tpg_data->vc_num; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc_cfg0); + + /* HBlank count 500 and V blank count is 600 */ + cam_io_w_mb(0x2581F4, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc_cfg1); + + val = (1 << tpg_reg->tpg_split_en_shift); + cam_io_w_mb(tpg_data->pix_pattern, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_common_gen_cfg); + cam_io_w_mb(0xAFFF, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vbi_cfg); + CAM_DBG(CAM_ISP, "TPG:%d set TPG VBI to 0xAFFF", + tpg_hw->hw_intf->hw_idx); + + /* Set the TOP tpg mux sel*/ + cam_io_w_mb((1 << tpg_hw->hw_intf->hw_idx), + soc_info->reg_map[1].mem_base + tpg_reg->top_mux_reg_offset); + + val = ((tpg_data->num_active_lanes - 1) << + tpg_reg->tpg_num_active_lines_shift) | + (1 << tpg_reg->tpg_fe_pkt_en_shift) | + (1 << tpg_reg->tpg_fs_pkt_en_shift) | + (tpg_data->phy_sel << tpg_reg->tpg_phy_sel_shift_val) | + (1 << tpg_reg->tpg_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_ctrl); + + tpg_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + CAM_DBG(CAM_ISP, "TPG:%d started", tpg_hw->hw_intf->hw_idx); + +end: + return rc; +} + +static int cam_top_tpg_stop(void *hw_priv, + void *stop_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_top_tpg_hw *tpg_hw; + struct cam_hw_info *tpg_hw_info; + struct cam_hw_soc_info *soc_info; + struct cam_isp_resource_node *tpg_res; + const struct cam_top_tpg_reg_offset *tpg_reg; + struct cam_top_tpg_cfg *tpg_data; + + if (!hw_priv || !stop_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "TPG: Invalid args"); + return -EINVAL; + } + + tpg_hw_info = (struct cam_hw_info *)hw_priv; + tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info; + tpg_reg = tpg_hw->tpg_info->tpg_reg; + tpg_res = (struct cam_isp_resource_node *) stop_args; + tpg_data = (struct cam_top_tpg_cfg *)tpg_res->res_state; + soc_info = &tpg_hw->hw_info->soc_info; + + if ((tpg_res->res_type != CAM_ISP_RESOURCE_TPG) || + (tpg_res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING)) { + CAM_DBG(CAM_ISP, "TPG:%d Invalid Res type:%d res_state:%d", + tpg_hw->hw_intf->hw_idx, + tpg_res->res_type, tpg_res->res_state); + rc = -EINVAL; + goto end; + } + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_ctrl); + + tpg_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + CAM_DBG(CAM_ISP, "TPG:%d stopped", tpg_hw->hw_intf->hw_idx); +end: + return rc; +} + +static int cam_top_tpg_read(void *hw_priv, + void *read_args, uint32_t arg_size) +{ + CAM_ERR(CAM_ISP, "TPG: un supported"); + + return -EINVAL; +} + +static int cam_top_tpg_write(void *hw_priv, + void *write_args, uint32_t arg_size) +{ + CAM_ERR(CAM_ISP, "TPG: un supported"); + return -EINVAL; +} + +static int cam_top_tpg_set_phy_clock( + struct cam_top_tpg_hw *csid_hw, void *cmd_args) +{ + struct cam_top_tpg_clock_update_args *clk_update = NULL; + + if (!csid_hw) + return -EINVAL; + + clk_update = + (struct cam_top_tpg_clock_update_args *)cmd_args; + + csid_hw->clk_rate = clk_update->clk_rate; + CAM_DBG(CAM_ISP, "CSI PHY clock rate %llu", csid_hw->clk_rate); + + return 0; +} + +static int cam_top_tpg_process_cmd(void *hw_priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_top_tpg_hw *tpg_hw; + struct cam_hw_info *tpg_hw_info; + + if (!hw_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "CSID: Invalid arguments"); + return -EINVAL; + } + + tpg_hw_info = (struct cam_hw_info *)hw_priv; + tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info; + + switch (cmd_type) { + case CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE: + rc = cam_top_tpg_set_phy_clock(tpg_hw, cmd_args); + break; + default: + CAM_ERR(CAM_ISP, "TPG:%d unsupported cmd:%d", + tpg_hw->hw_intf->hw_idx, cmd_type); + rc = -EINVAL; + break; + } + + return 0; +} + +int cam_top_tpg_hw_probe_init(struct cam_hw_intf *tpg_hw_intf, + uint32_t tpg_idx) +{ + int rc = -EINVAL; + struct cam_top_tpg_cfg *tpg_data; + struct cam_hw_info *tpg_hw_info; + struct cam_top_tpg_hw *tpg_hw = NULL; + uint32_t val = 0; + + if (tpg_idx >= CAM_TOP_TPG_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid tpg index:%d", tpg_idx); + return rc; + } + + tpg_hw_info = (struct cam_hw_info *)tpg_hw_intf->hw_priv; + tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info; + + tpg_hw->hw_intf = tpg_hw_intf; + tpg_hw->hw_info = tpg_hw_info; + + CAM_DBG(CAM_ISP, "type %d index %d", + tpg_hw->hw_intf->hw_type, tpg_idx); + + tpg_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&tpg_hw->hw_info->hw_mutex); + spin_lock_init(&tpg_hw->hw_info->hw_lock); + spin_lock_init(&tpg_hw->lock_state); + init_completion(&tpg_hw->hw_info->hw_complete); + + init_completion(&tpg_hw->tpg_complete); + + rc = cam_top_tpg_init_soc_resources(&tpg_hw->hw_info->soc_info, + tpg_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "TPG:%d Failed to init_soc", tpg_idx); + goto err; + } + + tpg_hw->hw_intf->hw_ops.get_hw_caps = cam_top_tpg_get_hw_caps; + tpg_hw->hw_intf->hw_ops.init = cam_top_tpg_init_hw; + tpg_hw->hw_intf->hw_ops.deinit = cam_top_tpg_deinit_hw; + tpg_hw->hw_intf->hw_ops.reset = NULL; + tpg_hw->hw_intf->hw_ops.reserve = cam_top_tpg_reserve; + tpg_hw->hw_intf->hw_ops.release = cam_top_tpg_release; + tpg_hw->hw_intf->hw_ops.start = cam_top_tpg_start; + tpg_hw->hw_intf->hw_ops.stop = cam_top_tpg_stop; + tpg_hw->hw_intf->hw_ops.read = cam_top_tpg_read; + tpg_hw->hw_intf->hw_ops.write = cam_top_tpg_write; + tpg_hw->hw_intf->hw_ops.process_cmd = cam_top_tpg_process_cmd; + + tpg_hw->tpg_res.res_type = CAM_ISP_RESOURCE_TPG; + tpg_hw->tpg_res.res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + tpg_hw->tpg_res.hw_intf = tpg_hw->hw_intf; + tpg_data = kzalloc(sizeof(*tpg_data), GFP_KERNEL); + if (!tpg_data) { + rc = -ENOMEM; + goto err; + } + tpg_hw->tpg_res.res_priv = tpg_data; + + cam_top_tpg_enable_soc_resources(&tpg_hw->hw_info->soc_info, + CAM_SVS_VOTE); + + val = cam_io_r_mb(tpg_hw->hw_info->soc_info.reg_map[0].mem_base + + tpg_hw->tpg_info->tpg_reg->tpg_hw_version); + CAM_DBG(CAM_ISP, "TPG:%d TPG HW version: 0x%x", + tpg_hw->hw_intf->hw_idx, val); + + cam_top_tpg_disable_soc_resources(&tpg_hw->hw_info->soc_info); +err: + + return rc; +} + +int cam_top_tpg_hw_deinit(struct cam_top_tpg_hw *top_tpg_hw) +{ + int rc = -EINVAL; + + if (!top_tpg_hw) { + CAM_ERR(CAM_ISP, "Invalid param"); + return rc; + } + + /* release the privdate data memory from resources */ + kfree(top_tpg_hw->tpg_res.res_priv); + cam_top_tpg_deinit_soc_resources(&top_tpg_hw->hw_info->soc_info); + + return 0; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.h new file mode 100644 index 000000000000..5a859ffb5d38 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TOP_TPG_HW_H_ +#define _CAM_TOP_TPG_HW_H_ + +#include "cam_hw.h" +#include "cam_top_tpg_hw_intf.h" +#include "cam_top_tpg_soc.h" + +enum cam_top_tpg_encode_format { + CAM_TOP_TPG_ENCODE_FORMAT_RAW6, + CAM_TOP_TPG_ENCODE_FORMAT_RAW8, + CAM_TOP_TPG_ENCODE_FORMAT_RAW10, + CAM_TOP_TPG_ENCODE_FORMAT_RAW12, + CAM_TOP_TPG_ENCODE_FORMAT_RAW14, + CAM_TOP_TPG_ENCODE_FORMAT_RAW16, + CAM_TOP_TPG_ENCODE_FORMAT_MAX, +}; + +struct cam_top_tpg_reg_offset { + uint32_t tpg_hw_version; + uint32_t tpg_hw_status; + uint32_t tpg_ctrl; + uint32_t tpg_vc_cfg0; + uint32_t tpg_vc_cfg1; + uint32_t tpg_lfsr_seed; + uint32_t tpg_dt_0_cfg_0; + uint32_t tpg_dt_1_cfg_0; + uint32_t tpg_dt_2_cfg_0; + uint32_t tpg_dt_3_cfg_0; + uint32_t tpg_dt_0_cfg_1; + uint32_t tpg_dt_1_cfg_1; + uint32_t tpg_dt_2_cfg_1; + uint32_t tpg_dt_3_cfg_1; + uint32_t tpg_dt_0_cfg_2; + uint32_t tpg_dt_1_cfg_2; + uint32_t tpg_dt_2_cfg_2; + uint32_t tpg_dt_3_cfg_2; + uint32_t tpg_color_bar_cfg; + uint32_t tpg_common_gen_cfg; + uint32_t tpg_vbi_cfg; + uint32_t tpg_test_bus_crtl; + uint32_t tpg_spare; + /* configurations */ + uint32_t major_version; + uint32_t minor_version; + uint32_t version_incr; + uint32_t tpg_en_shift_val; + uint32_t tpg_phy_sel_shift_val; + uint32_t tpg_num_active_lines_shift; + uint32_t tpg_fe_pkt_en_shift; + uint32_t tpg_fs_pkt_en_shift; + uint32_t tpg_line_interleaving_mode_shift; + uint32_t tpg_num_dts_shift_val; + uint32_t tpg_v_blank_cnt_shift; + uint32_t tpg_dt_encode_format_shift; + uint32_t tpg_payload_mode_color; + uint32_t tpg_split_en_shift; + uint32_t top_mux_reg_offset; +}; + +/** + * struct cam_top_tpg_hw_info- tpg hardware info + * + * @tpg_reg: tpg register offsets + * @hw_dts_version: HW DTS version + * @csid_max_clk: maximum csid clock + * @phy_max_clk maximum phy clock + * + */ +struct cam_top_tpg_hw_info { + const struct cam_top_tpg_reg_offset *tpg_reg; + uint32_t hw_dts_version; + uint32_t csid_max_clk; + uint32_t phy_max_clk; +}; + +/** + * struct cam_top_tpg_dt_cfg- tpg data type(dt) configuration + * + * @frame_width: frame width in pixel + * @frame_height: frame height in pixel + * @data_type: data type(dt) value + * @encode_format: encode format for this data type + * @payload_mode payload data, such color bar, color box etc + * + */ + +struct cam_top_tpg_dt_cfg { + uint32_t frame_width; + uint32_t frame_height; + uint32_t data_type; + uint32_t encode_format; + uint32_t payload_mode; +}; + +/** + * struct cam_top_tpg_cfg- tpg congiguration + * @pix_pattern : pixel pattern output of the tpg + * @phy_sel : phy selection 0:dphy or 1:cphy + * @num_active_lanes Number of active lines + * @vc_num: Virtual channel number + * @h_blank_count: horizontal blanking count value + * @h_blank_count: vertical blanking count value + * @vbi_cnt: vbi count + * @num_active_dts: number of active dts need to configure + * @dt_cfg: dt configuration values + * + */ +struct cam_top_tpg_cfg { + uint32_t pix_pattern; + uint32_t phy_sel; + uint32_t num_active_lanes; + uint32_t vc_num; + uint32_t v_blank_count; + uint32_t h_blank_count; + uint32_t vbi_cnt; + uint32_t num_active_dts; + struct cam_top_tpg_dt_cfg dt_cfg[4]; +}; + +/** + * struct cam_top_tpg_hw- tpg hw device resources data + * + * @hw_intf: contain the tpg hw interface information + * @hw_info: tpg hw device information + * @tpg_info: tpg hw specific information + * @tpg_res: tpg resource + * @tpg_cfg: tpg configuration + * @clk_rate clock rate + * @lock_state lock state + * @tpg_complete tpg completion + * + */ +struct cam_top_tpg_hw { + struct cam_hw_intf *hw_intf; + struct cam_hw_info *hw_info; + struct cam_top_tpg_hw_info *tpg_info; + struct cam_isp_resource_node tpg_res; + uint64_t clk_rate; + spinlock_t lock_state; + struct completion tpg_complete; +}; + +int cam_top_tpg_hw_probe_init(struct cam_hw_intf *tpg_hw_intf, + uint32_t tpg_idx); + +int cam_top_tpg_hw_deinit(struct cam_top_tpg_hw *top_tpg_hw); + +#endif /* _CAM_TOP_TPG_HW_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_dev.c new file mode 100644 index 000000000000..fd7dc87fb79a --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_dev.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include "cam_top_tpg_core.h" +#include "cam_top_tpg_dev.h" +#include "cam_top_tpg_hw_intf.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_top_tpg_hw_list[CAM_TOP_TPG_HW_NUM_MAX] = { + 0, 0}; + +static char tpg_dev_name[8]; + +int cam_top_tpg_probe(struct platform_device *pdev) +{ + + struct cam_hw_intf *tpg_hw_intf; + struct cam_hw_info *tpg_hw_info; + struct cam_top_tpg_hw *tpg_dev = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_top_tpg_hw_info *tpg_hw_data = NULL; + uint32_t tpg_dev_idx; + int rc = 0; + + CAM_DBG(CAM_ISP, "probe called"); + + tpg_hw_intf = kzalloc(sizeof(*tpg_hw_intf), GFP_KERNEL); + if (!tpg_hw_intf) { + rc = -ENOMEM; + goto err; + } + + tpg_hw_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!tpg_hw_info) { + rc = -ENOMEM; + goto free_hw_intf; + } + + tpg_dev = kzalloc(sizeof(struct cam_top_tpg_hw), GFP_KERNEL); + if (!tpg_dev) { + rc = -ENOMEM; + goto free_hw_info; + } + + /* get top tpg hw index */ + of_property_read_u32(pdev->dev.of_node, "cell-index", &tpg_dev_idx); + /* get top tpg hw information */ + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ISP, "No matching table for the top tpg hw"); + rc = -EINVAL; + goto free_dev; + } + + memset(tpg_dev_name, 0, sizeof(tpg_dev_name)); + snprintf(tpg_dev_name, sizeof(tpg_dev_name), + "tpg%1u", tpg_dev_idx); + + tpg_hw_intf->hw_idx = tpg_dev_idx; + tpg_hw_intf->hw_type = CAM_ISP_HW_TYPE_TPG; + tpg_hw_intf->hw_priv = tpg_hw_info; + + tpg_hw_info->core_info = tpg_dev; + tpg_hw_info->soc_info.pdev = pdev; + tpg_hw_info->soc_info.dev = &pdev->dev; + tpg_hw_info->soc_info.dev_name = tpg_dev_name; + tpg_hw_info->soc_info.index = tpg_dev_idx; + + tpg_hw_data = (struct cam_top_tpg_hw_info *)match_dev->data; + /* need to setup the pdev before call the tfe hw probe init */ + tpg_dev->tpg_info = tpg_hw_data; + + rc = cam_top_tpg_hw_probe_init(tpg_hw_intf, tpg_dev_idx); + if (rc) + goto free_dev; + + platform_set_drvdata(pdev, tpg_dev); + CAM_DBG(CAM_ISP, "TPG:%d probe successful", + tpg_hw_intf->hw_idx); + + + if (tpg_hw_intf->hw_idx < CAM_TOP_TPG_HW_NUM_MAX) + cam_top_tpg_hw_list[tpg_hw_intf->hw_idx] = tpg_hw_intf; + else + goto free_dev; + + return 0; + +free_dev: + kfree(tpg_dev); +free_hw_info: + kfree(tpg_hw_info); +free_hw_intf: + kfree(tpg_hw_intf); +err: + return rc; +} + +int cam_top_tpg_remove(struct platform_device *pdev) +{ + struct cam_top_tpg_hw *tpg_dev = NULL; + struct cam_hw_intf *tpg_hw_intf; + struct cam_hw_info *tpg_hw_info; + + tpg_dev = (struct cam_top_tpg_hw *)platform_get_drvdata(pdev); + tpg_hw_intf = tpg_dev->hw_intf; + tpg_hw_info = tpg_dev->hw_info; + + CAM_DBG(CAM_ISP, "TPG:%d remove", + tpg_dev->hw_intf->hw_idx); + + cam_top_tpg_hw_deinit(tpg_dev); + + /*release the tpg device memory */ + kfree(tpg_dev); + kfree(tpg_hw_info); + kfree(tpg_hw_intf); + return 0; +} + +int cam_top_tpg_hw_init(struct cam_hw_intf **top_tpg_hw, + uint32_t hw_idx) +{ + int rc = 0; + + if (cam_top_tpg_hw_list[hw_idx]) { + *top_tpg_hw = cam_top_tpg_hw_list[hw_idx]; + } else { + *top_tpg_hw = NULL; + rc = -1; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_dev.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_dev.h new file mode 100644 index 000000000000..7d921a315a90 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_dev.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TOP_TPG_DEV_H_ +#define _CAM_TOP_TPG_DEV_H_ + +int cam_top_tpg_probe(struct platform_device *pdev); +int cam_top_tpg_remove(struct platform_device *pdev); + +#endif /*_CAM_TOP_TPG_DEV_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_soc.c new file mode 100644 index 000000000000..7a4e941cb4ad --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_soc.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ +#include +#include "cam_top_tpg_soc.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +int cam_top_tpg_init_soc_resources(struct cam_hw_soc_info *soc_info, + void *irq_data) +{ + int rc = 0; + struct cam_cpas_register_params cpas_register_param; + struct cam_top_tpg_soc_private *soc_private; + + soc_private = kzalloc(sizeof(struct cam_top_tpg_soc_private), + GFP_KERNEL); + if (!soc_private) + return -ENOMEM; + + soc_info->soc_private = soc_private; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + /* Need to see if we want post process the clock list */ + rc = cam_soc_util_request_platform_resource(soc_info, NULL, + irq_data); + + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Error Request platform resources failed rc=%d", rc); + goto free_soc_private; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "tpg", + CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = soc_info->dev; + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc); + goto release_soc; + } else { + soc_private->cpas_handle = cpas_register_param.client_handle; + } + + return rc; + +release_soc: + cam_soc_util_release_platform_resource(soc_info); +free_soc_private: + kfree(soc_private); + + return rc; +} + +int cam_top_tpg_deinit_soc_resources( + struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_top_tpg_soc_private *soc_private; + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -ENODEV; + } + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + + return rc; +} + +int cam_top_tpg_enable_soc_resources( + struct cam_hw_soc_info *soc_info, enum cam_vote_level clk_level) +{ + int rc = 0; + struct cam_top_tpg_soc_private *soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + soc_private = soc_info->soc_private; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + + CAM_DBG(CAM_ISP, "csid camnoc_bw:%lld mnoc_ab_bw:%lld mnoc_ib_bw:%lld ", + axi_vote.axi_path[0].camnoc_bw, + axi_vote.axi_path[0].mnoc_ab_bw, + axi_vote.axi_path[0].mnoc_ib_bw); + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_ISP, "Error CPAS start failed"); + rc = -EFAULT; + goto end; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + clk_level, false); + if (rc) { + CAM_ERR(CAM_ISP, "enable platform failed"); + goto stop_cpas; + } + + return rc; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); +end: + return rc; +} + +int cam_top_tpg_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_top_tpg_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, false); + if (rc) + CAM_ERR(CAM_ISP, "Disable platform failed"); + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Error CPAS stop failed rc=%d", rc); + return rc; + } + + return rc; +} + diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_soc.h new file mode 100644 index 000000000000..0838c68745de --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_soc.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TOP_TPG_SOC_H_ +#define _CAM_TOP_TPG_SOC_H_ + +#include "cam_isp_hw.h" + +/* + * struct cam_top_tpg_soc_private: + * + * @Brief: Private SOC data specific to TPG HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver. + * This handle is used for all further interface + * with CPAS. + */ +struct cam_top_tpg_soc_private { + uint32_t cpas_handle; +}; + +/** + * struct cam_top_tpg_device_soc_info - tpg soc SOC info object + * + * @csi_vdd_voltage: csi vdd voltage value + * + */ +struct cam_top_tpg_device_soc_info { + int csi_vdd_voltage; +}; + +/** + * cam_top_tpg_init_soc_resources() + * + * @brief: csid initialization function for the soc info + * + * @soc_info: soc info structure pointer + * @irq_data: irq data for the callback function + * + */ +int cam_top_tpg_init_soc_resources(struct cam_hw_soc_info *soc_info, + void *irq_data); + +/** + * cam_top_tpg_deinit_soc_resources() + * + * @brief: tpg de initialization function for the soc info + * + * @soc_info: soc info structure pointer + * + */ +int cam_top_tpg_deinit_soc_resources(struct cam_hw_soc_info *soc_info); + +/** + * cam_top_tpg_enable_soc_resources() + * + * @brief: tpg soc resource enable function + * + * @soc_info: soc info structure pointer + * @clk_lvl: vote level to start with + * + */ +int cam_top_tpg_enable_soc_resources(struct cam_hw_soc_info *soc_info, + uint32_t clk_lvl); + +/** + * cam_top_tpg_disable_soc_resources() + * + * @brief: csid soc resource disable function + * + * @soc_info: soc info structure pointer + * + */ +int cam_top_tpg_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_TOP_TPG_SOC_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.c new file mode 100644 index 000000000000..ce56d38fcea0 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#include +#include "cam_top_tpg_core.h" +#include "cam_top_tpg_v1.h" +#include "cam_top_tpg_dev.h" + +#define CAM_TOP_TPG_DRV_NAME "tpg_v1" +#define CAM_TOP_TPG_VERSION_V1 0x10000000 + +static struct cam_top_tpg_hw_info cam_top_tpg_v1_hw_info = { + .tpg_reg = &cam_top_tpg_v1_reg_offset, + .hw_dts_version = CAM_TOP_TPG_VERSION_V1, + .csid_max_clk = 426400000, + .phy_max_clk = 384000000, +}; + +static const struct of_device_id cam_top_tpg_v1_dt_match[] = { + { + .compatible = "qcom,tpgv1", + .data = &cam_top_tpg_v1_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_top_tpg_v1_dt_match); + +static struct platform_driver cam_top_tpg_v1_driver = { + .probe = cam_top_tpg_probe, + .remove = cam_top_tpg_remove, + .driver = { + .name = CAM_TOP_TPG_DRV_NAME, + .of_match_table = cam_top_tpg_v1_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_top_tpg_v1_init_module(void) +{ + return platform_driver_register(&cam_top_tpg_v1_driver); +} + +static void __exit cam_top_tpg_v1_exit_module(void) +{ + platform_driver_unregister(&cam_top_tpg_v1_driver); +} + +module_init(cam_top_tpg_v1_init_module); +module_exit(cam_top_tpg_v1_exit_module); +MODULE_DESCRIPTION("CAM TOP TPG driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.h new file mode 100644 index 000000000000..addd8a2e5988 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TOP_TPG_V1_H_ +#define _CAM_TOP_TPG_V1_H_ + +#include "cam_top_tpg_core.h" + +static struct cam_top_tpg_reg_offset cam_top_tpg_v1_reg_offset = { + .tpg_hw_version = 0x0, + .tpg_hw_status = 0x4, + .tpg_ctrl = 0x60, + .tpg_vc_cfg0 = 0x64, + .tpg_vc_cfg1 = 0x68, + .tpg_lfsr_seed = 0x6c, + .tpg_dt_0_cfg_0 = 0x70, + .tpg_dt_1_cfg_0 = 0x74, + .tpg_dt_2_cfg_0 = 0x78, + .tpg_dt_3_cfg_0 = 0x7C, + .tpg_dt_0_cfg_1 = 0x80, + .tpg_dt_1_cfg_1 = 0x84, + .tpg_dt_2_cfg_1 = 0x88, + .tpg_dt_3_cfg_1 = 0x8C, + .tpg_dt_0_cfg_2 = 0x90, + .tpg_dt_1_cfg_2 = 0x94, + .tpg_dt_2_cfg_2 = 0x98, + .tpg_dt_3_cfg_2 = 0x9C, + .tpg_color_bar_cfg = 0xA0, + .tpg_common_gen_cfg = 0xA4, + .tpg_vbi_cfg = 0xA8, + .tpg_test_bus_crtl = 0xF8, + .tpg_spare = 0xFC, + /* configurations */ + .major_version = 1, + .minor_version = 0, + .version_incr = 0, + .tpg_en_shift_val = 0, + .tpg_phy_sel_shift_val = 3, + .tpg_num_active_lines_shift = 4, + .tpg_fe_pkt_en_shift = 2, + .tpg_fs_pkt_en_shift = 1, + .tpg_line_interleaving_mode_shift = 10, + .tpg_num_dts_shift_val = 8, + .tpg_v_blank_cnt_shift = 12, + .tpg_dt_encode_format_shift = 16, + .tpg_payload_mode_color = 0x8, + .tpg_split_en_shift = 5, + .top_mux_reg_offset = 0x1C, +}; + +#endif /*_CAM_TOP_TPG_V1_H_ */ diff --git a/include/uapi/media/cam_isp_tfe.h b/include/uapi/media/cam_isp_tfe.h new file mode 100644 index 000000000000..fc716311367d --- /dev/null +++ b/include/uapi/media/cam_isp_tfe.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ISP_TFE_H__ +#define __UAPI_CAM_ISP_TFE_H__ + +/* TFE output port resource id number */ +#define CAM_ISP_TFE_OUT_RES_BASE 0x1 + +#define CAM_ISP_TFE_OUT_RES_FULL (CAM_ISP_TFE_OUT_RES_BASE + 0) +#define CAM_ISP_TFE_OUT_RES_RAW_DUMP (CAM_ISP_TFE_OUT_RES_BASE + 1) +#define CAM_ISP_TFE_OUT_RES_PDAF (CAM_ISP_TFE_OUT_RES_BASE + 2) +#define CAM_ISP_TFE_OUT_RES_RDI_0 (CAM_ISP_TFE_OUT_RES_BASE + 3) +#define CAM_ISP_TFE_OUT_RES_RDI_1 (CAM_ISP_TFE_OUT_RES_BASE + 4) +#define CAM_ISP_TFE_OUT_RES_RDI_2 (CAM_ISP_TFE_OUT_RES_BASE + 5) +#define CAM_ISP_TFE_OUT_RES_STATS_HDR_BE (CAM_ISP_TFE_OUT_RES_BASE + 6) +#define CAM_ISP_TFE_OUT_RES_STATS_HDR_BHIST (CAM_ISP_TFE_OUT_RES_BASE + 7) +#define CAM_ISP_TFE_OUT_RES_STATS_TL_BG (CAM_ISP_TFE_OUT_RES_BASE + 8) +#define CAM_ISP_TFE_OUT_RES_STATS_BF (CAM_ISP_TFE_OUT_RES_BASE + 9) +#define CAM_ISP_TFE_OUT_RES_STATS_AWB_BG (CAM_ISP_TFE_OUT_RES_BASE + 10) +#define CAM_ISP_TFE_OUT_RES_MAX (CAM_ISP_TFE_OUT_RES_BASE + 11) + + +/* TFE input port resource type */ +#define CAM_ISP_TFE_IN_RES_BASE 0x1 + +#define CAM_ISP_TFE_IN_RES_TPG (CAM_ISP_TFE_IN_RES_BASE + 0) +#define CAM_ISP_TFE_IN_RES_PHY_0 (CAM_ISP_TFE_IN_RES_BASE + 1) +#define CAM_ISP_TFE_IN_RES_PHY_1 (CAM_ISP_TFE_IN_RES_BASE + 2) +#define CAM_ISP_TFE_IN_RES_PHY_2 (CAM_ISP_TFE_IN_RES_BASE + 3) +#define CAM_ISP_TFE_IN_RES_MAX (CAM_ISP_TFE_IN_RES_BASE + 4) + +#endif /* __UAPI_CAM_ISP_TFE_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 197dda0c6b6a..946bb90978dd 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -31,6 +31,7 @@ #define CAM_OIS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 13) #define CAM_CUSTOM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 14) #define CAM_OPE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 15) +#define CAM_TFE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 16) /* cam_req_mgr hdl info */ #define CAM_REQ_MGR_HDL_IDX_POS 8 diff --git a/include/uapi/media/cam_tfe.h b/include/uapi/media/cam_tfe.h new file mode 100644 index 000000000000..9055f7fbe55c --- /dev/null +++ b/include/uapi/media/cam_tfe.h @@ -0,0 +1,391 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_TFE_H__ +#define __UAPI_CAM_TFE_H__ + +#include "cam_defs.h" +#include "cam_isp_tfe.h" +#include "cam_cpas.h" + + +/* ISP TFE driver name */ +#define CAM_ISP_TFE_DEV_NAME "cam-isp" + +/* HW type */ +#define CAM_ISP_TFE_HW_BASE 0 +#define CAM_ISP_TFE_HW_CSID 1 +#define CAM_ISP_TFE_HW_TFE 2 +#define CAM_ISP_TFE_HW_MAX 3 + +/* Color Pattern */ +#define CAM_ISP_TFE_PATTERN_BAYER_RGRGRG 0 +#define CAM_ISP_TFE_PATTERN_BAYER_GRGRGR 1 +#define CAM_ISP_TFE_PATTERN_BAYER_BGBGBG 2 +#define CAM_ISP_TFE_PATTERN_BAYER_GBGBGB 3 +#define CAM_ISP_TFE_PATTERN_YUV_YCBYCR 4 +#define CAM_ISP_TFE_PATTERN_YUV_YCRYCB 5 +#define CAM_ISP_TFE_PATTERN_YUV_CBYCRY 6 +#define CAM_ISP_TFE_PATTERN_YUV_CRYCBY 7 +#define CAM_ISP_TFE_PATTERN_MAX 8 + +/* Usage Type */ +#define CAM_ISP_TFE_IN_RES_USAGE_SINGLE 0 +#define CAM_ISP_TFE_IN_RES_USAGE_DUAL 1 +#define CAM_ISP_TFE_IN_RES_USAGE_MAX 2 + +/* Resource ID */ +#define CAM_ISP_TFE_RES_ID_PORT 0 +#define CAM_ISP_TFE_RES_ID_MAX 1 + +/* Resource Type - Type of resource for the resource id + * defined in cam_isp_tfe.h + */ + +/* Lane Type in input resource for Port */ +#define CAM_ISP_TFE_IN_LANE_TYPE_DPHY 0 +#define CAM_ISP_TFE_IN_LANE_TYPE_CPHY 1 +#define CAM_ISP_TFE_IN_LANE_TYPE_MAX 2 + +/* ISP TFE packet opcode */ +#define CAM_ISP_TFE_PACKET_OP_BASE 0 +#define CAM_ISP_TFE_PACKET_INIT_DEV 1 +#define CAM_ISP_TFE_PACKET_CONFIG_DEV 2 +#define CAM_ISP_TFE_PACKET_OP_MAX 3 + +/* ISP TFE packet meta_data type for command buffer */ +#define CAM_ISP_TFE_PACKET_META_BASE 0 +#define CAM_ISP_TFE_PACKET_META_LEFT 1 +#define CAM_ISP_TFE_PACKET_META_RIGHT 2 +#define CAM_ISP_TFE_PACKET_META_COMMON 3 +#define CAM_ISP_TFE_PACKET_META_DUAL_CONFIG 4 +#define CAM_ISP_TFE_PACKET_META_GENERIC_BLOB_COMMON 5 +#define CAM_ISP_TFE_PACKET_META_REG_DUMP_PER_REQUEST 6 +#define CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_FLUSH 7 +#define CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_ERROR 8 + +/* ISP TFE Generic Cmd Buffer Blob types */ +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_HFR_CONFIG 0 +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_BW_CONFIG_V2 2 +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 3 + +/* DSP mode */ +#define CAM_ISP_TFE_DSP_MODE_NONE 0 +#define CAM_ISP_TFE_DSP_MODE_ONE_WAY 1 +#define CAM_ISP_TFE_DSP_MODE_ROUND 2 + +/* Per Path Usage Data */ +#define CAM_ISP_TFE_USAGE_INVALID 0 +#define CAM_ISP_TFE_USAGE_LEFT_PX 1 +#define CAM_ISP_TFE_USAGE_RIGHT_PX 2 +#define CAM_ISP_TFE_USAGE_RDI 3 + +/* Query devices */ +/** + * struct cam_isp_tfe_dev_cap_info - A cap info for particular hw type + * + * @hw_type: Hardware type for the cap info + * @reserved: reserved field for alignment + * @hw_version: Hardware version + * + */ +struct cam_isp_tfe_dev_cap_info { + uint32_t hw_type; + uint32_t reserved; + struct cam_hw_version hw_version; +}; + +/** + * struct cam_isp_tfe_query_cap_cmd - ISP TFE query device + * capability payload + * + * @device_iommu: returned iommu handles for device + * @cdm_iommu: returned iommu handles for cdm + * @num_dev: returned number of device capabilities + * @reserved: reserved field for alignment + * @dev_caps: returned device capability array + * + */ +struct cam_isp_tfe_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + int32_t num_dev; + uint32_t reserved; + struct cam_isp_tfe_dev_cap_info dev_caps[CAM_ISP_TFE_HW_MAX]; +}; + +/* Acquire Device */ +/** + * struct cam_isp_tfe_out_port_info - An output port resource info + * + * @res_id: output resource id defined in file + * cam_isp_tfe.h + * @format: output format of the resource + * @width: output width in pixels + * @height: output height in lines + * @stride: output stride + * @comp_grp_id: composite group id for the resource. + * @secure_mode: flag to tell if output should be run in secure + * mode or not. See cam_defs.h for definition + * @wm_mode: wm mode + * @reserved: reserved field for alignment + * + */ +struct cam_isp_tfe_out_port_info { + uint32_t res_id; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t comp_grp_id; + uint32_t secure_mode; + uint32_t wm_mode; + uint32_t reserved; +}; + +/** + * struct cam_isp_tfe_in_port_info - An input port resource info + * + * @res_id: input resource id CAM_ISP_TFE_IN_RES_XXX + * @lane_type: lane type: c-phy or d-phy. + * @lane_num: active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * @vc: input virtual channel number + * @dt: input data type number + * @format: input format + * @pix_pattern: pixel pattern + * @usage_type: whether dual tfe is required + * @left_start: left input start offset in pixels + * @left_end: left input stop offset in pixels + * @left_width: left input width in pixels + * @right_start: right input start offset in pixels. + * Only for Dual TFE + * @right_end: right input stop offset in + * pixels. Only for Dual TFE + * @right_width: right input width in pixels. + * Only for dual TFE + * @line_start: top of the line number + * @line_stop: bottome of the line number + * @height: input height in lines + * @batch_size: batch size for HFR mode + * @dsp_mode: DSP stream mode(Defines as + * CAM_ISP_TFE_DSP_MODE_*) + * @sensor_width: sensor width + * @sensor_height: sensor height + * @hbi_value: sensor HBI value + * @vbi_value: sensor VBI value + * @sensor_fps: sensor fps + * @init_frame_drop init frame drop value. + * @num_out_res: number of the output resource associated + * @data: payload that contains the output resources, + * array of cam_isp_tfe_out_port_info data + * + */ +struct cam_isp_tfe_in_port_info { + uint32_t res_id; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc; + uint32_t dt; + uint32_t format; + uint32_t pix_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_end; + uint32_t left_width; + uint32_t right_start; + uint32_t right_end; + uint32_t right_width; + uint32_t line_start; + uint32_t line_end; + uint32_t height; + uint32_t batch_size; + uint32_t dsp_mode; + uint32_t sensor_width; + uint32_t sensor_height; + uint32_t sensor_hbi; + uint32_t sensor_vbi; + uint32_t sensor_fps; + uint32_t init_frame_drop; + uint32_t num_out_res; + struct cam_isp_tfe_out_port_info data[1]; +}; + +/** + * struct cam_isp_tfe_resource - A resource bundle + * + * @resoruce_id: resource id for the resource bundle + * @length: length of the while resource blob + * @handle_type: type of the resource handle + * @reserved: reserved field for alignment + * @res_hdl: resource handle that points to the + * resource array + * + */ +struct cam_isp_tfe_resource { + uint32_t resource_id; + uint32_t length; + uint32_t handle_type; + uint32_t reserved; + uint64_t res_hdl; +}; + +/** + * struct cam_isp_tfe_port_hfr_config - HFR configuration for + * this port + * + * @resource_type: Resource type + * @subsample_pattern: Subsample pattern. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @subsample_period: Subsample period. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @framedrop_pattern: Framedrop pattern + * @framedrop_period: Framedrop period + * @reserved: Reserved for alignment + */ +struct cam_isp_tfe_port_hfr_config { + uint32_t resource_type; + uint32_t subsample_pattern; + uint32_t subsample_period; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_resource_hfr_config - Resource HFR + * configuration + * + * @num_ports: Number of ports + * @reserved: Reserved for alignment + * @port_hfr_config: HFR configuration for each IO port + */ +struct cam_isp_tfe_resource_hfr_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_tfe_port_hfr_config port_hfr_config[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_dual_stripe_config - stripe config per bus + * client + * + * @offset: Start horizontal offset relative to + * output buffer + * @width: Width of the stripe in pixels + * @port_id: Port id of ISP TFE output + * @reserved: Reserved for alignment + * + */ +struct cam_isp_tfe_dual_stripe_config { + uint32_t offset; + uint32_t width; + uint32_t port_id; + uint32_t reserved; +}; + +/** + * struct cam_isp_tfe_dual_config - dual isp configuration + * + * @num_ports Number of isp output ports + * @reserved Reserved field for alignment + * @stripes: Stripe information + * + */ +struct cam_isp_tfe_dual_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_tfe_dual_stripe_config stripes[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_clock_config - Clock configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_hz: Pixel Clock for Left ISP + * @right_pix_hz: Pixel Clock for Right ISP + * valid only if Dual + * @rdi_hz: RDI Clock. ISP TFE clock will be + * max of RDI and PIX clocks. For a + * particular context which ISP TFE + * HW the RDI is allocated to is + * not known to UMD. Hence pass the + * clock and let KMD decide. + */ +struct cam_isp_tfe_clock_config { + uint32_t usage_type; + uint32_t num_rdi; + uint64_t left_pix_hz; + uint64_t right_pix_hz; + uint64_t rdi_hz[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_csid_clock_config - CSID clock + * configuration + * + * @csid_clock CSID clock + * @csi_phy_clock Phy clock valid if tpg is selected + */ +struct cam_isp_tfe_csid_clock_config { + uint64_t csid_clock; + uint64_t phy_clock; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_bw_config_v2 - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_paths: Number of axi data paths + * @axi_path Per path vote info + */ +struct cam_isp_tfe_bw_config_v2 { + uint32_t usage_type; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_acquire_hw_info - ISP TFE acquire HW params + * + * @common_info_version : Version of common info struct used + * @common_info_size : Size of common info struct used + * @common_info_offset : Offset of common info from start of data + * @num_inputs : Number of inputs + * @input_info_version : Version of input info struct used + * @input_info_size : Size of input info struct used + * @input_info_offset : Offset of input info from start of data + * @data : Data pointer to point the cam_isp_tfe_in_port_info + * structure + */ +struct cam_isp_tfe_acquire_hw_info { + uint16_t common_info_version; + uint16_t common_info_size; + uint32_t common_info_offset; + uint32_t num_inputs; + uint32_t input_info_version; + uint32_t input_info_size; + uint32_t input_info_offset; + uint64_t data; +}; + +#define CAM_TFE_ACQUIRE_COMMON_VER0 0x1000 + +#define CAM_TFE_ACQUIRE_COMMON_SIZE_VER0 0x0 + +#define CAM_TFE_ACQUIRE_INPUT_VER0 0x2000 + +#define CAM_TFE_ACQUIRE_INPUT_SIZE_VER0 sizeof(struct cam_isp_tfe_in_port_info) + +#define CAM_TFE_ACQUIRE_OUT_VER0 0x3000 + +#define CAM_TFE_ACQUIRE_OUT_SIZE_VER0 sizeof(struct cam_isp_tfe_out_port_info) + +#endif /* __UAPI_CAM_TFE_H__ */ -- GitLab From c36cc8e7d959bf0b8d418b9a9ddbb366bc4e894d Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 16 Oct 2019 13:36:57 -0700 Subject: [PATCH 011/295] msm: camera: reqmgr: Add provision to obtain exposure time Currently CRM watchdog timer expiry is fixed at 1 second. This will not hold good if the sensor exposure time is increased beyond 1 second. In such situations obtain the time from userspace, and modify the CRM watchdog timer accordingly. CRs-Fixed: 2530691 Change-Id: I6251bcb2b915a9e317caffd350220e249214c8b2 Signed-off-by: Karthik Anantha Ram Signed-off-by: Mukund Madhusudan Atre --- include/uapi/media/cam_req_mgr.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 36471a290ad3..59564609035a 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -183,6 +183,11 @@ struct cam_req_mgr_flush_info { * @bubble_enable: Input Param - Cam req mgr will do bubble recovery if this * flag is set. * @sync_mode: Type of Sync mode for this request + * @additional_timeout: Additional timeout value (in ms) associated with + * this request. This value needs to be 0 in cases where long exposure is + * not configured for the sensor.The max timeout that will be supported + * is 50000 ms + * @reserved: Reserved * @req_id: Input Param - Request Id from which all requests will be flushed */ struct cam_req_mgr_sched_request { @@ -190,6 +195,8 @@ struct cam_req_mgr_sched_request { int32_t link_hdl; int32_t bubble_enable; int32_t sync_mode; + int32_t additional_timeout; + int32_t reserved; int64_t req_id; }; @@ -406,11 +413,13 @@ struct cam_mem_cache_ops_cmd { * @CAM_REQ_MGR_ERROR_TYPE_REQUEST: Error on a single request, not fatal * @CAM_REQ_MGR_ERROR_TYPE_BUFFER: Buffer was not filled, not fatal * @CAM_REQ_MGR_ERROR_TYPE_RECOVERY: Fatal error, can be recovered + * @CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE: SOF freeze, can be recovered */ #define CAM_REQ_MGR_ERROR_TYPE_DEVICE 0 #define CAM_REQ_MGR_ERROR_TYPE_REQUEST 1 #define CAM_REQ_MGR_ERROR_TYPE_BUFFER 2 #define CAM_REQ_MGR_ERROR_TYPE_RECOVERY 3 +#define CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE 4 /** * struct cam_req_mgr_error_msg -- GitLab From 2d5b827bb2f2b398b1c238f997b202ea724108dc Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Fri, 18 Oct 2019 16:25:36 -0700 Subject: [PATCH 012/295] msm: camera: reqmgr: Add support to modify timer for long exposure In case of long exposure shots, watchdog timer needs to be modified according to the requested value to avoid trigger. Add support for modifying timer value and changing it back to normal. CRs-Fixed: 2530691 Change-Id: I97bdd92d2ed461066bbf746bc6293094a444f8a5 Signed-off-by: Mukund Madhusudan Atre Signed-off-by: Karthik Anantha Ram --- drivers/cam_req_mgr/cam_req_mgr_core.c | 96 ++++++++++++++++++++++++-- drivers/cam_req_mgr/cam_req_mgr_core.h | 22 +++--- 2 files changed, 104 insertions(+), 14 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 427bc87d672e..faa15479ecda 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -443,6 +443,7 @@ static void __cam_req_mgr_flush_req_slot( slot->req_id = -1; slot->skip_idx = 1; slot->recover = 0; + slot->additional_timeout = 0; slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; slot->status = CRM_SLOT_STATUS_NO_REQ; @@ -486,6 +487,7 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, slot->req_id = -1; slot->skip_idx = 0; slot->recover = 0; + slot->additional_timeout = 0; slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; slot->status = CRM_SLOT_STATUS_NO_REQ; @@ -499,6 +501,66 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, } } +/** + * __cam_req_mgr_validate_crm_wd_timer() + * + * @brief : Validate/modify the wd timer based on associated + * timeout with the request + * @link : link pointer + * + */ +static void __cam_req_mgr_validate_crm_wd_timer( + struct cam_req_mgr_core_link *link) +{ + int idx = 0; + int next_frame_timeout = 0, current_frame_timeout = 0; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + + idx = in_q->rd_idx; + __cam_req_mgr_dec_idx( + &idx, (link->max_delay - 1), + in_q->num_slots); + next_frame_timeout = in_q->slot[idx].additional_timeout; + CAM_DBG(CAM_CRM, + "rd_idx: %d idx: %d next_frame_timeout: %d ms", + in_q->rd_idx, idx, next_frame_timeout); + + idx = in_q->rd_idx; + __cam_req_mgr_dec_idx( + &idx, link->max_delay, + in_q->num_slots); + current_frame_timeout = in_q->slot[idx].additional_timeout; + CAM_DBG(CAM_CRM, + "rd_idx: %d idx: %d current_frame_timeout: %d ms", + in_q->rd_idx, idx, current_frame_timeout); + + if ((next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT) > + link->watchdog->expires) { + CAM_DBG(CAM_CRM, + "Modifying wd timer expiry from %d ms to %d ms", + link->watchdog->expires, + (next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + next_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (current_frame_timeout) { + CAM_DBG(CAM_CRM, + "Reset wd timer to current frame from %d ms to %d ms", + link->watchdog->expires, + (current_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + current_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (link->watchdog->expires > + CAM_REQ_MGR_WATCHDOG_TIMEOUT) { + CAM_DBG(CAM_CRM, + "Reset wd timer to default from %d ms to %d ms", + link->watchdog->expires, CAM_REQ_MGR_WATCHDOG_TIMEOUT); + crm_timer_modify(link->watchdog, + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } +} + /** * __cam_req_mgr_check_for_lower_pd_devices() * @@ -1275,9 +1337,11 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, * - if in applied_state, somthign wrong. * - if in no_req state, no new req */ - CAM_DBG(CAM_REQ, "SOF Req[%lld] idx %d req_status %d link_hdl %x", + CAM_DBG(CAM_REQ, + "SOF Req[%lld] idx %d req_status %d link_hdl %x wd_timeout %d ms", in_q->slot[in_q->rd_idx].req_id, in_q->rd_idx, - in_q->slot[in_q->rd_idx].status, link->link_hdl); + in_q->slot[in_q->rd_idx].status, link->link_hdl, + in_q->slot[in_q->rd_idx].additional_timeout); slot = &in_q->slot[in_q->rd_idx]; if (slot->status == CRM_SLOT_STATUS_NO_REQ) { @@ -1393,6 +1457,9 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, link->trigger_mask |= trigger; + /* Check for any long exposure settings */ + __cam_req_mgr_validate_crm_wd_timer(link); + CAM_DBG(CAM_CRM, "Applied req[%lld] on link[%x] success", slot->req_id, link->link_hdl); spin_lock_bh(&link->link_state_spin_lock); @@ -1641,7 +1708,7 @@ static int __cam_req_mgr_process_sof_freeze(void *priv, void *data) memset(&msg, 0, sizeof(msg)); msg.session_hdl = session->session_hdl; - msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE; msg.u.err_msg.request_id = 0; msg.u.err_msg.link_hdl = link->link_hdl; @@ -2030,6 +2097,7 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) mutex_unlock(&link->req.lock); return -EINVAL; } + slot->additional_timeout = 0; __cam_req_mgr_in_q_skip_idx(in_q, idx); } } @@ -2081,10 +2149,11 @@ int cam_req_mgr_process_sched_req(void *priv, void *data) in_q = link->req.in_q; CAM_DBG(CAM_CRM, - "link_hdl %x req_id %lld at slot %d sync_mode %d is_master:%d", + "link_hdl %x req_id %lld at slot %d sync_mode %d is_master %d exp_timeout_val %d ms", sched_req->link_hdl, sched_req->req_id, in_q->wr_idx, sched_req->sync_mode, - link->is_master); + link->is_master, + sched_req->additional_timeout); mutex_lock(&link->req.lock); slot = &in_q->slot[in_q->wr_idx]; @@ -2098,6 +2167,22 @@ int cam_req_mgr_process_sched_req(void *priv, void *data) slot->sync_mode = sched_req->sync_mode; slot->skip_idx = 0; slot->recover = sched_req->bubble_enable; + if (sched_req->additional_timeout < 0) { + CAM_WARN(CAM_CRM, + "Requested timeout is invalid [%dms]", + sched_req->additional_timeout); + slot->additional_timeout = 0; + } else if (sched_req->additional_timeout > + CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX) { + CAM_WARN(CAM_CRM, + "Requested timeout [%dms] max supported timeout [%dms] resetting to max", + sched_req->additional_timeout, + CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX); + slot->additional_timeout = CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX; + } else { + slot->additional_timeout = sched_req->additional_timeout; + } + link->open_req_cnt++; __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); @@ -3261,6 +3346,7 @@ int cam_req_mgr_schedule_request( sched->req_id = sched_req->req_id; sched->sync_mode = sched_req->sync_mode; sched->link_hdl = sched_req->link_hdl; + sched->additional_timeout = sched_req->additional_timeout; if (session->force_err_recovery == AUTO_RECOVERY) { sched->bubble_enable = sched_req->bubble_enable; } else { diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index c790ce824244..0afdc69b0445 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -13,9 +13,10 @@ #define CAM_REQ_MGR_MAX_LINKED_DEV 16 #define MAX_REQ_SLOTS 48 -#define CAM_REQ_MGR_WATCHDOG_TIMEOUT 5000 -#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_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 @@ -226,13 +227,15 @@ struct cam_req_mgr_req_tbl { /** * struct cam_req_mgr_slot * - Internal Book keeping - * @idx : slot index - * @skip_idx : if req id in this slot needs to be skipped/not applied - * @status : state machine for life cycle of a slot + * @idx : slot index + * @skip_idx : if req id in this slot needs to be skipped/not applied + * @status : state machine for life cycle of a slot * - members updated due to external events - * @recover : if user enabled recovery for this request. - * @req_id : mask tracking which all devices have request ready - * @sync_mode : Sync mode in which req id in this slot has to applied + * @recover : if user enabled recovery for this request. + * @req_id : mask tracking which all devices have request ready + * @sync_mode : Sync mode in which req id in this slot has to applied + * @additional_timeout : Adjusted watchdog timeout value associated with + * this request */ struct cam_req_mgr_slot { int32_t idx; @@ -241,6 +244,7 @@ struct cam_req_mgr_slot { int32_t recover; int64_t req_id; int32_t sync_mode; + int32_t additional_timeout; }; /** -- GitLab From 939f1436eb7c6f3a4e23a565bfcc97c8d97a4242 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 11 Nov 2019 09:25:08 +0530 Subject: [PATCH 013/295] msm: camera: cpas: Update the QOS settings for Bengal camera Camera QOS settings are updated for Bengal target as per the Recommendations of hardware team. CRs-Fixed: 2531812 Change-Id: I068683445b0ced92c22a5bfdc56d936ca64385c3 Signed-off-by: Ravikishore Pampana --- drivers/cam_cpas/cpas_top/cpastop_v540_100.h | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cpastop_v540_100.h b/drivers/cam_cpas/cpas_top/cpastop_v540_100.h index 6ad0b91afd37..1357e586d26f 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v540_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v540_100.h @@ -88,21 +88,21 @@ static struct cam_camnoc_specific .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0xE30, /* CDM_PRIORITYLUT_LOW */ - .value = 0x22222222, + .value = 0x33333333, }, .priority_lut_high = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0xE34, /* CDM_PRIORITYLUT_HIGH */ - .value = 0x22222222, + .value = 0x33333333, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0xE38, /* CDM_URGENCY_LOW */ - .value = 0x2, + .value = 0x00000003, }, .danger_lut = { .enable = false, @@ -131,7 +131,7 @@ static struct cam_camnoc_specific .masked_value = 0, /* TFE_PRIORITYLUT_LOW */ .offset = 0x30, - .value = 0x66665433, + .value = 0x44443333, }, .priority_lut_high = { .enable = true, @@ -139,26 +139,26 @@ static struct cam_camnoc_specific .masked_value = 0, /* TFE_PRIORITYLUT_HIGH */ .offset = 0x34, - .value = 0x66666666, + .value = 0x66665555, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x38, /* TFE_URGENCY_LOW */ - .value = 0X10030, + .value = 0x00001030, }, .danger_lut = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x40, /* TFE_DANGERLUT_LOW */ - .value = 0xFFAA5500, + .value = 0xffff0000, }, .safe_lut = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x48, /* TFE_SAFELUT_LOW */ - .value = 0xFF00, + .value = 0x00000003, }, .ubwc_ctl = { /* @@ -177,20 +177,20 @@ static struct cam_camnoc_specific .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x430, /* OPE_PRIORITYLUT_LOW */ - .value = 0x66665433, + .value = 0x33333333, }, .priority_lut_high = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x434, /* OPE_PRIORITYLUT_HIGH */ - .value = 0x66666666, + .value = 0x33333333, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x438, /* OPE_URGENCY_LOW */ - .value = 0x3, + .value = 0x00000033, }, .danger_lut = { .enable = true, -- GitLab From 3feca8536a0f9eb41f206bd01fd5e1f776fdd31e Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Thu, 31 Oct 2019 11:36:50 +0530 Subject: [PATCH 014/295] msm: camera: tfe: Configure TPG hbi and vbi User space will send HBI and VBI values for tpg. Configure the TPG HBI and VBI values based on the user space given values. If user space does not send then configure the default values. Assign the isp context variable in the hw update data during the tfe hw config. Update proper comp group id for slave tfe. CRs-Fixed: 2545590 Change-Id: I2771d3c663c0fcb58306952f161c11a473846f8d Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 1 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 1 + .../isp_hw/top_tpg/cam_top_tpg_core.c | 24 ++++++++++++++----- 3 files changed, 20 insertions(+), 6 deletions(-) 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 7803f3a66b07..c1aab88262dc 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 @@ -2348,6 +2348,7 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, return -EINVAL; hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; + hw_update_data->isp_mgr_ctx = ctx; for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) { if (hw_update_data->bw_config_valid[i] == true) { 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 fdb7ed7eb12d..17c6e171c6c8 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 @@ -933,6 +933,7 @@ static int cam_tfe_bus_start_comp_grp( val = cam_io_r(common_data->mem_base + common_data->common_reg->comp_cfg_0); val |= (0x1 << rsrc_data->comp_grp_id); + val |= (0x1 << (rsrc_data->comp_grp_id + 16)); cam_io_w(val, common_data->mem_base + common_data->common_reg->comp_cfg_0); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c index 1ab170c9b2d5..ee8cbc5326fc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c @@ -444,17 +444,29 @@ static int cam_top_tpg_start(void *hw_priv, void *start_args, tpg_reg->tpg_num_dts_shift_val) | tpg_data->vc_num; cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc_cfg0); - /* HBlank count 500 and V blank count is 600 */ - cam_io_w_mb(0x2581F4, + /* + * if hblank is notset configureHBlank count 500 and + * V blank count is 600 + */ + + if (tpg_data->h_blank_count) + cam_io_w_mb(tpg_data->h_blank_count, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc_cfg1); + else + cam_io_w_mb(0x2581F4, soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc_cfg1); val = (1 << tpg_reg->tpg_split_en_shift); cam_io_w_mb(tpg_data->pix_pattern, soc_info->reg_map[0].mem_base + tpg_reg->tpg_common_gen_cfg); - cam_io_w_mb(0xAFFF, - soc_info->reg_map[0].mem_base + tpg_reg->tpg_vbi_cfg); - CAM_DBG(CAM_ISP, "TPG:%d set TPG VBI to 0xAFFF", - tpg_hw->hw_intf->hw_idx); + + /* if VBI is notset configureVBI to 0xAFF */ + if (tpg_data->v_blank_count) + cam_io_w_mb(tpg_data->v_blank_count, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vbi_cfg); + else + cam_io_w_mb(0xAFFF, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vbi_cfg); /* Set the TOP tpg mux sel*/ cam_io_w_mb((1 << tpg_hw->hw_intf->hw_idx), -- GitLab From f13156eabcacc58cfa114825e2a6c403be3fe44e Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Tue, 12 Nov 2019 18:16:56 +0530 Subject: [PATCH 015/295] msm: camera: common: Remove division on uint64_t Arm arch does not support dividing 64 bit integer, replacing it with do_div call. Fix variable type to work with both 32/64 bit arch. CRs-Fixed: 2543730 Change-Id: I6b30f089bc998e98c7f2e20dc7fc11eedf6e6bc7 Signed-off-by: Chandan Kumar Jha --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 2 +- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 29 ++++++++++++--------- 2 files changed, 18 insertions(+), 13 deletions(-) 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 7803f3a66b07..ba071f27a735 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 @@ -4052,7 +4052,7 @@ static void cam_tfe_mgr_print_io_bufs(struct cam_packet *packet, io_cfg[i].mem_handle[j]); continue; } - if (iova_addr >> 32) { + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { CAM_ERR(CAM_ISP, "Invalid mapped address"); rc = -EINVAL; continue; 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 bdda9f5ee576..70f15ea82fa8 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 @@ -312,16 +312,21 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) if (device_share_ratio > 1) { for (i = 0; i < clk_update.axi_vote.num_paths; i++) { - clk_update.axi_vote.axi_path[i].camnoc_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].mnoc_ab_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].mnoc_ib_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].ddr_ab_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].ddr_ib_bw /= - device_share_ratio; + do_div( + clk_update.axi_vote.axi_path[i].camnoc_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ib_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ib_bw, + device_share_ratio); } } @@ -637,10 +642,10 @@ static int cam_ope_calc_total_clk(struct cam_ope_hw_mgr *hw_mgr, static uint32_t cam_ope_mgr_calc_base_clk(uint32_t frame_cycles, uint64_t budget) { - uint64_t base_clk; uint64_t mul = 1000000000; + uint64_t base_clk = frame_cycles * mul; - base_clk = (frame_cycles * mul) / budget; + do_div(base_clk, budget); CAM_DBG(CAM_OPE, "budget = %lld fc = %d ib = %lld base_clk = %lld", budget, frame_cycles, -- GitLab From 2eeb1a0b4488f43400936c80b6049b4c1573d644 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Thu, 14 Nov 2019 16:22:45 +0530 Subject: [PATCH 016/295] msm: camera: ope: Corrected parameter for deiniting idle clock Corrected the parameter needed to be passed in cam_ope_deinit_idle_clk. CRs-Fixed: 2520602 Change-Id: Ibeb8558fd0724fff61f4a6ddadd3b3cf6a6b3ed2 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 70f15ea82fa8..cd3dd5950b69 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 @@ -499,7 +499,7 @@ static void cam_ope_device_timer_cb(struct timer_list *timer_data) task_data->data = timer->parent; task_data->type = OPE_WORKQ_TASK_MSG_TYPE; task->process_cb = cam_ope_deinit_idle_clk; - cam_req_mgr_workq_enqueue_task(task, &ope_hw_mgr, + cam_req_mgr_workq_enqueue_task(task, ope_hw_mgr, CRM_TASK_PRIORITY_0); spin_unlock_irqrestore(&ope_hw_mgr->hw_mgr_lock, flags); } -- GitLab From ae5ef9b275bb38f9fc359a24090024d5fd788d7e Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 25 Nov 2019 19:02:20 +0530 Subject: [PATCH 017/295] msm: camera: isp: Update bus width properly Do not read the hw register to update the bus width. Update register with stored height and user space given width Update the tfe core irq command register after clear the registers. CRs-Fixed: 2545590 Change-Id: I3fd9e0ce4319cd19b94e9c83fa63aab37f26027e Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 2 +- .../isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 10 +++++++++- drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 6 +----- .../cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 6 +++--- 4 files changed, 14 insertions(+), 10 deletions(-) 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 8a55c5800afb..4d29f48e6f1c 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 @@ -1445,7 +1445,7 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_rdi( csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; csid_acquire.res_id = path_res_id; csid_acquire.in_port = in_port; - csid_acquire.out_port = in_port->data; + csid_acquire.out_port = out_port; csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; csid_acquire.node_res = NULL; 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 e4348a4c097e..7cebadc4ca2e 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 @@ -315,6 +315,10 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw) rc = -ETIMEDOUT; } + 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); + /* perform the SW registers reset */ reinit_completion(&csid_hw->csid_top_complete); cam_io_w_mb(csid_reg->cmn_reg->csid_reg_rst_stb, @@ -1834,12 +1838,16 @@ static int cam_tfe_csid_reset_retain_sw_reg( if (rc < 0) { CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", csid_hw->hw_intf->hw_idx, rc); - rc = -ETIMEDOUT; + 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); rc = 0; } + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); cam_io_w_mb(1, soc_info->reg_map[0].mem_base + 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 17c6e171c6c8..78051e5f6a3e 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 @@ -1656,11 +1656,7 @@ static int cam_tfe_bus_update_wm(void *priv, void *cmd_args, wm_data = tfe_out_data->wm_res[i]->res_priv; /* update width register */ - val = cam_io_r_mb(wm_data->common_data->mem_base + - wm_data->hw_regs->image_cfg_0); - /* mask previously written width but preserve height */ - val = val & 0xFFFF0000; - val |= wm_data->width; + val = ((wm_data->height << 16) | (wm_data->width & 0xFFFF)); CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_cfg_0, val); CAM_DBG(CAM_ISP, "WM:%d image height and width 0x%x", 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 793558cc2931..54b41e3503f7 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 @@ -710,6 +710,9 @@ irqreturn_t cam_tfe_irq(int irq_num, void *data) cam_io_w(top_irq_status[i], mem_base + core_info->tfe_hw_info->top_irq_clear[i]); + cam_io_w_mb(core_info->tfe_hw_info->global_clear_bitmask, + mem_base + core_info->tfe_hw_info->top_irq_cmd); + CAM_DBG(CAM_ISP, "TFE:%d IRQ status_0:0x%x status_1:0x%x status_2:0x%x", core_info->core_index, top_irq_status[0], top_irq_status[1], top_irq_status[2]); @@ -738,9 +741,6 @@ irqreturn_t cam_tfe_irq(int irq_num, void *data) bus_irq_status[1]); } - cam_io_w_mb(core_info->tfe_hw_info->global_clear_bitmask, - mem_base + core_info->tfe_hw_info->top_irq_cmd); - /* check reset */ if ((top_irq_status[0] & core_info->tfe_hw_info->reset_irq_mask[0]) || (top_irq_status[1] & -- GitLab From eca61a4cd8c12ea3fd02e23f5863f61884cfface Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Sat, 30 Nov 2019 13:55:01 +0530 Subject: [PATCH 018/295] msm: camera: ope: Add fixes for probe, bus read and req_timer As we are accessing hw version register during probe so calling cpas_start and cpas_stop during probe. Disabling the read clients which are not enabled for the request. Resetting the req_timer when we receive the request from UMD. CRs-Fixed: 2520602 Change-Id: I4a739fedbb498bd0c6b5b1e4cef38de3e4c722ed Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 3 +- .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 146 +++++++++++++++++- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c | 35 ++++- 3 files changed, 173 insertions(+), 11 deletions(-) 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 cd3dd5950b69..a31dde0d7afb 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 @@ -2544,7 +2544,7 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, return -EINVAL; } 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]) { @@ -2718,7 +2718,6 @@ static int cam_ope_mgr_config_hw(void *hw_priv, void *hw_config_args) CAM_DBG(CAM_OPE, "req_id %llu, io config", ope_req->request_id); - cam_ope_req_timer_modify(ctx_data, 200); mutex_unlock(&ctx_data->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); 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 13737462faf4..934cb715cc97 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 @@ -82,9 +82,42 @@ static int cam_ope_bus_rd_combo_idx(uint32_t format) return rc; } +static int cam_ope_bus_is_rm_enabled( + struct cam_ope_request *ope_request, + uint32_t batch_idx, + uint32_t rm_id) +{ + int i, k; + int32_t combo_idx; + struct ope_io_buf *io_buf; + struct ope_bus_in_port_to_rm *in_port_to_rm; + + if (batch_idx >= OPE_MAX_BATCH_SIZE) { + CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx); + return -EINVAL; + } + + for (i = 0; i < ope_request->num_io_bufs[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); + for (k = 0; k < io_buf->num_planes; k++) { + if (rm_id == + in_port_to_rm->rm_port_id[combo_idx][k]) + return true; + } + } + + return false; +} + static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, int32_t ctx_id, uint32_t *kmd_buf, int batch_idx, - int io_idx, struct cam_ope_dev_prepare_req *prepare) + int io_idx, struct cam_ope_dev_prepare_req *prepare, + int32_t *num_stripes) { int k, l, m; uint32_t idx; @@ -154,6 +187,7 @@ static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, for (k = 0; k < io_buf->num_planes; k++) { for (l = 0; l < io_buf->num_stripes[k]; l++) { + *num_stripes = io_buf->num_stripes[k]; stripe_io = &io_buf->s_io[k][l]; rsc_type = io_buf->resource_type - 1; /* frame level info */ @@ -259,6 +293,97 @@ static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, return kmd_buf; } +static uint32_t *cam_ope_bus_rm_disable(struct ope_hw *ope_hw_info, + int32_t ctx_id, struct cam_ope_dev_prepare_req *prepare, + int batch_idx, int rm_idx, + uint32_t *kmd_buf, uint32_t num_stripes) +{ + int l; + uint32_t idx; + uint32_t req_idx; + uint32_t temp_reg[128]; + uint32_t count = 0; + uint32_t temp = 0; + uint32_t header_size; + struct cam_ope_ctx *ctx_data; + struct ope_bus_rd_ctx *bus_rd_ctx; + struct cam_ope_bus_rd_reg *rd_reg; + struct cam_ope_bus_rd_client_reg *rd_reg_client; + struct ope_bus_rd_io_port_cdm_batch *io_port_cdm_batch; + struct ope_bus_rd_io_port_cdm_info *io_port_cdm; + struct cam_cdm_utils_ops *cdm_ops; + + + if (ctx_id < 0 || !prepare) { + CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, prepare); + return NULL; + } + + if (batch_idx >= OPE_MAX_BATCH_SIZE) { + CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx); + return NULL; + } + + ctx_data = prepare->ctx_data; + req_idx = prepare->req_idx; + cdm_ops = ctx_data->ope_cdm.cdm_ops; + + bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; + io_port_cdm_batch = &bus_rd_ctx->io_port_cdm_batch; + rd_reg = ope_hw_info->bus_rd_reg; + + CAM_DBG(CAM_OPE, "kmd_buf = %x req_idx = %d offset = %d", + kmd_buf, req_idx, prepare->kmd_buf_offset); + + io_port_cdm = + &bus_rd_ctx->io_port_cdm_batch.io_port_cdm[batch_idx]; + + for (l = 0; l < num_stripes; l++) { + /* stripe level info */ + rd_reg_client = &rd_reg->rd_clients[rm_idx]; + + /* Core cfg: enable, Mode */ + temp_reg[count++] = rd_reg->offset + + rd_reg_client->core_cfg; + temp_reg[count++] = 0; + + header_size = cdm_ops->cdm_get_cmd_header_size( + CAM_CDM_CMD_REG_RANDOM); + idx = io_port_cdm->num_s_cmd_bufs[l]; + io_port_cdm->s_cdm_info[l][idx].len = + sizeof(temp) * (count + header_size); + io_port_cdm->s_cdm_info[l][idx].offset = + prepare->kmd_buf_offset; + io_port_cdm->s_cdm_info[l][idx].addr = kmd_buf; + io_port_cdm->num_s_cmd_bufs[l]++; + + kmd_buf = cdm_ops->cdm_write_regrandom( + kmd_buf, count/2, temp_reg); + prepare->kmd_buf_offset += ((count + header_size) * + sizeof(temp)); + + CAM_DBG(CAM_OPE, "b:%d s:%d", + batch_idx, l); + CAM_DBG(CAM_OPE, "kmdbuf:%x, offset:%d", + kmd_buf, prepare->kmd_buf_offset); + CAM_DBG(CAM_OPE, "count:%d temp_reg:%x", + count, temp_reg, header_size); + CAM_DBG(CAM_OPE, "header_size:%d", header_size); + CAM_DBG(CAM_OPE, "RD cmd bufs = %d", + io_port_cdm->num_s_cmd_bufs[l]); + CAM_DBG(CAM_OPE, "off:%d len:%d", + io_port_cdm->s_cdm_info[l][idx].offset, + io_port_cdm->s_cdm_info[l][idx].len); + CAM_DBG(CAM_OPE, "b:%d s:%d", + batch_idx, l); + count = 0; + } + + prepare->rd_cdm_batch = &bus_rd_ctx->io_port_cdm_batch; + + return kmd_buf; +} + static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, int32_t ctx_id, void *data) { @@ -269,6 +394,7 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, uint32_t temp_reg[32] = {0}; uint32_t header_size; uint32_t *kmd_buf; + int is_rm_enabled; struct cam_ope_dev_prepare_req *prepare; struct cam_ope_ctx *ctx_data; struct cam_ope_request *ope_request; @@ -279,6 +405,7 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, struct ope_bus_rd_io_port_cdm_batch *io_port_cdm_batch; struct ope_bus_rd_io_port_cdm_info *io_port_cdm; struct cam_cdm_utils_ops *cdm_ops; + int32_t num_stripes; if (ctx_id < 0 || !data) { CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data); @@ -323,7 +450,8 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, } kmd_buf = cam_ope_bus_rd_update(ope_hw_info, - ctx_id, kmd_buf, i, j, prepare); + ctx_id, kmd_buf, i, j, prepare, + &num_stripes); if (!kmd_buf) { rc = -EINVAL; goto end; @@ -336,6 +464,20 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, goto end; } + /* Disable RMs which are not enabled */ + for (i = 0; i < ope_request->num_batch; i++) { + 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) + continue; + + kmd_buf = cam_ope_bus_rm_disable(ope_hw_info, + ctx_id, prepare, i, j, + kmd_buf, num_stripes); + } + } + /* Go command */ count = 0; temp_reg[count++] = rd_reg->offset + diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c index c6351100e85f..ac06a9d4aeb7 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c @@ -114,6 +114,7 @@ int cam_ope_probe(struct platform_device *pdev) int rc = 0; uint32_t hw_idx; struct cam_ope_dev_probe ope_probe; + struct cam_ope_cpas_vote cpas_vote; of_property_read_u32(pdev->dev.of_node, "cell-index", &hw_idx); @@ -176,25 +177,45 @@ int cam_ope_probe(struct platform_device *pdev) CAM_ERR(CAM_OPE, "failed to init_soc"); goto init_soc_failed; } + core_info->hw_type = OPE_DEV_OPE; + core_info->hw_idx = hw_idx; + rc = cam_ope_register_cpas(&ope_dev->soc_info, + core_info, ope_dev_intf->hw_idx); + if (rc < 0) + goto register_cpas_failed; rc = cam_ope_enable_soc_resources(&ope_dev->soc_info); if (rc < 0) { CAM_ERR(CAM_OPE, "enable soc resorce failed: %d", rc); goto enable_soc_failed; } + 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_OPE_WR_VID; + cpas_vote.axi_vote.axi_path[0].transac_type = + CAM_AXI_TRANSACTION_WRITE; + cpas_vote.axi_vote.axi_path[0].camnoc_bw = + CAM_CPAS_DEFAULT_AXI_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 = + CAM_CPAS_DEFAULT_AXI_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 = + CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote.ahb_vote, &cpas_vote.axi_vote); rc = cam_ope_init_hw_version(&ope_dev->soc_info, ope_dev->core_info); if (rc) goto init_hw_failure; - core_info->hw_type = OPE_DEV_OPE; - core_info->hw_idx = hw_idx; - rc = cam_ope_register_cpas(&ope_dev->soc_info, - core_info, ope_dev_intf->hw_idx); - if (rc < 0) - goto register_cpas_failed; - cam_ope_disable_soc_resources(&ope_dev->soc_info, true); + cam_cpas_stop(core_info->cpas_handle); ope_dev->hw_state = CAM_HW_STATE_POWER_DOWN; ope_probe.hfi_en = ope_soc_info.hfi_en; -- GitLab From 07354d9623f4c24bf46e61bdc10abd49bee6adc2 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 2 Dec 2019 12:11:14 +0530 Subject: [PATCH 019/295] msm: camera: ope: Avoid dead lock during flush During flush OPE driver takes lock on OPE context and calls the CDM flush, in which CDM notifies OPE for all pending requests. If at the same time CDM is notifying OPE for successful request that thread also tries to take lock on OPE context. CDM also tries to takes lock on CDM client in each notify call. Due to which, dead lock is occurring. So taking the lock on OPE context in OPE flush after CDM flush. CRs-Fixed: 2520602 Change-Id: I6ae9105d33a49a638141973cdd6a4a99621dc4c5 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 a31dde0d7afb..61154b7b4b37 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 @@ -2804,6 +2804,7 @@ static int cam_ope_mgr_flush_all(struct cam_ope_ctx *ctx_data, rc = cam_cdm_flush_hw(ctx_data->ope_cdm.cdm_handle); + mutex_lock(&ctx_data->ctx_mutex); 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, @@ -2823,6 +2824,7 @@ static int cam_ope_mgr_flush_all(struct cam_ope_ctx *ctx_data, ctx_data->req_list[i] = NULL; clear_bit(i, ctx_data->bitmap); } + mutex_unlock(&ctx_data->ctx_mutex); return rc; } @@ -2855,9 +2857,7 @@ static int cam_ope_mgr_hw_flush(void *hw_priv, void *hw_flush_args) switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: - mutex_lock(&ctx_data->ctx_mutex); cam_ope_mgr_flush_all(ctx_data, flush_args); - mutex_unlock(&ctx_data->ctx_mutex); break; case CAM_FLUSH_TYPE_REQ: mutex_lock(&ctx_data->ctx_mutex); -- GitLab From cccd85b3792e663255ef91414b3b999e4fdd23f2 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Sat, 16 Nov 2019 19:36:38 +0530 Subject: [PATCH 020/295] msm: camera: ope: Fixed for IRQ mask and log printing Adding fixes to set IRQ mask after reset and strings to print OPE CPAS PATH enums. CRs-Fixed: 2520602 Change-Id: I5873b8b0494623c36ca94edf7a26cc952fbb5e68 Signed-off-by: Rishabh Jain --- drivers/cam_cpas/cam_cpas_intf.c | 12 ++++++++++++ drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 2 +- .../cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 8 +------- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 7 ------- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 2 ++ .../cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c | 4 ---- drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c | 8 ++++++++ 7 files changed, 24 insertions(+), 19 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index a1d8b4026059..5308eaf0ac26 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -83,6 +83,18 @@ const char *cam_cpas_axi_util_path_type_to_string( case CAM_AXI_PATH_DATA_IPE_WR_REF: return "IPE_WR_REF"; + /* OPE Paths */ + case CAM_AXI_PATH_DATA_OPE_RD_IN: + return "OPE_RD_IN"; + case CAM_AXI_PATH_DATA_OPE_RD_REF: + return "OPE_RD_REF"; + case CAM_AXI_PATH_DATA_OPE_WR_VID: + return "OPE_WR_VID"; + case CAM_AXI_PATH_DATA_OPE_WR_DISP: + return "OPE_WR_DISP"; + case CAM_AXI_PATH_DATA_OPE_WR_REF: + return "OPE_WR_REF"; + /* Common Paths */ case CAM_AXI_PATH_DATA_ALL: return "DATA_ALL"; 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 8a55c5800afb..cad8c8e863fc 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 @@ -3372,7 +3372,7 @@ static int cam_isp_tfe_packet_generic_blob_handler(void *user_data, if ((hfr_config->num_ports != 0) && (blob_size < (sizeof(struct cam_isp_tfe_resource_hfr_config) + (hfr_config->num_ports - 1) * - sizeof(struct cam_isp_tfe_resource_hfr_config)))) { + sizeof(struct cam_isp_tfe_port_hfr_config)))) { CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", blob_size, sizeof(struct cam_isp_tfe_resource_hfr_config) + 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 17c6e171c6c8..797d913605bf 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 @@ -535,7 +535,7 @@ static int cam_tfe_bus_acquire_wm( rsrc_data->format); return -EINVAL; } - } else if (rsrc_data->index == 0) { + } else if (rsrc_data->index == 0 || rsrc_data->index == 1) { /* WM 0 FULL_OUT */ switch (rsrc_data->format) { case CAM_FORMAT_MIPI_RAW_8: @@ -571,12 +571,6 @@ static int cam_tfe_bus_acquire_wm( rsrc_data->height = 0; rsrc_data->stride = 1; rsrc_data->en_cfg = (0x1 << 16) | 0x1; - } else if (rsrc_data->index == 1) { - /* WM 1 Raw dump */ - rsrc_data->stride = rsrc_data->width; - rsrc_data->en_cfg = 0x1; - /* LSB aligned */ - rsrc_data->pack_fmt |= 0x10; } else { CAM_ERR(CAM_ISP, "Invalid WM:%d requested", rsrc_data->index); return -EINVAL; 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 cd3dd5950b69..dea4656d2941 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 @@ -1858,13 +1858,6 @@ static int cam_ope_get_acquire_info(struct cam_ope_hw_mgr *hw_mgr, return -EINVAL; } - if (args->acquire_info_size < - sizeof(struct ope_acquire_dev_info)) { - CAM_ERR(CAM_OPE, "Invalid acquire size = %d", - args->acquire_info_size); - return -EINVAL; - } - if (copy_from_user(&ctx->ope_acquire, (void __user *)args->acquire_info, sizeof(struct ope_acquire_dev_info))) { 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 aa29a05f90e3..122771715357 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 @@ -67,6 +67,7 @@ * @budget_ns: Time required to process frame * @frame_cycles: Frame cycles needed to process the frame * @rt_flag: Flag to indicate real time stream + * @reserved: Reserved for future use * @num_paths: Number of paths for per path bw vote * @axi_path: Per path vote info for OPE */ @@ -74,6 +75,7 @@ struct cam_ope_clk_bw_req_internal_v2 { uint64_t budget_ns; uint32_t frame_cycles; uint32_t rt_flag; + uint32_t reserved; uint32_t num_paths; struct cam_axi_per_path_bw_vote axi_path[CAM_OPE_MAX_PER_PATH_VOTES]; }; 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 77a6c8d0af17..44e5cd98d133 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 @@ -691,7 +691,6 @@ static int cam_ope_bus_wr_isr(struct ope_hw *ope_hw_info, uint32_t irq_status_0, irq_status_1; 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) { CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); @@ -713,17 +712,14 @@ 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) { - irq_data->error = 1; CAM_ERR(CAM_OPE, "ope bus wr vioalation"); } if (irq_status_0 & bus_wr_reg_val->img_size_violation) { - irq_data->error = 1; CAM_ERR(CAM_OPE, "ope bus wr img_size_violation"); } 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 e71ab9cef552..3d5fd7d5714b 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 @@ -66,6 +66,10 @@ static int cam_ope_top_reset(struct ope_hw *ope_hw_info, 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; } @@ -131,6 +135,10 @@ 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); + if (!rc || rc < 0) { CAM_ERR(CAM_OPE, "reset error result = %d", rc); if (!rc) -- GitLab From ba91a17f5241e39f4d0b9543e730a355b53adaef Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 4 Nov 2019 11:16:39 -0800 Subject: [PATCH 021/295] msm: camera: reqmgr: Change v4l2 notify error log type In case userspace fails to dequeue a v4l2 event with a valid request, kernel will dump that message as error and rest will be rate limited. CRs-Fixed: 2558548 Change-Id: I1c6769f47d0e1ca4a3ce5c6467f6c280104ae2b8 Signed-off-by: Karthik Anantha Ram --- drivers/cam_req_mgr/cam_req_mgr_dev.c | 42 ++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index f2452d9c340c..cdb2210a2efb 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -204,31 +204,39 @@ static void cam_v4l2_event_queue_notify_error(const struct v4l2_event *old, ev_header = CAM_REQ_MGR_GET_PAYLOAD_PTR((*old), struct cam_req_mgr_message); + switch (old->id) { case V4L_EVENT_CAM_REQ_MGR_SOF: - CAM_ERR(CAM_CRM, "Failed to notify SOF event"); - CAM_ERR(CAM_CRM, "Sess %X FrameId %lld ReqId %lld link %X", - ev_header->session_hdl, - ev_header->u.frame_msg.frame_id, - ev_header->u.frame_msg.request_id, - ev_header->u.frame_msg.link_hdl); + case V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS: + if (ev_header->u.frame_msg.request_id) + CAM_ERR(CAM_CRM, + "Failed to notify %s Sess %X FrameId %lld FrameMeta %d ReqId %lld link %X", + ((old->id == V4L_EVENT_CAM_REQ_MGR_SOF) ? + "SOF_TS" : "BOOT_TS"), + ev_header->session_hdl, + ev_header->u.frame_msg.frame_id, + ev_header->u.frame_msg.frame_id_meta, + ev_header->u.frame_msg.request_id, + ev_header->u.frame_msg.link_hdl); + else + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_CRM, 5, 1, + "Failed to notify %s Sess %X FrameId %lld FrameMeta %d ReqId %lld link %X", + ((old->id == V4L_EVENT_CAM_REQ_MGR_SOF) ? + "SOF_TS" : "BOOT_TS"), + ev_header->session_hdl, + ev_header->u.frame_msg.frame_id, + ev_header->u.frame_msg.frame_id_meta, + ev_header->u.frame_msg.request_id, + ev_header->u.frame_msg.link_hdl); break; case V4L_EVENT_CAM_REQ_MGR_ERROR: - CAM_ERR(CAM_CRM, "Failed to notify ERROR"); - CAM_ERR(CAM_CRM, "Sess %X ReqId %d Link %X Type %d", - ev_header->u.err_msg.error_type, + CAM_ERR(CAM_CRM, + "Failed to notify ERROR Sess %X ReqId %d Link %X Type %d", + ev_header->session_hdl, ev_header->u.err_msg.request_id, ev_header->u.err_msg.link_hdl, ev_header->u.err_msg.error_type); break; - case V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS: - CAM_ERR(CAM_CRM, "Failed to notify BOOT_TS event"); - CAM_ERR(CAM_CRM, "Sess %X FrameId %lld ReqId %lld link %X", - ev_header->session_hdl, - ev_header->u.frame_msg.frame_id, - ev_header->u.frame_msg.request_id, - ev_header->u.frame_msg.link_hdl); - break; default: CAM_ERR(CAM_CRM, "Failed to notify crm event id %d", old->id); -- GitLab From c73bf6cda1efd4d663fdc46a49cc351ee2bb2387 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 9 Sep 2019 22:48:13 -0700 Subject: [PATCH 022/295] msm: camera: common: Update uapi to support custom hw features This change provides provision to propagate frame id to userspace as part of shutter notification. The change also add new acquire params for IFE when custom HW is in the pipeline. CRs-Fixed: 2524308 Change-Id: Ia6f6efb1edc6e6a01d7b37aeb2787b1e98d8f81e Signed-off-by: Karthik Anantha Ram --- include/uapi/media/cam_isp.h | 5 +++++ include/uapi/media/cam_req_mgr.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index 79314b59363f..e4778cfc9cc2 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -126,6 +126,11 @@ #define CAM_ISP_USAGE_RIGHT_PX 2 #define CAM_ISP_USAGE_RDI 3 +/* Acquire with custom hw */ +#define CAM_ISP_ACQ_CUSTOM_NONE 0 +#define CAM_ISP_ACQ_CUSTOM_PRIMARY 1 +#define CAM_ISP_ACQ_CUSTOM_SECONDARY 2 + /* Query devices */ /** * struct cam_isp_dev_cap_info - A cap info for particular hw type diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 795259a5b86c..934e9bdf4bb0 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -446,6 +446,9 @@ struct cam_req_mgr_error_msg { * @timestamp: timestamp of the frame * @link_hdl: link handle associated with this message * @sof_status: sof status success or fail + * @frame_id_meta: refers to the meta for + * that frame in specific usecases + * @reserved: reserved */ struct cam_req_mgr_frame_msg { uint64_t request_id; @@ -453,6 +456,8 @@ struct cam_req_mgr_frame_msg { uint64_t timestamp; int32_t link_hdl; uint32_t sof_status; + uint32_t frame_id_meta; + uint32_t reserved; }; /** -- GitLab From 2caf9493e47508df76ea4835f8b3ed71fad202fc Mon Sep 17 00:00:00 2001 From: Mangalaram ARCHANA Date: Fri, 25 Oct 2019 11:55:18 +0530 Subject: [PATCH 023/295] msm: camera: cpas: Fix TCSR Register programming Fix TCSR register programming to enable SAT. CRs-Fixed: 2553475 Change-Id: Iaeae7cd06dcbccaa8bf1f98657efff734d048b9f Signed-off-by: Mangalaram ARCHANA --- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 643a72277dc8..0c4cd7d1e51c 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -519,7 +519,7 @@ static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data) static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) { - int i; + int i, reg_val; struct cam_cpas_hw_errata_wa_list *errata_wa_list = camnoc_info->errata_wa_list; struct cam_cpas_hw_errata_wa *errata_wa; @@ -547,8 +547,9 @@ static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) if (errata_wa_list) { errata_wa = &errata_wa_list->tcsr_camera_hf_sf_ares_glitch; if (errata_wa->enable) { - scm_io_write(errata_wa->data.reg_info.offset, - errata_wa->data.reg_info.value); + reg_val = scm_io_read(errata_wa->data.reg_info.offset); + reg_val |= errata_wa->data.reg_info.value; + scm_io_write(errata_wa->data.reg_info.offset, reg_val); } } -- GitLab From 21c88c4b41256ba7a22620ce9c76f30fe669f9bf Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Tue, 3 Dec 2019 14:05:48 +0530 Subject: [PATCH 024/295] msm: camera: cci: Correct the queue size for cci version 1.2 Correct the queue size for cci version 1.2 as below, 1. Queue 0 size = 64. 2. Queue 1 size = 16. CRs-Fixed: 2578562 Change-Id: Ifc9407427fe2bf0996c77dc00c5dfe7e5ba22140 Signed-off-by: Tony Lijo Jose --- drivers/cam_sensor_module/cam_cci/cam_cci_dev.h | 2 ++ drivers/cam_sensor_module/cam_cci/cam_cci_soc.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) 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 439e3058a70b..eea6e42069a5 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -34,6 +34,8 @@ #define V4L2_IDENT_CCI 50005 #define CCI_I2C_QUEUE_0_SIZE 128 #define CCI_I2C_QUEUE_1_SIZE 32 +#define CCI_I2C_QUEUE_0_SIZE_V_1_2 64 +#define CCI_I2C_QUEUE_1_SIZE_V_1_2 16 #define CYCLES_PER_MICRO_SEC_DEFAULT 4915 #define CCI_MAX_DELAY 1000000 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 092f42bbe0d9..0c2c76d6300b 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -17,6 +17,7 @@ int cam_cci_init(struct v4l2_subdev *sd, struct cam_axi_vote axi_vote = {0}; struct cam_hw_soc_info *soc_info = NULL; void __iomem *base = NULL; + uint32_t max_queue_0_size = 0, max_queue_1_size = 0; cci_dev = v4l2_get_subdevdata(sd); if (!cci_dev || !c_ctrl) { @@ -116,14 +117,23 @@ 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")) { + 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 { + max_queue_0_size = CCI_I2C_QUEUE_0_SIZE; + max_queue_1_size = CCI_I2C_QUEUE_1_SIZE; + } + for (i = 0; i < NUM_MASTERS; i++) { for (j = 0; j < NUM_QUEUES; j++) { if (j == QUEUE_0) cci_dev->cci_i2c_queue_info[i][j].max_queue_size - = CCI_I2C_QUEUE_0_SIZE; + = max_queue_0_size; else cci_dev->cci_i2c_queue_info[i][j].max_queue_size - = CCI_I2C_QUEUE_1_SIZE; + = max_queue_1_size; CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0 : %d Q1 : %d", i, cci_dev->cci_i2c_queue_info[i][j].max_queue_size, -- GitLab From 0f7bc6af20b711ed5c72c0b00c93b6d070bdaa33 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Fri, 15 Nov 2019 09:31:24 +0530 Subject: [PATCH 025/295] msm: camera: common: secure camera fixes Isp bus port secure mode not coming properly. Added proper logic to get the bus port secure mode correctly. Use secure iommu handle to get secure buffer for ope. Add spin lock for tfe irq handler. Use proper bw structure to copy the user send blob data. CRs-Fixed: 2545590 Change-Id: Icb8ecf869681c370efa084991505036f90a35065 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 4 ++-- .../hw_utils/cam_isp_packet_parser.c | 20 ++++++++++++++++--- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 17 ++++++++-------- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 2 ++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 12 ++++++----- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 11 +++++----- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 17 +++++++++++++--- 8 files changed, 58 insertions(+), 27 deletions(-) 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 afa45ef05521..4783c3d65084 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 @@ -5200,7 +5200,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, memset(&prepare_hw_data->bw_config_v2[bw_config->usage_type], 0, sizeof( prepare_hw_data->bw_config_v2[bw_config->usage_type])); - bw_config_size = sizeof(struct cam_isp_bw_config_internal_v2) + + bw_config_size = sizeof(struct cam_isp_bw_config_v2) + ((bw_config->num_paths - 1) * sizeof(struct cam_axi_per_path_bw_vote)); memcpy(&prepare_hw_data->bw_config_v2[bw_config->usage_type], 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 c5fffe016d8c..be00f75d71a0 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 @@ -2354,7 +2354,7 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, if (hw_update_data->bw_config_valid[i] == true) { CAM_DBG(CAM_ISP, "idx=%d, bw_config_version=%d", - ctx, ctx->ctx_index, i, + ctx->ctx_index, i, hw_update_data->bw_config_version); if (hw_update_data->bw_config_version == CAM_ISP_BW_CONFIG_V2) { @@ -3486,7 +3486,7 @@ static int cam_isp_tfe_packet_generic_blob_handler(void *user_data, memset(&prepare_hw_data->bw_config_v2[bw_config->usage_type], 0, sizeof( prepare_hw_data->bw_config_v2[bw_config->usage_type])); - bw_config_size = sizeof(struct cam_isp_bw_config_internal_v2) + + bw_config_size = sizeof(struct cam_isp_tfe_bw_config_v2) + ((bw_config->num_paths - 1) * sizeof(struct cam_axi_per_path_bw_vote)); memcpy(&prepare_hw_data->bw_config_v2[bw_config->usage_type], diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index b87326694424..e0c2f55ef704 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -475,6 +475,7 @@ int cam_isp_add_io_buffers( struct cam_isp_hw_get_wm_update bus_rd_update; struct cam_hw_fence_map_entry *out_map_entries; struct cam_hw_fence_map_entry *in_map_entries; + struct cam_isp_hw_get_cmd_update secure_mode; uint32_t kmd_buf_remain_size; uint32_t i, j, num_out_buf, num_in_buf; uint32_t res_id_out, res_id_in, plane_id; @@ -482,7 +483,8 @@ int cam_isp_add_io_buffers( size_t size; int32_t hdl; int mmu_hdl; - bool mode, is_buf_secure; + bool is_buf_secure; + uint32_t mode; io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) &prepare->packet->payload + @@ -611,10 +613,16 @@ int cam_isp_add_io_buffers( break; hdl = io_cfg[i].mem_handle[plane_id]; + secure_mode.cmd_type = + CAM_ISP_HW_CMD_GET_SECURE_MODE; + secure_mode.res = res; + secure_mode.data = (void *)&mode; rc = res->hw_intf->hw_ops.process_cmd( res->hw_intf->hw_priv, CAM_ISP_HW_CMD_GET_SECURE_MODE, - &mode, sizeof(bool)); + &secure_mode, + sizeof( + struct cam_isp_hw_get_cmd_update)); if (rc) return -EINVAL; @@ -722,10 +730,16 @@ int cam_isp_add_io_buffers( break; hdl = io_cfg[i].mem_handle[plane_id]; + secure_mode.cmd_type = + CAM_ISP_HW_CMD_GET_SECURE_MODE; + secure_mode.res = res; + secure_mode.data = (void *)&mode; rc = res->hw_intf->hw_ops.process_cmd( res->hw_intf->hw_priv, CAM_ISP_HW_CMD_GET_SECURE_MODE, - &mode, sizeof(bool)); + &secure_mode, + sizeof( + struct cam_isp_hw_get_cmd_update)); if (rc) return -EINVAL; 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 158ab9034c89..57221c2c050f 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 @@ -1043,12 +1043,13 @@ static int cam_tfe_bus_deinit_comp_grp( static int cam_tfe_bus_get_secure_mode(void *priv, void *cmd_args, uint32_t arg_size) { - bool *mode = cmd_args; - struct cam_isp_resource_node *res = - (struct cam_isp_resource_node *) priv; - struct cam_tfe_bus_tfe_out_data *rsrc_data = - (struct cam_tfe_bus_tfe_out_data *)res->res_priv; + struct cam_isp_hw_get_cmd_update *secure_mode = cmd_args; + struct cam_tfe_bus_tfe_out_data *rsrc_data; + uint32_t *mode; + rsrc_data = (struct cam_tfe_bus_tfe_out_data *) + secure_mode->res->res_priv; + mode = (uint32_t *)secure_mode->data; *mode = (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? true : false; @@ -1657,7 +1658,7 @@ static int cam_tfe_bus_update_wm(void *priv, void *cmd_args, wm_data->index, reg_val_pair[j-1]); val = io_cfg->planes[i].plane_stride; - CAM_DBG(CAM_ISP, "before stride %d", val); + 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) @@ -1674,7 +1675,7 @@ static int cam_tfe_bus_update_wm(void *priv, void *cmd_args, CAM_TFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_cfg_2, io_cfg->planes[i].plane_stride); - wm_data->stride = val; + wm_data->stride = io_cfg->planes[i].plane_stride; CAM_DBG(CAM_ISP, "WM %d image stride 0x%x", wm_data->index, reg_val_pair[j-1]); } @@ -1833,7 +1834,7 @@ static int cam_tfe_bus_update_stripe_cfg(void *priv, void *cmd_args, wm_data = tfe_out_data->wm_res[i]->res_priv; wm_data->width = stripe_config->width; wm_data->offset = stripe_config->offset; - CAM_DBG(CAM_ISP, "id:%x WM:%d width:0x%x offset:%x", + CAM_DBG(CAM_ISP, "id:%x WM:%d width:0x%x offset:0x%x", stripe_args->res->res_id, wm_data->index, wm_data->width, wm_data->offset); } 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 54b41e3503f7..eb0c4bb2cb0e 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 @@ -702,6 +702,7 @@ irqreturn_t cam_tfe_irq(int irq_num, void *data) return IRQ_HANDLED; } + spin_lock(&core_info->spin_lock); for (i = 0; i < CAM_TFE_TOP_IRQ_REG_NUM; i++) top_irq_status[i] = cam_io_r(mem_base + core_info->tfe_hw_info->top_irq_status[i]); @@ -740,6 +741,7 @@ irqreturn_t cam_tfe_irq(int irq_num, void *data) core_info->core_index, bus_irq_status[0], bus_irq_status[1]); } + spin_unlock(&core_info->spin_lock); /* check reset */ if ((top_irq_status[0] & core_info->tfe_hw_info->reset_irq_mask[0]) || diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 450de00b7b48..7dc3b88e1cb6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1980,12 +1980,14 @@ static int cam_vfe_bus_deinit_comp_grp( static int cam_vfe_bus_get_secure_mode(void *priv, void *cmd_args, uint32_t arg_size) { - bool *mode = cmd_args; - struct cam_isp_resource_node *res = - (struct cam_isp_resource_node *) priv; - struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = - (struct cam_vfe_bus_ver2_vfe_out_data *)res->res_priv; + struct cam_isp_hw_get_cmd_update *secure_mode = cmd_args; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data; + uint32_t *mode; + + rsrc_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + secure_mode->res->res_priv; + mode = (uint32_t *)secure_mode->data; *mode = (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? true : false; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 5146b81a5f03..116cf7205875 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -1863,12 +1863,13 @@ static int cam_vfe_bus_ver3_deinit_comp_grp( static int cam_vfe_bus_ver3_get_secure_mode(void *priv, void *cmd_args, uint32_t arg_size) { - bool *mode = cmd_args; - struct cam_isp_resource_node *res = - (struct cam_isp_resource_node *) priv; - struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = - (struct cam_vfe_bus_ver3_vfe_out_data *)res->res_priv; + struct cam_isp_hw_get_cmd_update *secure_mode = cmd_args; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data; + uint32_t *mode; + rsrc_data = (struct cam_vfe_bus_ver3_vfe_out_data *) + secure_mode->res->res_priv; + mode = (uint32_t *)secure_mode->data; *mode = (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? true : false; 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 c449fb86d082..2b57cd288c5b 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 @@ -1383,6 +1383,7 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, uint32_t unpack_format; struct ope_in_res_info *in_res; struct ope_out_res_info *out_res; + bool is_secure; in_frame_process = (struct ope_frame_process *)frame_process_addr; @@ -1471,9 +1472,19 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, for (k = 0; k < in_io_buf->num_planes; k++) { io_buf->num_stripes[k] = in_io_buf->num_stripes[k]; - rc = cam_mem_get_io_buf( - in_io_buf->mem_handle[k], - hw_mgr->iommu_hdl, &iova_addr, &len); + is_secure = cam_mem_is_secure_buf( + in_io_buf->mem_handle[k]); + if (is_secure) + rc = cam_mem_get_io_buf( + in_io_buf->mem_handle[k], + hw_mgr->iommu_sec_hdl, + &iova_addr, &len); + else + rc = cam_mem_get_io_buf( + in_io_buf->mem_handle[k], + hw_mgr->iommu_hdl, + &iova_addr, &len); + if (rc) { CAM_ERR(CAM_OPE, "get buf failed: %d", rc); -- GitLab From e21a32133f13abc57e84456384851f1a33c6cbae Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Mon, 9 Dec 2019 15:55:26 +0530 Subject: [PATCH 026/295] msm: camera: ope: Fix OPE AHB voting issue Initialize AHB voting variable in OPE acquire to fix AHB voting issue for OPE. CRs-Fixed: 2580645 Change-Id: I5bf8c0b1315a351abd80341100bdaf42333c4c24 Signed-off-by: Suresh Vankadara --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 1 + 1 file changed, 1 insertion(+) 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 c449fb86d082..4b7026c07754 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 @@ -2147,6 +2147,7 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) } } + 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; -- GitLab From ae401df59623f2a3954dd8b3d3fc523ca6921493 Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Mon, 9 Dec 2019 21:36:44 +0530 Subject: [PATCH 027/295] msm: camera: cci: Handle burst read for cci hw 1.2 CCI hw 1.2 does not support burst read due to the absence of READ THRESHOLD irq. Due to this we need to handle the cci burst read as a sequence of reads (each read is of chunk size 0xE). CRs-Fixed: 2585335 Change-Id: Icbc327475e6dd8838b1d665f71d62dc6efebb7d7 Signed-off-by: Tony Lijo Jose --- .../cam_sensor_module/cam_cci/cam_cci_core.c | 81 ++++++++++++++++++- .../cam_sensor_module/cam_cci/cam_cci_dev.h | 2 + .../cam_sensor_module/cam_cci/cam_cci_soc.c | 13 +-- 3 files changed, 89 insertions(+), 7 deletions(-) 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 8701c6b9d62e..14c196b71851 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1498,6 +1498,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) { @@ -1701,7 +1771,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 eea6e42069a5..d940faaf1503 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -60,6 +60,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 8192 #define CCI_I2C_MAX_WRITE 8192 @@ -72,6 +73,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 0c2c76d6300b..effbbba47368 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -117,8 +117,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 { @@ -177,10 +176,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; -- GitLab From 7233e788452121d90fe39fdee6f7f1756968db68 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Tue, 3 Dec 2019 14:35:26 -0800 Subject: [PATCH 028/295] msm: camera: memmgr: Add support to disable DelayedUnmap Add interface to umd to give an option whether to disable Delayed Unamp feature for a given buffer mapping. DelayedUnmap is enabled by default if umd doesn't explicitly asks for disable. CRs-Fixed: 2580128 Change-Id: I66f87a9dbdfc4d9cecdc02eb24c1c670c9985cae Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_req_mgr/cam_mem_mgr.c | 5 +++++ drivers/cam_smmu/cam_smmu_api.c | 36 +++++++++++++++++++------------ drivers/cam_smmu/cam_smmu_api.h | 7 +++--- include/uapi/media/cam_req_mgr.h | 1 + 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index a0b1e66f8e0c..eef1583451ba 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -505,12 +505,16 @@ static int cam_mem_util_map_hw_va(uint32_t flags, int i; int rc = -1; int dir = cam_mem_util_get_dma_dir(flags); + bool dis_delayed_unmap = false; if (dir < 0) { CAM_ERR(CAM_MEM, "fail to map DMA direction, dir=%d", dir); return dir; } + if (flags & CAM_MEM_FLAG_DISABLE_DELAYED_UNMAP) + dis_delayed_unmap = true; + CAM_DBG(CAM_MEM, "map_hw_va : fd = %d, flags = 0x%x, dir=%d, num_hdls=%d", fd, flags, dir, num_hdls); @@ -534,6 +538,7 @@ static int cam_mem_util_map_hw_va(uint32_t flags, for (i = 0; i < num_hdls; i++) { rc = cam_smmu_map_user_iova(mmu_hdls[i], fd, + dis_delayed_unmap, dir, (dma_addr_t *)hw_vaddr, len, diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index fb32768d7f6b..83748a935b91 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -221,8 +221,9 @@ static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx, dma_addr_t virt_addr); static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, - enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, - size_t *len_ptr, enum cam_smmu_region_id region_id); + bool dis_delayed_unmap, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id); static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, struct dma_buf *buf, enum dma_data_direction dma_dir, @@ -1722,7 +1723,7 @@ EXPORT_SYMBOL(cam_smmu_release_sec_heap); static int cam_smmu_map_buffer_validate(struct dma_buf *buf, int idx, enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, size_t *len_ptr, enum cam_smmu_region_id region_id, - struct cam_dma_buff_info **mapping_info) + bool dis_delayed_unmap, struct cam_dma_buff_info **mapping_info) { struct dma_buf_attachment *attach = NULL; struct sg_table *table = NULL; @@ -1797,7 +1798,8 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, } iommu_cb_set.cb_info[idx].shared_mapping_size += *len_ptr; } else if (region_id == CAM_SMMU_REGION_IO) { - attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + if (!dis_delayed_unmap) + attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; table = dma_buf_map_attachment(attach, dma_dir); if (IS_ERR_OR_NULL(table)) { @@ -1815,8 +1817,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, goto err_unmap_sg; } - CAM_DBG(CAM_SMMU, "iova=%pK, region_id=%d, paddr=%pK, len=%d", - iova, region_id, *paddr_ptr, *len_ptr); + CAM_DBG(CAM_SMMU, + "iova=%pK, region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", + iova, region_id, *paddr_ptr, *len_ptr, attach->dma_map_attrs); if (table->sgl) { CAM_DBG(CAM_SMMU, @@ -1884,8 +1887,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, - enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, - size_t *len_ptr, enum cam_smmu_region_id region_id) + bool dis_delayed_unmap, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id) { int rc = -1; struct cam_dma_buff_info *mapping_info = NULL; @@ -1895,7 +1899,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, buf = dma_buf_get(ion_fd); rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, - region_id, &mapping_info); + region_id, dis_delayed_unmap, &mapping_info); if (rc) { CAM_ERR(CAM_SMMU, "buffer validation failure"); @@ -1919,7 +1923,7 @@ static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, struct cam_dma_buff_info *mapping_info = NULL; rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, - region_id, &mapping_info); + region_id, false, &mapping_info); if (rc) { CAM_ERR(CAM_SMMU, "buffer validation failure"); @@ -1956,6 +1960,11 @@ static int cam_smmu_unmap_buf_and_remove_from_list( return -EINVAL; } + CAM_DBG(CAM_SMMU, + "region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", + mapping_info->region_id, mapping_info->paddr, mapping_info->len, + mapping_info->attach->dma_map_attrs); + if (mapping_info->region_id == CAM_SMMU_REGION_SHARED) { CAM_DBG(CAM_SMMU, "Removing SHARED buffer paddr = %pK, len = %zu", @@ -1984,7 +1993,6 @@ static int cam_smmu_unmap_buf_and_remove_from_list( iommu_cb_set.cb_info[idx].shared_mapping_size -= mapping_info->len; } else if (mapping_info->region_id == CAM_SMMU_REGION_IO) { - mapping_info->attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; iommu_cb_set.cb_info[idx].io_mapping_size -= mapping_info->len; } @@ -2738,7 +2746,7 @@ static int cam_smmu_map_iova_validate_params(int handle, return rc; } -int cam_smmu_map_user_iova(int handle, int ion_fd, +int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr, size_t *len_ptr, enum cam_smmu_region_id region_id) { @@ -2789,8 +2797,8 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, goto get_addr_end; } - rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir, - paddr_ptr, len_ptr, region_id); + rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, + dis_delayed_unmap, dma_dir, paddr_ptr, len_ptr, region_id); if (rc < 0) { CAM_ERR(CAM_SMMU, "mapping or add list fail, idx=%d, fd=%d, region=%d, rc=%d", diff --git a/drivers/cam_smmu/cam_smmu_api.h b/drivers/cam_smmu/cam_smmu_api.h index 6932505f0aaf..935e813d450a 100644 --- a/drivers/cam_smmu/cam_smmu_api.h +++ b/drivers/cam_smmu/cam_smmu_api.h @@ -98,6 +98,8 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param op); * * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) * @param ion_fd: ION handle identifying the memory buffer. + * @param dis_delayed_unmap: Whether to disable Delayed Unmap feature + * for this mapping * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, * DMA_TO_DEVICE or DMA_FROM_DEVICE * @dma_addr : Pointer to physical address where mapped address will be @@ -107,9 +109,8 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param op); * @len_ptr : Length of buffer mapped returned by CAM SMMU driver. * @return Status of operation. Negative in case of error. Zero otherwise. */ -int cam_smmu_map_user_iova(int handle, - int ion_fd, enum cam_smmu_map_dir dir, - dma_addr_t *dma_addr, size_t *len_ptr, +int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, + enum cam_smmu_map_dir dir, dma_addr_t *dma_addr, size_t *len_ptr, enum cam_smmu_region_id region_id); /** diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 934e9bdf4bb0..b1170004281c 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -276,6 +276,7 @@ struct cam_req_mgr_link_control { #define CAM_MEM_FLAG_CACHE (1<<10) #define CAM_MEM_FLAG_HW_SHARED_ACCESS (1<<11) #define CAM_MEM_FLAG_CDSP_OUTPUT (1<<12) +#define CAM_MEM_FLAG_DISABLE_DELAYED_UNMAP (1<<13) #define CAM_MEM_MMU_MAX_HANDLE 16 -- GitLab From 6d2403cc2a455451a4be86ff035bd61de88e8154 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 25 Sep 2019 20:27:50 -0700 Subject: [PATCH 029/295] msm: camera: custom: Add support for acquire_hw_v1 Split the acquire in custom node to acquire device and acquire hw to be in line with IFE for multicamera usecases. CRs-Fixed: 2524308 Change-Id: I7be7d5227dcd304d095d7e3d7fac32800fecc199 Signed-off-by: Karthik Anantha Ram --- drivers/cam_cust/cam_custom_context.c | 231 ++++++++++++++-- drivers/cam_cust/cam_custom_context.h | 2 + .../cam_custom_hw_mgr/cam_custom_hw_mgr.c | 249 ++++++++---------- include/uapi/media/cam_custom.h | 17 ++ 4 files changed, 334 insertions(+), 165 deletions(-) diff --git a/drivers/cam_cust/cam_custom_context.c b/drivers/cam_cust/cam_custom_context.c index 7f38392a7d57..3e69ebd15109 100644 --- a/drivers/cam_cust/cam_custom_context.c +++ b/drivers/cam_cust/cam_custom_context.c @@ -19,7 +19,7 @@ #include "cam_custom_context.h" #include "cam_common_util.h" -static const char custom_dev_name[] = "custom hw"; +static const char custom_dev_name[] = "cam-custom"; static int __cam_custom_ctx_handle_irq_in_activated( void *context, uint32_t evt_id, void *evt_data); @@ -275,6 +275,67 @@ static int __cam_custom_stop_dev_in_activated(struct cam_context *ctx, return 0; } +static int __cam_custom_ctx_release_hw_in_top_state( + struct cam_context *ctx, void *cmd) +{ + int rc = 0; + struct cam_hw_release_args rel_arg; + struct cam_req_mgr_flush_request flush_req; + struct cam_custom_context *custom_ctx = + (struct cam_custom_context *) ctx->ctx_priv; + + if (custom_ctx->hw_ctx) { + rel_arg.ctxt_to_hw_map = custom_ctx->hw_ctx; + rc = ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, + &rel_arg); + custom_ctx->hw_ctx = NULL; + if (rc) + CAM_ERR(CAM_CUSTOM, + "Failed to release HW for ctx:%u", ctx->ctx_id); + } else { + CAM_ERR(CAM_CUSTOM, "No HW resources acquired for this ctx"); + } + + ctx->last_flush_req = 0; + custom_ctx->frame_id = 0; + custom_ctx->active_req_cnt = 0; + custom_ctx->hw_acquired = false; + custom_ctx->init_received = false; + + /* check for active requests as well */ + flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; + flush_req.link_hdl = ctx->link_hdl; + flush_req.dev_hdl = ctx->dev_hdl; + + CAM_DBG(CAM_CUSTOM, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, + &flush_req); + spin_unlock_bh(&ctx->lock); + ctx->state = CAM_CTX_ACQUIRED; + + CAM_DBG(CAM_CUSTOM, "Release HW success[%u] next state %d", + ctx->ctx_id, ctx->state); + + return rc; +} + +static int __cam_custom_ctx_release_hw_in_activated_state( + struct cam_context *ctx, void *cmd) +{ + int rc = 0; + + rc = __cam_custom_stop_dev_in_activated(ctx, NULL); + if (rc) + CAM_ERR(CAM_CUSTOM, "Stop device failed rc=%d", rc); + + rc = __cam_custom_ctx_release_hw_in_top_state(ctx, cmd); + if (rc) + CAM_ERR(CAM_CUSTOM, "Release hw failed rc=%d", rc); + + return rc; +} + static int __cam_custom_release_dev_in_acquired(struct cam_context *ctx, struct cam_release_dev_cmd *cmd) { @@ -283,14 +344,16 @@ static int __cam_custom_release_dev_in_acquired(struct cam_context *ctx, (struct cam_custom_context *) ctx->ctx_priv; struct cam_req_mgr_flush_request flush_req; - rc = cam_context_release_dev_to_hw(ctx, cmd); - if (rc) - CAM_ERR(CAM_CUSTOM, "Unable to release device"); + if (cmd && ctx_custom->hw_ctx) { + CAM_ERR(CAM_CUSTOM, "releasing hw"); + __cam_custom_ctx_release_hw_in_top_state(ctx, NULL); + } ctx->ctx_crm_intf = NULL; ctx->last_flush_req = 0; ctx_custom->frame_id = 0; ctx_custom->active_req_cnt = 0; + ctx_custom->hw_acquired = false; ctx_custom->init_received = false; if (!list_empty(&ctx->active_req_list)) @@ -381,33 +444,128 @@ static int __cam_custom_ctx_apply_req_in_activated_state( return rc; } -static int __cam_custom_ctx_acquire_dev_in_available(struct cam_context *ctx, - struct cam_acquire_dev_cmd *cmd) +static int __cam_custom_ctx_acquire_hw_v1( + struct cam_context *ctx, void *args) { - int rc; - struct cam_custom_context *custom_ctx; + int rc = 0; + struct cam_acquire_hw_cmd_v1 *cmd = + (struct cam_acquire_hw_cmd_v1 *)args; + struct cam_hw_acquire_args param; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + struct cam_custom_acquire_hw_info *acquire_hw_info = NULL; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CUSTOM, "HW interface is not ready"); + rc = -EFAULT; + goto end; + } - custom_ctx = (struct cam_custom_context *) ctx->ctx_priv; + CAM_DBG(CAM_CUSTOM, + "session_hdl 0x%x, hdl type %d, res %lld", + cmd->session_handle, cmd->handle_type, cmd->resource_hdl); - if (cmd->num_resources > CAM_CUSTOM_DEV_CTX_RES_MAX) { - CAM_ERR(CAM_CUSTOM, "Too much resources in the acquire"); + if (cmd->handle_type != 1) { + CAM_ERR(CAM_CUSTOM, "Only user pointer is supported"); + rc = -EINVAL; + goto end; + } + + if (cmd->data_size < sizeof(*acquire_hw_info)) { + CAM_ERR(CAM_CUSTOM, "data_size is not a valid value"); + goto end; + } + + acquire_hw_info = kzalloc(cmd->data_size, GFP_KERNEL); + if (!acquire_hw_info) { rc = -ENOMEM; - return rc; + goto end; } - if (cmd->handle_type != 1) { - CAM_ERR(CAM_CUSTOM, "Only user pointer is supported"); - rc = -EINVAL; + CAM_DBG(CAM_CUSTOM, "start copy resources from user"); + + if (copy_from_user(acquire_hw_info, (void __user *)cmd->resource_hdl, + cmd->data_size)) { + rc = -EFAULT; + goto free_res; + } + + memset(¶m, 0, sizeof(param)); + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.acquire_info_size = cmd->data_size; + param.acquire_info = (uint64_t) acquire_hw_info; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_CUSTOM, "Acquire HW failed"); + goto free_res; + } + + ctx_custom->hw_ctx = param.ctxt_to_hw_map; + ctx_custom->hw_acquired = true; + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + CAM_DBG(CAM_CUSTOM, + "Acquire HW success on session_hdl 0x%xs for ctx_id %u", + ctx->session_hdl, ctx->ctx_id); + + kfree(acquire_hw_info); + return rc; + +free_res: + kfree(acquire_hw_info); +end: + return rc; +} + +static int __cam_custom_ctx_acquire_dev_in_available( + struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) +{ + int rc = 0; + struct cam_create_dev_hdl req_hdl_param; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CUSTOM, "HW interface is not ready"); + rc = -EFAULT; return rc; } - rc = cam_context_acquire_dev_to_hw(ctx, cmd); - if (!rc) { - ctx->state = CAM_CTX_ACQUIRED; - custom_ctx->hw_ctx = ctx->ctxt_to_hw_map; + CAM_DBG(CAM_CUSTOM, + "session_hdl 0x%x, num_resources %d, hdl type %d, res %lld", + cmd->session_handle, cmd->num_resources, + cmd->handle_type, cmd->resource_hdl); + + if (cmd->num_resources != CAM_API_COMPAT_CONSTANT) { + CAM_ERR(CAM_CUSTOM, "Invalid num_resources 0x%x", + cmd->num_resources); + return -EINVAL; } - CAM_DBG(CAM_CUSTOM, "Acquire done %d", ctx->ctx_id); + req_hdl_param.session_hdl = cmd->session_handle; + req_hdl_param.v4l2_sub_dev_flag = 0; + req_hdl_param.media_entity_flag = 0; + req_hdl_param.ops = ctx->crm_ctx_intf; + req_hdl_param.priv = ctx; + + CAM_DBG(CAM_CUSTOM, "get device handle from bridge"); + ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); + if (ctx->dev_hdl <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_CUSTOM, "Can not create device handle"); + return rc; + } + + cmd->dev_handle = ctx->dev_hdl; + ctx->session_hdl = cmd->session_handle; + ctx->state = CAM_CTX_ACQUIRED; + + CAM_DBG(CAM_CUSTOM, + "Acquire dev success on session_hdl 0x%x for ctx %u", + cmd->session_handle, ctx->ctx_id); + return rc; } @@ -642,6 +800,13 @@ static int __cam_custom_ctx_config_dev_in_acquired(struct cam_context *ctx, struct cam_config_dev_cmd *cmd) { int rc = 0; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + + if (!ctx_custom->hw_acquired) { + CAM_ERR(CAM_CUSTOM, "HW not acquired, reject config packet"); + return -EAGAIN; + } rc = __cam_custom_ctx_config_dev(ctx, cmd); @@ -826,6 +991,27 @@ static int __cam_custom_ctx_handle_irq_in_activated(void *context, return rc; } +static int __cam_custom_ctx_acquire_hw_in_acquired( + struct cam_context *ctx, void *args) +{ + int rc = -EINVAL; + uint32_t api_version; + + if (!ctx || !args) { + CAM_ERR(CAM_CUSTOM, "Invalid input pointer"); + return rc; + } + + api_version = *((uint32_t *)args); + if (api_version == 1) + rc = __cam_custom_ctx_acquire_hw_v1(ctx, args); + else + CAM_ERR(CAM_CUSTOM, "Unsupported api version %d", + api_version); + + return rc; +} + /* top state machine */ static struct cam_ctx_ops cam_custom_dev_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { @@ -847,8 +1033,10 @@ static struct cam_ctx_ops /* Acquired */ { .ioctl_ops = { + .acquire_hw = __cam_custom_ctx_acquire_hw_in_acquired, .release_dev = __cam_custom_release_dev_in_acquired, .config_dev = __cam_custom_ctx_config_dev_in_acquired, + .release_hw = __cam_custom_ctx_release_hw_in_top_state, }, .crm_ops = { .link = __cam_custom_ctx_link_in_acquired, @@ -866,6 +1054,7 @@ static struct cam_ctx_ops .start_dev = __cam_custom_ctx_start_dev_in_ready, .release_dev = __cam_custom_release_dev_in_acquired, .config_dev = __cam_custom_ctx_config_dev, + .release_hw = __cam_custom_ctx_release_hw_in_top_state, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_ready, @@ -883,6 +1072,8 @@ static struct cam_ctx_ops .release_dev = __cam_custom_ctx_release_dev_in_activated, .config_dev = __cam_custom_ctx_config_dev, + .release_hw = + __cam_custom_ctx_release_hw_in_activated_state, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_activated, diff --git a/drivers/cam_cust/cam_custom_context.h b/drivers/cam_cust/cam_custom_context.h index 91acf1e5ee80..27268b20c526 100644 --- a/drivers/cam_cust/cam_custom_context.h +++ b/drivers/cam_cust/cam_custom_context.h @@ -67,6 +67,7 @@ struct cam_custom_dev_ctx_req { * custom HW will invoke CRM cb at those event. * @active_req_cnt: Counter for the active request * @frame_id: Frame id tracking for the custom context + * @hw_acquired: Flag to indicate if HW is acquired for this context * @req_base: common request structure * @req_custom: custom request structure * @@ -80,6 +81,7 @@ struct cam_custom_context { uint32_t subscribe_event; uint32_t active_req_cnt; int64_t frame_id; + bool hw_acquired; struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; struct cam_custom_dev_ctx_req req_custom[CAM_CTX_REQ_MAX]; }; diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c index 1db06bb3ab1f..f2e5a1ff3407 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c @@ -380,7 +380,7 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, &ctx->res_list_custom_cid, list) { rc = cam_custom_hw_mgr_init_hw_res(hw_mgr_res); if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT CID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not INIT CID(id :%d)", hw_mgr_res->res_id); goto deinit_hw; } @@ -391,7 +391,7 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, &ctx->res_list_custom_csid, list) { rc = cam_custom_hw_mgr_init_hw_res(hw_mgr_res); if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT CSID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not INIT CSID(id :%d)", hw_mgr_res->res_id); goto deinit_hw; } @@ -411,7 +411,7 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, &ctx->res_list_custom_csid, list) { rc = cam_custom_hw_mgr_start_hw_res(hw_mgr_res); if (rc) { - CAM_ERR(CAM_ISP, "Can not START CSID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not START CSID(id :%d)", hw_mgr_res->res_id); goto err; } @@ -422,7 +422,7 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, &ctx->res_list_custom_cid, list) { rc = cam_custom_hw_mgr_start_hw_res(hw_mgr_res); if (rc) { - CAM_ERR(CAM_ISP, "Can not START CID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not START CID(id :%d)", hw_mgr_res->res_id); goto err; } @@ -760,7 +760,7 @@ static int cam_custom_hw_mgr_release_hw_for_ctx( &custom_ctx->res_list_custom_cid, list) { rc = cam_custom_hw_mgr_free_hw_res(hw_mgr_res); if (rc) - CAM_ERR(CAM_ISP, "Can not release CID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not release CID(id :%d)", hw_mgr_res->res_id); cam_custom_hw_mgr_put_res( &custom_ctx->free_res_list, &hw_mgr_res); @@ -771,7 +771,7 @@ static int cam_custom_hw_mgr_release_hw_for_ctx( &custom_ctx->res_list_custom_csid, list) { rc = cam_custom_hw_mgr_free_hw_res(hw_mgr_res); if (rc) - CAM_ERR(CAM_ISP, "Can not release CSID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not release CSID(id :%d)", hw_mgr_res->res_id); cam_custom_hw_mgr_put_res( &custom_ctx->free_res_list, &hw_mgr_res); @@ -811,41 +811,82 @@ static int cam_custom_mgr_release_hw(void *hw_mgr_priv, return rc; } -static void cam_custom_hw_mgr_acquire_get_unified_dev_str( - struct cam_custom_in_port_info *in, - struct cam_isp_in_port_generic_info *gen_port_info) +static int cam_custom_hw_mgr_acquire_get_unified_dev_str( + struct cam_custom_acquire_hw_info *acquire_hw_info, + uint32_t *input_size, + struct cam_isp_in_port_generic_info **gen_port_info) { - int i; + int32_t rc = 0, i; + uint32_t in_port_length = 0; + struct cam_custom_in_port_info *in = NULL; + struct cam_isp_in_port_generic_info *port_info = NULL; + + in = (struct cam_custom_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset + *input_size); + + in_port_length = sizeof(struct cam_custom_in_port_info) + + (in->num_out_res - 1) * + sizeof(struct cam_custom_out_port_info); + + *input_size += in_port_length; + + if ((*input_size) > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_CUSTOM, "Input is not proper"); + rc = -EINVAL; + return rc; + } + + port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), GFP_KERNEL); + + if (!port_info) + return -ENOMEM; - gen_port_info->res_type = in->res_type + + port_info->res_type = in->res_type + CAM_ISP_IFE_IN_RES_BASE - CAM_CUSTOM_IN_RES_BASE; - gen_port_info->lane_type = in->lane_type; - gen_port_info->lane_num = in->lane_num; - gen_port_info->lane_cfg = in->lane_cfg; - gen_port_info->vc[0] = in->vc[0]; - gen_port_info->dt[0] = in->dt[0]; - gen_port_info->num_valid_vc_dt = in->num_valid_vc_dt; - gen_port_info->format = in->format; - gen_port_info->test_pattern = in->test_pattern; - gen_port_info->usage_type = in->usage_type; - gen_port_info->left_start = in->left_start; - gen_port_info->left_stop = in->left_stop; - gen_port_info->left_width = in->left_width; - gen_port_info->right_start = in->right_start; - gen_port_info->right_stop = in->right_stop; - gen_port_info->right_width = in->right_width; - gen_port_info->line_start = in->line_start; - gen_port_info->line_stop = in->line_stop; - gen_port_info->height = in->height; - gen_port_info->pixel_clk = in->pixel_clk; - gen_port_info->cust_node = 1; - gen_port_info->num_out_res = in->num_out_res; - gen_port_info->num_bytes_out = in->num_bytes_out; + port_info->lane_type = in->lane_type; + port_info->lane_num = in->lane_num; + port_info->lane_cfg = in->lane_cfg; + port_info->vc[0] = in->vc[0]; + port_info->dt[0] = in->dt[0]; + port_info->num_valid_vc_dt = in->num_valid_vc_dt; + port_info->format = in->format; + port_info->test_pattern = in->test_pattern; + port_info->usage_type = in->usage_type; + port_info->left_start = in->left_start; + port_info->left_stop = in->left_stop; + port_info->left_width = in->left_width; + port_info->right_start = in->right_start; + port_info->right_stop = in->right_stop; + port_info->right_width = in->right_width; + port_info->line_start = in->line_start; + port_info->line_stop = in->line_stop; + port_info->height = in->height; + port_info->pixel_clk = in->pixel_clk; + port_info->cust_node = 1; + port_info->num_out_res = in->num_out_res; + port_info->num_bytes_out = in->num_bytes_out; + + port_info->data = kcalloc(in->num_out_res, + sizeof(struct cam_isp_out_port_generic_info), + GFP_KERNEL); + if (port_info->data == NULL) { + rc = -ENOMEM; + goto release_port_mem; + } for (i = 0; i < in->num_out_res; i++) { - gen_port_info->data[i].res_type = in->data[i].res_type; - gen_port_info->data[i].format = in->data[i].format; + port_info->data[i].res_type = in->data[i].res_type; + port_info->data[i].format = in->data[i].format; } + + *gen_port_info = port_info; + return 0; + +release_port_mem: + kfree(port_info); + return rc; } static int cam_custom_mgr_acquire_hw_for_ctx( @@ -896,18 +937,16 @@ static int cam_custom_mgr_acquire_hw( void *hw_mgr_priv, void *acquire_hw_args) { - int rc = -1; - int32_t i; - uint32_t in_port_length; + int rc = -1, i; + uint32_t input_size = 0; struct cam_custom_hw_mgr_ctx *custom_ctx; struct cam_custom_hw_mgr *custom_hw_mgr; - struct cam_hw_acquire_args *acquire_args = - (struct cam_hw_acquire_args *) acquire_hw_args; - struct cam_custom_in_port_info *in_port_info; - struct cam_custom_resource *custom_rsrc; + struct cam_custom_acquire_hw_info *acquire_hw_info = NULL; struct cam_isp_in_port_generic_info *gen_port_info = NULL; + struct cam_hw_acquire_args *acquire_args = + (struct cam_hw_acquire_args *)acquire_hw_args; - if (!hw_mgr_priv || !acquire_args || (acquire_args->num_acq <= 0)) { + if (!hw_mgr_priv || !acquire_args) { CAM_ERR(CAM_CUSTOM, "Invalid params"); return -EINVAL; } @@ -923,127 +962,47 @@ static int cam_custom_mgr_acquire_hw( } mutex_unlock(&g_custom_hw_mgr.ctx_mutex); - /* Handle Acquire Here */ custom_ctx->hw_mgr = custom_hw_mgr; custom_ctx->cb_priv = acquire_args->context_data; custom_ctx->event_cb = acquire_args->event_cb; - custom_rsrc = kcalloc(acquire_args->num_acq, - sizeof(*custom_rsrc), GFP_KERNEL); - if (!custom_rsrc) { - rc = -ENOMEM; - goto free_ctx; - } - - CAM_DBG(CAM_CUSTOM, "start copy %d resources from user", - acquire_args->num_acq); + acquire_hw_info = + (struct cam_custom_acquire_hw_info *)acquire_args->acquire_info; - if (copy_from_user(custom_rsrc, - (void __user *)acquire_args->acquire_info, - ((sizeof(*custom_rsrc)) * acquire_args->num_acq))) { - rc = -EFAULT; - goto free_ctx; - } + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + rc = cam_custom_hw_mgr_acquire_get_unified_dev_str( + acquire_hw_info, &input_size, &gen_port_info); - for (i = 0; i < acquire_args->num_acq; i++) { - if (custom_rsrc[i].resource_id != CAM_CUSTOM_RES_ID_PORT) - continue; - - CAM_DBG(CAM_CUSTOM, "acquire no = %d total = %d", i, - acquire_args->num_acq); - - CAM_DBG(CAM_CUSTOM, - "start copy from user handle %lld with len = %d", - custom_rsrc[i].res_hdl, - custom_rsrc[i].length); - - in_port_length = sizeof(struct cam_custom_in_port_info); - if (in_port_length > custom_rsrc[i].length) { - CAM_ERR(CAM_CUSTOM, "buffer size is not enough"); - rc = -EINVAL; + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, "Failed in parsing: %d", rc); goto free_res; } - in_port_info = memdup_user( - u64_to_user_ptr(custom_rsrc[i].res_hdl), - custom_rsrc[i].length); - - if (!IS_ERR(in_port_info)) { - if (in_port_info->num_out_res > - CAM_CUSTOM_HW_OUT_RES_MAX) { - CAM_ERR(CAM_CUSTOM, "too many output res %d", - in_port_info->num_out_res); - rc = -EINVAL; - kfree(in_port_info); - goto free_res; - } - - in_port_length = - sizeof(struct cam_custom_in_port_info) + - (in_port_info->num_out_res - 1) * - sizeof(struct cam_custom_out_port_info); - - if (in_port_length > custom_rsrc[i].length) { - CAM_ERR(CAM_CUSTOM, - "buffer size is not enough"); - rc = -EINVAL; - kfree(in_port_info); - goto free_res; - } - - gen_port_info = kzalloc( - sizeof(struct cam_isp_in_port_generic_info), - GFP_KERNEL); - if (gen_port_info == NULL) { - rc = -ENOMEM; - goto free_res; - } - - gen_port_info->data = kcalloc( - sizeof(struct cam_isp_out_port_generic_info), - in_port_info->num_out_res, GFP_KERNEL); - if (gen_port_info->data == NULL) { - kfree(gen_port_info); - gen_port_info = NULL; - rc = -ENOMEM; - goto free_res; - } - - cam_custom_hw_mgr_acquire_get_unified_dev_str( - in_port_info, gen_port_info); - - rc = cam_custom_mgr_acquire_hw_for_ctx(custom_ctx, - gen_port_info, &acquire_args->acquired_hw_id[i], - acquire_args->acquired_hw_path[i]); - - kfree(in_port_info); - if (gen_port_info != NULL) { - kfree(gen_port_info->data); - kfree(gen_port_info); - gen_port_info = NULL; - } - - if (rc) { - CAM_ERR(CAM_CUSTOM, "can not acquire resource"); - goto free_res; - } - } else { - CAM_ERR(CAM_CUSTOM, - "Copy from user failed with in_port = %pK", - in_port_info); - rc = -EFAULT; - goto free_res; + CAM_DBG(CAM_CUSTOM, "in_res_type %x", gen_port_info->res_type); + rc = cam_custom_mgr_acquire_hw_for_ctx(custom_ctx, + gen_port_info, &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); + if (rc) { + CAM_ERR(CAM_CUSTOM, "can not acquire resource"); + goto free_mem; } + + kfree(gen_port_info->data); + kfree(gen_port_info); + gen_port_info = NULL; } custom_ctx->ctx_in_use = 1; acquire_args->ctxt_to_hw_map = custom_ctx; + cam_custom_hw_mgr_put_ctx(&custom_hw_mgr->used_ctx_list, &custom_ctx); CAM_DBG(CAM_CUSTOM, "Exit...(success)"); return 0; +free_mem: + kfree(gen_port_info->data); + kfree(gen_port_info); free_res: cam_custom_hw_mgr_release_hw_for_ctx(custom_ctx); -free_ctx: cam_custom_hw_mgr_put_ctx(&custom_hw_mgr->free_ctx_list, &custom_ctx); err: CAM_DBG(CAM_CUSTOM, "Exit...(rc=%d)", rc); diff --git a/include/uapi/media/cam_custom.h b/include/uapi/media/cam_custom.h index b36891f4a0dc..37edce171e4b 100644 --- a/include/uapi/media/cam_custom.h +++ b/include/uapi/media/cam_custom.h @@ -170,6 +170,23 @@ struct cam_custom_resource { uint64_t res_hdl; }; +/** + * struct cam_custom_acquire_hw_info - Custom acquire HW params + * + * @num_inputs : Number of inputs + * @input_info_size : Size of input info struct used + * @input_info_offset : Offset of input info from start of data + * @reserved : reserved + * @data : Start of data region + */ +struct cam_custom_acquire_hw_info { + uint32_t num_inputs; + uint32_t input_info_size; + uint32_t input_info_offset; + uint32_t reserved; + uint64_t data; +}; + /** * struct cam_custom_cmd_buf_type_1 - cmd buf type 1 * -- GitLab From 1b30be51f915d4d53eca23332e8da6cd39e4329d Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 16 Dec 2019 15:37:49 +0530 Subject: [PATCH 030/295] msm: camera: tfe: Fix variable initialization issues Fix the variable initialization issues in tfe csid and tfe hw manager. CRs-Fixed: 2585713 Change-Id: I2682159796c3fe951ee7489b923521b115cb1c7b Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 2 +- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) 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 be00f75d71a0..e950069339fd 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 @@ -119,7 +119,7 @@ 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) { - int rc, i; + int rc = -EINVAL, i; if (!num_reg_dump_buf || !reg_dump_buf_desc) { CAM_DBG(CAM_ISP, 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 7cebadc4ca2e..e1459e0da458 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 @@ -1755,6 +1755,10 @@ static int cam_tfe_csid_release(void *hw_priv, return -EINVAL; } + 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 *)release_args; + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH) { CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", csid_hw->hw_intf->hw_idx, res->res_type, @@ -1762,10 +1766,6 @@ static int cam_tfe_csid_release(void *hw_priv, return -EINVAL; } - 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 *)release_args; - 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)) { @@ -1872,6 +1872,11 @@ static int cam_tfe_csid_init_hw(void *hw_priv, return -EINVAL; } + 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", csid_hw->hw_intf->hw_idx, @@ -1879,11 +1884,6 @@ static int cam_tfe_csid_init_hw(void *hw_priv, return -EINVAL; } - 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; - 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) { @@ -1946,18 +1946,18 @@ static int cam_tfe_csid_deinit_hw(void *hw_priv, return -EINVAL; } - if (res->res_type == CAM_ISP_RESOURCE_PIX_PATH) { + 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) { 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"); - 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; - 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", -- GitLab From a87bb52dd364b5744925395dc7a8d040fd1591a4 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Wed, 11 Dec 2019 09:29:48 +0530 Subject: [PATCH 031/295] msm: camera: isp: Dual tfe event check with proper hw idx Dual tfe events such as sof, eof and epoch need to come for both master and slave hardware. Master and slave can be with any hw index. Daul tfe hardware events need to check with acquired master and slave index. Remove the bus stride alignment check, it is not required for tfe. For some bus port format alignment can be 3 or 5. CSID immediate stop need to configure for csid slave also as immediate stop Command does not take it from master csid. CRs-Fixed: 2585713 Change-Id: I32d7c62843f22ab6d2185795f0959c202a49f295 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 3 ++ drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 43 +++++++++++-------- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h | 2 + .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 12 ++++++ .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 8 ---- 5 files changed, 42 insertions(+), 26 deletions(-) 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 4783c3d65084..604e230db7ee 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 @@ -3729,6 +3729,9 @@ 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]) + continue; + if (hw_idx != hw_mgr->ife_devices[i]->hw_idx) continue; CAM_DBG(CAM_ISP, "VFE (id = %d) reset", hw_idx); 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 be00f75d71a0..6cba243e4295 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 @@ -1328,6 +1328,8 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_pxl( 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); } @@ -2679,6 +2681,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); @@ -4665,12 +4670,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; @@ -4685,19 +4693,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; @@ -4705,15 +4712,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++; } 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 cd701b18d311..1e15bd20f5e8 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 @@ -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/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 7cebadc4ca2e..e7e1c074a41b 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; } 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 57221c2c050f..215b2cce19ef 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 @@ -1657,14 +1657,6 @@ 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); -- GitLab From 1a732aa4ff1fe6d8916b95a9600a76ce4b46dcd5 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Wed, 30 Oct 2019 18:30:06 +0530 Subject: [PATCH 032/295] msm: camera: isp: Notify CRM to pause SOF timer after flush Adding CRM interface to stop SOF timer from isp during flush. During flush hardware is getting stop and will not send SOF notification to CRM so need to pause SOF timer. Whenever SOF timer will get expire,do not need to send error to UMD during pause time. CRs-Fixed: 2564389 Change-Id: I6d85f2c658c30dbe211f0ec9d83bca323a5c265b Signed-off-by: Chandan Kumar Jha --- drivers/cam_isp/cam_isp_context.c | 9 ++++ drivers/cam_req_mgr/cam_req_mgr_core.c | 55 +++++++++++++++++++++ drivers/cam_req_mgr/cam_req_mgr_interface.h | 16 ++++++ drivers/cam_req_mgr/cam_req_mgr_timer.h | 12 +++-- 4 files changed, 87 insertions(+), 5 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 5f8506ad0cfa..f4d07e1f8ed8 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -2216,6 +2216,7 @@ static int __cam_isp_ctx_flush_req_in_top_state( struct cam_hw_stop_args stop_args; struct cam_hw_reset_args reset_args; struct cam_hw_cmd_args hw_cmd_args; + struct cam_req_mgr_timer_notify timer; ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; @@ -2261,6 +2262,14 @@ static int __cam_isp_ctx_flush_req_in_top_state( CAM_INFO(CAM_ISP, "Stop HW complete. Reset HW next."); CAM_DBG(CAM_ISP, "Flush wait and active lists"); + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_timer) { + timer.link_hdl = ctx->link_hdl; + timer.dev_hdl = ctx->dev_hdl; + timer.state = false; + ctx->ctx_crm_intf->notify_timer(&timer); + } + spin_lock_bh(&ctx->lock); if (!list_empty(&ctx->wait_req_list)) rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index faa15479ecda..00677b9d864e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1744,6 +1744,10 @@ static void __cam_req_mgr_sof_freeze(struct timer_list *timer_data) } link = (struct cam_req_mgr_core_link *)timer->parent; + + if (link->watchdog->pause_timer) + return; + task = cam_req_mgr_workq_get_task(link->workq); if (!task) { CAM_ERR(CAM_CRM, "No empty task"); @@ -2643,6 +2647,52 @@ static int cam_req_mgr_cb_notify_err( return rc; } +/** + * cam_req_mgr_cb_notify_timer() + * + * @brief : Notify SOF timer to pause after flush + * @timer_data : contains information about frame_id, link etc. + * + * @return : 0 on success + * + */ +static int cam_req_mgr_cb_notify_timer( + struct cam_req_mgr_timer_notify *timer_data) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + + if (!timer_data) { + CAM_ERR(CAM_CRM, "timer data is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(timer_data->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", timer_data->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state < CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + spin_unlock_bh(&link->link_state_spin_lock); + + + if (!timer_data->state) + link->watchdog->pause_timer = true; + +end: + return rc; +} + /** * cam_req_mgr_cb_notify_trigger() * @@ -2682,6 +2732,10 @@ static int cam_req_mgr_cb_notify_trigger( rc = -EPERM; goto end; } + + if (link->watchdog->pause_timer) + link->watchdog->pause_timer = false; + crm_timer_reset(link->watchdog); spin_unlock_bh(&link->link_state_spin_lock); @@ -2711,6 +2765,7 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { .notify_trigger = cam_req_mgr_cb_notify_trigger, .notify_err = cam_req_mgr_cb_notify_err, .add_req = cam_req_mgr_cb_add_req, + .notify_timer = cam_req_mgr_cb_notify_timer, }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index f4b662dd4138..5df13b26e215 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -14,6 +14,7 @@ struct cam_req_mgr_trigger_notify; struct cam_req_mgr_error_notify; struct cam_req_mgr_add_request; +struct cam_req_mgr_timer_notify; struct cam_req_mgr_device_info; struct cam_req_mgr_core_dev_link_setup; struct cam_req_mgr_apply_request; @@ -35,6 +36,7 @@ typedef int (*cam_req_mgr_notify_trigger)( struct cam_req_mgr_trigger_notify *); typedef int (*cam_req_mgr_notify_err)(struct cam_req_mgr_error_notify *); typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *); +typedef int (*cam_req_mgr_notify_timer)(struct cam_req_mgr_timer_notify *); /** * @brief: cam req mgr to camera device drivers @@ -64,6 +66,7 @@ struct cam_req_mgr_crm_cb { cam_req_mgr_notify_trigger notify_trigger; cam_req_mgr_notify_err notify_err; cam_req_mgr_add_req add_req; + cam_req_mgr_notify_timer notify_timer; }; /** @@ -206,6 +209,19 @@ struct cam_req_mgr_trigger_notify { uint64_t sof_timestamp_val; }; +/** + * struct cam_req_mgr_timer_notify + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @frame_id : frame id for internal tracking + * @state : timer state i.e ON or OFF + */ +struct cam_req_mgr_timer_notify { + int32_t link_hdl; + int32_t dev_hdl; + bool state; +}; + /** * struct cam_req_mgr_error_notify * @link_hdl : link identifier diff --git a/drivers/cam_req_mgr/cam_req_mgr_timer.h b/drivers/cam_req_mgr/cam_req_mgr_timer.h index 9f9ba71a3879..be200f1b2693 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_timer.h +++ b/drivers/cam_req_mgr/cam_req_mgr_timer.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_TIMER_H_ @@ -12,16 +12,18 @@ #include "cam_req_mgr_core_defs.h" /** struct cam_req_mgr_timer - * @expires : timeout value for timer - * @sys_timer : system timer variable - * @parent : priv data - link pointer - * @timer_cb : callback func which will be called when timeout expires + * @expires : timeout value for timer + * @sys_timer : system timer variable + * @parent : priv data - link pointer + * @timer_cb : callback func which will be called when timeout expires + * @pause_timer : flag to pause SOF timer */ struct cam_req_mgr_timer { int32_t expires; struct timer_list sys_timer; void *parent; void (*timer_cb)(struct timer_list *timer_data); + bool pause_timer; }; /** -- GitLab From 72ceb2c247745355909c58e3e80f2d1cc93002ba Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Thu, 19 Dec 2019 12:30:20 +0530 Subject: [PATCH 033/295] msm: camera: config: Update camera config Update camera config with supported camera hardwares. CRs-Fixed: 2588031 Change-Id: Ib5831a023729f09c39a795a8065b959abb8a885d Signed-off-by: Ravikishore Pampana --- config/bengalcamera.conf | 2 ++ config/bengalcameraconf.h | 5 +++-- config/konacamera.conf | 11 ++++++++++- config/konacameraconf.h | 10 +++++++--- config/litocamera.conf | 5 +++++ config/litocameraconf.h | 6 +++++- drivers/Makefile | 30 +++++++++++++++--------------- 7 files changed, 47 insertions(+), 22 deletions(-) diff --git a/config/bengalcamera.conf b/config/bengalcamera.conf index 451723eebce3..0db46fd848a4 100644 --- a/config/bengalcamera.conf +++ b/config/bengalcamera.conf @@ -2,3 +2,5 @@ # Copyright (c) 2019, The Linux Foundation. All rights reserved. export CONFIG_SPECTRA_CAMERA=y +export CONFIG_SPECTRA_CAMERA_ISP=y +export CONFIG_SPECTRA_CAMERA_OPE=y diff --git a/config/bengalcameraconf.h b/config/bengalcameraconf.h index 1a7714018004..126187d99ed3 100644 --- a/config/bengalcameraconf.h +++ b/config/bengalcameraconf.h @@ -3,5 +3,6 @@ * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ -#define CONFIG_SPECTRA_CAMERA 1 - +#define CONFIG_SPECTRA_CAMERA 1 +#define CONFIG_SPECTRA_CAMERA_ISP 1 +#define CONFIG_SPECTRA_CAMERA_OPE 1 diff --git a/config/konacamera.conf b/config/konacamera.conf index 9b08bcb80c2b..3123906bf37f 100644 --- a/config/konacamera.conf +++ b/config/konacamera.conf @@ -1 +1,10 @@ -export CONFIG_SPECTRA_CAMERA=y \ No newline at end of file +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2019, The Linux Foundation. All rights reserved. + +export CONFIG_SPECTRA_CAMERA=y +export CONFIG_SPECTRA_CAMERA_CUST=y +export CONFIG_SPECTRA_CAMERA_FD=y +export CONFIG_SPECTRA_CAMERA_ICP=y +export CONFIG_SPECTRA_CAMERA_JPEG=y +export CONFIG_SPECTRA_CAMERA_ISP=y +export CONFIG_SPECTRA_CAMERA_LRME=y diff --git a/config/konacameraconf.h b/config/konacameraconf.h index 875b95587ab6..2a753fb9934a 100644 --- a/config/konacameraconf.h +++ b/config/konacameraconf.h @@ -3,6 +3,10 @@ * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ - -#define CONFIG_SPECTRA_CAMERA 1 - +#define CONFIG_SPECTRA_CAMERA 1 +#define CONFIG_SPECTRA_CAMERA_CUST 1 +#define CONFIG_SPECTRA_CAMERA_FD 1 +#define CONFIG_SPECTRA_CAMERA_ICP 1 +#define CONFIG_SPECTRA_CAMERA_JPEG 1 +#define CONFIG_SPECTRA_CAMERA_ISP 1 +#define CONFIG_SPECTRA_CAMERA_LRME 1 diff --git a/config/litocamera.conf b/config/litocamera.conf index 451723eebce3..977636e7897c 100644 --- a/config/litocamera.conf +++ b/config/litocamera.conf @@ -2,3 +2,8 @@ # Copyright (c) 2019, The Linux Foundation. All rights reserved. export CONFIG_SPECTRA_CAMERA=y +export CONFIG_SPECTRA_CAMERA_FD=y +export CONFIG_SPECTRA_CAMERA_ICP=y +export CONFIG_SPECTRA_CAMERA_JPEG=y +export CONFIG_SPECTRA_CAMERA_ISP=y +export CONFIG_SPECTRA_CAMERA_LRME=y diff --git a/config/litocameraconf.h b/config/litocameraconf.h index 1a7714018004..90cacf1b899a 100644 --- a/config/litocameraconf.h +++ b/config/litocameraconf.h @@ -4,4 +4,8 @@ */ #define CONFIG_SPECTRA_CAMERA 1 - +#define CONFIG_SPECTRA_CAMERA_FD 1 +#define CONFIG_SPECTRA_CAMERA_ICP 1 +#define CONFIG_SPECTRA_CAMERA_JPEG 1 +#define CONFIG_SPECTRA_CAMERA_ISP 1 +#define CONFIG_SPECTRA_CAMERA_LRME 1 diff --git a/drivers/Makefile b/drivers/Makefile index 2da1af6c15cb..cf1e956f5c7b 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,15 +1,15 @@ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpas/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_module/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_cust/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_ope/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpas/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm/ +obj-$(CONFIG_SPECTRA_CAMERA_ISP) += cam_isp/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_module/ +obj-$(CONFIG_SPECTRA_CAMERA_ICP) += cam_icp/ +obj-$(CONFIG_SPECTRA_CAMERA_JPEG) += cam_jpeg/ +obj-$(CONFIG_SPECTRA_CAMERA_FD) += cam_fd/ +obj-$(CONFIG_SPECTRA_CAMERA_LRME) += cam_lrme/ +obj-$(CONFIG_SPECTRA_CAMERA_CUST) += cam_cust/ +obj-$(CONFIG_SPECTRA_CAMERA_OPE) += cam_ope/ \ No newline at end of file -- GitLab From d18248a0d1e7df2803fa0e967a36923535111e0d Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 19 Nov 2019 18:26:47 -0800 Subject: [PATCH 034/295] msm: camera: icp: Increase the wait time for abort ACK This change attempts to retry waiting atleast 1 time for a duration of 1 second for the abort ACK from FW. Also adds some debug messages during flush and removes mutex usage during page fault dump. CRs-Fixed: 2588575 Change-Id: I2f273baa3d56ab2dc0368d882470360a3702c53c Signed-off-by: Karthik Anantha Ram --- drivers/cam_icp/cam_icp_context.c | 3 - .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 62 +++++++++++++++++-- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 7d2ef39e0aeb..180ea7152a76 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -37,8 +37,6 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, return -EINVAL; } - mutex_lock(&ctx->ctx_mutex); - if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) { CAM_ERR(CAM_ICP, "Invalid state icp ctx %d state %d", ctx->ctx_id, ctx->state); @@ -64,7 +62,6 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, } end: - mutex_unlock(&ctx->ctx_mutex); return rc; } diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index e82c04b44890..c12b78e402b7 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -3026,6 +3026,36 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) hw_mgr->a5_jtag_debug); } +static int cam_icp_retry_wait_for_abort( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int retry_cnt = 1; + unsigned long rem_jiffies; + int timeout = 1000; + + CAM_WARN(CAM_ICP, "FW timeout in abort ctx: %u retry_left: %d", + ctx_data->ctx_id, retry_cnt); + while (retry_cnt > 0) { + rem_jiffies = wait_for_completion_timeout( + &ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + retry_cnt--; + if (retry_cnt > 0) { + CAM_WARN(CAM_ICP, + "FW timeout in abort ctx: %u retry_left: %u", + ctx_data->ctx_id, retry_cnt); + continue; + } + } + + if (retry_cnt > 0) + return 0; + } + + return -ETIMEDOUT; +} + static int cam_icp_mgr_abort_handle( struct cam_icp_hw_ctx_data *ctx_data) { @@ -3069,10 +3099,14 @@ static int cam_icp_mgr_abort_handle( rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, msecs_to_jiffies((timeout))); if (!rem_jiffies) { - rc = -ETIMEDOUT; - CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command"); - cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); - cam_hfi_queue_dump(); + rc = cam_icp_retry_wait_for_abort(ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, + "FW timeout/err in abort handle command ctx: %u", + ctx_data->ctx_id); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } } kfree(abort_cmd); @@ -4800,6 +4834,24 @@ static int cam_icp_mgr_flush_req(struct cam_icp_hw_ctx_data *ctx_data, return 0; } +static void cam_icp_mgr_flush_info_dump( + struct cam_hw_flush_args *flush_args, uint32_t ctx_id) +{ + int i; + + for (i = 0; i < flush_args->num_req_active; i++) { + CAM_DBG(CAM_ICP, "Flushing active request %lld in ctx %u", + *(int64_t *)flush_args->flush_req_active[i], + ctx_id); + } + + for (i = 0; i < flush_args->num_req_pending; i++) { + CAM_DBG(CAM_ICP, "Flushing pending request %lld in ctx %u", + *(int64_t *)flush_args->flush_req_pending[i], + ctx_id); + } +} + static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; @@ -4833,6 +4885,8 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) if (!atomic_read(&hw_mgr->recovery) && flush_args->num_req_active) { mutex_unlock(&hw_mgr->hw_mgr_mutex); + cam_icp_mgr_flush_info_dump(flush_args, + ctx_data->ctx_id); cam_icp_mgr_abort_handle(ctx_data); } else { mutex_unlock(&hw_mgr->hw_mgr_mutex); -- GitLab From 933e7e369813efe5b69315237c0a6784489c7de7 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Sun, 8 Dec 2019 12:56:06 -0800 Subject: [PATCH 035/295] msm: camera: icp: Enqueue the abort cmd in workq The request frame cmds are submitted to the FW in workq context. The abort cmd as part of flush is triggered in user thread context. This change will enqueue the abort as part of flush to FW in workq, thereby ensuring that if there are any pending frames they are submitted prior to the abort cmd. CRs-Fixed: 2588575 Change-Id: I5034ca500cf39dfa0e553c49917fedb8bd084b0b Signed-off-by: Karthik Anantha Ram --- drivers/cam_core/cam_context_utils.c | 1 + drivers/cam_core/cam_hw_mgr_intf.h | 3 + .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 109 +++++++++++++++++- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 2 + drivers/cam_smmu/cam_smmu_api.c | 4 +- 5 files changed, 113 insertions(+), 6 deletions(-) diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 5ec9c6cdc7b1..8090bd0071a6 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -615,6 +615,7 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) ctx->dev_name, ctx->ctx_id); flush_args.num_req_pending = 0; + flush_args.last_flush_req = ctx->last_flush_req; while (true) { spin_lock(&ctx->lock); if (list_empty(&temp_list)) { diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 28426b8dc757..fe074734f389 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -258,6 +258,8 @@ struct cam_hw_config_args { * @num_req_active: Num request to flush, valid when flush type is REQ * @flush_req_active: Request active pointers to flush * @flush_type: The flush type + * @last_flush_req: last flush req_id notified to hw_mgr for the + * given stream * */ struct cam_hw_flush_args { @@ -267,6 +269,7 @@ struct cam_hw_flush_args { uint32_t num_req_active; void *flush_req_active[20]; enum flush_type_t flush_type; + uint32_t last_flush_req; }; /** diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index c12b78e402b7..ecf4fe444e6d 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -3056,11 +3056,63 @@ static int cam_icp_retry_wait_for_abort( return -ETIMEDOUT; } +static int cam_icp_mgr_abort_handle_wq( + void *priv, void *data) +{ + int rc; + size_t packet_size; + struct hfi_cmd_work_data *task_data = NULL; + struct cam_icp_hw_ctx_data *ctx_data; + struct hfi_cmd_ipebps_async *abort_cmd; + + if (!data || !priv) { + CAM_ERR(CAM_ICP, "Invalid params %pK %pK", data, priv); + return -EINVAL; + } + + task_data = (struct hfi_cmd_work_data *)data; + ctx_data = + (struct cam_icp_hw_ctx_data *)task_data->data; + packet_size = + sizeof(struct hfi_cmd_ipebps_async) + + sizeof(struct hfi_cmd_abort) - + sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct); + abort_cmd = kzalloc(packet_size, GFP_KERNEL); + CAM_DBG(CAM_ICP, "abort pkt size = %d", (int) packet_size); + if (!abort_cmd) { + rc = -ENOMEM; + return rc; + } + + abort_cmd->size = packet_size; + abort_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_ABORT; + else + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_ABORT; + + abort_cmd->num_fw_handles = 1; + abort_cmd->fw_handles[0] = ctx_data->fw_handle; + abort_cmd->user_data1 = PTR_TO_U64(ctx_data); + abort_cmd->user_data2 = (uint64_t)0x0; + + rc = hfi_write_cmd(abort_cmd); + if (rc) { + kfree(abort_cmd); + return rc; + } + CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK ctx_id %d", + ctx_data->fw_handle, ctx_data, ctx_data->ctx_id); + + kfree(abort_cmd); + return rc; +} + static int cam_icp_mgr_abort_handle( struct cam_icp_hw_ctx_data *ctx_data) { int rc = 0; - unsigned long rem_jiffies; + unsigned long rem_jiffies = 0; size_t packet_size; int timeout = 1000; struct hfi_cmd_ipebps_async *abort_cmd; @@ -3196,6 +3248,7 @@ static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id) hw_mgr->ctx_data[ctx_id].fw_handle = 0; hw_mgr->ctx_data[ctx_id].scratch_mem_size = 0; + hw_mgr->ctx_data[ctx_id].last_flush_req = 0; for (i = 0; i < CAM_FRAME_CMD_MAX; i++) clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap); kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap); @@ -3803,6 +3856,11 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) CAM_ERR(CAM_ICP, "Fail to send reconfig io cmd"); } + if (req_id <= ctx_data->last_flush_req) + CAM_WARN(CAM_ICP, + "Anomaly submitting flushed req %llu [last_flush %llu] in ctx %u", + req_id, ctx_data->last_flush_req, ctx_data->ctx_id); + rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args); if (rc) goto config_err; @@ -4852,6 +4910,46 @@ static void cam_icp_mgr_flush_info_dump( } } +static int cam_icp_mgr_enqueue_abort( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int timeout = 1000, rc; + unsigned long rem_jiffies = 0; + struct hfi_cmd_work_data *task_data; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + return -ENOMEM; + } + + reinit_completion(&ctx_data->wait_complete); + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)ctx_data; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_abort_handle_wq; + cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = cam_icp_retry_wait_for_abort(ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, + "FW timeout/err in abort handle command ctx: %u", + ctx_data->ctx_id); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + return rc; + } + } + + CAM_DBG(CAM_ICP, "Abort after flush is success"); + return 0; +} + static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; @@ -4876,9 +4974,10 @@ static int cam_icp_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); - + 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); switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: mutex_lock(&hw_mgr->hw_mgr_mutex); @@ -4887,7 +4986,7 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) mutex_unlock(&hw_mgr->hw_mgr_mutex); cam_icp_mgr_flush_info_dump(flush_args, ctx_data->ctx_id); - cam_icp_mgr_abort_handle(ctx_data); + cam_icp_mgr_enqueue_abort(ctx_data); } else { mutex_unlock(&hw_mgr->hw_mgr_mutex); } diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 7ca32efd9318..8cab9a80cd30 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -232,6 +232,7 @@ struct cam_ctx_clk_info { * @watch_dog: watchdog timer handle * @watch_dog_reset_counter: Counter for watch dog reset * @icp_dev_io_info: io config resource + * @last_flush_req: last flush req for this ctx */ struct cam_icp_hw_ctx_data { void *context_priv; @@ -253,6 +254,7 @@ struct cam_icp_hw_ctx_data { struct cam_req_mgr_timer *watch_dog; uint32_t watch_dog_reset_counter; struct cam_icp_acquire_dev_info icp_dev_io_info; + uint64_t last_flush_req; }; /** diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 83748a935b91..0817f66f5392 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -296,6 +296,7 @@ static void cam_smmu_page_fault_work(struct work_struct *work) buf_info); } } + cam_smmu_dump_cb_info(idx); kfree(payload); } @@ -432,8 +433,9 @@ static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr) if (closest_mapping) { buf_handle = GET_MEM_HANDLE(idx, closest_mapping->ion_fd); CAM_INFO(CAM_SMMU, - "Closest map fd %d 0x%lx 0x%lx-0x%lx buf=%pK mem %0x", + "Closest map fd %d 0x%lx %llu-%llu 0x%lx-0x%lx buf=%pK mem %0x", closest_mapping->ion_fd, current_addr, + mapping->len, closest_mapping->len, (unsigned long)closest_mapping->paddr, (unsigned long)closest_mapping->paddr + mapping->len, closest_mapping->buf, -- GitLab From 7ff13b27746f2b57180bcfbde95d95f0bd5ef911 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 19 Dec 2019 22:26:37 -0800 Subject: [PATCH 036/295] msm: camera: smmu: Add support for non-contiguous mermory region Add support to discard a memory region inside the full dma map virtual address space region. CRs-Fixed: 2580128 Change-Id: I76cc778f2437a01a4efabec836ce92c47d983d61 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_icp/fw_inc/hfi_intf.h | 2 + drivers/cam_icp/fw_inc/hfi_reg.h | 2 + drivers/cam_icp/hfi.c | 17 +++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 74 ++++++++-- drivers/cam_smmu/cam_smmu_api.c | 136 +++++++++++++++++- drivers/cam_smmu/cam_smmu_api.h | 13 +- 6 files changed, 226 insertions(+), 18 deletions(-) diff --git a/drivers/cam_icp/fw_inc/hfi_intf.h b/drivers/cam_icp/fw_inc/hfi_intf.h index 1dcf4ee3668a..afd42d23b9fb 100644 --- a/drivers/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/cam_icp/fw_inc/hfi_intf.h @@ -32,6 +32,7 @@ struct hfi_mem { * @sec_heap: secondary heap hfi memory for firmware * @qdss: qdss mapped memory for fw * @io_mem: io memory info + * @io_mem2: 2nd io memory info * @icp_base: icp base address */ struct hfi_mem_info { @@ -44,6 +45,7 @@ struct hfi_mem_info { struct hfi_mem shmem; struct hfi_mem qdss; struct hfi_mem io_mem; + struct hfi_mem io_mem2; void __iomem *icp_base; }; diff --git a/drivers/cam_icp/fw_inc/hfi_reg.h b/drivers/cam_icp/fw_inc/hfi_reg.h index f67a7044f26b..68701c8f7d22 100644 --- a/drivers/cam_icp/fw_inc/hfi_reg.h +++ b/drivers/cam_icp/fw_inc/hfi_reg.h @@ -39,6 +39,8 @@ #define HFI_REG_QDSS_IOVA_SIZE 0x70 #define HFI_REG_IO_REGION_IOVA 0x74 #define HFI_REG_IO_REGION_SIZE 0x78 +#define HFI_REG_IO2_REGION_IOVA 0x7C +#define HFI_REG_IO2_REGION_SIZE 0x80 /* end of ICP CSR registers */ diff --git a/drivers/cam_icp/hfi.c b/drivers/cam_icp/hfi.c index 783b5c3723be..b20565cf2d44 100644 --- a/drivers/cam_icp/hfi.c +++ b/drivers/cam_icp/hfi.c @@ -671,6 +671,15 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem, cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, icp_base + HFI_REG_IO_REGION_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.iova, + icp_base + HFI_REG_IO2_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.len, + icp_base + HFI_REG_IO2_REGION_SIZE); + + CAM_INFO(CAM_HFI, "Resume IO1 : [0x%x 0x%x] IO2 [0x%x 0x%x]", + hfi_mem->io_mem.iova, hfi_mem->io_mem.len, + hfi_mem->io_mem2.iova, hfi_mem->io_mem2.len); + return rc; } @@ -862,6 +871,14 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, icp_base + HFI_REG_IO_REGION_IOVA); cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, icp_base + HFI_REG_IO_REGION_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.iova, + icp_base + HFI_REG_IO2_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.len, + icp_base + HFI_REG_IO2_REGION_SIZE); + + CAM_INFO(CAM_HFI, "Init IO1 : [0x%x 0x%x] IO2 [0x%x 0x%x]", + hfi_mem->io_mem.iova, hfi_mem->io_mem.len, + hfi_mem->io_mem2.iova, hfi_mem->io_mem2.len); hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION); diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index e82c04b44890..5add1234fa38 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -2710,18 +2710,21 @@ static int cam_icp_allocate_qdss_mem(void) static int cam_icp_get_io_mem_info(void) { int rc; - size_t len; - dma_addr_t iova; + size_t len, discard_iova_len; + dma_addr_t iova, discard_iova_start; rc = cam_smmu_get_io_region_info(icp_hw_mgr.iommu_hdl, - &iova, &len); + &iova, &len, &discard_iova_start, &discard_iova_len); if (rc) return rc; icp_hw_mgr.hfi_mem.io_mem.iova_len = len; icp_hw_mgr.hfi_mem.io_mem.iova_start = iova; + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start = discard_iova_start; + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len = discard_iova_len; - CAM_DBG(CAM_ICP, "iova: %llx, len: %zu", iova, len); + CAM_DBG(CAM_ICP, "iova: %llx, len: %zu discard iova %llx len %llx", + iova, len, discard_iova_start, discard_iova_len); return rc; } @@ -3014,12 +3017,38 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; - hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; - hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + if (icp_hw_mgr.hfi_mem.io_mem.discard_iova_start && + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len) { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start - + icp_hw_mgr.hfi_mem.io_mem.iova_start; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start + + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len; + hfi_mem.io_mem2.len = + icp_hw_mgr.hfi_mem.io_mem.iova_start + + icp_hw_mgr.hfi_mem.io_mem.iova_len - + hfi_mem.io_mem2.iova; + } else { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; - CAM_DBG(CAM_ICP, "IO region IOVA = %X length = %lld", - hfi_mem.io_mem.iova, - hfi_mem.io_mem.len); + /* IO Region 2 */ + hfi_mem.io_mem2.iova = 0x0; + hfi_mem.io_mem2.len = 0x0; + } + + CAM_DBG(CAM_ICP, + "IO region1 IOVA = %X length = %lld, IO region2 IOVA = %X length = %lld", + hfi_mem.io_mem.iova, + hfi_mem.io_mem.len, + hfi_mem.io_mem2.iova, + hfi_mem.io_mem2.len); return cam_hfi_resume(&hfi_mem, a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, @@ -3401,8 +3430,31 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; - hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; - hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + if (icp_hw_mgr.hfi_mem.io_mem.discard_iova_start && + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len) { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start - + icp_hw_mgr.hfi_mem.io_mem.iova_start; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start + + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len; + hfi_mem.io_mem2.len = + icp_hw_mgr.hfi_mem.io_mem.iova_start + + icp_hw_mgr.hfi_mem.io_mem.iova_len - + hfi_mem.io_mem2.iova; + } else { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = 0x0; + hfi_mem.io_mem2.len = 0x0; + } return cam_hfi_init(0, &hfi_mem, a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 83748a935b91..650a0c298b53 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -14,6 +14,8 @@ #include #include #include +#include + #include #include #include @@ -137,6 +139,10 @@ struct cam_context_bank_info { bool is_mul_client; int device_count; int num_shared_hdl; + + /* discard iova - non-zero values are valid */ + dma_addr_t discard_iova_start; + size_t discard_iova_len; }; struct cam_iommu_cb_set { @@ -1450,11 +1456,13 @@ int cam_smmu_dealloc_qdss(int32_t smmu_hdl) EXPORT_SYMBOL(cam_smmu_dealloc_qdss); int cam_smmu_get_io_region_info(int32_t smmu_hdl, - dma_addr_t *iova, size_t *len) + dma_addr_t *iova, size_t *len, + dma_addr_t *discard_iova_start, size_t *discard_iova_len) { int32_t idx; - if (!iova || !len || (smmu_hdl == HANDLE_INIT)) { + if (!iova || !len || !discard_iova_start || !discard_iova_len || + (smmu_hdl == HANDLE_INIT)) { CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); return -EINVAL; } @@ -1476,10 +1484,15 @@ int cam_smmu_get_io_region_info(int32_t smmu_hdl, mutex_lock(&iommu_cb_set.cb_info[idx].lock); *iova = iommu_cb_set.cb_info[idx].io_info.iova_start; *len = iommu_cb_set.cb_info[idx].io_info.iova_len; + *discard_iova_start = + iommu_cb_set.cb_info[idx].io_info.discard_iova_start; + *discard_iova_len = + iommu_cb_set.cb_info[idx].io_info.discard_iova_len; CAM_DBG(CAM_SMMU, - "I/O area for hdl = %x start addr = %pK len = %zu", - smmu_hdl, *iova, *len); + "I/O area for hdl = %x Region:[%pK %zu] Discard:[%pK %zu]", + smmu_hdl, *iova, *len, + *discard_iova_start, *discard_iova_len); mutex_unlock(&iommu_cb_set.cb_info[idx].lock); return 0; @@ -3324,6 +3337,11 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, rc = -ENODEV; goto end; } + + if (cb->discard_iova_start) + iommu_dma_reserve_iova(dev, cb->discard_iova_start, + cb->discard_iova_len); + cb->state = CAM_SMMU_ATTACH; } else { CAM_ERR(CAM_SMMU, "Context bank does not have IO region"); @@ -3390,6 +3408,52 @@ static int cam_alloc_smmu_context_banks(struct device *dev) return 0; } +static int cam_smmu_get_discard_memory_regions(struct device_node *of_node, + dma_addr_t *discard_iova_start, size_t *discard_iova_len) +{ + uint32_t discard_iova[2] = { 0 }; + int num_values = 0; + int rc = 0; + + if (!discard_iova_start || !discard_iova_len) + return -EINVAL; + + *discard_iova_start = 0; + *discard_iova_len = 0; + + num_values = of_property_count_u32_elems(of_node, + "iova-region-discard"); + if (num_values <= 0) { + CAM_DBG(CAM_UTIL, "No discard region specified"); + return 0; + } else if (num_values != 2) { + CAM_ERR(CAM_UTIL, "Invalid discard region specified %d", + num_values); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, + "iova-region-discard", + discard_iova, num_values); + if (rc) { + CAM_ERR(CAM_UTIL, "Can not read discard region %d", num_values); + return rc; + } else if (!discard_iova[0] || !discard_iova[1]) { + CAM_ERR(CAM_UTIL, + "Incorrect Discard region specified [0x%x 0x%x]", + discard_iova[0], discard_iova[1]); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, "Discard region [0x%x 0x%x]", + discard_iova[0], discard_iova[0] + discard_iova[1]); + + *discard_iova_start = discard_iova[0]; + *discard_iova_len = discard_iova[1]; + + return 0; +} + static int cam_smmu_get_memory_regions_info(struct device_node *of_node, struct cam_context_bank_info *cb) { @@ -3488,6 +3552,16 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, cb->io_support = 1; cb->io_info.iova_start = region_start; cb->io_info.iova_len = region_len; + rc = cam_smmu_get_discard_memory_regions(child_node, + &cb->io_info.discard_iova_start, + &cb->io_info.discard_iova_len); + if (rc) { + CAM_ERR(CAM_SMMU, + "Invalid Discard region specified in IO region, rc=%d", + rc); + of_node_put(mem_map_node); + return -EINVAL; + } break; case CAM_SMMU_REGION_SECHEAP: cb->secheap_support = 1; @@ -3512,6 +3586,60 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, CAM_DBG(CAM_SMMU, "region_len -> %X", region_len); CAM_DBG(CAM_SMMU, "region_id -> %X", region_id); } + + if (cb->io_support) { + rc = cam_smmu_get_discard_memory_regions(of_node, + &cb->discard_iova_start, + &cb->discard_iova_len); + if (rc) { + CAM_ERR(CAM_SMMU, + "Invalid Discard region specified in CB, rc=%d", + rc); + of_node_put(mem_map_node); + return -EINVAL; + } + + /* Make sure Discard region is properly specified */ + if ((cb->discard_iova_start != + cb->io_info.discard_iova_start) || + (cb->discard_iova_len != + cb->io_info.discard_iova_len)) { + CAM_ERR(CAM_SMMU, + "Mismatch Discard region specified, [0x%x 0x%x] [0x%x 0x%x]", + cb->discard_iova_start, + cb->discard_iova_len, + cb->io_info.discard_iova_start, + cb->io_info.discard_iova_len); + of_node_put(mem_map_node); + return -EINVAL; + } else if (cb->discard_iova_start && cb->discard_iova_len) { + if ((cb->discard_iova_start <= + cb->io_info.iova_start) || + (cb->discard_iova_start >= + cb->io_info.iova_start + cb->io_info.iova_len) || + (cb->discard_iova_start + cb->discard_iova_len >= + cb->io_info.iova_start + cb->io_info.iova_len)) { + CAM_ERR(CAM_SMMU, + "[%s] : Incorrect Discard region specified [0x%x 0x%x] in [0x%x 0x%x]", + cb->name, + cb->discard_iova_start, + cb->discard_iova_start + cb->discard_iova_len, + cb->io_info.iova_start, + cb->io_info.iova_start + cb->io_info.iova_len); + of_node_put(mem_map_node); + return -EINVAL; + } + + CAM_INFO(CAM_SMMU, + "[%s] : Discard region specified [0x%x 0x%x] in [0x%x 0x%x]", + cb->name, + cb->discard_iova_start, + cb->discard_iova_start + cb->discard_iova_len, + cb->io_info.iova_start, + cb->io_info.iova_start + cb->io_info.iova_len); + } + } + of_node_put(mem_map_node); if (!num_regions) { diff --git a/drivers/cam_smmu/cam_smmu_api.h b/drivers/cam_smmu/cam_smmu_api.h index 935e813d450a..4a4a0d312f9d 100644 --- a/drivers/cam_smmu/cam_smmu_api.h +++ b/drivers/cam_smmu/cam_smmu_api.h @@ -60,12 +60,16 @@ typedef void (*cam_smmu_client_page_fault_handler)(struct iommu_domain *domain, /** * @brief : Structure to store region information * - * @param iova_start : Start address of region - * @param iova_len : length of region + * @param iova_start : Start address of region + * @param iova_len : length of region + * @param discard_iova_start : iova addr start from where should not be used + * @param discard_iova_len : length of discard iova region */ struct cam_smmu_region_info { dma_addr_t iova_start; size_t iova_len; + dma_addr_t discard_iova_start; + size_t discard_iova_len; }; /** @@ -387,10 +391,13 @@ int cam_smmu_dealloc_qdss(int32_t smmu_hdl); * @param smmu_hdl: SMMU handle identifying the context bank * @param iova: IOVA address of allocated I/O region * @param len: Length of allocated I/O memory + * @param discard_iova_start: Start address of io space to discard + * @param discard_iova_len: Length of io space to discard * * @return Status of operation. Negative in case of error. Zero otherwise. */ int cam_smmu_get_io_region_info(int32_t smmu_hdl, - dma_addr_t *iova, size_t *len); + dma_addr_t *iova, size_t *len, + dma_addr_t *discard_iova_start, size_t *discard_iova_len); #endif /* _CAM_SMMU_API_H_ */ -- GitLab From 88432ee85ba46913f7a240819b52164b956443de Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 19 Dec 2019 22:25:37 -0800 Subject: [PATCH 037/295] msm: camera: smmu: Use iommu best match algo for camera Use best fit match algo for smmu map instead of first match algo to avoid fragmentation in smmu virtual space. CRs-Fixed: 2580128 Change-Id: I434e6e4396bc713e6e12e3da7ae4b78cc2da6a42 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_smmu/cam_smmu_api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 650a0c298b53..a6dc071ebd69 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -3338,6 +3338,8 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, goto end; } + iommu_dma_enable_best_fit_algo(dev); + if (cb->discard_iova_start) iommu_dma_reserve_iova(dev, cb->discard_iova_start, cb->discard_iova_len); -- GitLab From f078feeca214f69a8d3e1621a0ce0bb43daee33c Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Tue, 17 Dec 2019 17:18:18 +0530 Subject: [PATCH 038/295] msm: camera: ope: Optimize allocation of IO configuration Allocate IO configuration separately from request allocation according to received IO config during packet parsing. CRs-Fixed: 2587416 Change-Id: I29a994b85cc4aaef085c0dfddc83318cce130b6c Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 31 +++++++++++++++++-- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 2 +- .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 6 ++-- .../ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c | 6 ++-- 4 files changed, 36 insertions(+), 9 deletions(-) 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 c55d22590c99..2e87625ccff4 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 @@ -125,6 +125,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) { @@ -1140,6 +1154,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); @@ -1273,7 +1288,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; @@ -1433,7 +1448,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); @@ -2286,6 +2309,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); @@ -2638,6 +2662,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); @@ -2793,6 +2818,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 +2851,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); 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 122771715357..78fc3499a352 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 @@ -398,7 +398,7 @@ 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; 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 934cb715cc97..c34ccdd6d76c 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 @@ -98,7 +98,7 @@ 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 = @@ -171,7 +171,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); @@ -434,7 +434,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; 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 44e5cd98d133..2ade0924be94 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 @@ -43,7 +43,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) @@ -217,7 +217,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); @@ -483,7 +483,7 @@ static int cam_ope_bus_wr_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]; CAM_DBG(CAM_OPE, "batch = %d io buf num = %d dir = %d", i, j, io_buf->direction); if (io_buf->direction != CAM_BUF_OUTPUT) -- GitLab From d49a766926ebf2666fe4d0ab471ef8ab8048bcff Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 23 Dec 2019 14:54:50 +0530 Subject: [PATCH 039/295] msm: camera: ope: Fix for KW Issues Fix KW Issues in OPE driver. CRs-Fixed: 2585713 Change-Id: I355d65a92f9862a3b290be05555df0338a842bdd Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 9 +++++--- .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 21 +++++++++++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) 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 c55d22590c99..c587033eba61 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 @@ -1305,12 +1305,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 +1334,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; 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 934cb715cc97..c8ad29a48307 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 @@ -104,6 +104,10 @@ static int cam_ope_bus_is_rm_enabled( 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]) @@ -324,6 +328,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 +412,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); @@ -469,12 +478,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; + } } } -- GitLab From 59ba70d931fef2e30fbad9956cb884beabbf98ca Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Wed, 18 Dec 2019 18:25:56 +0530 Subject: [PATCH 040/295] msm: camera: ope: Add support for stripe level height configuration For some usecase, height changes of stripe level. So, added the support to configure height at stripe level. CRs-Fixed: 2520602 Change-Id: I59a77b7ef7a82efac4c32fec9978469ef40ef0ae Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 2 +- include/uapi/media/cam_ope.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) 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 c55d22590c99..1736f061ac08 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 @@ -1510,7 +1510,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 = diff --git a/include/uapi/media/cam_ope.h b/include/uapi/media/cam_ope.h index 7b4ed57b778e..e8d0426c746f 100644 --- a/include/uapi/media/cam_ope.h +++ b/include/uapi/media/cam_ope.h @@ -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 * @@ -92,6 +93,7 @@ struct ope_stripe_info { uint32_t x_init; uint32_t stripe_location; uint32_t width; + uint32_t height; uint32_t disable_bus; uint32_t reserved; }; -- GitLab From 155b66eba2b27f711ee24e685d20339940896a42 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Wed, 25 Dec 2019 10:27:37 +0530 Subject: [PATCH 041/295] msm: camera: tfe: Enable the delay line clc Delay line CLC is required for tfe stats. Enable it by default. CRs-Fixed: 2585713 Change-Id: Ic668097eb941ecffcd892a4ed48e6a0701847961 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 3 +++ 1 file changed, 3 insertions(+) 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 eb0c4bb2cb0e..f886fd53087b 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 @@ -1604,6 +1604,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(8); + cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg_0); -- GitLab From 8fccb26c05e088d0f898d566327f3cdc3febcdc3 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 5 Sep 2019 23:45:51 -0700 Subject: [PATCH 042/295] msm: camera: csiphy: Correct Dphy mission mode sequence DPHY mission mode sequence is not full functional for mission mode. Correct and add mandate register settings for the bringup of DPHY mission mode. CRs-Fixed: 2545921 Change-Id: Ia1bbf496c5aa993cf0e404c81f7b69b7b889c6f1 Signed-off-by: Jigarkumar Zala --- .../include/cam_csiphy_1_2_1_hwreg.h | 130 ++++++++---------- 1 file changed, 60 insertions(+), 70 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index 4f9fd086a97d..c78af37b579e 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -14,7 +14,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_1 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 21, + .csiphy_2ph_config_array_size = 19, .csiphy_3ph_config_array_size = 34, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -55,118 +55,108 @@ struct csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0600, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; -- GitLab From 136df5340b60eb489605aa0b7654ce701558ff5b Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 10 Oct 2019 17:22:23 -0700 Subject: [PATCH 043/295] msm: camera: csiphy: Update DPHY combo mode sequence DPHY combo mode bring up sequence is missing with some important register settings. Correct and update required register setting to bringup DPHY combo mode. CRs-Fixed: 2545921 Change-Id: I1dfb71f1775aa6d6b1173a7de7f14ce74eac08e1 Signed-off-by: Jigarkumar Zala --- .../include/cam_csiphy_1_2_1_hwreg.h | 138 +++++++++--------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index c78af37b579e..32fbf47eabd9 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -14,7 +14,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_1 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 19, + .csiphy_2ph_config_array_size = 20, .csiphy_3ph_config_array_size = 34, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -71,6 +71,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -92,6 +93,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -113,6 +115,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -134,6 +137,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -155,6 +159,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -164,118 +169,113 @@ struct csiphy_reg_t csiphy_2ph_v1_2_1_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0x16, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x060c, 0x16, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; -- GitLab From 578d53adfff647cc6b4cded236f2734914e40561 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Mon, 28 Oct 2019 12:11:02 -0700 Subject: [PATCH 044/295] msm: camera: icp: Use CAM_PERF for clock, bw related logs Use CAM_PERF logging group while printing logs related to clock, bandwidth updates. CRs-Fixed: 2523062 Change-Id: Icaa912ae308c307d55e318c0861850093d0ee456 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_icp/icp_hw/bps_hw/bps_core.c | 16 ++-- drivers/cam_icp/icp_hw/bps_hw/bps_soc.c | 2 +- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 91 ++++++++++--------- drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c | 16 ++-- drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c | 2 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 21 +++-- 6 files changed, 75 insertions(+), 73 deletions(-) diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c index 232f29c81db6..8a079bd14202 100644 --- a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c @@ -40,7 +40,7 @@ static int cam_bps_cpas_vote(struct cam_bps_device_core_info *core_info, &cpas_vote->axi_vote); if (rc < 0) - CAM_ERR(CAM_ICP, "cpas vote is failed: %d", rc); + CAM_ERR(CAM_PERF, "cpas vote is failed: %d", rc); return rc; } @@ -171,7 +171,7 @@ static int cam_bps_handle_pc(struct cam_hw_info *bps_dev) hw_info->pwr_ctrl, true, 0x1); if ((pwr_status >> BPS_PWR_ON_MASK)) - CAM_WARN(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", + CAM_WARN(CAM_PERF, "BPS: pwr_status(%x):pwr_ctrl(%x)", pwr_status, pwr_ctrl); } cam_bps_get_gdsc_control(soc_info); @@ -181,7 +181,7 @@ static int cam_bps_handle_pc(struct cam_hw_info *bps_dev) cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); - CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", pwr_ctrl, pwr_status); return 0; @@ -203,7 +203,7 @@ static int cam_bps_handle_resume(struct cam_hw_info *bps_dev) cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); if (pwr_ctrl & BPS_COLLAPSE_MASK) { - CAM_DBG(CAM_ICP, "BPS: pwr_ctrl set(%x)", pwr_ctrl); + CAM_DBG(CAM_PERF, "BPS: pwr_ctrl set(%x)", pwr_ctrl); cam_cpas_reg_write(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, 0); @@ -214,7 +214,7 @@ static int cam_bps_handle_resume(struct cam_hw_info *bps_dev) CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); - CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", pwr_ctrl, pwr_status); return rc; @@ -370,7 +370,7 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; int32_t clk_level = 0, err = 0; - CAM_DBG(CAM_ICP, "bps_src_clk rate = %d", (int)clk_rate); + CAM_DBG(CAM_PERF, "bps_src_clk rate = %d", (int)clk_rate); if (!core_info->clk_enable) { if (clk_upd_cmd->ipe_bps_pc_enable) { @@ -390,10 +390,10 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, CAM_ERR(CAM_ICP, "BPS resume failed"); } } - CAM_DBG(CAM_ICP, "clock rate %d", clk_rate); + CAM_DBG(CAM_PERF, "clock rate %d", clk_rate); rc = cam_bps_update_clk_rate(soc_info, clk_rate); if (rc) - CAM_ERR(CAM_ICP, "Failed to update clk"); + CAM_ERR(CAM_PERF, "Failed to update clk %d", clk_rate); err = cam_soc_util_get_clk_level(soc_info, clk_rate, soc_info->src_clk_idx, diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c index bf152d1fc485..481eeafdb0b2 100644 --- a/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c @@ -140,7 +140,7 @@ int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info, if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) && (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { - CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d", + CAM_DBG(CAM_PERF, "clk_rate %d greater than max, reset to %d", clk_rate, soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index d577f4c9b3d6..a09f1e35f485 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -182,7 +182,7 @@ static bool cam_icp_is_over_clk(struct cam_icp_hw_mgr *hw_mgr, curr_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data, hw_mgr_clk_info->curr_clk); - CAM_DBG(CAM_ICP, "bc_idx = %d cc_idx = %d %d %d", + CAM_DBG(CAM_PERF, "bc_idx = %d cc_idx = %d %d %d", base_clk_idx, curr_clk_idx, hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); @@ -202,7 +202,7 @@ static int cam_icp_get_lower_clk_rate(struct cam_icp_hw_mgr *hw_mgr, if (i > 0) return ctx_data->clk_info.clk_rate[i - 1]; - CAM_DBG(CAM_ICP, "Already clk at lower level"); + CAM_DBG(CAM_PERF, "Already clk at lower level"); return base_clk; } @@ -216,7 +216,7 @@ static int cam_icp_get_next_clk_rate(struct cam_icp_hw_mgr *hw_mgr, if (i < CAM_MAX_VOTE - 1) return ctx_data->clk_info.clk_rate[i + 1]; - CAM_DBG(CAM_ICP, "Already clk at higher level"); + CAM_DBG(CAM_PERF, "Already clk at higher level"); return base_clk; } @@ -256,7 +256,7 @@ static int cam_icp_supported_clk_rates(struct cam_icp_hw_mgr *hw_mgr, for (i = 0; i < CAM_MAX_VOTE; i++) { ctx_data->clk_info.clk_rate[i] = soc_info->clk_rate[i][soc_info->src_clk_idx]; - CAM_DBG(CAM_ICP, "clk_info[%d] = %d", + CAM_DBG(CAM_PERF, "clk_info[%d] = %d", i, ctx_data->clk_info.clk_rate[i]); } @@ -307,7 +307,7 @@ static int cam_icp_ctx_timer_reset(struct cam_icp_hw_ctx_data *ctx_data) { if (ctx_data && ctx_data->watch_dog) { ctx_data->watch_dog_reset_counter++; - CAM_DBG(CAM_ICP, "reset timer : ctx_id = %d, counter=%d", + CAM_DBG(CAM_PERF, "reset timer : ctx_id = %d, counter=%d", ctx_data->ctx_id, ctx_data->watch_dog_reset_counter); crm_timer_reset(ctx_data->watch_dog); } @@ -322,7 +322,7 @@ static void cam_icp_device_timer_reset(struct cam_icp_hw_mgr *hw_mgr, return; if (hw_mgr->clk_info[device_index].watch_dog) { - CAM_DBG(CAM_ICP, "reset timer : device_index = %d", + CAM_DBG(CAM_PERF, "reset timer : device_index = %d", device_index); crm_timer_reset(hw_mgr->clk_info[device_index].watch_dog); hw_mgr->clk_info[device_index].watch_dog_reset_counter++; @@ -396,7 +396,7 @@ static int32_t cam_icp_deinit_idle_clk(void *priv, void *data) goto done; } - CAM_DBG(CAM_ICP, "Disable %d", clk_info->hw_type); + CAM_DBG(CAM_PERF, "Disable %d", clk_info->hw_type); clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag; @@ -441,7 +441,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) mutex_lock(&ctx_data->ctx_mutex); if ((ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) || (ctx_data->watch_dog_reset_counter == 0)) { - CAM_DBG(CAM_ICP, "state %d, counter=%d", + CAM_DBG(CAM_PERF, "state %d, counter=%d", ctx_data->state, ctx_data->watch_dog_reset_counter); mutex_unlock(&ctx_data->ctx_mutex); return 0; @@ -453,7 +453,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) return -EBUSY; } - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "E :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", ctx_data->ctx_id, ctx_data->clk_info.uncompressed_bw, @@ -560,7 +560,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) } if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { - CAM_WARN(CAM_ICP, + CAM_WARN(CAM_PERF, "Invalid path %d, start offset=%d, max=%d", ctx_data->clk_info.axi_path[i] .path_data_type, @@ -641,7 +641,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) ipe1_dev_intf->hw_ops.process_cmd(ipe1_dev_intf->hw_priv, id, &clk_update, sizeof(clk_update)); - CAM_DBG(CAM_ICP, "X :ctx_id = %d curr_fc = %u bc = %u", + CAM_DBG(CAM_PERF, "X :ctx_id = %d curr_fc = %u bc = %u", ctx_data->ctx_id, ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk); mutex_unlock(&ctx_data->ctx_mutex); @@ -739,7 +739,7 @@ static int cam_icp_ctx_timer_start(struct cam_icp_hw_ctx_data *ctx_data) ctx_data->watch_dog_reset_counter = 0; - CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + CAM_DBG(CAM_PERF, "start timer : ctx_id = %d", ctx_data->ctx_id); return rc; } @@ -767,7 +767,7 @@ static int cam_icp_device_timer_start(struct cam_icp_hw_mgr *hw_mgr) static int cam_icp_ctx_timer_stop(struct cam_icp_hw_ctx_data *ctx_data) { if (ctx_data->watch_dog) { - CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + CAM_DBG(CAM_PERF, "stop timer : ctx_id = %d", ctx_data->ctx_id); ctx_data->watch_dog_reset_counter = 0; crm_timer_exit(&ctx_data->watch_dog); ctx_data->watch_dog = NULL; @@ -802,7 +802,7 @@ static uint32_t cam_icp_mgr_calc_base_clk(uint32_t frame_cycles, base_clk = frame_cycles * mul; do_div(base_clk, budget); - CAM_DBG(CAM_ICP, "budget = %lld fc = %d ib = %lld base_clk = %lld", + CAM_DBG(CAM_PERF, "budget = %lld fc = %d ib = %lld base_clk = %lld", budget, frame_cycles, (long long)(frame_cycles * mul), base_clk); @@ -818,7 +818,7 @@ static bool cam_icp_busy_prev_reqs(struct hfi_frame_process_info *frm_process, for (i = 0, cnt = 0; i < CAM_FRAME_CMD_MAX; i++) { if (frm_process->request_id[i]) { if (frm_process->fw_process_flag[i]) { - CAM_DBG(CAM_ICP, "r id = %lld busy = %d", + CAM_DBG(CAM_PERF, "r id = %lld busy = %d", frm_process->request_id[i], frm_process->fw_process_flag[i]); cnt++; @@ -1010,7 +1010,7 @@ static bool cam_icp_debug_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_debug_clk; hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_debug_clk; hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_debug_clk; - CAM_DBG(CAM_ICP, "bc = %d cc = %d", + CAM_DBG(CAM_PERF, "bc = %d cc = %d", hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); return true; } @@ -1025,7 +1025,7 @@ static bool cam_icp_default_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_default_clk; hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_default_clk; hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_default_clk; - CAM_DBG(CAM_ICP, "bc = %d cc = %d", + CAM_DBG(CAM_PERF, "bc = %d cc = %d", hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); return true; } @@ -1049,7 +1049,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, */ for (i = 0; i < clk_info->num_paths; i++) - CAM_DBG(CAM_ICP, "clk_info camnoc = %lld busy = %d", + CAM_DBG(CAM_PERF, "clk_info camnoc = %lld busy = %d", clk_info->axi_path[i].camnoc_bw, busy); if (clk_info->num_paths == ctx_data->clk_info.num_paths) { @@ -1072,7 +1072,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, } if (!update_required) { - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Incoming BW hasn't changed, no update required, num_paths=%d", clk_info->num_paths); return false; @@ -1104,7 +1104,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, } if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { - CAM_WARN(CAM_ICP, + CAM_WARN(CAM_PERF, "Invalid path %d, start offset=%d, max=%d", ctx_data->clk_info.axi_path[i].path_data_type, CAM_AXI_PATH_DATA_IPE_START_OFFSET, @@ -1148,7 +1148,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, } if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { - CAM_WARN(CAM_ICP, + CAM_WARN(CAM_PERF, "Invalid path %d, start offset=%d, max=%d", ctx_data->clk_info.axi_path[i].path_data_type, CAM_AXI_PATH_DATA_IPE_START_OFFSET, @@ -1171,7 +1171,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, hw_mgr_clk_info->axi_path[path_index].ddr_ib_bw += ctx_data->clk_info.axi_path[i].ddr_ib_bw; - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Consolidate Path Vote : Dev[%s] i[%d] path_idx[%d] : [%s %s] [%lld %lld]", cam_icp_dev_type_to_name( ctx_data->icp_dev_acquire_info->dev_type), @@ -1204,14 +1204,14 @@ static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, * recalculate bandwidth of all contexts of same hardware and update * voting of bandwidth */ - CAM_DBG(CAM_ICP, "ubw ctx = %lld clk_info ubw = %lld busy = %d", + CAM_DBG(CAM_PERF, "ubw ctx = %lld clk_info ubw = %lld busy = %d", ctx_data->clk_info.uncompressed_bw, clk_info->uncompressed_bw, busy); if ((clk_info->uncompressed_bw == ctx_data->clk_info.uncompressed_bw) && (ctx_data->clk_info.uncompressed_bw == hw_mgr_clk_info->uncompressed_bw)) { - CAM_DBG(CAM_ICP, "Update not required bw=%lld", + CAM_DBG(CAM_PERF, "Update not required bw=%lld", ctx_data->clk_info.uncompressed_bw); return false; } @@ -1219,7 +1219,8 @@ static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, if (busy && (ctx_data->clk_info.uncompressed_bw > clk_info->uncompressed_bw)) { - CAM_DBG(CAM_ICP, "Busy, Update not req existing=%lld, new=%lld", + CAM_DBG(CAM_PERF, + "Busy, Update not req existing=%lld, new=%lld", ctx_data->clk_info.uncompressed_bw, clk_info->uncompressed_bw); return false; @@ -1240,7 +1241,7 @@ static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, ctx->clk_info.uncompressed_bw; hw_mgr_clk_info->compressed_bw += ctx->clk_info.compressed_bw; - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Current context=[%lld %lld] Total=[%lld %lld]", ctx->clk_info.uncompressed_bw, ctx->clk_info.compressed_bw, @@ -1266,11 +1267,11 @@ static bool cam_icp_check_clk_update(struct cam_icp_hw_mgr *hw_mgr, if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_BPS); hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; - CAM_DBG(CAM_ICP, "Reset bps timer"); + CAM_DBG(CAM_PERF, "Reset bps timer"); } else { cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_IPE); hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; - CAM_DBG(CAM_ICP, "Reset ipe timer"); + CAM_DBG(CAM_PERF, "Reset ipe timer"); } if (icp_hw_mgr.icp_debug_clk) @@ -1280,7 +1281,7 @@ static bool cam_icp_check_clk_update(struct cam_icp_hw_mgr *hw_mgr, frame_info = &ctx_data->hfi_frame_process; req_id = frame_info->request_id[idx]; busy = cam_icp_busy_prev_reqs(frame_info, req_id); - CAM_DBG(CAM_ICP, "busy = %d req_id = %lld", busy, req_id); + CAM_DBG(CAM_PERF, "busy = %d req_id = %lld", busy, req_id); clk_info = &ctx_data->hfi_frame_process.clk_info[idx]; if (!clk_info->frame_cycles) @@ -1298,7 +1299,7 @@ static bool cam_icp_check_clk_update(struct cam_icp_hw_mgr *hw_mgr, rc = cam_icp_update_clk_free(hw_mgr, ctx_data, hw_mgr_clk_info, clk_info, base_clk); - CAM_DBG(CAM_ICP, "bc = %d cc = %d busy = %d overclk = %d uc = %d", + CAM_DBG(CAM_PERF, "bc = %d cc = %d busy = %d overclk = %d uc = %d", hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk, busy, hw_mgr_clk_info->over_clked, rc); @@ -1328,7 +1329,7 @@ static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { clk_info = &ctx_data->hfi_frame_process.clk_info[idx]; - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Ctx[%pK][%d] Req[%lld] Current camno=%lld, mnoc=%lld", ctx_data, ctx_data->ctx_id, req_id, hw_mgr_clk_info->uncompressed_bw, @@ -1339,14 +1340,14 @@ static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, } else if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V2) { clk_info_v2 = &ctx_data->hfi_frame_process.clk_info_v2[idx]; - CAM_DBG(CAM_ICP, "index=%d, num_paths=%d, ctx_data=%pK", + CAM_DBG(CAM_PERF, "index=%d, num_paths=%d, ctx_data=%pK", idx, clk_info_v2->num_paths, ctx_data); bw_updated = cam_icp_update_bw_v2(hw_mgr, ctx_data, hw_mgr_clk_info, clk_info_v2, busy); for (i = 0; i < hw_mgr_clk_info->num_paths; i++) { - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Final path_type: %s, transac_type: %s, camnoc_bw = %lld mnoc_ab_bw = %lld, mnoc_ib_bw = %lld, device: %s", cam_cpas_axi_util_path_type_to_string( hw_mgr_clk_info->axi_path[i].path_data_type), @@ -1359,7 +1360,7 @@ static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, ctx_data->icp_dev_acquire_info->dev_type)); } } else { - CAM_ERR(CAM_ICP, "Invalid bw config version: %d", + CAM_ERR(CAM_PERF, "Invalid bw config version: %d", ctx_data->bw_config_version); return false; } @@ -1418,7 +1419,7 @@ static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr, } /* update a5 clock */ - CAM_DBG(CAM_ICP, "Update ICP clk to level [%d]", + CAM_DBG(CAM_PERF, "Update ICP clk to level [%d]", clk_upd_cmd.clk_level); a5_dev_intf->hw_ops.process_cmd(a5_dev_intf->hw_priv, CAM_ICP_A5_CMD_CLK_UPDATE, &clk_upd_cmd.clk_level, @@ -1625,7 +1626,7 @@ static int cam_icp_mgr_ipe_bps_resume(struct cam_icp_hw_mgr *hw_mgr, core_info_mask = ICP_PWR_CLP_IPE0; } - CAM_DBG(CAM_ICP, "core_info %X", core_info_mask); + CAM_DBG(CAM_PERF, "core_info %X", core_info_mask); if (icp_hw_mgr.ipe_bps_pc_flag) rc = hfi_enable_ipe_bps_pc(true, core_info_mask); else @@ -1657,7 +1658,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, dev = ctx_data->icp_dev_acquire_info->dev_type; if (dev == CAM_ICP_RES_TYPE_BPS) { - CAM_DBG(CAM_ICP, "bps ctx cnt %d", hw_mgr->bps_ctxt_cnt); + CAM_DBG(CAM_PERF, "bps ctx cnt %d", hw_mgr->bps_ctxt_cnt); if (ctx_data) --hw_mgr->bps_ctxt_cnt; @@ -1678,7 +1679,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, hw_mgr->bps_clk_state = false; } } else { - CAM_DBG(CAM_ICP, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt); + CAM_DBG(CAM_PERF, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt); if (ctx_data) --hw_mgr->ipe_ctxt_cnt; @@ -2938,7 +2939,7 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) struct cam_hw_intf *a5_dev_intf = NULL; struct cam_hw_info *a5_dev = NULL; - CAM_DBG(CAM_ICP, "ENTER"); + CAM_DBG(CAM_PERF, "ENTER"); a5_dev_intf = hw_mgr->a5_dev_intf; if (!a5_dev_intf) { @@ -2958,7 +2959,7 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); } a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0); - CAM_DBG(CAM_ICP, "EXIT"); + CAM_DBG(CAM_PERF, "EXIT"); return rc; } @@ -4312,7 +4313,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, switch (blob_type) { case CAM_ICP_CMD_GENERIC_BLOB_CLK: - CAM_WARN_RATE_LIMIT_CUSTOM(CAM_ICP, 300, 1, + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_PERF, 300, 1, "Using deprecated blob type GENERIC_BLOB_CLK"); if (blob_size != sizeof(struct cam_icp_clk_bw_request)) { CAM_ERR(CAM_ICP, "Mismatch blob size %d expected %lu", @@ -4336,7 +4337,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, soc_req = (struct cam_icp_clk_bw_request *)blob_data; *clk_info = *soc_req; - CAM_DBG(CAM_ICP, "budget:%llu fc: %llu %d BW %lld %lld", + CAM_DBG(CAM_PERF, "budget:%llu fc: %llu %d BW %lld %lld", clk_info->budget_ns, clk_info->frame_cycles, clk_info->rt_flag, clk_info->uncompressed_bw, clk_info->compressed_bw); @@ -4363,7 +4364,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, soc_req_v2 = (struct cam_icp_clk_bw_request_v2 *)blob_data; if (soc_req_v2->num_paths > CAM_ICP_MAX_PER_PATH_VOTES) { - CAM_ERR(CAM_ICP, "Invalid num paths: %d", + CAM_ERR(CAM_PERF, "Invalid num paths: %d", soc_req_v2->num_paths); return -EINVAL; } @@ -4402,7 +4403,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, clk_info->frame_cycles = clk_info_v2->frame_cycles; clk_info->rt_flag = clk_info_v2->rt_flag; - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "budget=%llu, frame_cycle=%llu, rt_flag=%d, num_paths=%d, clk_update_size=%d, index=%d, ctx_data=%pK", clk_info_v2->budget_ns, clk_info_v2->frame_cycles, clk_info_v2->rt_flag, @@ -4412,7 +4413,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, ctx_data); for (i = 0; i < clk_info_v2->num_paths; i++) { - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "[%d] : path_type=%d, trans_type=%d, camnoc=%lld, mnoc_ab=%lld, mnoc_ib=%lld", i, clk_info_v2->axi_path[i].path_data_type, diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c index a0de07833b72..4263cf7ea669 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -39,7 +39,7 @@ static int cam_ipe_cpas_vote(struct cam_ipe_device_core_info *core_info, &cpas_vote->axi_vote); if (rc) - CAM_ERR(CAM_ICP, "cpas vote is failed: %d", rc); + CAM_ERR(CAM_PERF, "cpas vote is failed: %d", rc); return rc; } @@ -168,7 +168,7 @@ static int cam_ipe_handle_pc(struct cam_hw_info *ipe_dev) hw_info->pwr_ctrl, true, 0x1); if (pwr_status >> IPE_PWR_ON_MASK) - CAM_WARN(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", + CAM_WARN(CAM_PERF, "BPS: pwr_status(%x):pwr_ctrl(%x)", pwr_status, pwr_ctrl); } @@ -179,7 +179,7 @@ static int cam_ipe_handle_pc(struct cam_hw_info *ipe_dev) cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); - CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", pwr_ctrl, pwr_status); return 0; @@ -202,7 +202,7 @@ static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev) CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); if (pwr_ctrl & IPE_COLLAPSE_MASK) { - CAM_DBG(CAM_ICP, "IPE pwr_ctrl set(%x)", pwr_ctrl); + CAM_DBG(CAM_PERF, "IPE pwr_ctrl set(%x)", pwr_ctrl); cam_cpas_reg_write(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, 0); @@ -214,7 +214,7 @@ static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev) cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); - CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", pwr_ctrl, pwr_status); return rc; @@ -364,7 +364,7 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; int32_t clk_level = 0, err = 0; - CAM_DBG(CAM_ICP, "ipe_src_clk rate = %d", (int)clk_rate); + CAM_DBG(CAM_PERF, "ipe_src_clk rate = %d", (int)clk_rate); if (!core_info->clk_enable) { if (clk_upd_cmd->ipe_bps_pc_enable) { cam_ipe_handle_pc(ipe_dev); @@ -383,11 +383,11 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, CAM_ERR(CAM_ICP, "bps resume failed"); } } - CAM_DBG(CAM_ICP, "clock rate %d", clk_rate); + CAM_DBG(CAM_PERF, "clock rate %d", clk_rate); rc = cam_ipe_update_clk_rate(soc_info, clk_rate); if (rc) - CAM_ERR(CAM_ICP, "Failed to update clk"); + CAM_ERR(CAM_PERF, "Failed to update clk %d", clk_rate); err = cam_soc_util_get_clk_level(soc_info, clk_rate, soc_info->src_clk_idx, diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c index a33c7b68bf97..11cc7f7a3317 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c @@ -143,7 +143,7 @@ int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info, if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) && (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { - CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d", + CAM_DBG(CAM_PERF, "clk_rate %d greater than max, reset to %d", clk_rate, soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; 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 604e230db7ee..c77ddfd657bb 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 @@ -3204,7 +3204,7 @@ static int cam_isp_blob_bw_update_v2( sizeof( struct cam_vfe_bw_update_args_v2)); if (rc) - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_PERF, "BW Update failed rc: %d", rc); } else { CAM_WARN(CAM_ISP, "NULL hw_intf!"); @@ -3303,7 +3303,7 @@ static int cam_isp_blob_bw_update( &bw_upd_args, sizeof(struct cam_vfe_bw_update_args)); if (rc) - CAM_ERR(CAM_ISP, "BW Update failed"); + CAM_ERR(CAM_PERF, "BW Update failed"); } else CAM_WARN(CAM_ISP, "NULL hw_intf!"); } @@ -3352,7 +3352,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { if (hw_update_data->bw_config_valid[i] == true) { - CAM_DBG(CAM_ISP, "idx=%d, bw_config_version=%d", + CAM_DBG(CAM_PERF, "idx=%d, bw_config_version=%d", ctx, ctx->ctx_index, i, hw_update_data->bw_config_version); @@ -3362,7 +3362,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, (struct cam_isp_bw_config *) &hw_update_data->bw_config[i], ctx); if (rc) - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_PERF, "Bandwidth Update Failed rc: %d", rc); } else if (hw_update_data->bw_config_version == CAM_ISP_BW_CONFIG_V2) { @@ -3370,11 +3370,11 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, (struct cam_isp_bw_config_v2 *) &hw_update_data->bw_config_v2[i], ctx); if (rc) - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_PERF, "Bandwidth Update Failed rc: %d", rc); } else { - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_PERF, "Invalid bw config version: %d", hw_update_data->bw_config_version); } @@ -4846,7 +4846,7 @@ static int cam_isp_blob_clock_update( if (hw_intf && hw_intf->hw_ops.process_cmd) { clock_upd_args.node_res = hw_mgr_res->hw_res[i]; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_PERF, "res_id=%u i= %d clk=%llu\n", hw_mgr_res->res_id, i, clk_rate); @@ -4859,7 +4859,8 @@ static int cam_isp_blob_clock_update( sizeof( struct cam_vfe_clock_update_args)); if (rc) - CAM_ERR(CAM_ISP, "Clock Update failed"); + CAM_ERR(CAM_PERF, + "Clock Update failed"); } else CAM_WARN(CAM_ISP, "NULL hw_intf!"); } @@ -5085,14 +5086,14 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, rc = cam_isp_blob_clock_update(blob_type, blob_info, clock_config, prepare); if (rc) - CAM_ERR(CAM_ISP, "Clock Update Failed"); + CAM_ERR(CAM_PERF, "Clock Update Failed, rc=%d", rc); } break; case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: { struct cam_isp_bw_config *bw_config; struct cam_isp_prepare_hw_update_data *prepare_hw_data; - CAM_WARN_RATE_LIMIT_CUSTOM(CAM_ISP, 300, 1, + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_PERF, 300, 1, "Deprecated Blob TYPE_BW_CONFIG"); if (blob_size < sizeof(struct cam_isp_bw_config)) { CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); -- GitLab From 9857d65da3f0f32619caa56543aa71fa76f4f334 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 29 Oct 2019 11:52:12 +0530 Subject: [PATCH 045/295] msm: camera: common: va_end should follow va_start Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function. CRs-Fixed: 2549155 Change-Id: I6a3214ce863c4af0425d061184cfa44682f89545 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_utils/cam_debug_util.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/cam_utils/cam_debug_util.c b/drivers/cam_utils/cam_debug_util.c index e0957890dc8b..bc7aab55b0fe 100644 --- a/drivers/cam_utils/cam_debug_util.c +++ b/drivers/cam_utils/cam_debug_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundataion. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundataion. All rights reserved. */ #include @@ -120,6 +120,7 @@ void cam_debug_log(unsigned int module_id, const char *func, const int line, pr_info("CAM_DBG: %s: %s: %d: %s\n", cam_get_module_name(module_id), func, line, str_buffer); - va_end(args); } + + va_end(args); } -- GitLab From 5378717f2cd8d0c958e97557f0a79424fdf792b2 Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Wed, 30 Oct 2019 17:54:18 -0700 Subject: [PATCH 046/295] msm: camera: sync: Dump fence info in case of fence exhaust Add error message in case of fence exhaust. Add support to dump fence table in case of fence exhaust. CRs-Fixed: 2556458 Change-Id: I9910a04c69b54fe99541524b6581fa9994fd523f Signed-off-by: Karthik Jayakumar --- drivers/cam_sync/cam_sync.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index 45d2793fb671..33b14f17ceb7 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -25,6 +25,24 @@ struct sync_device *sync_dev; */ static bool trigger_cb_without_switch; +static void cam_sync_print_fence_table(void) +{ + int idx; + + for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++) { + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + CAM_INFO(CAM_SYNC, + "index[%u]: sync_id=%d, name=%s, type=%d, state=%d, ref_cnt=%d", + idx, + sync_dev->sync_table[idx].sync_id, + sync_dev->sync_table[idx].name, + sync_dev->sync_table[idx].type, + sync_dev->sync_table[idx].state, + sync_dev->sync_table[idx].ref_cnt); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + } +} + int cam_sync_create(int32_t *sync_obj, const char *name) { int rc; @@ -33,8 +51,13 @@ int cam_sync_create(int32_t *sync_obj, const char *name) do { idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); - if (idx >= CAM_SYNC_MAX_OBJS) + if (idx >= CAM_SYNC_MAX_OBJS) { + CAM_ERR(CAM_SYNC, + "Error: Unable to create sync idx = %d reached max!", + idx); + cam_sync_print_fence_table(); return -ENOMEM; + } CAM_DBG(CAM_SYNC, "Index location available at idx: %ld", idx); bit = test_and_set_bit(idx, sync_dev->bitmap); } while (bit); -- GitLab From 35ca59b9945ab406332d74884a4ca01ec2484548 Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Thu, 31 Oct 2019 14:49:12 -0700 Subject: [PATCH 047/295] msm: camera: icp: Remove qcom soc dependency Remove soc_info from icp driver as it was unused. CRs-Fixed: 2557184 Change-Id: I7b85768502f825753ea4b9650b5c3f9df67643fb Signed-off-by: Karthik Jayakumar --- drivers/cam_icp/hfi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/cam_icp/hfi.c b/drivers/cam_icp/hfi.c index b20565cf2d44..89a95aca62e1 100644 --- a/drivers/cam_icp/hfi.c +++ b/drivers/cam_icp/hfi.c @@ -11,7 +11,6 @@ #include #include #include -#include #include "cam_io_util.h" #include "hfi_reg.h" @@ -20,7 +19,6 @@ #include "hfi_intf.h" #include "cam_icp_hw_mgr_intf.h" #include "cam_debug_util.h" -#include "cam_soc_util.h" #define HFI_VERSION_INFO_MAJOR_VAL 1 #define HFI_VERSION_INFO_MINOR_VAL 1 @@ -690,7 +688,7 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, struct hfi_qtbl *qtbl; struct hfi_qtbl_hdr *qtbl_hdr; struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr; - uint32_t hw_version, soc_version, fw_version, status = 0; + uint32_t hw_version, fw_version, status = 0; uint32_t retry_cnt = 0; struct sfr_buf *sfr_buffer; @@ -712,7 +710,6 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, memcpy(&g_hfi->map, hfi_mem, sizeof(g_hfi->map)); g_hfi->hfi_state = HFI_DEINIT; - soc_version = socinfo_get_version(); if (debug) { cam_io_w_mb( (uint32_t)(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN | -- GitLab From 50197fbfb306e56362229e183a15cc7dc7f8fc7e Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Fri, 1 Nov 2019 14:59:32 -0700 Subject: [PATCH 048/295] msm: camera: core: Fix extraneous variable declaration Remove an extra variable declaration within a for loop. CRs-Fixed: 2554484 Change-Id: I89885eeb8f89893ad7054d54a694a040e4c0bfbb Signed-off-by: Karthik Jayakumar --- drivers/cam_core/cam_context_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 8090bd0071a6..423961aaf2af 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -481,7 +481,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, return rc; put_ctx_ref: - for (j; j >= 0; j--) + for (; j >= 0; j--) cam_context_putref(ctx); put_ref: for (--i; i >= 0; i--) { -- GitLab From 2fc2029b6f534360efb876f6572db1925fb38726 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Wed, 23 Oct 2019 12:07:49 +0530 Subject: [PATCH 049/295] msm: camera: csiphy: Update registers for CSIPHY v1.2 Update register settings for CPHY/DPHY/combo DPHY modes as per the latest HPG (revision J). CRs-Fixed: 2563037 Change-Id: I137141a490bedce4632991e5eb12887d0c9fa30e Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 88 ++++++++----------- 1 file changed, 38 insertions(+), 50 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 35e2a4ab1d6a..e00e2bdf344d 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -12,9 +12,9 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 5, + .csiphy_common_array_size = 6, .csiphy_reset_array_size = 4, - .csiphy_2ph_config_array_size = 19, + .csiphy_2ph_config_array_size = 18, .csiphy_3ph_config_array_size = 33, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -23,9 +23,10 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { struct csiphy_reg_t csiphy_common_reg_1_2[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x5A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0824, 0x72, 0x00, CSIPHY_2PH_REGS}, }; struct csiphy_reg_t csiphy_reset_reg_1_2[] = { @@ -55,18 +56,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -76,18 +76,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -97,18 +96,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -118,18 +116,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -139,18 +136,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -159,23 +155,22 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { }; struct csiphy_reg_t - csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { +csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0060, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -185,18 +180,17 @@ struct csiphy_reg_t {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -206,18 +200,17 @@ struct csiphy_reg_t {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0260, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -227,18 +220,17 @@ struct csiphy_reg_t {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0460, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -248,18 +240,17 @@ struct csiphy_reg_t {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -382,14 +373,11 @@ struct data_rate_settings_t data_rate_delta_table_1_2 = { { /* (2.5 * 10**3 * 2.28) rounded value*/ .bandwidth = 5700000000, - .data_rate_reg_array_size = 6, + .data_rate_reg_array_size = 3, .csiphy_data_rate_regs = { {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, } }, { @@ -397,12 +385,12 @@ struct data_rate_settings_t data_rate_delta_table_1_2 = { .bandwidth = 7980000000, .data_rate_reg_array_size = 15, .csiphy_data_rate_regs = { + {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x2D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x2D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x2D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -419,21 +407,21 @@ struct data_rate_settings_t data_rate_delta_table_1_2 = { .bandwidth = 10260000000, .data_rate_reg_array_size = 15, .csiphy_data_rate_regs = { + {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x10C, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x30C, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x50C, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, }, } } -- GitLab From 2fb55447b9535d8d723a9d685a728f81a3498b59 Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Thu, 24 Oct 2019 13:49:43 -0700 Subject: [PATCH 050/295] msm: camera: sensor: Remove true/false redefinitions Remove defines in header files that redefine true and false. CRs-Fixed: 2556282 Change-Id: Ibf87f35efd403faa05e72b070dcfca59e0196a29 Signed-off-by: Karthik Jayakumar --- .../cam_actuator/cam_actuator_dev.h | 4 ---- drivers/cam_sensor_module/cam_cci/cam_cci_core.c | 4 ++-- drivers/cam_sensor_module/cam_cci/cam_cci_dev.c | 14 +++++++------- drivers/cam_sensor_module/cam_cci/cam_cci_dev.h | 3 --- drivers/cam_sensor_module/cam_cci/cam_cci_soc.c | 6 +++--- .../cam_sensor_module/cam_sensor/cam_sensor_dev.h | 3 --- 6 files changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h index e4e5e4305246..e4bfaed4414f 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h @@ -30,16 +30,12 @@ #define NUM_MASTERS 2 #define NUM_QUEUES 2 -#define TRUE 1 -#define FALSE 0 - #define ACTUATOR_DRIVER_I2C "i2c_actuator" #define CAMX_ACTUATOR_DEV_NAME "cam-actuator-driver" #define MSM_ACTUATOR_MAX_VREGS (10) #define ACTUATOR_MAX_POLL_COUNT 10 - enum cam_actuator_apply_state_t { ACT_APPLY_SETTINGS_NOW, ACT_APPLY_SETTINGS_LATER, 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 14c196b71851..74b324678f15 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -49,8 +49,8 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev, } else if (rc == 0) { CAM_ERR(CAM_CCI, "wait timeout"); - /* Set reset pending flag to TRUE */ - cci_dev->cci_master_info[master].reset_pending = TRUE; + /* Set reset pending flag to true */ + cci_dev->cci_master_info[master].reset_pending = true; /* Set proper mask to RESET CMD address based on MASTER */ if (master == MASTER_0) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index e30574da5c0b..f377c07a6c36 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -69,18 +69,18 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) if (irq_status0 & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { struct cam_cci_master_info *cci_master_info; - if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { + if (cci_dev->cci_master_info[MASTER_0].reset_pending == true) { cci_master_info = &cci_dev->cci_master_info[MASTER_0]; cci_dev->cci_master_info[MASTER_0].reset_pending = - FALSE; + false; if (!cci_master_info->status) complete(&cci_master_info->reset_complete); cci_master_info->status = 0; } - if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { + if (cci_dev->cci_master_info[MASTER_1].reset_pending == true) { cci_master_info = &cci_dev->cci_master_info[MASTER_1]; cci_dev->cci_master_info[MASTER_1].reset_pending = - FALSE; + false; if (!cci_master_info->status) complete(&cci_master_info->reset_complete); cci_master_info->status = 0; @@ -205,12 +205,12 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) CAM_DBG(CAM_CCI, "RD_PAUSE ON MASTER_1"); if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { - cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + cci_dev->cci_master_info[MASTER_0].reset_pending = true; cam_io_w_mb(CCI_M0_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { - cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE; + cci_dev->cci_master_info[MASTER_1].reset_pending = true; cam_io_w_mb(CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } @@ -316,7 +316,7 @@ static int cam_cci_irq_routine(struct v4l2_subdev *sd, u32 status, &cci_dev->soc_info; ret = cam_cci_irq(soc_info->irq_line->start, cci_dev); - *handled = TRUE; + *handled = true; return 0; } 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 d940faaf1503..34cc348facd4 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -44,9 +44,6 @@ #define NUM_MASTERS 2 #define NUM_QUEUES 2 -#define TRUE 1 -#define FALSE 0 - #define CCI_PINCTRL_STATE_DEFAULT "cci_default" #define CCI_PINCTRL_STATE_SLEEP "cci_suspend" 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 effbbba47368..eebfec135e79 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -53,8 +53,8 @@ int cam_cci_init(struct v4l2_subdev *sd, for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); - /* Set reset pending flag to TRUE */ - cci_dev->cci_master_info[master].reset_pending = TRUE; + /* Set reset pending flag to true */ + cci_dev->cci_master_info[master].reset_pending = true; /* Set proper mask to RESET CMD address */ if (master == MASTER_0) cam_io_w_mb(CCI_M0_RESET_RMSK, @@ -140,7 +140,7 @@ int cam_cci_init(struct v4l2_subdev *sd, } } - cci_dev->cci_master_info[master].reset_pending = TRUE; + cci_dev->cci_master_info[master].reset_pending = true; cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h index 37e0affdf991..b1963e15eb59 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -28,9 +28,6 @@ #define NUM_MASTERS 2 #define NUM_QUEUES 2 -#define TRUE 1 -#define FALSE 0 - #undef CDBG #ifdef CAM_SENSOR_DEBUG #define CDBG(fmt, args...) pr_err(fmt, ##args) -- GitLab From 0203876688ea8c72305db6562a41c8385104fdc1 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Tue, 31 Dec 2019 10:47:41 +0530 Subject: [PATCH 051/295] msm: camera: ope: Fix false alarm for OPE HW timeout Resetting the timer before setting the respective request bit in bitmap to avoid flase alarm in case of timer timeout. CRs-Fixed: 2592991 Change-Id: I5afed26dea7ebfb9371a43323815d45cd37a6384 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2fb2af808b93..dd695ae0ea55 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 @@ -2575,8 +2575,8 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, CAM_ERR(CAM_OPE, "Invalid ctx req slot = %d", request_idx); return -EINVAL; } - set_bit(request_idx, ctx_data->bitmap); cam_ope_req_timer_reset(ctx_data); + set_bit(request_idx, ctx_data->bitmap); ctx_data->req_list[request_idx] = kzalloc(sizeof(struct cam_ope_request), GFP_KERNEL); if (!ctx_data->req_list[request_idx]) { -- GitLab From 7112ddf3038f2a47115a267aa90c1821d78ac671 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Fri, 13 Dec 2019 17:38:29 +0530 Subject: [PATCH 052/295] msm: camera: tfe: Support register dump per request Dump request descriptor need to store for every request id. Added code to store the data on per request basis. Debug fs entries created with u32. CRs-Fixed: 2585713 Change-Id: I2bac930e86675180bf001634d0a0070374f9afb5 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 61 +++++++++++++++------ drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h | 6 +- 2 files changed, 48 insertions(+), 19 deletions(-) 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 0f52c8625cc9..e96e0887cdfe 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 @@ -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. */ #include @@ -1932,6 +1932,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); @@ -3059,6 +3060,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++) { @@ -3771,6 +3773,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) { @@ -3909,24 +3912,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++) { @@ -4181,8 +4210,8 @@ static int cam_tfe_mgr_cmd(void *hw_mgr_priv, void *cmd_args) CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_FLUSH); 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; } @@ -4197,8 +4226,8 @@ static int cam_tfe_mgr_cmd(void *hw_mgr_priv, void *cmd_args) CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_ERROR); 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; @@ -5055,7 +5084,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)) { @@ -5071,7 +5100,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)) { 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 1e15bd20f5e8..66eabc3fb442 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 @@ -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_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; }; /** -- GitLab From cb6696532fc382e339533497de43a535c81ce98a Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Fri, 20 Dec 2019 14:26:14 +0530 Subject: [PATCH 053/295] msm: camera: cpas: Add support to GPU limit Camera Open/CLose is indicated to GPU for Cx Ipeak GPU limit. CRs-Fixed: 2590752 Change-Id: I9571b2eb8cc4780ff2ed1e9a28d1cf65a8746261 Signed-off-by: Suresh Vankadara --- drivers/cam_cpas/cam_cpas_hw.c | 27 ++++++++++++++++++++++++++- drivers/cam_cpas/cam_cpas_soc.c | 5 ++++- drivers/cam_cpas/cam_cpas_soc.h | 7 ++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index ae0368acdb05..7d2ee82a093e 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.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 @@ -1174,6 +1174,23 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, if (rc) goto done; + if ((soc_private->cx_ipeak_gpu_limit) && + (!cpas_core->streamon_clients)) { + soc_private->gpu_pwr_limit = + kgsl_pwr_limits_add(KGSL_DEVICE_3D0); + if (soc_private->gpu_pwr_limit) { + rc = kgsl_pwr_limits_set_freq( + soc_private->gpu_pwr_limit, + soc_private->cx_ipeak_gpu_limit); + if (rc) { + kgsl_pwr_limits_del( + soc_private->gpu_pwr_limit); + soc_private->gpu_pwr_limit = NULL; + goto done; + } + } + } + if (cpas_core->streamon_clients == 0) { atomic_set(&cpas_core->irq_count, 1); rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, @@ -1308,6 +1325,14 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n", atomic_read(&cpas_core->irq_count)); cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + + if (soc_private->cx_ipeak_gpu_limit && + soc_private->gpu_pwr_limit) { + kgsl_pwr_limits_set_default( + soc_private->gpu_pwr_limit); + kgsl_pwr_limits_del(soc_private->gpu_pwr_limit); + soc_private->gpu_pwr_limit = NULL; + } } ahb_vote.type = CAM_VOTE_ABSOLUTE; diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index c86753dd24d9..16345d662af2 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/drivers/cam_cpas/cam_cpas_soc.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 @@ -553,6 +553,9 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, goto cleanup_tree; } + of_property_read_u32(of_node, "qcom,cx-ipeak-gpu-limit", + &soc_private->cx_ipeak_gpu_limit); + return 0; cleanup_tree: diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index fea9c3c97593..663a5e8c838d 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/drivers/cam_cpas/cam_cpas_soc.h @@ -1,11 +1,12 @@ /* 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 _CAM_CPAS_SOC_H_ #define _CAM_CPAS_SOC_H_ +#include #include "cam_soc_util.h" #include "cam_cpas_hw.h" @@ -88,6 +89,8 @@ struct cam_cpas_tree_node { * camnoc axi clock * @camnoc_axi_min_ib_bw: Min camnoc BW which varies based on target * @feature_mask: feature mask value for hw supported features + * @cx_ipeak_gpu_limit: Flag for Cx Ipeak GPU mitigation + * @gpu_pwr_limit: Handle for Cx Ipeak GPU Mitigation * */ struct cam_cpas_private_soc { @@ -105,6 +108,8 @@ struct cam_cpas_private_soc { uint32_t camnoc_axi_clk_bw_margin; uint64_t camnoc_axi_min_ib_bw; uint32_t feature_mask; + uint32_t cx_ipeak_gpu_limit; + struct kgsl_pwr_limit *gpu_pwr_limit; }; void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private); -- GitLab From 350430cc0ca1db631a689b4a9cc65f4f3c503e21 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Fri, 3 Jan 2020 14:48:53 +0530 Subject: [PATCH 054/295] msm: camera: ope: Increase max number of stripes Increasing max number of stripes to 48 from 32 to support big resolution. CRs-Fixed: 2593149 Change-Id: I1f573c907bcb6360719293474a39a917ff74cf92 Signed-off-by: Rishabh Jain --- include/uapi/media/cam_ope.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/media/cam_ope.h b/include/uapi/media/cam_ope.h index e8d0426c746f..812212f3170b 100644 --- a/include/uapi/media/cam_ope.h +++ b/include/uapi/media/cam_ope.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_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 /** -- GitLab From 21f578dc1cd50f4dd7ce164c3f1387b7222f8597 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Tue, 31 Dec 2019 11:02:01 +0530 Subject: [PATCH 055/295] msm: camera: ope: Change packer and unpacker format in case NV12 In case of NV12 format, change the packer and unpacker format of chroma plane to odd even byte swapped format. CRs-Fixed: 2591646 Change-Id: If9d86adc569150d4ee678160cad2aeb1e56ec395 Signed-off-by: Rishabh Jain --- .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 33 ++++++++++++++++++- .../ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c | 30 ++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) 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 a3a7e3086bdf..8422e3dcc862 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 @@ -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. */ #include @@ -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; @@ -243,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; 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 2ade0924be94..0f3d6e3b34fc 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 @@ -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. */ #include @@ -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, @@ -286,6 +304,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); -- GitLab From 30884d80c3a048dd8c5862f3019a1f2a02cd4882 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Wed, 30 Oct 2019 13:39:40 +0530 Subject: [PATCH 056/295] msm: camera: isp: Set device enable flag after enable csid hardware Device enable flag is getting set after configuring the CSID csi rx and csid path configuration. If irq comes after configuring the csi rx hardware then irq handler is not handling as it is checking the device enable flag. So set device enable flag after enabling the hardware. CRs-Fixed: 2541840 Change-Id: I022b6dccef4153c34bc8cf99e7a18e2978f92d3f Signed-off-by: Ravikishore Pampana --- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index af9f67286d82..96c88567dc31 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1194,6 +1194,7 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) struct cam_hw_soc_info *soc_info; uint32_t i, val; int clk_lvl; + unsigned long flags; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; @@ -1274,6 +1275,10 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", csid_hw->hw_intf->hw_idx, val); + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 1; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + return 0; disable_soc: @@ -3257,7 +3262,6 @@ int cam_ife_csid_init_hw(void *hw_priv, struct cam_hw_info *csid_hw_info; struct cam_isp_resource_node *res; const struct cam_ife_csid_reg_offset *csid_reg; - unsigned long flags; if (!hw_priv || !init_args || (arg_size != sizeof(struct cam_isp_resource_node))) { @@ -3338,9 +3342,6 @@ int cam_ife_csid_init_hw(void *hw_priv, if (rc) cam_ife_csid_disable_hw(csid_hw); - spin_lock_irqsave(&csid_hw->lock_state, flags); - csid_hw->device_enabled = 1; - spin_unlock_irqrestore(&csid_hw->lock_state, flags); end: mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; -- GitLab From c1e0ea718cba7075d26bdd6b1cf3a4f682d2c541 Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Mon, 4 Nov 2019 13:50:06 -0800 Subject: [PATCH 057/295] msm: camera: utils: Remove deprecated clk_set_flag functions Removed unused functions that called clk_set_flag, which has been deprecated in linux kernel 5.x. CRs-Fixed: 2554484 Change-Id: I0062383b0b059e6b359229f4b33470713289abb4 Signed-off-by: Karthik Jayakumar --- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c | 39 ------------------- drivers/cam_utils/cam_soc_util.c | 12 ------ drivers/cam_utils/cam_soc_util.h | 14 ------- 3 files changed, 65 deletions(-) diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c index d05530ae4e17..c3d5a68c6910 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c @@ -71,39 +71,6 @@ static int cam_fd_hw_soc_util_setup_regbase_indices( return 0; } -static int cam_fd_soc_set_clk_flags(struct cam_hw_soc_info *soc_info) -{ - int i, rc = 0; - - if (soc_info->num_clk > CAM_SOC_MAX_CLK) { - CAM_ERR(CAM_FD, "Invalid num clk %d", soc_info->num_clk); - return -EINVAL; - } - - /* set memcore and mem periphery logic flags to 0 */ - for (i = 0; i < soc_info->num_clk; i++) { - if ((strcmp(soc_info->clk_name[i], "fd_core_clk") == 0) || - (strcmp(soc_info->clk_name[i], "fd_core_uar_clk") == - 0)) { - rc = cam_soc_util_set_clk_flags(soc_info, i, - CLKFLAG_NORETAIN_MEM); - if (rc) - CAM_ERR(CAM_FD, - "Failed in NORETAIN_MEM i=%d, rc=%d", - i, rc); - - cam_soc_util_set_clk_flags(soc_info, i, - CLKFLAG_NORETAIN_PERIPH); - if (rc) - CAM_ERR(CAM_FD, - "Failed in NORETAIN_PERIPH i=%d, rc=%d", - i, rc); - } - } - - return rc; -} - void cam_fd_soc_register_write(struct cam_hw_soc_info *soc_info, enum cam_fd_reg_base reg_base, uint32_t reg_offset, uint32_t reg_value) { @@ -228,12 +195,6 @@ int cam_fd_soc_init_resources(struct cam_hw_soc_info *soc_info, return rc; } - rc = cam_fd_soc_set_clk_flags(soc_info); - if (rc) { - CAM_ERR(CAM_FD, "failed in set_clk_flags rc=%d", rc); - goto release_res; - } - soc_private = kzalloc(sizeof(struct cam_fd_soc_private), GFP_KERNEL); if (!soc_private) { rc = -ENOMEM; diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 8c89c5d07936..219d7569d0e2 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -368,18 +368,6 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, return clk_round_rate(soc_info->clk[clk_index], clk_rate); } -int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, - uint32_t clk_index, unsigned long flags) -{ - if (!soc_info || (clk_index >= soc_info->num_clk)) { - CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d", - soc_info, clk_index); - return -EINVAL; - } - - return clk_set_flags(soc_info->clk[clk_index], flags); -} - /** * cam_soc_util_set_clk_rate() * diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index 19cb0ae2a81c..a717b6b72817 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -373,20 +373,6 @@ int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info, long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, uint32_t clk_index, unsigned long clk_rate); -/** - * cam_soc_util_set_clk_flags() - * - * @brief: Camera SOC util to set the flags for a specified clock - * - * @soc_info: Device soc information - * @clk_index: Clock index in soc_info for which flags are to be set - * @flags: Flags to set - * - * @return: Success or Failure - */ -int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, - uint32_t clk_index, unsigned long flags); - /** * cam_soc_util_set_src_clk_rate() * -- GitLab From 0392065b5969d6b31e7d3033b43e8b2ed2fd1fd9 Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Mon, 4 Nov 2019 11:38:29 -0800 Subject: [PATCH 058/295] msm: camera: cci: Fix cam_cci_get_subdev for conditional compilation Fixes cci_get_subdev to return NULL or computed value depending on camera driver configuration. CRs-Fixed: 2554484 Change-Id: I79933ddf28e2c0d23739308b57b5b40d3b56d78e Signed-off-by: Karthik Jayakumar --- drivers/cam_sensor_module/cam_cci/cam_cci_dev.c | 11 +++++++++-- drivers/cam_sensor_module/cam_cci/cam_cci_dev.h | 9 +-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index f377c07a6c36..e52e16cb5f96 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -14,9 +14,16 @@ static struct v4l2_subdev *g_cci_subdev[MAX_CCI]; struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) { + struct v4l2_subdev *sub_device = NULL; + if (cci_dev_index < MAX_CCI) - return g_cci_subdev[cci_dev_index]; - return NULL; + sub_device = g_cci_subdev[cci_dev_index]; + else + CAM_WARN(CAM_CCI, "Index: %u is beyond max num CCI allowed: %u", + cci_dev_index, + MAX_CCI); + + return sub_device; } static long cam_cci_subdev_ioctl(struct v4l2_subdev *sd, 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 34cc348facd4..8b78cde86738 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -299,14 +299,7 @@ struct cci_write_async { irqreturn_t cam_cci_irq(int irq_num, void *data); -#ifdef CONFIG_SPECTRA_CAMERA -extern struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index); -#else -static inline struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) -{ - return NULL; -} -#endif +struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index); #define VIDIOC_MSM_CCI_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) -- GitLab From 813bbd36ae9ff2fa47cf2ab06572d0f9402bc5c7 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 7 Nov 2019 19:34:58 -0800 Subject: [PATCH 059/295] msm: camera: cpas: Update ife_rd safe lut value Do not set safe_lut value for ife_rd path, default values is good as per recommendation. CRs-Fixed: 2561696 Change-Id: Icce19f7814329d2e96e94d18096aa12069626429 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_cpas/cpas_top/cpastop_v480_100.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h index 510b97062fbc..0d46e0ddcc20 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h @@ -357,7 +357,7 @@ static struct cam_camnoc_specific .value = 0x0, }, .safe_lut = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x1048, /* IFE_RDI_RD_SAFELUT_LOW */ .value = 0x0, -- GitLab From c23527247d85c5850b195f9e27fabb9eb0a53ea3 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 6 Jan 2020 11:41:06 +0530 Subject: [PATCH 060/295] msm: camera: isp: Get packet opcode from hw manager While processing the user space submitted isp packet, isp context need to know the packet opcode. Get the opcode from the hw manager than the direct accessing the opcode from packet. Ife umd sends different opcodes then tfe umd. Both ife and tfe kernel packet opcodes are same. So hw manager can consume this differences. CRs-Fixed: 2585713 Change-Id: I54813af233cd8bfa640f2688c1334510a5b85f1c Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/cam_isp_context.c | 23 +++++++++++++++++-- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 14 ++++++++++- .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 7 +++++- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index f4d07e1f8ed8..53bf819ed181 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.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 @@ -3024,6 +3024,9 @@ static int __cam_isp_ctx_config_dev_in_top_state( struct cam_req_mgr_add_request add_req; struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + uint32_t packet_opcode = 0; CAM_DBG(CAM_ISP, "get free request object......"); @@ -3072,7 +3075,23 @@ static int __cam_isp_ctx_config_dev_in_top_state( CAM_DBG(CAM_ISP, "Packet size 0x%x", packet->header.size); CAM_DBG(CAM_ISP, "packet op %d", packet->header.op_code); - if ((((packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_UPDATE_DEV) + /* Query the packet opcode */ + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_GET_PACKET_OPCODE; + isp_hw_cmd_args.cmd_data = (void *)packet; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "HW command failed"); + goto free_req; + } + + packet_opcode = isp_hw_cmd_args.u.packet_op_code; + CAM_DBG(CAM_ISP, "packet op %d", packet_opcode); + + if ((packet_opcode == CAM_ISP_PACKET_UPDATE_DEV) && (packet->header.request_id <= ctx->last_flush_req)) { CAM_INFO(CAM_ISP, "request %lld has been flushed, reject packet", 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 c77ddfd657bb..68cce277fc83 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 @@ -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 @@ -5740,6 +5740,7 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) struct cam_ife_hw_mgr_ctx *ctx = (struct cam_ife_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"); @@ -5780,6 +5781,17 @@ static int cam_ife_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 + 1) & 0xF) == + CAM_ISP_PACKET_INIT_DEV) + isp_hw_cmd_args->u.packet_op_code = + CAM_ISP_PACKET_INIT_DEV; + else + isp_hw_cmd_args->u.packet_op_code = + CAM_ISP_PACKET_UPDATE_DEV; + break; default: CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", hw_cmd_args->cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 5cce370fd8df..a0c0e60a30a4 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_MGR_INTF_H_ @@ -224,6 +224,7 @@ enum cam_isp_hw_mgr_command { CAM_ISP_HW_MGR_CMD_RESUME_HW, CAM_ISP_HW_MGR_CMD_SOF_DEBUG, CAM_ISP_HW_MGR_CMD_CTX_TYPE, + CAM_ISP_HW_MGR_GET_PACKET_OPCODE, CAM_ISP_HW_MGR_CMD_MAX, }; @@ -237,14 +238,18 @@ enum cam_isp_ctx_type { * struct cam_isp_hw_cmd_args - Payload for hw manager command * * @cmd_type HW command type + * @cmd_data command data * @sof_irq_enable To debug if SOF irq is enabled * @ctx_type RDI_ONLY, PIX and RDI, or FS2 + * @packet_op_code packet opcode */ struct cam_isp_hw_cmd_args { uint32_t cmd_type; + void *cmd_data; union { uint32_t sof_irq_enable; uint32_t ctx_type; + uint32_t packet_op_code; } u; }; -- GitLab From e50e566369b4b56a4c78cfc858e2c42cac39f84f Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 6 Jan 2020 14:34:10 +0530 Subject: [PATCH 061/295] msm: camera: tfe: Add packet code get command for tfe Add packet opcode get command in the tfe hw manager. This is required during the packet config in the isp context to check the packet type init or config. CRs-Fixed: 2599088 Change-Id: Id1ecf60bccc00aedf317d9cd223c4daea83fe84e Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) 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 e96e0887cdfe..9641409fecf8 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 @@ -4146,6 +4146,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"); @@ -4184,6 +4185,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); @@ -4231,7 +4243,6 @@ static int cam_tfe_mgr_cmd(void *hw_mgr_priv, void *cmd_args) return rc; } break; - default: CAM_ERR(CAM_ISP, "Invalid cmd"); } -- GitLab From 8f82ae1bd1db51274a73d2658a5a94d4172cb488 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Wed, 8 Jan 2020 14:44:42 +0530 Subject: [PATCH 062/295] msm: camera: ope: Trigger recovery in case of violation on write bus In case of violation on write client, propagate the error to trigger the recovery. CRs-Fixed: 2591910 Change-Id: Iccab9f3e6cfb2c9926a1b5035a0abeee7088658e Signed-off-by: Rishabh Jain --- .../ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) 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 2ade0924be94..bbeafbd1f241 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 @@ -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. */ #include @@ -688,11 +688,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 +713,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 +781,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); -- GitLab From aa8b8721454ead530e12547b489a1e5bbbe270c3 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Wed, 8 Jan 2020 15:50:58 +0530 Subject: [PATCH 063/295] msm: camera: ope: Protect ope hw reset with mutex In flush or error cases, there is possibility that flush all and error case can concurrently request for ope reset. This ope reset process command may execute parallelly and cause list corruption issues. Add mutex to ope hw before doing the reset. CRs-Fixed: 2599233 Change-Id: Icd7cb809901a84169ea13d496689904a885b4622 Signed-off-by: Ravikishore Pampana --- drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c | 6 ++++-- drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.h | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) 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 3d5fd7d5714b..d6b6694443b2 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 @@ -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. */ #include @@ -44,7 +44,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, @@ -70,6 +71,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; } 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 cb22521f1310..428d66f7e9b8 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 @@ -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 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 */ -- GitLab From 7520ed699435cb24585899ab5bbecda5ebe7d67a Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Tue, 7 Jan 2020 16:21:44 +0530 Subject: [PATCH 064/295] msm: camera: ope: Add a check for valid request in cdm callback Add a check in cdm callback helper function to make sure request is valid and same request is not processed again. CRs-Fixed: 2595373 Change-Id: I3913059671907c6d3b324721d60914962e4e973f Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) 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 dd695ae0ea55..3100090996ed 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 @@ -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 @@ -1112,13 +1112,25 @@ 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", + CAM_DBG(CAM_OPE, "CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", handle, userdata, status, cookie); ctx = userdata; - ope_req = ctx->req_list[cookie]; mutex_lock(&ctx->ctx_mutex); + + if (cookie >= CAM_CTX_REQ_MAX) { + CAM_ERR(CAM_OPE, "Invalid reqIdx = %llu", cookie); + goto end; + } + + if (!test_bit(cookie, ctx->bitmap)) { + CAM_INFO(CAM_OPE, "Request not present reqIdx = %d", cookie); + goto end; + } + + ope_req = ctx->req_list[cookie]; + if (ctx->ctx_state != OPE_CTX_STATE_ACQUIRED) { CAM_DBG(CAM_OPE, "ctx %u is in %d state", ctx->ctx_id, ctx->ctx_state); -- GitLab From 2c397b51641d8f4c72430058aa193c9b6135f173 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 14 Oct 2019 15:08:23 +0530 Subject: [PATCH 065/295] msm: camera: req_mgr: LDAR Debug framework implementation When user space detects an error or does not receive response for a request, Lets do a reset(LDAR) is triggered. Before LDAR, user space sends flush command to the kernel space. To debug the cause for this situation and to dump the information, user space sends a dump command to the kernel space before sending flush. As a part of this command, it passes the culprit request id and the buffer into which the information can be dumped. Kernel space traverses across the drivers and find the culprit hw and dumps the relevant information in the buffer. This data is written to a file for offline processing. This commit implements the framework for traversal across the RT and NRT devices. CRs-Fixed: 2602180 Change-Id: I7e24006c20c23bfab163a2ad13b4ac6e2913bb9e Signed-off-by: Gaurav Jindal --- drivers/cam_core/cam_context.c | 65 ++++++++++ drivers/cam_core/cam_context.h | 49 ++++++++ drivers/cam_core/cam_context_utils.c | 127 ++++++++++++++++++++ drivers/cam_core/cam_context_utils.h | 3 +- drivers/cam_core/cam_hw_mgr_intf.h | 19 +++ drivers/cam_core/cam_node.c | 77 ++++++++++++ drivers/cam_req_mgr/cam_req_mgr_core.c | 60 +++++++++ drivers/cam_req_mgr/cam_req_mgr_core.h | 6 + drivers/cam_req_mgr/cam_req_mgr_dev.c | 24 ++++ drivers/cam_req_mgr/cam_req_mgr_interface.h | 24 ++++ include/uapi/media/cam_defs.h | 22 ++++ include/uapi/media/cam_req_mgr.h | 2 + 12 files changed, 477 insertions(+), 1 deletion(-) diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index 642d530054d8..3daf99cd1855 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -230,6 +230,34 @@ int cam_context_handle_crm_process_evt(struct cam_context *ctx, return rc; } +int cam_context_handle_crm_dump_req(struct cam_context *ctx, + struct cam_req_mgr_dump_info *dump) +{ + int rc = 0; + + if (!ctx) { + CAM_ERR(CAM_CORE, "Invalid Context"); + return -EINVAL; + } + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context %s ctx_id %d is not ready", + ctx->dev_name, ctx->ctx_id); + return -EINVAL; + } + mutex_lock(&ctx->ctx_mutex); + + if (ctx->state_machine[ctx->state].crm_ops.dump_req) + rc = ctx->state_machine[ctx->state].crm_ops.dump_req(ctx, + dump); + else + CAM_ERR(CAM_CORE, "No crm dump req for %s dev %d, state %d", + ctx->dev_name, ctx->dev_hdl, ctx->state); + + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, uint32_t buf_info) { @@ -524,6 +552,43 @@ int cam_context_handle_info_dump(void *context, return rc; } +int cam_context_handle_dump_dev(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc = 0; + + if (!ctx) { + CAM_ERR(CAM_CORE, "Invalid Context"); + return -EINVAL; + } + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context %s ctx_id %d is not ready", + ctx->dev_name, ctx->ctx_id); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, + "Context %s ctx_id %d Invalid dump command payload", + ctx->dev_name, ctx->ctx_id); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + CAM_DBG(CAM_CORE, "dump device in dev %d, name %s state %d", + ctx->dev_hdl, ctx->dev_name, ctx->state); + if (ctx->state_machine[ctx->state].ioctl_ops.dump_dev) + rc = ctx->state_machine[ctx->state].ioctl_ops.dump_dev( + ctx, cmd); + else + CAM_WARN(CAM_CORE, "No dump device in dev %d, name %s state %d", + ctx->dev_hdl, ctx->dev_name, ctx->state); + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + int cam_context_init(struct cam_context *ctx, const char *dev_name, uint64_t dev_id, diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 2c1c685e76b8..770451faadf2 100644 --- a/drivers/cam_core/cam_context.h +++ b/drivers/cam_core/cam_context.h @@ -23,6 +23,12 @@ struct cam_context; #define CAM_CTX_CFG_MAX 20 #define CAM_CTX_RES_MAX 20 +/* max tag dump header string length*/ +#define CAM_CTXT_DUMP_TAG_MAX_LEN 32 + +/* Number of words to be dumped for context*/ +#define CAM_CTXT_DUMP_NUM_WORDS 10 + /** * enum cam_ctx_state - context top level states * @@ -86,6 +92,7 @@ struct cam_ctx_request { * @flush_dev: Function pointer for flush device * @acquire_hw: Function pointer for acquire hw * @release_hw: Function pointer for release hw + * @dump_dev: Function pointer for dump dev * */ struct cam_ctx_ioctl_ops { @@ -103,6 +110,8 @@ struct cam_ctx_ioctl_ops { struct cam_flush_dev_cmd *cmd); int (*acquire_hw)(struct cam_context *ctx, void *args); int (*release_hw)(struct cam_context *ctx, void *args); + int (*dump_dev)(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd); }; /** @@ -114,6 +123,7 @@ struct cam_ctx_ioctl_ops { * @apply_req: Apply setting for the context * @flush_req: Flush request to remove request ids * @process_evt: Handle event notification from CRM.(optional) + * @dump_req: Dump information for the issue request * */ struct cam_ctx_crm_ops { @@ -129,6 +139,8 @@ struct cam_ctx_crm_ops { struct cam_req_mgr_flush_request *flush); int (*process_evt)(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *evt_data); + int (*dump_req)(struct cam_context *ctx, + struct cam_req_mgr_dump_info *dump); }; @@ -219,6 +231,19 @@ struct cam_context { uint32_t last_flush_req; }; +/** + * struct cam_context_dump_header - Function for context dump header + * + * @tag : Tag for context dump header + * @size : Size of data + * @word_size : Word size of data + */ +struct cam_context_dump_header { + uint8_t tag[CAM_CTXT_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + /** * cam_context_shutdown() * @@ -301,6 +326,18 @@ int cam_context_handle_crm_flush_req(struct cam_context *ctx, int cam_context_handle_crm_process_evt(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *process_evt); +/** + * cam_context_handle_crm_dump_req() + * + * @brief: Handle CRM dump request + * + * @ctx: Object pointer for cam_context + * @dump: Dump request command payload + * + */ +int cam_context_handle_crm_dump_req(struct cam_context *ctx, + struct cam_req_mgr_dump_info *dump); + /** * cam_context_dump_pf_info() * @@ -410,6 +447,18 @@ int cam_context_handle_start_dev(struct cam_context *ctx, int cam_context_handle_stop_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); +/** + * cam_context_handle_dump_dev() + * + * @brief: Handle dump device command + * + * @ctx: Object pointer for cam_context + * @cmd: Dump device command payload + * + */ +int cam_context_handle_dump_dev(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd); + /** * cam_context_handle_info_dump() * diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 8090bd0071a6..5bf5cd28f84f 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -1046,3 +1046,130 @@ int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx) end: return rc; } + +static int cam_context_dump_context(struct cam_context *ctx, + struct cam_hw_dump_args *dump_args) +{ + int rc; + int i; + size_t buf_len; + size_t remain_len; + uint8_t *dst; + uint64_t *addr, *start; + uint32_t min_len; + uintptr_t cpu_addr; + struct cam_ctx_request *req; + struct cam_context_dump_header *hdr; + + if (!ctx || !dump_args) { + CAM_ERR(CAM_CORE, "Invalid parameters %pK %pK", + ctx, dump_args); + return -EINVAL; + } + + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->active_req_list)) { + CAM_ERR(CAM_CTXT, "[%s][%d] no active request", + ctx->dev_name, ctx->ctx_id); + spin_unlock_bh(&ctx->lock); + return -EIO; + } + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + spin_unlock_bh(&ctx->lock); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &cpu_addr, &buf_len); + if (rc) { + CAM_ERR(CAM_CTXT, "Invalid hdl %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + if (dump_args->offset >= buf_len) { + CAM_WARN(CAM_CTXT, "dump buffer overshoot offset %zu len %zu", + dump_args->offset, buf_len); + return -ENOSPC; + } + + remain_len = buf_len - dump_args->offset; + min_len = sizeof(struct cam_context_dump_header) + + (CAM_CTXT_DUMP_NUM_WORDS + req->num_in_map_entries + + (req->num_out_map_entries * 2)) * sizeof(uint64_t); + + if (remain_len < min_len) { + CAM_WARN(CAM_CTXT, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + dst = (uint8_t *)cpu_addr + dump_args->offset; + hdr = (struct cam_context_dump_header *)dst; + scnprintf(hdr->tag, CAM_CTXT_DUMP_TAG_MAX_LEN, + "%s_CTXT_DUMP:", ctx->dev_name); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_context_dump_header)); + start = addr; + *addr++ = ctx->ctx_id; + *addr++ = refcount_read(&(ctx->refcount.refcount)); + *addr++ = ctx->last_flush_req; + *addr++ = ctx->state; + *addr++ = req->num_out_map_entries; + for (i = 0; i < req->num_out_map_entries; i++) { + *addr++ = req->out_map_entries[i].resource_handle; + *addr++ = req->out_map_entries[i].sync_id; + } + *addr++ = req->num_in_map_entries; + for (i = 0; i < req->num_in_map_entries; i++) + *addr++ = req->in_map_entries[i].sync_id; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_context_dump_header); + return rc; +} + +int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc = 0; + struct cam_hw_dump_args dump_args; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + return -EINVAL; + } + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + return -EFAULT; + } + memset(&dump_args, 0, sizeof(dump_args)); + if (ctx->hw_mgr_intf->hw_dump) { + dump_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + dump_args.buf_handle = cmd->buf_handle; + dump_args.offset = cmd->offset; + dump_args.request_id = cmd->issue_req_id; + dump_args.error_type = cmd->error_type; + rc = ctx->hw_mgr_intf->hw_dump( + ctx->hw_mgr_intf->hw_mgr_priv, + &dump_args); + if (rc) { + CAM_ERR(CAM_CTXT, "[%s][%d] handle[%u] failed", + ctx->dev_name, ctx->ctx_id, dump_args.buf_handle); + return rc; + } + /* Offset will change if the issue request id is found with + * the hw and has been lying with it beyond threshold time. + * If offset does not change, do not dump the context + * information as the current context has no problem with + * the provided request id. + */ + if (dump_args.offset > cmd->offset) { + cam_context_dump_context(ctx, &dump_args); + CAM_INFO(CAM_CTXT, "[%s] ctx: %d Filled Length %u", + ctx->dev_name, ctx->ctx_id, + dump_args.offset - cmd->offset); + cmd->offset = dump_args.offset; + } + } else { + CAM_DBG(CAM_CTXT, "%s hw dump not registered", ctx->dev_name); + } + return rc; +} diff --git a/drivers/cam_core/cam_context_utils.h b/drivers/cam_core/cam_context_utils.h index 087fdbf36544..79dec3142e8a 100644 --- a/drivers/cam_core/cam_context_utils.h +++ b/drivers/cam_core/cam_context_utils.h @@ -30,5 +30,6 @@ int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, struct cam_packet *packet, unsigned long iova, uint32_t buf_info, bool *mem_found); int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx); - +int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd); #endif /* _CAM_CONTEXT_UTILS_H_ */ diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index fe074734f389..1e2c1f7a7008 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -300,6 +300,23 @@ struct cam_hw_reset_args { void *ctxt_to_hw_map; }; +/** + * struct cam_hw_dump_args - Dump arguments + * + * @request_id: request_id + * @offset: Buffer offset. This is updated by the drivers. + * @buf_handle: Buffer handle + * @error_type: Error type, to be used to extend dump information + * @ctxt_to_hw_map: HW context from the acquire + */ +struct cam_hw_dump_args { + uint64_t request_id; + size_t offset; + uint32_t buf_handle; + uint32_t error_type; + void *ctxt_to_hw_map; +}; + /* enum cam_hw_mgr_command - Hardware manager command type */ enum cam_hw_mgr_command { CAM_HW_MGR_CMD_INTERNAL, @@ -355,6 +372,7 @@ struct cam_hw_cmd_args { * @hw_close: Function pointer for HW deinit * @hw_flush: Function pointer for HW flush * @hw_reset: Function pointer for HW reset + * @hw_dump: Function pointer for HW dump * */ struct cam_hw_mgr_intf { @@ -376,6 +394,7 @@ struct cam_hw_mgr_intf { int (*hw_close)(void *hw_priv, void *hw_close_args); int (*hw_flush)(void *hw_priv, void *hw_flush_args); int (*hw_reset)(void *hw_priv, void *hw_reset_args); + int (*hw_dump)(void *hw_priv, void *hw_dump_args); }; #endif /* _CAM_HW_MGR_INTF_H_ */ diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index 4fefa2f35db3..672ae35b6226 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -435,6 +435,39 @@ static int __cam_node_handle_release_dev(struct cam_node *node, return rc; } +static int __cam_node_handle_dump_dev(struct cam_node *node, + struct cam_dump_req_cmd *dump) +{ + int rc; + struct cam_context *ctx = NULL; + + if (!dump) + return -EINVAL; + + if (dump->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (dump->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(dump->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + dump->dev_handle); + return -EINVAL; + } + + rc = cam_context_handle_dump_dev(ctx, dump); + if (rc) + CAM_ERR(CAM_CORE, "Dump failure for node %s", node->name); + + return rc; +} + static int __cam_node_handle_release_hw_v1(struct cam_node *node, struct cam_release_hw_cmd_v1 *release) { @@ -575,6 +608,25 @@ static int __cam_node_crm_process_evt( return cam_context_handle_crm_process_evt(ctx, evt_data); } +static int __cam_node_crm_dump_req(struct cam_req_mgr_dump_info *dump) +{ + struct cam_context *ctx = NULL; + + if (!dump) { + CAM_ERR(CAM_CORE, "Invalid dump request payload"); + return -EINVAL; + } + + ctx = (struct cam_context *) cam_get_device_priv(dump->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + dump->dev_hdl); + return -EINVAL; + } + + return cam_context_handle_crm_dump_req(ctx, dump); +} + int cam_node_deinit(struct cam_node *node) { if (node) @@ -630,6 +682,7 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, node->crm_node_intf.link_setup = __cam_node_crm_link_setup; node->crm_node_intf.flush_req = __cam_node_crm_flush_req; node->crm_node_intf.process_evt = __cam_node_crm_process_evt; + node->crm_node_intf.dump_req = __cam_node_crm_dump_req; mutex_init(&node->list_mutex); INIT_LIST_HEAD(&node->free_ctx_list); @@ -877,6 +930,30 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) } break; } + case CAM_DUMP_REQ: { + struct cam_dump_req_cmd dump; + + if (copy_from_user(&dump, u64_to_user_ptr(cmd->handle), + sizeof(dump))) { + rc = -EFAULT; + break; + } + rc = __cam_node_handle_dump_dev(node, &dump); + if (rc) { + CAM_ERR(CAM_CORE, + "Dump device %s failed(rc = %d) ", + node->name, rc); + break; + } + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &dump, sizeof(dump))) { + CAM_ERR(CAM_CORE, + "Dump device %s copy_to_user fail", + node->name); + rc = -EFAULT; + } + break; + } default: CAM_ERR(CAM_CORE, "Unknown op code %d", cmd->op_code); rc = -EINVAL; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 00677b9d864e..36685ad18711 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3698,6 +3698,66 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) return rc; } +int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req) +{ + int rc = 0; + int i; + struct cam_req_mgr_dump_info info; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_core_session *session = NULL; + struct cam_req_mgr_connected_device *device = NULL; + + if (!dump_req) { + CAM_ERR(CAM_CRM, "dump req is NULL"); + return -EFAULT; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + /* session hdl's priv data is cam session struct */ + session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(dump_req->session_handle); + if (!session) { + CAM_ERR(CAM_CRM, "Invalid session %x", + dump_req->session_handle); + rc = -EINVAL; + goto end; + } + if (session->num_links <= 0) { + CAM_WARN(CAM_CRM, "No active links in session %x", + dump_req->session_handle); + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(dump_req->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", dump_req->link_hdl); + rc = -EINVAL; + goto end; + } + info.offset = dump_req->offset; + for (i = 0; i < link->num_devs; i++) { + device = &link->l_dev[i]; + info.link_hdl = dump_req->link_hdl; + info.dev_hdl = device->dev_hdl; + info.req_id = dump_req->issue_req_id; + info.buf_handle = dump_req->buf_handle; + info.error_type = dump_req->error_type; + if (device->ops && device->ops->dump_req) { + rc = device->ops->dump_req(&info); + if (rc) + CAM_ERR(CAM_REQ, + "Fail dump req %llu dev %d rc %d", + info.req_id, device->dev_hdl, rc); + } + } + dump_req->offset = info.offset; + CAM_INFO(CAM_REQ, "req %llu, offset %zu", + dump_req->issue_req_id, dump_req->offset); +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return 0; +} int cam_req_mgr_core_device_init(void) { diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 0afdc69b0445..056b421ff81e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -503,4 +503,10 @@ void cam_req_mgr_handle_core_shutdown(void); */ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control); +/** + * cam_req_mgr_dump_request() + * @brief: Dumps the request information + * @dump_req: Dump request + */ +int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req); #endif diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index cdb2210a2efb..5d5ff6229268 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -519,6 +519,30 @@ static long cam_private_ioctl(struct file *file, void *fh, rc = -EINVAL; } break; + case CAM_REQ_MGR_REQUEST_DUMP: { + struct cam_dump_req_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_dump_req_cmd))) { + rc = -EFAULT; + break; + } + rc = cam_req_mgr_dump_request(&cmd); + if (rc) { + CAM_ERR(CAM_CORE, "dump fail for dev %d req %llu rc %d", + cmd.dev_handle, cmd.issue_req_id, rc); + break; + } + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &cmd, sizeof(struct cam_dump_req_cmd))) + rc = -EFAULT; + } + break; default: return -ENOIOCTLCMD; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index 5df13b26e215..dfa44fc6b0bc 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -20,6 +20,7 @@ struct cam_req_mgr_core_dev_link_setup; struct cam_req_mgr_apply_request; struct cam_req_mgr_flush_request; struct cam_req_mgr_link_evt_data; +struct cam_req_mgr_dump_info; #define SKIP_NEXT_FRAME 0x100 @@ -47,6 +48,7 @@ typedef int (*cam_req_mgr_notify_timer)(struct cam_req_mgr_timer_notify *); * @cam_req_mgr_apply_req : CRM asks device to apply certain request id. * @cam_req_mgr_flush_req : Flush or cancel request * cam_req_mgr_process_evt : generic events + * @cam_req_mgr_dump_req : dump request */ typedef int (*cam_req_mgr_get_dev_info) (struct cam_req_mgr_device_info *); typedef int (*cam_req_mgr_link_setup)( @@ -54,6 +56,7 @@ typedef int (*cam_req_mgr_link_setup)( typedef int (*cam_req_mgr_apply_req)(struct cam_req_mgr_apply_request *); typedef int (*cam_req_mgr_flush_req)(struct cam_req_mgr_flush_request *); typedef int (*cam_req_mgr_process_evt)(struct cam_req_mgr_link_evt_data *); +typedef int (*cam_req_mgr_dump_req)(struct cam_req_mgr_dump_info *); /** * @brief : cam_req_mgr_crm_cb - func table @@ -77,6 +80,7 @@ struct cam_req_mgr_crm_cb { * @apply_req : payload to apply request id on a device linked * @flush_req : payload to flush request * @process_evt : payload to generic event + * @dump_req : payload to dump request */ struct cam_req_mgr_kmd_ops { cam_req_mgr_get_dev_info get_dev_info; @@ -84,6 +88,7 @@ struct cam_req_mgr_kmd_ops { cam_req_mgr_apply_req apply_req; cam_req_mgr_flush_req flush_req; cam_req_mgr_process_evt process_evt; + cam_req_mgr_dump_req dump_req; }; /** @@ -349,4 +354,23 @@ struct cam_req_mgr_send_request { int32_t link_hdl; struct cam_req_mgr_req_queue *in_q; }; + +/** + * struct cam_req_mgr_dump_info + * @req_id : request id to dump + * @offset : offset of buffer + * @error_type : error type + * @buf_handle : buf handle + * @link_hdl : link identifier + * @dev_hdl : device handle for cross check + * + */ +struct cam_req_mgr_dump_info { + uint64_t req_id; + size_t offset; + uint32_t error_type; + uint32_t buf_handle; + int32_t link_hdl; + int32_t dev_hdl; +}; #endif diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index 23b4ba98f92a..52d14a2d3fb3 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -26,6 +26,7 @@ #define CAM_COMMON_OPCODE_BASE_v2 0x150 #define CAM_ACQUIRE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x1) #define CAM_RELEASE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x2) +#define CAM_DUMP_REQ (CAM_COMMON_OPCODE_BASE_v2 + 0x3) #define CAM_EXT_OPCODE_BASE 0x200 #define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1) @@ -868,5 +869,26 @@ struct cam_reg_dump_input_info { uint32_t dump_set_offsets[1]; }; +/** + * struct cam_dump_req_cmd - + * Dump the information of issue req id + * + * @issue_req_id : Issue Request Id + * @offset : Offset for the buffer + * @buf_handle : Buffer Handle + * @error_type : Error type, using it, dumping information can be extended + * @session_handle : Session Handle + * @link_hdl : link handle + * @dev_handle : Device Handle + */ +struct cam_dump_req_cmd { + uint64_t issue_req_id; + size_t offset; + uint32_t buf_handle; + uint32_t error_type; + int32_t session_handle; + int32_t link_hdl; + int32_t dev_handle; +}; #endif /* __UAPI_CAM_DEFS_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index b1170004281c..7528557a8423 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -261,6 +261,8 @@ struct cam_req_mgr_link_control { #define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12) #define CAM_REQ_MGR_LINK_CONTROL (CAM_COMMON_OPCODE_MAX + 13) #define CAM_REQ_MGR_LINK_V2 (CAM_COMMON_OPCODE_MAX + 14) +#define CAM_REQ_MGR_REQUEST_DUMP (CAM_COMMON_OPCODE_MAX + 15) + /* end of cam_req_mgr opcodes */ #define CAM_MEM_FLAG_HW_READ_WRITE (1<<0) -- GitLab From ff7aca94a1e98d97c5dc4e5b1072023c4457659a Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 13 Jan 2020 13:41:26 +0530 Subject: [PATCH 066/295] msm: camera: ope: Remove the BW & clock vote in release context Remove the BW and clock votes while releasing the context. This will make sure that once the context is free then it's BW and clock votes doesn't get added to another context. CRs-Fixed: 2595319 Change-Id: Ibea9ac9e763dff7de6cf833ce132ef5041fb04f4 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 80 +++++++++++++++++++++ 1 file changed, 80 insertions(+) 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 3100090996ed..8d2c8345b171 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 @@ -2137,6 +2137,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; @@ -2277,6 +2290,64 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) 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; @@ -2334,6 +2405,15 @@ static int cam_ope_mgr_release_ctx(struct cam_ope_hw_mgr *hw_mgr, int ctx_id) hw_mgr->ctx[ctx_id].ope_cdm.cdm_handle = 0; hw_mgr->ctx[ctx_id].req_cnt = 0; cam_ope_put_free_ctx(hw_mgr, ctx_id); + + rc = cam_ope_mgr_remove_bw(hw_mgr, ctx_id); + if (rc) + CAM_ERR(CAM_OPE, "OPE remove bw failed: %d", rc); + + 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); -- GitLab From 30ab5e978a56f3e987068ba634531bd3d0485de9 Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Fri, 10 Jan 2020 12:20:15 +0530 Subject: [PATCH 067/295] msm: camera: ope: Reduce OPE BUS memory Update OPE BUS driver to reduce memory allocation at boot time. CRs-Fixed: 2600812 Change-Id: I37efa314f8ce3bbdc66e35e327e46132a1b8c07f Signed-off-by: Suresh Vankadara --- .../ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c | 39 +++++++++---------- .../ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.h | 4 +- 2 files changed, 20 insertions(+), 23 deletions(-) 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 5a0ef5cad3cf..5c0a09762059 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 @@ -151,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; - } + kzfree(wr_info->bus_wr_ctx[ctx_id]); + wr_info->bus_wr_ctx[ctx_id] = NULL; return rc; } @@ -226,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; @@ -404,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; @@ -494,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 + @@ -505,7 +495,7 @@ 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)); @@ -561,14 +551,21 @@ 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] = kzalloc(sizeof(struct ope_bus_wr_ctx), + GFP_KERNEL); + 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; 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 13b42f456059..ed9b8cca68df 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 @@ -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 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 */ -- GitLab From 54e7d00bd006ce45b92d7e037f8dfdeb4fee8c45 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Fri, 17 Jan 2020 09:14:16 +0530 Subject: [PATCH 068/295] msm: camera: ope: Fix return value for ope acquire Avoid overwriting of return status in case of any failure in OPE acquire. CRs-Fixed: 2604193 Change-Id: I518e34b3cb333f48318086cf989b8bea76d50dd5 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) 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 3100090996ed..fa3abe24bb9f 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 @@ -2241,11 +2241,10 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) 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: @@ -2254,23 +2253,24 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) 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"); } } 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); -- GitLab From 568ba18713196512c75ae311f39a3a9fd49d6f5b Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Thu, 16 Jan 2020 14:17:42 +0530 Subject: [PATCH 069/295] msm: camera: ope: Fix false alarm for OPE request timeout In case of timeout, validate the timeout by checking the time difference between last request and timeout. CRs-Fixed: 2600977 Change-Id: I2668463cd4b2e8fbf0058e07316e9b6244973a3c Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 17 ++++++++++++++++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 6 +++++- 2 files changed, 21 insertions(+), 2 deletions(-) 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 3100090996ed..eda8476173ae 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 @@ -239,6 +239,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 timespec64 ts; + uint64_t ts_ns; if (!ctx_data) { CAM_ERR(CAM_OPE, "ctx_data is NULL, failed to update clk"); @@ -254,6 +256,15 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) return 0; } + get_monotonic_boottime64(&ts); + ts_ns = (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + if (ts_ns - ctx_data->last_req_time < + OPE_REQUEST_TIMEOUT * 1000000) { + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + 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); @@ -386,7 +397,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"); @@ -2537,6 +2548,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", @@ -2587,6 +2599,9 @@ 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_ope_req_timer_reset(ctx_data); set_bit(request_idx, ctx_data->bitmap); ctx_data->req_list[request_idx] = 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 78fc3499a352..c8a60215ab66 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 @@ -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_OPE_HW_MGR_H @@ -60,6 +60,8 @@ #define CLK_HW_MAX 0x1 #define OPE_DEVICE_IDLE_TIMEOUT 400 +#define OPE_REQUEST_TIMEOUT 200 + /** @@ -431,6 +433,7 @@ 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 @@ -451,6 +454,7 @@ 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; -- GitLab From 18327b1990d0875f26ea51e71f37f22528953f73 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Wed, 6 Nov 2019 16:38:00 +0530 Subject: [PATCH 070/295] msm: camera: csiphy: Update reset sequence for csiphy v1.2 Add a transition of 1 to 0 in the PHY reset register during the PHY reset sequence to fix UNBOUNDED_FRAME errors for CPHY sensor. CRs-Fixed: 2563019 Change-Id: I019e4cfdfa2042416e62b306dca0448d6a05c3b8 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index e00e2bdf344d..20e14a354515 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -13,7 +13,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 6, - .csiphy_reset_array_size = 4, + .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 18, .csiphy_3ph_config_array_size = 33, .csiphy_2ph_clock_lane = 0x1, @@ -33,6 +33,7 @@ struct csiphy_reg_t csiphy_reset_reg_1_2[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; -- GitLab From 219cd37c87b9c0a704d7c722a74dd86ea300a40f Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Fri, 8 Nov 2019 13:33:36 +0530 Subject: [PATCH 071/295] msm: camera: csiphy: Fix csiphy v1.2 skew calibration settings Correct the skew calibration register settings in the DPHY sequence for csiphy v1.2. CRs-Fixed: 2563037 Change-Id: Idd97600b66dd00ff67db902dbd9d649aa005b4ec Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 20e14a354515..3bed231e0246 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -71,7 +71,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -111,7 +111,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -131,7 +131,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -151,7 +151,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0660, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, }, }; @@ -171,10 +171,10 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x000C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -211,10 +211,10 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -231,10 +231,10 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { -- GitLab From 27f855f6ca9101b12adaf798c21e7831fd6a2651 Mon Sep 17 00:00:00 2001 From: Sureshnaidu Laveti Date: Mon, 18 Nov 2019 14:00:11 -0800 Subject: [PATCH 072/295] msm: camera: sensor: Support for read operation Supporting read operation for sensor and sub modules OIS and actuator. CRs-Fixed: 2538801 Change-Id: I83ad154dd577d5a664c4d68792a90489e725fbfd Signed-off-by: Jigarkumar Zala Signed-off-by: Sureshnaidu Laveti --- .../cam_actuator/cam_actuator_core.c | 68 +++- .../cam_flash/cam_flash_core.c | 6 +- .../cam_sensor_module/cam_ois/cam_ois_core.c | 67 +++- .../cam_sensor/cam_sensor_core.c | 42 ++- .../cam_sensor/cam_sensor_dev.c | 4 +- .../cam_sensor_utils/cam_sensor_cmn_header.h | 13 +- .../cam_sensor_utils/cam_sensor_util.c | 308 +++++++++++++++++- .../cam_sensor_utils/cam_sensor_util.h | 7 +- 8 files changed, 495 insertions(+), 20 deletions(-) diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c index c609b8f85015..d886d8ebaecb 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -554,7 +554,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_sensor_i2c_command_parser( &a_ctrl->io_master_info, i2c_reg_settings, - &cmd_desc[i], 1); + &cmd_desc[i], 1, NULL); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed:parse init settings: %d", @@ -612,7 +612,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_sensor_i2c_command_parser( &a_ctrl->io_master_info, i2c_reg_settings, - cmd_desc, 1); + cmd_desc, 1, NULL); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Auto move lens parsing failed: %d", rc); @@ -643,7 +643,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_sensor_i2c_command_parser( &a_ctrl->io_master_info, i2c_reg_settings, - cmd_desc, 1); + cmd_desc, 1, NULL); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Manual move lens parsing failed: %d", rc); @@ -662,6 +662,68 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, } cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; + case CAM_ACTUATOR_PACKET_OPCODE_READ: { + struct cam_buf_io_cfg *io_cfg; + struct i2c_settings_array i2c_read_settings; + + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to read actuator: %d", + a_ctrl->cam_act_state); + goto end; + } + CAM_DBG(CAM_ACTUATOR, "number of I/O configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs == 0) { + CAM_ERR(CAM_ACTUATOR, "No I/O configs to process"); + rc = -EINVAL; + goto end; + } + + INIT_LIST_HEAD(&(i2c_read_settings.list_head)); + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_ACTUATOR, "I/O config is invalid(NULL)"); + rc = -EINVAL; + goto end; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + i2c_read_settings.is_settings_valid = 1; + i2c_read_settings.request_id = 0; + rc = cam_sensor_i2c_command_parser(&a_ctrl->io_master_info, + &i2c_read_settings, + cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "actuator read pkt parsing failed: %d", rc); + goto end; + } + + rc = cam_sensor_i2c_read_data( + &i2c_read_settings, + &a_ctrl->io_master_info); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "cannot read data, rc:%d", rc); + delete_request(&i2c_read_settings); + goto end; + } + + rc = delete_request(&i2c_read_settings); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed in deleting the read settings"); + goto end; + } + break; + } default: CAM_ERR(CAM_ACTUATOR, "Wrong Opcode: %d", csl_packet->header.op_code & 0xFFFFFF); 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 293d1422b393..063848104f63 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -1070,7 +1070,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = cam_sensor_i2c_command_parser( &fctrl->io_master_info, i2c_reg_settings, - &cmd_desc[i], 1); + &cmd_desc[i], 1, NULL); if (rc < 0) { CAM_ERR(CAM_FLASH, "pkt parsing failed: %d", rc); @@ -1150,7 +1150,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_sensor_i2c_command_parser( &fctrl->io_master_info, - i2c_reg_settings, cmd_desc, 1); + i2c_reg_settings, cmd_desc, 1, NULL); if (rc) { CAM_ERR(CAM_FLASH, "Failed in parsing i2c packets"); @@ -1181,7 +1181,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_sensor_i2c_command_parser( &fctrl->io_master_info, - i2c_reg_settings, cmd_desc, 1); + i2c_reg_settings, cmd_desc, 1, NULL); if (rc) { CAM_ERR(CAM_FLASH, "Failed in parsing i2c NRT packets"); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index b6035252a234..8ced8a28c309 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -540,7 +540,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) rc = cam_sensor_i2c_command_parser( &o_ctrl->io_master_info, i2c_reg_settings, - &cmd_desc[i], 1); + &cmd_desc[i], 1, NULL); if (rc < 0) { CAM_ERR(CAM_OIS, "init parsing failed: %d", rc); @@ -557,7 +557,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) rc = cam_sensor_i2c_command_parser( &o_ctrl->io_master_info, i2c_reg_settings, - &cmd_desc[i], 1); + &cmd_desc[i], 1, NULL); if (rc < 0) { CAM_ERR(CAM_OIS, "Calib parsing failed: %d", rc); @@ -629,7 +629,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) i2c_reg_settings->request_id = 0; rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, i2c_reg_settings, - cmd_desc, 1); + cmd_desc, 1, NULL); if (rc < 0) { CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc); return rc; @@ -648,6 +648,67 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) return rc; } break; + case CAM_OIS_PACKET_OPCODE_READ: { + struct cam_buf_io_cfg *io_cfg; + struct i2c_settings_array i2c_read_settings; + + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state to read OIS: %d", + o_ctrl->cam_ois_state); + return rc; + } + CAM_DBG(CAM_OIS, "number of I/O configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs == 0) { + CAM_ERR(CAM_OIS, "No I/O configs to process"); + rc = -EINVAL; + return rc; + } + + INIT_LIST_HEAD(&(i2c_read_settings.list_head)); + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_OIS, "I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + i2c_read_settings.is_settings_valid = 1; + i2c_read_settings.request_id = 0; + rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, + &i2c_read_settings, + cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS read pkt parsing failed: %d", rc); + return rc; + } + + rc = cam_sensor_i2c_read_data( + &i2c_read_settings, + &o_ctrl->io_master_info); + if (rc < 0) { + CAM_ERR(CAM_OIS, "cannot read data rc: %d", rc); + delete_request(&i2c_read_settings); + return rc; + } + + rc = delete_request(&i2c_read_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Failed in deleting the read settings"); + return rc; + } + break; + } default: CAM_ERR(CAM_OIS, "Invalid Opcode: %d", (csl_packet->header.op_code & 0xFFFFFF)); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 2fa447dbace4..6902122b3f66 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -87,6 +87,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, struct cam_control *ioctl_ctrl = NULL; struct cam_packet *csl_packet = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_buf_io_cfg *io_cfg = NULL; struct i2c_settings_array *i2c_reg_settings = NULL; size_t len_of_buff = 0; size_t remain_len = 0; @@ -187,7 +188,28 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, i2c_reg_settings->is_settings_valid = 1; break; } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_READ: { + i2c_reg_settings = &(i2c_data->read_settings); + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + + CAM_DBG(CAM_SENSOR, "number of IO configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs == 0) { + CAM_ERR(CAM_SENSOR, "No I/O configs to process"); + goto end; + } + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_SENSOR, "I/O config is invalid(NULL)"); + goto end; + } + break; + } case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: { if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { @@ -239,7 +261,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_sensor_i2c_command_parser(&s_ctrl->io_master_info, - i2c_reg_settings, cmd_desc, 1); + i2c_reg_settings, cmd_desc, 1, io_cfg); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Fail parsing I2C Pkt: %d", rc); goto end; @@ -951,6 +973,24 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } s_ctrl->sensor_state = CAM_SENSOR_CONFIG; } + + if (s_ctrl->i2c_data.read_settings.is_settings_valid) { + rc = cam_sensor_i2c_read_data( + &s_ctrl->i2c_data.read_settings, + &s_ctrl->io_master_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "cannot read data: %d", rc); + delete_request(&s_ctrl->i2c_data.read_settings); + goto release_mutex; + } + rc = delete_request( + &s_ctrl->i2c_data.read_settings); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in deleting the read settings"); + goto release_mutex; + } + } } break; default: diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c index f847079c730a..765a1244a0aa 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #include "cam_sensor_dev.h" @@ -179,6 +179,7 @@ static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client, INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.read_settings.list_head)); for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head)); @@ -314,6 +315,7 @@ static int32_t cam_sensor_driver_platform_probe( INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.read_settings.list_head)); for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head)); diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index e43e8abe0809..563414e640cc 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -152,13 +152,15 @@ enum cam_sensor_packet_opcodes { CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF, + CAM_SENSOR_PACKET_OPCODE_SENSOR_READ, CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP = 127 }; enum cam_actuator_packet_opcodes { CAM_ACTUATOR_PACKET_OPCODE_INIT, CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS, - CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS + CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS, + CAM_ACTUATOR_PACKET_OPCODE_READ }; enum cam_eeprom_packet_opcodes { @@ -168,7 +170,8 @@ enum cam_eeprom_packet_opcodes { enum cam_ois_packet_opcodes { CAM_OIS_PACKET_OPCODE_INIT, - CAM_OIS_PACKET_OPCODE_OIS_CONTROL + CAM_OIS_PACKET_OPCODE_OIS_CONTROL, + CAM_OIS_PACKET_OPCODE_READ }; enum msm_bus_perf_setting { @@ -218,7 +221,8 @@ enum cam_sensor_i2c_cmd_type { CAM_SENSOR_I2C_WRITE_RANDOM, CAM_SENSOR_I2C_WRITE_BURST, CAM_SENSOR_I2C_WRITE_SEQ, - CAM_SENSOR_I2C_READ, + CAM_SENSOR_I2C_READ_RANDOM, + CAM_SENSOR_I2C_READ_SEQ, CAM_SENSOR_I2C_POLL }; @@ -270,6 +274,8 @@ struct cam_sensor_i2c_reg_setting { enum camera_sensor_i2c_type addr_type; enum camera_sensor_i2c_type data_type; unsigned short delay; + uint8_t *read_buff; + uint32_t read_buff_len; }; struct cam_sensor_i2c_seq_reg { @@ -297,6 +303,7 @@ struct i2c_data_settings { struct i2c_settings_array config_settings; struct i2c_settings_array streamon_settings; struct i2c_settings_array streamoff_settings; + struct i2c_settings_array read_settings; struct i2c_settings_array *per_frame; }; diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 0d82579e7999..078e3e08657a 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -233,6 +233,134 @@ static int32_t cam_sensor_handle_continuous_write( return rc; } +static int32_t cam_sensor_get_io_buffer( + struct cam_buf_io_cfg *io_cfg, + struct cam_sensor_i2c_reg_setting *i2c_settings) +{ + uintptr_t buf_addr = 0x0; + size_t buf_size = 0; + int32_t rc = 0; + + if (io_cfg->direction == CAM_BUF_OUTPUT) { + rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], + &buf_addr, &buf_size); + if ((rc < 0) || (!buf_addr)) { + CAM_ERR(CAM_SENSOR, + "invalid buffer, rc: %d, buf_addr: %pK", + rc, buf_addr); + return -EINVAL; + } + CAM_DBG(CAM_SENSOR, + "buf_addr: %pK, buf_size: %zu, offsetsize: %d", + (void *)buf_addr, buf_size, io_cfg->offsets[0]); + if (io_cfg->offsets[0] >= buf_size) { + CAM_ERR(CAM_SENSOR, + "invalid size:io_cfg->offsets[0]: %d, buf_size: %d", + io_cfg->offsets[0], buf_size); + return -EINVAL; + } + i2c_settings->read_buff = + (uint8_t *)buf_addr + io_cfg->offsets[0]; + i2c_settings->read_buff_len = + buf_size - io_cfg->offsets[0]; + } else { + CAM_ERR(CAM_SENSOR, "Invalid direction: %d", + io_cfg->direction); + rc = -EINVAL; + } + return rc; +} + +static int32_t cam_sensor_handle_random_read( + struct cam_cmd_i2c_random_rd *cmd_i2c_random_rd, + struct i2c_settings_array *i2c_reg_settings, + uint16_t *cmd_length_in_bytes, + int32_t *offset, + struct list_head **list, + struct cam_buf_io_cfg *io_cfg) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt = 0; + + i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, + cmd_i2c_random_rd->header.count); + if ((i2c_list == NULL) || + (i2c_list->i2c_settings.reg_setting == NULL)) { + CAM_ERR(CAM_SENSOR, + "Failed in allocating i2c_list: %pK", + i2c_list); + return -ENOMEM; + } + + rc = cam_sensor_get_io_buffer(io_cfg, &(i2c_list->i2c_settings)); + if (rc) { + CAM_ERR(CAM_SENSOR, "Failed to get read buffer: %d", rc); + } else { + *cmd_length_in_bytes = sizeof(struct i2c_rdwr_header) + + (sizeof(struct cam_cmd_read) * + (cmd_i2c_random_rd->header.count)); + i2c_list->op_code = CAM_SENSOR_I2C_READ_RANDOM; + i2c_list->i2c_settings.addr_type = + cmd_i2c_random_rd->header.addr_type; + i2c_list->i2c_settings.data_type = + cmd_i2c_random_rd->header.data_type; + i2c_list->i2c_settings.size = + cmd_i2c_random_rd->header.count; + + for (cnt = 0; cnt < (cmd_i2c_random_rd->header.count); + cnt++) { + i2c_list->i2c_settings.reg_setting[cnt].reg_addr = + cmd_i2c_random_rd->data_read[cnt].reg_data; + } + *offset = cnt; + *list = &(i2c_list->list); + } + + return rc; +} + +static int32_t cam_sensor_handle_continuous_read( + struct cam_cmd_i2c_continuous_rd *cmd_i2c_continuous_rd, + struct i2c_settings_array *i2c_reg_settings, + uint16_t *cmd_length_in_bytes, int32_t *offset, + struct list_head **list, + struct cam_buf_io_cfg *io_cfg) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt = 0; + + i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, 1); + if ((i2c_list == NULL) || + (i2c_list->i2c_settings.reg_setting == NULL)) { + CAM_ERR(CAM_SENSOR, + "Failed in allocating i2c_list: %pK", + i2c_list); + return -ENOMEM; + } + + rc = cam_sensor_get_io_buffer(io_cfg, &(i2c_list->i2c_settings)); + if (rc) { + CAM_ERR(CAM_SENSOR, "Failed to get read buffer: %d", rc); + } else { + *cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd); + i2c_list->op_code = CAM_SENSOR_I2C_READ_SEQ; + + i2c_list->i2c_settings.addr_type = + cmd_i2c_continuous_rd->header.addr_type; + i2c_list->i2c_settings.data_type = + cmd_i2c_continuous_rd->header.data_type; + i2c_list->i2c_settings.size = + cmd_i2c_continuous_rd->header.count; + i2c_list->i2c_settings.reg_setting[0].reg_addr = + cmd_i2c_continuous_rd->reg_addr; + + *offset = cnt; + *list = &(i2c_list->list); + } + + return rc; +} + static int cam_sensor_handle_slave_info( struct camera_io_master *io_master, uint32_t *cmd_buf) @@ -271,8 +399,11 @@ static int cam_sensor_handle_slave_info( /** * Name : cam_sensor_i2c_command_parser * Description : Parse CSL CCI packet and apply register settings - * Parameters : s_ctrl input/output sub_device - * arg input cam_control + * Parameters : io_master input master information + * i2c_reg_settings output register settings to fill + * cmd_desc input command description + * num_cmd_buffers input number of command buffers to process + * io_cfg input buffer details for read operation only * Description : * Handle multiple I2C RD/WR and WAIT cmd formats in one command * buffer, for example, a command buffer of m x RND_WR + 1 x HW_ @@ -283,11 +414,12 @@ int cam_sensor_i2c_command_parser( struct camera_io_master *io_master, struct i2c_settings_array *i2c_reg_settings, struct cam_cmd_buf_desc *cmd_desc, - int32_t num_cmd_buffers) + int32_t num_cmd_buffers, + struct cam_buf_io_cfg *io_cfg) { int16_t rc = 0, i = 0; size_t len_of_buff = 0; - uintptr_t generic_ptr; + uintptr_t generic_ptr; uint16_t cmd_length_in_bytes = 0; size_t remain_len = 0; size_t tot_size = 0; @@ -472,7 +604,7 @@ int cam_sensor_i2c_command_parser( } case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: { if (remain_len - byte_cnt < - sizeof(struct cam_cmd_i2c_info)) { + sizeof(struct cam_cmd_i2c_info)) { CAM_ERR(CAM_SENSOR, "Not enough buffer space"); rc = -EINVAL; @@ -493,6 +625,88 @@ int cam_sensor_i2c_command_parser( byte_cnt += cmd_length_in_bytes; break; } + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_RD: { + uint16_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_random_rd *i2c_random_rd = + (struct cam_cmd_i2c_random_rd *)cmd_buf; + + if (remain_len - byte_cnt < + sizeof(struct cam_cmd_i2c_random_rd)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto end; + } + + tot_size = sizeof(struct i2c_rdwr_header) + + (sizeof(struct cam_cmd_read) * + i2c_random_rd->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided %d, %d, %d", + tot_size, remain_len, byte_cnt); + rc = -EINVAL; + goto end; + } + + rc = cam_sensor_handle_random_read( + i2c_random_rd, + i2c_reg_settings, + &cmd_length_in_bytes, &j, &list, + io_cfg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in random read %d", rc); + goto end; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD: { + uint16_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_continuous_rd + *i2c_continuous_rd = + (struct cam_cmd_i2c_continuous_rd *)cmd_buf; + + if (remain_len - byte_cnt < + sizeof(struct cam_cmd_i2c_continuous_rd)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto end; + } + + tot_size = + sizeof(struct cam_cmd_i2c_continuous_rd); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided %d, %d, %d", + tot_size, remain_len, byte_cnt); + rc = -EINVAL; + goto end; + } + + rc = cam_sensor_handle_continuous_read( + i2c_continuous_rd, + i2c_reg_settings, + &cmd_length_in_bytes, &j, &list, + io_cfg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in continuous read %d", rc); + goto end; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } default: CAM_ERR(CAM_SENSOR, "Invalid Command Type:%d", cmm_hdr->cmd_type); @@ -576,6 +790,90 @@ int cam_sensor_util_i2c_apply_setting( return rc; } +int32_t cam_sensor_i2c_read_data( + struct i2c_settings_array *i2c_settings, + struct camera_io_master *io_master_info) +{ + int32_t rc = 0; + struct i2c_settings_list *i2c_list; + uint32_t cnt = 0; + uint8_t *read_buff = NULL; + uint32_t buff_length = 0; + uint32_t read_length = 0; + + list_for_each_entry(i2c_list, + &(i2c_settings->list_head), list) { + read_buff = i2c_list->i2c_settings.read_buff; + buff_length = i2c_list->i2c_settings.read_buff_len; + if ((read_buff == NULL) || (buff_length == 0)) { + CAM_ERR(CAM_SENSOR, + "Invalid input buffer, buffer: %pK, length: %d", + read_buff, buff_length); + return -EINVAL; + } + + if (i2c_list->op_code == CAM_SENSOR_I2C_READ_RANDOM) { + read_length = i2c_list->i2c_settings.data_type * + i2c_list->i2c_settings.size; + if ((read_length > buff_length) || + (read_length < i2c_list->i2c_settings.size)) { + CAM_ERR(CAM_SENSOR, + "Invalid size, readLen:%d, bufLen:%d, size: %d", + read_length, buff_length, + i2c_list->i2c_settings.size); + return -EINVAL; + } + for (cnt = 0; cnt < (i2c_list->i2c_settings.size); + cnt++) { + struct cam_sensor_i2c_reg_array *reg_setting = + &(i2c_list->i2c_settings.reg_setting[cnt]); + rc = camera_io_dev_read(io_master_info, + reg_setting->reg_addr, + ®_setting->reg_data, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed: random read I2C settings: %d", + rc); + return rc; + } + if (i2c_list->i2c_settings.data_type < + CAMERA_SENSOR_I2C_TYPE_MAX) { + memcpy(read_buff, + ®_setting->reg_data, + i2c_list->i2c_settings.data_type); + read_buff += + i2c_list->i2c_settings.data_type; + } + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_READ_SEQ) { + read_length = i2c_list->i2c_settings.size; + if (read_length > buff_length) { + CAM_ERR(CAM_SENSOR, + "Invalid buffer size, readLen: %d, bufLen: %d", + read_length, buff_length); + return -EINVAL; + } + rc = camera_io_dev_read_seq( + io_master_info, + i2c_list->i2c_settings.reg_setting[0].reg_addr, + read_buff, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "failed: seq read I2C settings: %d", + rc); + return rc; + } + } + } + + return rc; +} + int32_t msm_camera_fill_vreg_params( struct cam_hw_soc_info *soc_info, struct cam_sensor_power_setting *power_setting, diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h index c923efe61dc5..3600b5636cab 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h @@ -30,11 +30,16 @@ int msm_camera_pinctrl_init int cam_sensor_i2c_command_parser(struct camera_io_master *io_master, struct i2c_settings_array *i2c_reg_settings, - struct cam_cmd_buf_desc *cmd_desc, int32_t num_cmd_buffers); + struct cam_cmd_buf_desc *cmd_desc, int32_t num_cmd_buffers, + struct cam_buf_io_cfg *io_cfg); int cam_sensor_util_i2c_apply_setting(struct camera_io_master *io_master_info, struct i2c_settings_list *i2c_list); +int32_t cam_sensor_i2c_read_data( + struct i2c_settings_array *i2c_settings, + struct camera_io_master *io_master_info); + int32_t delete_request(struct i2c_settings_array *i2c_array); int cam_sensor_util_request_gpio_table( struct cam_hw_soc_info *soc_info, int gpio_en); -- GitLab From 894348fbfd116d0ec795a41a5d039348284f427c Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Wed, 16 Oct 2019 10:39:45 +0530 Subject: [PATCH 073/295] msm: camera: icp: icp debug improvement ON receiving HFI_EVENT_SYS_ERROR event_id as part of sys_error msg and event_data1 is set to HFI_ERR_SYS_FATAL, trigger the crash. CRs-Fixed: 2549369 Change-Id: Iddf56f46b2c07a703a787b0dedebd801081c93d6 Signed-off-by: Tejas Prajapati --- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index a09f1e35f485..26b43490b42e 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -2361,6 +2361,10 @@ static int cam_icp_mgr_process_fatal_error( if (event_notify->event_id == HFI_EVENT_SYS_ERROR) { CAM_INFO(CAM_ICP, "received HFI_EVENT_SYS_ERROR"); + if (event_notify->event_data1 == HFI_ERR_SYS_FATAL) { + CAM_ERR(CAM_ICP, "received HFI_ERR_SYS_FATAL"); + BUG(); + } rc = cam_icp_mgr_trigger_recovery(hw_mgr); cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); } -- GitLab From 9ff1993c1f79faf4c5c84d18e15951249799027d Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 20 Jan 2020 14:49:59 +0530 Subject: [PATCH 074/295] msm: camera: ope: Avoid deadlock during recovery after HW hang In case of OPE HW hang, during recovery deadlock is occurring during callback from CDM to OPE. Fixing the issue by calling the recovery from workqueue. CRs-Fixed: 2606254 Change-Id: I052056981687c6e5f96c4d2d0a323e9c105d0503 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 126 +++++++++++--------- 1 file changed, 71 insertions(+), 55 deletions(-) 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 eda8476173ae..fdb63d419bc6 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 @@ -227,10 +227,65 @@ 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); + + 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; +} + 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; @@ -241,6 +296,8 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) int path_index; struct timespec64 ts; uint64_t ts_ns; + 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"); @@ -267,7 +324,18 @@ 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); + task = cam_req_mgr_workq_get_task(ope_hw_mgr->msg_work); + if (!task) { + CAM_ERR(CAM_OPE, "no empty task"); + 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; @@ -550,19 +618,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) { @@ -1187,45 +1242,6 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, 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; -- GitLab From 9d84145aef30f447d1ff6cd76806ac7875e94152 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 30 Dec 2019 11:55:42 +0530 Subject: [PATCH 075/295] msm: camera: tfe: tfe debug enhancement If any tfe error comes read each CLC Hardware status and log it. Move the tfe bus error processing to the bus file. Log the bus overflow client name if bus overflow comes. Log the bus client name if image violation comes. CRs-Fixed: 2585713 Change-Id: I1fceb45d58267d5f2f650841dd6dd95fcb6a6f2b Signed-off-by: Ravikishore Pampana --- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe530.h | 78 +++++ .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 122 ++++++- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.h | 18 +- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 308 ++++++++++++------ .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h | 65 ++-- 5 files changed, 464 insertions(+), 127 deletions(-) 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 2deb3dd6b835..ff9528b56e70 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 215b2cce19ef..9eaec1d1d17f 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 @@ -95,6 +95,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 { @@ -491,6 +495,15 @@ 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; + + /* + * 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; @@ -1573,8 +1586,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 +1698,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 +1710,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 +1723,7 @@ static int cam_tfe_bus_bottom_half(void *priv, cam_tfe_bus_bufdone_bottom_half(bus_priv, evt_payload); } +end: return 0; } 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 e5736c6f97c4..cc6703baf9e7 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 f886fd53087b..70d40eb6a3b1 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,6 +221,78 @@ int cam_tfe_irq_config(void *tfe_core_data, return 0; } +static void cam_tfe_log_tfe_in_debug_status( + struct cam_tfe_top_priv *top_priv) +{ + void __iomem *mem_base; + struct cam_tfe_camif_data *camif_data; + struct cam_tfe_rdi_data *rdi_data; + uint32_t i, val_0, val_1; + + mem_base = top_priv->common_data.soc_info->reg_map[0].mem_base; + + for (i = 0; i < CAM_TFE_TOP_IN_PORT_MAX; i++) { + if ((top_priv->in_rsrc[i].res_state != + CAM_ISP_RESOURCE_STATE_STREAMING)) + continue; + + if (top_priv->in_rsrc[i].res_id == CAM_ISP_HW_TFE_IN_CAMIF) { + camif_data = (struct cam_tfe_camif_data *) + top_priv->in_rsrc[i].res_priv; + val_0 = cam_io_r(mem_base + + camif_data->camif_reg->debug_0); + val_1 = cam_io_r(mem_base + + camif_data->camif_reg->debug_1); + CAM_INFO(CAM_ISP, + "camif debug1:0x%x Height:0x%x, width:0x%x", + 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 <= + CAM_ISP_HW_TFE_IN_RDI2)) { + rdi_data = (struct cam_tfe_rdi_data *) + top_priv->in_rsrc[i].res_priv; + val_0 = cam_io_r(mem_base + + rdi_data->rdi_reg->rdi_debug_0); + val_1 = cam_io_r(mem_base + + rdi_data->rdi_reg->rdi_debug_1); + CAM_INFO(CAM_ISP, + "RDI res id:%d debug1:0x%x Height:0x%x, width:0x%x", + 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, @@ -220,15 +302,31 @@ static void cam_tfe_log_error_irq_status( 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; + + 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 + @@ -242,22 +340,14 @@ static void cam_tfe_log_error_irq_status( 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_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); - 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); @@ -274,42 +364,19 @@ static void cam_tfe_log_error_irq_status( "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 != - CAM_ISP_RESOURCE_STATE_STREAMING)) - continue; - - if (top_priv->in_rsrc[i].res_id == CAM_ISP_HW_TFE_IN_CAMIF) { - camif_data = (struct cam_tfe_camif_data *) - top_priv->in_rsrc[i].res_priv; - val_0 = cam_io_r(mem_base + - camif_data->camif_reg->debug_0); - val_1 = cam_io_r(mem_base + - camif_data->camif_reg->debug_1); - CAM_INFO(CAM_ISP, - "camif debug1:0x%x Height:0x%x, width:0x%x", - val_1, - ((val_0 >> 16) & 0x1FFF), - (val_0 & 0x1FFF)); - } else if ((top_priv->in_rsrc[i].res_id >= - CAM_ISP_HW_TFE_IN_RDI0) || - (top_priv->in_rsrc[i].res_id <= - CAM_ISP_HW_TFE_IN_RDI2)) { - rdi_data = (struct cam_tfe_rdi_data *) - top_priv->in_rsrc[i].res_priv; - val_0 = cam_io_r(mem_base + - rdi_data->rdi_reg->rdi_debug_0); - val_1 = cam_io_r(mem_base + - rdi_data->rdi_reg->rdi_debug_1); + 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, - "RDI res id:%d debug1:0x%x Height:0x%x, width:0x%x", - top_priv->in_rsrc[i].res_id, - val_1, ((val_0 >> 16) & 0x1FFF), - (val_0 & 0x1FFF)); - } + "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); } - val_0 = cam_io_r(mem_base + - top_priv->common_data.common_reg->perf_stall_count); + + 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]) { @@ -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"); - - 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); + core_info->tfe_bus->bottom_half_handler( + core_info->tfe_bus->bus_priv, false, evt_payload, true); - /* 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); @@ -592,7 +679,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 +693,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 +706,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 +719,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 +729,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 +741,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 +851,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) { @@ -1465,10 +1562,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 +1595,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; @@ -1605,7 +1714,7 @@ static int cam_tfe_camif_resource_start( val |= (1 << rsrc_data->reg_data->camif_pd_rdi2_src_sel_shift); /* enables the Delay Line CLC in the pixel pipeline */ - val |= BIT(8); + 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); @@ -1758,10 +1867,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; 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 71170d1e27e3..3f7208a7babb 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,9 @@ #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 + enum cam_tfe_lut_word_size { CAM_TFE_LUT_WORD_SIZE_32, CAM_TFE_LUT_WORD_SIZE_64, @@ -112,6 +115,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 +184,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 +203,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 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 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 top_version; - void *top_hw_info; - - uint32_t bus_version; - void *bus_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 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 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 num_clc; + struct cam_tfe_clc_hw_status *clc_hw_status_info; + + uint32_t top_version; + void *top_hw_info; + + uint32_t bus_version; + void *bus_hw_info; }; struct cam_tfe_hw_core_info { -- GitLab From 10f0f82959cf380f4f6e3267e932238490d916fe Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Mon, 4 Nov 2019 12:13:04 +0530 Subject: [PATCH 076/295] msm: camera: core: Prevent crash on kref_put kref_put causes crash if refcount is zero. This change prevents crash by checking if refcount value. CRs-Fixed: 2553290 Change-Id: Ie9a950b289cdb2b8fca8c5d025be540d926eadbd Signed-off-by: Trishansh Bhardwaj --- drivers/cam_core/cam_context.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index 642d530054d8..1c17422d01d0 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -597,7 +597,12 @@ int cam_context_deinit(struct cam_context *ctx) void cam_context_putref(struct cam_context *ctx) { - kref_put(&ctx->refcount, cam_node_put_ctxt_to_free_list); + if (kref_read(&ctx->refcount)) + kref_put(&ctx->refcount, cam_node_put_ctxt_to_free_list); + else + WARN(1, "ctx %s %d state %d devhdl %X\n", ctx->dev_name, + ctx->ctx_id, ctx->state, ctx->dev_hdl); + CAM_DBG(CAM_CORE, "ctx device hdl %ld, ref count %d, dev_name %s", ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)), -- GitLab From 745134b72357a74b42a65c97a5829cca8aab393f Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Tue, 12 Nov 2019 12:22:39 -0800 Subject: [PATCH 077/295] msm: camera: req_mgr: Fix kmem_cache definition Add fixes to cam_req_mgr to include kmem_cache struct definitions. CRs-Fixed: 2554484 Change-Id: I368aa32e085431eff1976dfc09929e730d63b405 Signed-off-by: Karthik Jayakumar --- drivers/cam_req_mgr/Makefile | 2 +- drivers/cam_req_mgr/cam_req_mgr_dev.c | 6 +++++- drivers/cam_req_mgr/cam_req_mgr_timer.c | 4 +++- drivers/cam_req_mgr/cam_req_mgr_timer.h | 1 - 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/cam_req_mgr/Makefile b/drivers/cam_req_mgr/Makefile index 50599d879255..8ecc89ffd8bb 100644 --- a/drivers/cam_req_mgr/Makefile +++ b/drivers/cam_req_mgr/Makefile @@ -4,7 +4,7 @@ ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils -ccflags-y += -I$(src) +ccflags-y += -I$(srctree)/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_core.o\ cam_req_mgr_dev.o \ diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index cdb2210a2efb..3f9db55ab9a1 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -6,12 +6,17 @@ #include #include #include +#include + +#include + #include #include #include #include #include #include + #include "cam_req_mgr_dev.h" #include "cam_req_mgr_util.h" #include "cam_req_mgr_core.h" @@ -19,7 +24,6 @@ #include "cam_mem_mgr.h" #include "cam_debug_util.h" #include "cam_common_util.h" -#include #define CAM_REQ_MGR_EVENT_MAX 30 diff --git a/drivers/cam_req_mgr/cam_req_mgr_timer.c b/drivers/cam_req_mgr/cam_req_mgr_timer.c index ba44534fa48d..eb2a6d599b0f 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_timer.c +++ b/drivers/cam_req_mgr/cam_req_mgr_timer.c @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include "cam_req_mgr_timer.h" #include "cam_debug_util.h" +extern struct kmem_cache *g_cam_req_mgr_timer_cachep; + void crm_timer_reset(struct cam_req_mgr_timer *crm_timer) { if (!crm_timer) diff --git a/drivers/cam_req_mgr/cam_req_mgr_timer.h b/drivers/cam_req_mgr/cam_req_mgr_timer.h index be200f1b2693..d2e20498df9a 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_timer.h +++ b/drivers/cam_req_mgr/cam_req_mgr_timer.h @@ -62,5 +62,4 @@ int crm_timer_init(struct cam_req_mgr_timer **timer, */ void crm_timer_exit(struct cam_req_mgr_timer **timer); -extern struct kmem_cache *g_cam_req_mgr_timer_cachep; #endif -- GitLab From e3d4ab11d28a3864630419c542022df370dcd268 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Mon, 11 Nov 2019 12:15:16 +0530 Subject: [PATCH 078/295] msm: camera: isp: csid hw register reset with IRQ CSID hw register reset is done with the the help of IRQ to make sure it is reset every time before we start a new session. CRs-Fixed: 2563958 Change-Id: I33c870003eb1e99d458b7650b5b3218f61cccd3b Signed-off-by: Tejas Prajapati --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 148 ++++++++++++------ .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 1 + 2 files changed, 97 insertions(+), 52 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 96c88567dc31..0694287392b6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -43,6 +43,8 @@ /* Max CSI Rx irq error count threshold value */ #define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 100 +static int cam_ife_csid_reset_regs( + struct cam_ife_csid_hw *csid_hw, bool reset_hw); static int cam_ife_csid_is_ipp_ppp_format_supported( uint32_t in_format) { @@ -419,7 +421,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) const struct cam_ife_csid_reg_offset *csid_reg; int rc = 0; uint32_t val = 0, i; - uint32_t status; + unsigned long flags; soc_info = &csid_hw->hw_info->soc_info; csid_reg = csid_hw->csid_info->csid_reg; @@ -434,6 +436,8 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) CAM_DBG(CAM_ISP, "CSID:%d Csid reset", csid_hw->hw_intf->hw_idx); + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* Mask all interrupts */ cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); @@ -481,6 +485,8 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + cam_io_w_mb(0x80, soc_info->reg_map[0].mem_base + csid_hw->csid_info->csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); @@ -497,37 +503,14 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_cfg0_addr); - /* perform the top CSID HW registers reset */ - cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, - soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_rst_strobes_addr); - - rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_status_addr, - status, (status & 0x1) == 0x1, - CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); - rc = -ETIMEDOUT; - } - - /* perform the SW registers reset */ - cam_io_w_mb(csid_reg->cmn_reg->csid_reg_rst_stb, - soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_rst_strobes_addr); - - rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_status_addr, - status, (status & 0x1) == 0x1, - CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); - rc = -ETIMEDOUT; - } + /* reset HW regs first, then SW */ + rc = cam_ife_csid_reset_regs(csid_hw, true); + if (rc < 0) + goto end; + rc = cam_ife_csid_reset_regs(csid_hw, false); + if (rc < 0) + goto end; - usleep_range(3000, 3010); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); if (val != 0) @@ -535,6 +518,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) csid_hw->hw_intf->hw_idx, val); csid_hw->error_irq_count = 0; +end: return rc; } @@ -654,7 +638,7 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, return -EINVAL; } - init_completion(complete); + reinit_completion(complete); reset_strb_val = csid_reg->cmn_reg->path_rst_stb_all; /* Reset the corresponding ife csid path */ @@ -1239,6 +1223,8 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) if (rc) goto disable_soc; + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* clear all interrupts */ cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); @@ -1270,6 +1256,8 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_hw_version_addr); CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", @@ -1562,7 +1550,7 @@ static int cam_ife_csid_enable_csi2( } } - /*Enable the CSI2 rx inerrupts */ + /*Enable the CSI2 rx interrupts */ val = CSID_CSI2_RX_INFO_RST_DONE | CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW | CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW | @@ -3077,6 +3065,7 @@ int cam_ife_csid_reset(void *hw_priv, csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; reset = (struct cam_csid_reset_cfg_args *)reset_args; + mutex_lock(&csid_hw->hw_info->hw_mutex); switch (reset->reset_type) { case CAM_IFE_CSID_RESET_GLOBAL: rc = cam_ife_csid_global_reset(csid_hw); @@ -3090,6 +3079,7 @@ int cam_ife_csid_reset(void *hw_priv, rc = -EINVAL; break; } + mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; } @@ -3214,43 +3204,86 @@ int cam_ife_csid_release(void *hw_priv, return rc; } -static int cam_ife_csid_reset_retain_sw_reg( - struct cam_ife_csid_hw *csid_hw) +static int cam_ife_csid_reset_regs( + struct cam_ife_csid_hw *csid_hw, bool reset_hw) { int rc = 0; - uint32_t status; const struct cam_ife_csid_reg_offset *csid_reg = csid_hw->csid_info->csid_reg; struct cam_hw_soc_info *soc_info; + uint32_t val = 0; + unsigned long flags; soc_info = &csid_hw->hw_info->soc_info; + + reinit_completion(&csid_hw->csid_top_complete); + + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* 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); cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); - cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + if (reset_hw) { + /* enable top reset complete IRQ */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + } + + /* perform the top CSID registers reset */ + val = reset_hw ? csid_reg->cmn_reg->csid_rst_stb : + csid_reg->cmn_reg->csid_reg_rst_stb; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_rst_strobes_addr); - rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_status_addr, - status, (status & 0x1) == 0x1, - CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); + + /* + * for SW reset, we enable the IRQ after since the mask + * register has been reset + */ + if (!reset_hw) { + /* enable top reset complete IRQ */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + } + + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + CAM_DBG(CAM_ISP, "CSID reset start"); + rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, + msecs_to_jiffies(IFE_CSID_TIMEOUT)); + if (rc <= 0) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr); + if (val & 0x1) { + /* clear top reset IRQ */ + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", + csid_hw->hw_intf->hw_idx, + reset_hw ? "hw" : "sw", + rc); + rc = 0; + goto end; + } + CAM_ERR(CAM_ISP, "CSID:%d csid_reset %s fail rc = %d", + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); rc = -ETIMEDOUT; + goto end; } else { - CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d", - csid_hw->hw_intf->hw_idx, rc); + CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); rc = 0; } - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_clear_addr); - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_irq_cmd_addr); +end: return rc; } @@ -3335,9 +3368,9 @@ int cam_ife_csid_init_hw(void *hw_priv, break; } - rc = cam_ife_csid_reset_retain_sw_reg(csid_hw); + rc = cam_ife_csid_reset_regs(csid_hw, true); if (rc < 0) - CAM_ERR(CAM_ISP, "CSID: Failed in SW reset"); + CAM_ERR(CAM_ISP, "CSID: Failed in HW reset"); if (rc) cam_ife_csid_disable_hw(csid_hw); @@ -3814,7 +3847,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } } + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); /* clear */ + cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); if (csid_reg->cmn_reg->num_pix) @@ -3844,6 +3881,8 @@ irqreturn_t cam_ife_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); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); @@ -3855,6 +3894,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) "irq_status_udi0= 0x%x irq_status_udi1= 0x%x irq_status_udi2= 0x%x", irq_status_udi[0], irq_status_udi[1], irq_status_udi[2]); + if (irq_status_top & CSID_TOP_IRQ_DONE) { + CAM_DBG(CAM_ISP, "csid top reset complete"); + complete(&csid_hw->csid_top_complete); + } + if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); complete(&csid_hw->csid_csi2_complete); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 7bfb0dac4231..1b5c6d40cb21 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -40,6 +40,7 @@ #define CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW BIT(26) #define CSID_CSI2_RX_INFO_RST_DONE BIT(27) +#define CSID_TOP_IRQ_DONE BIT(0) #define CSID_PATH_INFO_RST_DONE BIT(1) #define CSID_PATH_ERROR_FIFO_OVERFLOW BIT(2) #define CSID_PATH_INFO_SUBSAMPLED_EOF BIT(3) -- GitLab From 2f09f3a9e433e6cc6e7d5a3b6840d4386ae15c18 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Mon, 11 Nov 2019 11:46:42 +0530 Subject: [PATCH 079/295] msm: camera: reqmgr: Improve master slave sync If link is not ready on master epoch, but it becomes ready on slave epoch, then master skips apply and slave applies request and goes ahead of master. Fix this by skipping apply on slave if master slot in not in applied state. CRs-Fixed: 2562008 Change-Id: Ic612eedfeedf2a6ea50737a49a6f1f31a5de1dc2 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_req_mgr/cam_req_mgr_core.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 00677b9d864e..0a4af3c097d0 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1106,6 +1106,8 @@ static int __cam_req_mgr_check_sync_req_is_ready( int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; int32_t sync_num_slots = 0; uint64_t sync_frame_duration = 0; + uint64_t sof_timestamp_delta = 0; + uint64_t master_slave_diff = 0; bool ready = true, sync_ready = true; if (!link->sync_link) { @@ -1139,6 +1141,11 @@ static int __cam_req_mgr_check_sync_req_is_ready( else sync_frame_duration = DEFAULT_FRAME_DURATION; + sof_timestamp_delta = + link->sof_timestamp >= sync_link->sof_timestamp + ? link->sof_timestamp - sync_link->sof_timestamp + : sync_link->sof_timestamp - link->sof_timestamp; + CAM_DBG(CAM_CRM, "sync link %x last frame_duration is %d ns", sync_link->link_hdl, sync_frame_duration); @@ -1260,11 +1267,10 @@ static int __cam_req_mgr_check_sync_req_is_ready( * difference of two SOF timestamp less than * (sync_frame_duration / 5). */ - do_div(sync_frame_duration, 5); - if ((link->sof_timestamp > sync_link->sof_timestamp) && - (sync_link->sof_timestamp > 0) && - (link->sof_timestamp - sync_link->sof_timestamp < - sync_frame_duration) && + master_slave_diff = sync_frame_duration; + do_div(master_slave_diff, 5); + if ((sync_link->sof_timestamp > 0) && + (sof_timestamp_delta < master_slave_diff) && (sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) { /* @@ -1287,6 +1293,11 @@ static int __cam_req_mgr_check_sync_req_is_ready( "sync link %x too quickly, skip next frame of sync link", sync_link->link_hdl); link->sync_link_sof_skip = true; + } else if (sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) { + CAM_DBG(CAM_CRM, + "link %x other not applied", link->link_hdl); + return -EAGAIN; } } -- GitLab From 0e60d354cf9144afff5b6b3af5dee7c63a2241b1 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Mon, 11 Nov 2019 11:59:21 +0530 Subject: [PATCH 080/295] msm: camera: icp: Increase MAX_PKT_SIZE_MSGQ for ICP Increase ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS to improve workqueue delay tolerance. CRs-Fixed: 2564981 Change-Id: Ic61e79588a834e651e7b2f5e44acd3fcbc9d8f77 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_icp/fw_inc/hfi_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_icp/fw_inc/hfi_reg.h b/drivers/cam_icp/fw_inc/hfi_reg.h index 68701c8f7d22..df4ae01d7ef2 100644 --- a/drivers/cam_icp/fw_inc/hfi_reg.h +++ b/drivers/cam_icp/fw_inc/hfi_reg.h @@ -76,7 +76,7 @@ #define ICP_SHARED_MEM_IN_BYTES (1024 * 1024) #define ICP_UNCACHED_HEAP_SIZE_IN_BYTES (2 * 1024 * 1024) #define ICP_HFI_MAX_PKT_SIZE_IN_WORDS 25600 -#define ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS 256 +#define ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS 1024 #define ICP_HFI_QTBL_HOSTID1 0x01000000 #define ICP_HFI_QTBL_STATUS_ENABLED 0x00000001 -- GitLab From cb02d402eec75333a34ee9e811da5b54a59dbd01 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Thu, 23 Jan 2020 11:35:25 +0530 Subject: [PATCH 081/295] msm: camera: cdm: Fix irq_data value in case of inline irq In case of wrong value of irq_data, cdm will notify all the clients waiting on that fifo, which will result into early signal. Fixing the irq_data value by masking the value with proper mask. CRs-Fixed: 2603834 Change-Id: Id06cba51b3da8733982e7d8a7d2208f094ff0180 Signed-off-by: Rishabh Jain --- drivers/cam_cdm/cam_cdm.h | 3 ++- drivers/cam_cdm/cam_cdm_hw_core.c | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index ade86fe5dd24..89efeeec4f8a 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.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 _CAM_CDM_H_ @@ -100,6 +100,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 | \ diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index dcb88c66b8a4..36aca39de6c6 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.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 @@ -1139,7 +1139,8 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) 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) -- GitLab From 41a4d71e41f8850f24a4b56dd029d84127e8f855 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Wed, 13 Nov 2019 00:04:55 -0800 Subject: [PATCH 082/295] msm: camera: isp: Reset overflow pending flag in start hw While start hw, either a fresh start or resume after flush, reset the overflow pending flag as we reset the hw and start fresh with applying init packet. In case where overflow happening at the same time as halt immediately, we set overflow pending flag to true. Eventhough while halt immediate and resume scenario, we reset the hw, not resetting overflow pending flag causes not to apply any new packets while resume. CRs-Fixed: 2565049 Change-Id: Ia9c871402343306945fe1b8f8373659e52630fe2 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 35 +++++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) 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 68cce277fc83..149672479922 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 @@ -3323,9 +3323,10 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, struct cam_ife_hw_mgr_ctx *ctx; struct cam_isp_prepare_hw_update_data *hw_update_data; - CAM_DBG(CAM_ISP, "Enter"); if (!hw_mgr_priv || !config_hw_args) { - CAM_ERR(CAM_ISP, "Invalid arguments"); + CAM_ERR(CAM_ISP, + "Invalid arguments, hw_mgr_priv=%pK, config_hw_args=%pK", + hw_mgr_priv, config_hw_args); return -EINVAL; } @@ -3333,21 +3334,28 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, ctx = (struct cam_ife_hw_mgr_ctx *)cfg->ctxt_to_hw_map; if (!ctx) { CAM_ERR(CAM_ISP, "Invalid context is used"); - return -EPERM; + return -EINVAL; } if (!ctx->ctx_in_use || !ctx->cdm_cmd) { - CAM_ERR(CAM_ISP, "Invalid context parameters"); + CAM_ERR(CAM_ISP, + "Invalid context parameters : ctx_in_use=%d, cdm_cmd=%pK", + ctx->ctx_in_use, ctx->cdm_cmd); + return -EPERM; + } + + if (atomic_read(&ctx->overflow_pending)) { + CAM_DBG(CAM_ISP, + "Ctx[%pK][%d] Overflow pending, cannot apply req %llu", + ctx, ctx->ctx_index, cfg->request_id); return -EPERM; } - if (atomic_read(&ctx->overflow_pending)) - return -EINVAL; hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; hw_update_data->isp_mgr_ctx = ctx; - CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld", - ctx, ctx->ctx_index, cfg->request_id); + CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld, init_packet=%d", + ctx, ctx->ctx_index, cfg->request_id, cfg->init_packet); for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { if (hw_update_data->bw_config_valid[i] == true) { @@ -3421,7 +3429,9 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, atomic_set(&ctx->cdm_done, 0); rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); if (rc) { - CAM_ERR(CAM_ISP, "Failed to apply the configs"); + CAM_ERR(CAM_ISP, + "Failed to apply the configs for req %llu, rc %d", + cfg->request_id, rc); return rc; } @@ -3924,11 +3934,16 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } start_only: + + atomic_set(&ctx->overflow_pending, 0); + /* Apply initial configuration */ CAM_DBG(CAM_ISP, "Config HW"); rc = cam_ife_mgr_config_hw(hw_mgr_priv, &start_isp->hw_config); if (rc) { - CAM_ERR(CAM_ISP, "Config HW failed"); + CAM_ERR(CAM_ISP, + "Config HW failed, start_only=%d, rc=%d", + start_isp->start_only, rc); goto cdm_streamoff; } -- GitLab From 2ff04ea26d684ea65ddede88f8de9f6960394cf3 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 21 Nov 2019 22:45:46 +0530 Subject: [PATCH 083/295] msm: camera: isp: prioritize RUP over EPOCH in bottom half When epoch comes along with RUP we report bubble as per current state machine. This was because in camif_bottom_half handler we are handling EPOCH before RUP. This change prioritize RUP over EPOCH and EOF over SOF to handle race. CRs-Fixed: 2567120 Change-Id: I236bcc44b609f8ef7f963f19d33d46a3d95ba0d2 Signed-off-by: Vikram Sharma --- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 0ed1c6ede3ce..c776888c9871 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -709,6 +709,16 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, CAM_DBG(CAM_ISP, "irq_status_0 = 0x%x irq_status_1 = 0x%x", irq_status0, irq_status1); + if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "Received EOF"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + if (irq_status0 & camif_priv->reg_data->sof_irq_mask) { if ((camif_priv->enable_sof_irq_debug) && (camif_priv->irq_debug_cnt <= @@ -732,16 +742,6 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_SUCCESS; } - if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { - CAM_DBG(CAM_ISP, "Received EPOCH"); - - if (camif_priv->event_cb) - camif_priv->event_cb(camif_priv->priv, - CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); - - ret = CAM_VFE_IRQ_STATUS_SUCCESS; - } - if (irq_status0 & camif_priv->reg_data->reg_update_irq_mask) { CAM_DBG(CAM_ISP, "Received REG_UPDATE_ACK"); @@ -752,12 +752,12 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_SUCCESS; } - if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { - CAM_DBG(CAM_ISP, "Received EOF"); + if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "Received EPOCH"); if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, - CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); ret = CAM_VFE_IRQ_STATUS_SUCCESS; } -- GitLab From 9ff743ae2f38ebe65cdcca432c638a851763c86a Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Fri, 17 Jan 2020 21:08:45 +0530 Subject: [PATCH 084/295] msm: camera: flash: Switch off flash on provider crash Switch off the flash if the camera service crashes. CRs-Fixed: 2599316 Change-Id: If01fb0312a8a7b085e1fc7acb2da32207f78d881 Signed-off-by: Tony Lijo Jose --- drivers/cam_sensor_module/cam_flash/cam_flash_core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 063848104f63..daa55420becf 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.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 @@ -1774,6 +1774,12 @@ 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); + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "LED OFF FAILED: %d", + rc); + } rc = fctrl->func_tbl.power_ops(fctrl, false); if (rc) CAM_ERR(CAM_FLASH, "Power Down Failed rc: %d", -- GitLab From d77f1ea18b3f62a836ebe57e482433af955ca463 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Fri, 24 Jan 2020 12:51:44 +0530 Subject: [PATCH 085/295] msm: camera: ope: Initialize ope hw mutex structure Initialize ope HW mutex structure during top init. otherwise it will lead to NULL pointer dereference. CRs-Fixed: 2609594 Change-Id: I118ea9e9a63d69e12207252687e7af30cfa0754b Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c | 1 + 1 file changed, 1 insertion(+) 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 d6b6694443b2..d3f4e648b36f 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 @@ -123,6 +123,7 @@ 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); -- GitLab From 32b3fed4f2316372cc76076963b98a639bc37613 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Wed, 22 Jan 2020 13:40:42 +0530 Subject: [PATCH 086/295] msm: camera: cdm: Flush all available FIFOs during reset Flush all the available FIFO during CDM reset to avoid FIFO execution of stale entries. CRs-Fixed: 2608094 Change-Id: I200d932f470849fe4c3935cbed96717531fe8b30 Signed-off-by: Rishabh Jain --- drivers/cam_cdm/cam_cdm.h | 1 + drivers/cam_cdm/cam_cdm_hw_core.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index 89efeeec4f8a..7f8c90f9285d 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 diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 36aca39de6c6..e27fc7befa9d 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1248,6 +1248,7 @@ 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; @@ -1258,6 +1259,8 @@ int cam_hw_cdm_reset_hw(struct cam_hw_info *cdm_hw, uint32_t handle) mutex_lock(&cdm_core->bl_fifo[i].fifo_lock); 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)) { @@ -1267,7 +1270,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; } @@ -1312,6 +1315,7 @@ 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; @@ -1343,6 +1347,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)) { @@ -1352,7 +1358,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; } -- GitLab From 9f9de8e4f683487fff2b86fc5b2449cf6f0b9954 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Fri, 24 Jan 2020 17:51:50 +0530 Subject: [PATCH 087/295] msm: camera: cpas: Add mandatory bw option for axi ports clocks Bw voting is mandatory to enable rt_axi and nrt_axi clocks. Adding support for the same. CRs-Fixed: 2585073 Change-Id: I236b3940faea3925e668e0e5ddbf61e8e569b2f7 Signed-off-by: Rishabh Jain Signed-off-by: Alok Chauhan --- drivers/cam_cpas/cam_cpas_hw.c | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 7d2ee82a093e..bec4f21a989a 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -797,6 +797,45 @@ static int cam_cpas_util_apply_client_axi_vote( return rc; } +static int cam_cpas_util_apply_default_axi_vote( + struct cam_hw_info *cpas_hw, bool enable) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_axi_port *axi_port = NULL; + uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0; + int rc = 0, i = 0; + + mutex_lock(&cpas_core->tree_lock); + for (i = 0; i < cpas_core->num_axi_ports; i++) { + if (!cpas_core->axi_port[i].ab_bw || + !cpas_core->axi_port[i].ib_bw) + axi_port = &cpas_core->axi_port[i]; + else + continue; + + if (enable) + mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + else + mnoc_ib_bw = 0; + + CAM_DBG(CAM_CPAS, "Port=[%s] :ab[%llu] ib[%llu]", + axi_port->axi_port_name, mnoc_ab_bw, mnoc_ib_bw); + + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, + mnoc_ab_bw, mnoc_ib_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", + mnoc_ab_bw, mnoc_ib_bw, rc); + goto unlock_tree; + } + } + +unlock_tree: + mutex_unlock(&cpas_core->tree_lock); + return rc; +} + static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, uint32_t client_handle, struct cam_axi_vote *client_axi_vote) { @@ -1192,6 +1231,10 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, } if (cpas_core->streamon_clients == 0) { + rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, true); + if (rc) + goto done; + atomic_set(&cpas_core->irq_count, 1); rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, applied_level); @@ -1352,6 +1395,11 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); + if (rc) + goto done; + + if (cpas_core->streamon_clients == 0) + rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, false); done: mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); -- GitLab From b121b58d3b042cea4dd9634e9b39900407561df0 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Thu, 23 Jan 2020 20:00:29 +0530 Subject: [PATCH 088/295] msm: camera: ope: Use vzalloc to allocate the write bus ctx structure Kzalloc doesn't gaurantee for the allocation for memory with order more than 3. So using vzalloc to allocate the memory. CRs-Fixed: 2608914 Change-Id: I085afa8a74995593bdff691b9f3c0d83221da3da Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c | 5 ++--- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 9 +++------ 2 files changed, 5 insertions(+), 9 deletions(-) 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 5c0a09762059..bade41972a26 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 @@ -158,7 +158,7 @@ static int cam_ope_bus_wr_release(struct ope_hw *ope_hw_info, return -EINVAL; } - kzfree(wr_info->bus_wr_ctx[ctx_id]); + vfree(wr_info->bus_wr_ctx[ctx_id]); wr_info->bus_wr_ctx[ctx_id] = NULL; return rc; @@ -556,8 +556,7 @@ static int cam_ope_bus_wr_acquire(struct ope_hw *ope_hw_info, return -EINVAL; } - wr_info->bus_wr_ctx[ctx_id] = kzalloc(sizeof(struct ope_bus_wr_ctx), - GFP_KERNEL); + 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; 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 63c0207c72a2..2f51cb0cc4e5 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 @@ -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. */ #include @@ -310,14 +310,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; } -- GitLab From 32f119d59d9ff1ade5c38b9249c24312bf795789 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Sun, 26 Jan 2020 17:49:38 +0530 Subject: [PATCH 089/295] msm: camera: ope: Fix handling of init hw failure In case of init hw failure, stop cpas and disable soc resources. CRs-Fixed: 2609556 Change-Id: Ie2af3854397500b72691f1422e033448a981ad89 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 33 +++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) 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 63c0207c72a2..661769ac0c46 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 @@ -156,7 +156,8 @@ int cam_ope_init_hw(void *device_priv, if (!device_priv) { CAM_ERR(CAM_OPE, "Invalid cam_dev_info"); - return -EINVAL; + rc = -EINVAL; + goto end; } soc_info = &ope_dev->soc_info; @@ -164,7 +165,8 @@ 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; @@ -191,28 +193,35 @@ int cam_ope_init_hw(void *device_priv, &cpas_vote.ahb_vote, &cpas_vote.axi_vote); if (rc) { CAM_ERR(CAM_OPE, "cpass start failed: %d", rc); - return rc; + goto end; } 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 end; +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; +end: return rc; } -- GitLab From 93b249aab2fa2379e7d54bd290bd88f4fe51b271 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Fri, 22 Nov 2019 10:35:25 +0530 Subject: [PATCH 090/295] msm: camera: req_mgr: Link state check before process trigger workq Due to scheduling delays, process trigger workq can be delayed. In the meantime, link state can be reset to IDLE. This can cause abnormal behaviour resulting in stability issues. Also, at the time of apply fail for flash, failed_dev is not updated. This causes crash while notifying the error on link. This commit prevents the execution of workq process trigger if the link has been reset to IDLE state. Also, failed_dev is updated if the apply for flash fails. CRs-Fixed: 2572511 Change-Id: Iaea1e0a7a24afc9e408a1530a5875f6b6c41a45b Signed-off-by: Gaurav Jindal --- drivers/cam_req_mgr/cam_req_mgr_core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 1c3fa33961e7..b47639a30968 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -681,8 +681,10 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, apply_req.trigger_point = trigger; if (dev->ops && dev->ops->apply_req) { rc = dev->ops->apply_req(&apply_req); - if (rc) + if (rc) { + *failed_dev = dev; return rc; + } CAM_DBG(CAM_REQ, "SEND: link_hdl: %x pd: %d req_id %lld", link->link_hdl, pd, apply_req.request_id); @@ -2456,6 +2458,14 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) link->link_hdl, in_q->rd_idx, in_q->slot[in_q->rd_idx].status); spin_lock_bh(&link->link_state_spin_lock); + + if (link->state < CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto release_lock; + } + if (link->state == CAM_CRM_LINK_STATE_ERR) CAM_WARN(CAM_CRM, "Error recovery idx %d status %d", in_q->rd_idx, -- GitLab From 7f172e299c3e778163c0734192d0ddb288229cd9 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Mon, 2 Dec 2019 16:36:43 +0530 Subject: [PATCH 091/295] msm: camera: csiphy: Update common sequence for csiphy v1.2 Add a high-to-low transition in the CTRL0 register during the common power-up sequence. CRs-Fixed: 2580437 Change-Id: I66541d3d787fa2f161e5d8e647fb11c8075a1947 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 3bed231e0246..179ccebddc54 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -12,7 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 6, + .csiphy_common_array_size = 7, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 18, .csiphy_3ph_config_array_size = 33, @@ -24,6 +24,7 @@ struct csiphy_reg_t csiphy_common_reg_1_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, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0824, 0x72, 0x00, CSIPHY_2PH_REGS}, -- GitLab From 1043b2f8b1d21bf6acb04c00f02caa4ff1aafaa7 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Fri, 25 Oct 2019 15:36:03 +0530 Subject: [PATCH 092/295] msm: camera: reqmgr: reset the slot on buf_done Reset the slot with the valid request on receiving the buf_done which is reported on next EPOCH. In case of back to back irqs slot is marked as skip idx it will apply the request and try to reset a slot based on MAX_PD + 1 calculation which might have the request for which we have got a bubble. To make sure this does not happen, reset a slot only on the buf_done for valid request. If STOP ioctl is called from UMD for ISP, it will flush all the lists. But this is not notified to CRM which might have a stale entry of the half applied request, so on STOP ioctl clear all the slots. In case of SAT mode if one of the link has generated bubble, while the sync_link has the sync_request slot reset sync_link will not let the link recover of the bubble. To make sure the recovery sync_mode is set to 0 for two consecutive slots of the link. CRs-Fixed: 2551701 Change-Id: If4b6f8a4a831ffddcef2cae6292d066778c18b04 Signed-off-by: Tejas Prajapati --- drivers/cam_isp/cam_isp_context.c | 36 +++++- drivers/cam_isp/cam_isp_context.h | 14 +++ drivers/cam_req_mgr/cam_req_mgr_core.c | 115 +++++++++++++++++++- drivers/cam_req_mgr/cam_req_mgr_core.h | 2 + drivers/cam_req_mgr/cam_req_mgr_interface.h | 17 +++ 5 files changed, 179 insertions(+), 5 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 53bf819ed181..e7236fa2d628 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -708,6 +708,7 @@ static int __cam_isp_ctx_handle_buf_done_for_request( CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); + ctx_isp->req_info.last_bufdone_req_id = req->request_id; } __cam_isp_ctx_update_state_monitor_array(ctx_isp, @@ -907,6 +908,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -1077,7 +1079,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, * If no wait req in epoch, this is an error case. * The recovery is to go back to sof state */ - CAM_ERR(CAM_ISP, "No wait request"); + CAM_ERR(CAM_ISP, "Ctx:%d No wait request", ctx->ctx_id); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; /* Send SOF event as empty frame*/ @@ -1093,7 +1095,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, req_isp->bubble_detected = true; req_isp->reapply = true; - CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); + CAM_INFO(CAM_ISP, "ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { struct cam_req_mgr_error_notify notify; @@ -1242,7 +1245,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( * If no pending req in epoch, this is an error case. * Just go back to the bubble state. */ - CAM_ERR(CAM_ISP, "No pending request."); + CAM_ERR(CAM_ISP, "ctx:%d No pending request.", ctx->ctx_id); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); @@ -1254,6 +1257,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; + CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); req_isp->reapply = true; if (req_isp->bubble_report && ctx->ctx_crm_intf && @@ -1592,6 +1597,7 @@ static int __cam_isp_ctx_fs2_sof_in_sof_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -1769,6 +1775,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -2457,6 +2464,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_top_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -2553,9 +2561,10 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; + CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); req_isp->reapply = true; - CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { struct cam_req_mgr_error_notify notify; @@ -2654,6 +2663,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -2726,6 +2736,7 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -2923,6 +2934,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, ctx_isp->reported_req_id = 0; ctx_isp->hw_acquired = false; ctx_isp->init_received = false; + ctx_isp->req_info.last_bufdone_req_id = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -2983,6 +2995,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx_isp->hw_acquired = false; ctx_isp->init_received = false; ctx_isp->rdi_only_context = false; + ctx_isp->req_info.last_bufdone_req_id = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -3932,6 +3945,18 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( __cam_isp_ctx_substate_val_to_type( ctx_isp->substate_activated)); + if (ctx->ctx_crm_intf && + ctx->ctx_crm_intf->notify_stop) { + struct cam_req_mgr_notify_stop notify; + + notify.link_hdl = ctx->link_hdl; + CAM_DBG(CAM_ISP, + "Notify CRM about device stop ctx %u link 0x%x", + ctx->ctx_id, ctx->link_hdl); + ctx->ctx_crm_intf->notify_stop(¬ify); + } else + CAM_ERR(CAM_ISP, "cb not present"); + while (!list_empty(&ctx->pending_req_list)) { req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, list); @@ -3979,11 +4004,13 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( } list_add_tail(&req->list, &ctx->free_req_list); } + ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; ctx_isp->bubble_frame_cnt = 0; ctx_isp->last_applied_req_id = 0; + ctx_isp->req_info.last_bufdone_req_id = 0; atomic_set(&ctx_isp->process_bubble, 0); atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -4443,6 +4470,7 @@ int cam_isp_context_init(struct cam_isp_context *ctx, ctx->frame_id = 0; ctx->active_req_cnt = 0; ctx->reported_req_id = 0; + ctx->req_info.last_bufdone_req_id = 0; ctx->bubble_frame_cnt = 0; ctx->hw_ctx = NULL; ctx->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index a0908710ffd9..4e690251bf6c 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -150,6 +150,18 @@ struct cam_isp_context_state_monitor { }; /** + * struct cam_isp_context_req_id_info - ISP context request id + * information for bufdone. + * + *@last_bufdone_req_id: Last bufdone request id + * + */ + +struct cam_isp_context_req_id_info { + int64_t last_bufdone_req_id; +}; +/** + * * struct cam_isp_context - ISP context object * * @base: Common context object pointer @@ -171,6 +183,7 @@ struct cam_isp_context_state_monitor { * will invoke CRM cb at those event. * @last_applied_req_id: Last applied request id * @state_monitor_head: Write index to the state monitoring array + * @req_info Request id information about last buf done * @cam_isp_ctx_state_monitor: State monitoring array * @rdi_only_context: Get context type information. * true, if context is rdi only context @@ -204,6 +217,7 @@ struct cam_isp_context { atomic64_t state_monitor_head; struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; + struct cam_isp_context_req_id_info req_info; bool rdi_only_context; bool hw_acquired; bool init_received; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index b47639a30968..5e3015118d94 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -480,7 +480,9 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, CAM_DBG(CAM_CRM, "RESET: idx: %d: slot->status %d", idx, slot->status); /* Check if CSL has already pushed new request*/ - if (slot->status == CRM_SLOT_STATUS_REQ_ADDED) + if (slot->status == CRM_SLOT_STATUS_REQ_ADDED || + in_q->last_applied_idx == idx || + idx < 0) return; /* Reset input queue slot */ @@ -1500,6 +1502,10 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, reset_step = link->sync_link->max_delay; } + + if (slot->req_id > 0) + in_q->last_applied_idx = idx; + __cam_req_mgr_dec_idx( &idx, reset_step + 1, in_q->num_slots); @@ -2403,6 +2409,12 @@ int cam_req_mgr_process_error(void *priv, void *data) __cam_req_mgr_tbl_set_all_skip_cnt(&link->req.l_tbl); in_q->rd_idx = idx; in_q->slot[idx].status = CRM_SLOT_STATUS_REQ_ADDED; + if (link->sync_link) { + in_q->slot[idx].sync_mode = 0; + __cam_req_mgr_inc_idx(&idx, 1, + link->req.l_tbl->num_slots); + in_q->slot[idx].sync_mode = 0; + } spin_lock_bh(&link->link_state_spin_lock); link->state = CAM_CRM_LINK_STATE_ERR; spin_unlock_bh(&link->link_state_spin_lock); @@ -2415,6 +2427,31 @@ int cam_req_mgr_process_error(void *priv, void *data) return rc; } +/** + * cam_req_mgr_process_stop() + * + * @brief: This runs in workque thread context. stop notification. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_stop(void *priv, void *data) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + __cam_req_mgr_flush_req_slot(link); +end: + return rc; +} + /** * cam_req_mgr_process_trigger() * @@ -2428,6 +2465,7 @@ int cam_req_mgr_process_error(void *priv, void *data) static int cam_req_mgr_process_trigger(void *priv, void *data) { int rc = 0; + int32_t idx = -1; struct cam_req_mgr_trigger_notify *trigger_data = NULL; struct cam_req_mgr_core_link *link = NULL; struct cam_req_mgr_req_queue *in_q = NULL; @@ -2450,6 +2488,17 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) in_q = link->req.in_q; mutex_lock(&link->req.lock); + + if (trigger_data->trigger == CAM_TRIGGER_POINT_SOF) { + idx = __cam_req_mgr_find_slot_for_req(in_q, + trigger_data->req_id); + if (idx >= 0) { + if (idx == in_q->last_applied_idx) + in_q->last_applied_idx = -1; + __cam_req_mgr_reset_req_slot(link, idx); + } + } + /* * Check if current read index is in applied state, if yes make it free * and increment read index to next slot. @@ -2714,6 +2763,68 @@ static int cam_req_mgr_cb_notify_timer( return rc; } +/* + * cam_req_mgr_cb_notify_stop() + * + * @brief : Stop received from device, resets the morked slots + * @err_info : contains information about error occurred like bubble/overflow + * + * @return : 0 on success, negative in case of failure + * + */ +static int cam_req_mgr_cb_notify_stop( + struct cam_req_mgr_notify_stop *stop_info) +{ + int rc = 0; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_notify_stop *notify_stop; + struct crm_task_payload *task_data; + + if (!stop_info) { + CAM_ERR(CAM_CRM, "stop_info is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(stop_info->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", stop_info->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state != CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + crm_timer_reset(link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "no empty task"); + rc = -EBUSY; + goto end; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_ERR; + notify_stop = (struct cam_req_mgr_notify_stop *)&task_data->u; + notify_stop->link_hdl = stop_info->link_hdl; + task->process_cb = &cam_req_mgr_process_stop; + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + +end: + return rc; +} + + + /** * cam_req_mgr_cb_notify_trigger() * @@ -2774,6 +2885,7 @@ static int cam_req_mgr_cb_notify_trigger( notify_trigger->link_hdl = trigger_data->link_hdl; notify_trigger->dev_hdl = trigger_data->dev_hdl; notify_trigger->trigger = trigger_data->trigger; + notify_trigger->req_id = trigger_data->req_id; notify_trigger->sof_timestamp_val = trigger_data->sof_timestamp_val; task->process_cb = &cam_req_mgr_process_trigger; rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); @@ -2787,6 +2899,7 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { .notify_err = cam_req_mgr_cb_notify_err, .add_req = cam_req_mgr_cb_add_req, .notify_timer = cam_req_mgr_cb_notify_timer, + .notify_stop = cam_req_mgr_cb_notify_stop, }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 056b421ff81e..df4a890079a8 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -253,12 +253,14 @@ struct cam_req_mgr_slot { * @slot : request slot holding incoming request id and bubble info. * @rd_idx : indicates slot index currently in process. * @wr_idx : indicates slot index to hold new upcoming req. + * @last_applied_idx : indicates slot index last applied successfully. */ struct cam_req_mgr_req_queue { int32_t num_slots; struct cam_req_mgr_slot slot[MAX_REQ_SLOTS]; int32_t rd_idx; int32_t wr_idx; + int32_t last_applied_idx; }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index dfa44fc6b0bc..de3a4606be1d 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -15,6 +15,7 @@ struct cam_req_mgr_trigger_notify; struct cam_req_mgr_error_notify; struct cam_req_mgr_add_request; struct cam_req_mgr_timer_notify; +struct cam_req_mgr_notify_stop; struct cam_req_mgr_device_info; struct cam_req_mgr_core_dev_link_setup; struct cam_req_mgr_apply_request; @@ -38,6 +39,7 @@ typedef int (*cam_req_mgr_notify_trigger)( typedef int (*cam_req_mgr_notify_err)(struct cam_req_mgr_error_notify *); typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *); typedef int (*cam_req_mgr_notify_timer)(struct cam_req_mgr_timer_notify *); +typedef int (*cam_req_mgr_notify_stop)(struct cam_req_mgr_notify_stop *); /** * @brief: cam req mgr to camera device drivers @@ -64,12 +66,14 @@ typedef int (*cam_req_mgr_dump_req)(struct cam_req_mgr_dump_info *); * @notify_trigger : payload for trigger indication event * @notify_err : payload for different error occurred at device * @add_req : payload to inform which device and what request is received + * @notify_stop : payload to inform stop event */ struct cam_req_mgr_crm_cb { cam_req_mgr_notify_trigger notify_trigger; cam_req_mgr_notify_err notify_err; cam_req_mgr_add_req add_req; cam_req_mgr_notify_timer notify_timer; + cam_req_mgr_notify_stop notify_stop; }; /** @@ -147,6 +151,7 @@ enum cam_req_mgr_device_error { CRM_KMD_ERR_PAGE_FAULT, CRM_KMD_ERR_OVERFLOW, CRM_KMD_ERR_TIMEOUT, + CRM_KMD_ERR_STOPPED, CRM_KMD_ERR_MAX, }; @@ -205,6 +210,7 @@ enum cam_req_mgr_link_evt_type { * @trigger : trigger point of this notification, CRM will send apply * only to the devices which subscribe to this point. * @sof_timestamp_val: Captured time stamp value at sof hw event + * @req_id : req id which returned buf_done */ struct cam_req_mgr_trigger_notify { int32_t link_hdl; @@ -212,6 +218,7 @@ struct cam_req_mgr_trigger_notify { int64_t frame_id; uint32_t trigger; uint64_t sof_timestamp_val; + uint64_t req_id; }; /** @@ -258,6 +265,16 @@ struct cam_req_mgr_add_request { }; +/** + * struct cam_req_mgr_notify_stop + * @link_hdl : link identifier + * + */ +struct cam_req_mgr_notify_stop { + int32_t link_hdl; +}; + + /* CRM to KMD devices */ /** * struct cam_req_mgr_device_info -- GitLab From a64b437da7407e8dfe62ed63eac145e37502e431 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Wed, 4 Dec 2019 14:33:28 +0530 Subject: [PATCH 093/295] msm: camera: isp: Change master slave combination for dual IFE For some targets, there is a requirement to have the lower IFE as master. Current implementation selects the higher IFE as the master. This commit changes the acquire logic to reserve the lower IFE first and then the higher IFE as slave. This logic is for dual ife use cases. For single IFE use case, acquire logic is not changed. Also, removes the hard coded check for master hw index during the irq handling. Stores the master hw index in ife hardware manager context and check against it. Change-Id: Ifd3a28e80a0a4d16e3d9278b7ed61290c620ec79 CRs-Fixed: 2571273 Signed-off-by: Gaurav Jindal --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 154 +++++++++++--------- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 4 + 2 files changed, 93 insertions(+), 65 deletions(-) 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 149672479922..739b594ba6fb 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 @@ -1036,7 +1036,7 @@ static int cam_ife_hw_mgr_acquire_res_bus_rd( /*TBD */ vfe_acquire.vfe_out.is_master = 1; vfe_acquire.vfe_out.dual_slave_core = - (hw_intf->hw_idx == 0) ? 1 : 0; + ife_ctx->slave_hw_idx; } else { vfe_acquire.vfe_out.is_master = 0; vfe_acquire.vfe_out.dual_slave_core = @@ -1047,7 +1047,7 @@ static int cam_ife_hw_mgr_acquire_res_bus_rd( CAM_ISP_HW_SPLIT_RIGHT; vfe_acquire.vfe_out.is_master = 0; vfe_acquire.vfe_out.dual_slave_core = - (hw_intf->hw_idx == 0) ? 1 : 0; + ife_ctx->master_hw_idx; } rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &vfe_acquire, @@ -1225,7 +1225,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( /*TBD */ vfe_acquire.vfe_out.is_master = 1; vfe_acquire.vfe_out.dual_slave_core = - (hw_intf->hw_idx == 0) ? 1 : 0; + ife_ctx->slave_hw_idx; } else { vfe_acquire.vfe_out.is_master = 0; vfe_acquire.vfe_out.dual_slave_core = @@ -1236,9 +1236,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( CAM_ISP_HW_SPLIT_RIGHT; vfe_acquire.vfe_out.is_master = 0; vfe_acquire.vfe_out.dual_slave_core = - (hw_intf->hw_idx == 0) ? 1 : 0; + ife_ctx->master_hw_idx; } - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &vfe_acquire, sizeof(struct cam_vfe_acquire_args)); @@ -1637,6 +1636,54 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( return rc; } +static int cam_ife_hw_mgr_acquire_csid_hw( + struct cam_ife_hw_mgr *ife_hw_mgr, + struct cam_csid_hw_reserve_resource_args *csid_acquire, + bool is_start_lower_idx) +{ + int i; + int rc = -1; + struct cam_hw_intf *hw_intf; + + if (!ife_hw_mgr || !csid_acquire) { + CAM_ERR(CAM_ISP, + "Invalid args ife hw mgr %pK csid_acquire %pK", + ife_hw_mgr, csid_acquire); + return -EINVAL; + } + + if (is_start_lower_idx) { + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + csid_acquire, + sizeof(struct + cam_csid_hw_reserve_resource_args)); + if (!rc) + return rc; + } + return rc; + } + + for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + csid_acquire, + sizeof(struct + cam_csid_hw_reserve_resource_args)); + if (!rc) + return rc; + } + + return rc; +} + static int cam_ife_mgr_acquire_cid_res( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_generic_info *in_port, @@ -1729,52 +1776,21 @@ static int cam_ife_mgr_acquire_cid_res( } /* Acquire Left if not already acquired */ - if (ife_ctx->is_fe_enable) { - for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { - if (!ife_hw_mgr->csid_devices[i]) - continue; - - hw_intf = ife_hw_mgr->csid_devices[i]; - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &csid_acquire, sizeof(csid_acquire)); - if (rc) - continue; - else { - cid_res_temp->hw_res[acquired_cnt++] = - csid_acquire.node_res; - break; - } - } - if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { - CAM_ERR(CAM_ISP, - "Can not acquire ife cid resource for path %d", - path_res_id); - goto put_res; - } - } else { - for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { - if (!ife_hw_mgr->csid_devices[i]) - continue; + /* For dual IFE cases, start acquiring the lower idx first */ + if (ife_ctx->is_fe_enable || in_port->usage_type) + rc = cam_ife_hw_mgr_acquire_csid_hw(ife_hw_mgr, + &csid_acquire, true); + else + rc = cam_ife_hw_mgr_acquire_csid_hw(ife_hw_mgr, + &csid_acquire, false); - hw_intf = ife_hw_mgr->csid_devices[i]; - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &csid_acquire, sizeof(csid_acquire)); - if (rc) - continue; - else { - cid_res_temp->hw_res[acquired_cnt++] = - csid_acquire.node_res; - break; - } - } - if (i == -1 || !csid_acquire.node_res) { - CAM_ERR(CAM_ISP, - "Can not acquire ife cid resource for path %d", - path_res_id); - goto put_res; - } + if (rc || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; } - + cid_res_temp->hw_res[acquired_cnt++] = csid_acquire.node_res; acquire_successful: CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d", @@ -1785,7 +1801,9 @@ static int cam_ife_mgr_acquire_cid_res( cid_res_temp->res_id = csid_acquire.node_res->res_id; cid_res_temp->is_dual_isp = in_port->usage_type; ife_ctx->is_dual = (bool)in_port->usage_type; - + if (ife_ctx->is_dual) + ife_ctx->master_hw_idx = + cid_res_temp->hw_res[0]->hw_intf->hw_idx; if (in_port->num_out_res) cid_res_temp->is_secure = out_port->secure_mode; @@ -1822,6 +1840,8 @@ static int cam_ife_mgr_acquire_cid_res( goto end; } cid_res_temp->hw_res[1] = csid_acquire.node_res; + ife_ctx->slave_hw_idx = + cid_res_temp->hw_res[1]->hw_intf->hw_idx; CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d", in_port->usage_type); } @@ -6230,9 +6250,10 @@ static int cam_ife_hw_mgr_handle_hw_rup( switch (event_info->res_id) { case CAM_ISP_HW_VFE_IN_CAMIF: - if (ife_hw_mgr_ctx->is_dual) - if (event_info->hw_idx != 1) - break; + if ((ife_hw_mgr_ctx->is_dual) && + (event_info->hw_idx != + ife_hw_mgr_ctx->master_hw_idx)) + break; if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) break; @@ -6273,8 +6294,8 @@ static int cam_ife_hw_mgr_check_irq_for_dual_vfe( { int32_t rc = -1; 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 (!ife_hw_mgr_ctx->is_dual) return 0; @@ -6293,24 +6314,27 @@ static int cam_ife_hw_mgr_check_irq_for_dual_vfe( return 0; } - if (event_cnt[core_idx0] == event_cnt[core_idx1]) { + master_hw_idx = ife_hw_mgr_ctx->master_hw_idx; + slave_hw_idx = ife_hw_mgr_ctx->slave_hw_idx; + + 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; } - 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))) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "One of the VFE could not generate hw event %d core_0_cnt %d core_1_cnt %d", - hw_event_type, event_cnt[core_idx0], - event_cnt[core_idx1]); + "One of the VFE could not generate hw event %d master[%d] core_cnt %d slave[%d] core_cnt %d", + hw_event_type, master_hw_idx, event_cnt[master_hw_idx], + slave_hw_idx, event_cnt[slave_hw_idx]); rc = -1; return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 6ca5a8f42314..d508a21f8a0f 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -44,6 +44,8 @@ struct cam_ife_hw_mgr_debug { * @list: used by the ctx list. * @common: common acquired context data * @ctx_index: acquired context id. + * @master_hw_idx: hw index for master core + * @slave_hw_idx: hw index for slave core * @hw_mgr: IFE hw mgr which owns this context * @ctx_in_use: flag to tell whether context is active * @res_list_ife_in: Starting resource(TPG,PHY0, PHY1...) Can only be @@ -87,6 +89,8 @@ struct cam_ife_hw_mgr_ctx { struct cam_isp_hw_mgr_ctx common; uint32_t ctx_index; + uint32_t master_hw_idx; + uint32_t slave_hw_idx; struct cam_ife_hw_mgr *hw_mgr; uint32_t ctx_in_use; -- GitLab From 483aaf989dbd73040cde5e797fc5d6710b258f86 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Tue, 3 Dec 2019 18:10:44 +0530 Subject: [PATCH 094/295] msm: camera: jpeg: Add mutex lock to protect jpeg list corruption Due to race conditions, situation can arise where the process_irq and flush for jpeg are being handled in parallel. This will cause the jpeg list corruption. This commit protects the code of adding back to free list in process_irq with the mutex. CRs-Fixed: 2578247 Change-Id: I28ee48bc0d5cfcf3ae4a936b2eb2976226ad88d5 Signed-off-by: Gaurav Jindal --- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 532b426437b9..b2b1a47ea31d 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -177,7 +177,9 @@ static int cam_jpeg_mgr_process_irq(void *priv, void *data) PTR_TO_U64(p_cfg_req->hw_cfg_args.priv); ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data); + mutex_lock(&g_jpeg_hw_mgr.hw_mgr_mutex); list_add_tail(&p_cfg_req->list, &hw_mgr->free_req_list); + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); return rc; } -- GitLab From 6ea0ad7dc2f1776e3cf33db91377be7b7d6b6c96 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Tue, 3 Dec 2019 21:39:28 +0530 Subject: [PATCH 095/295] msm: camera: sensor: Add null check for read buffer Add proper null checks for function arguments, including read buffer, before dereferencing them. CRs-Fixed: 2581538 Change-Id: I8c49bbc419e2ac5579341c7dc789da0ed1c4d123 Signed-off-by: Shravan Nevatia --- .../cam_sensor_module/cam_sensor_utils/cam_sensor_util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 078e3e08657a..cf10ee5d7edf 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -241,6 +241,12 @@ static int32_t cam_sensor_get_io_buffer( size_t buf_size = 0; int32_t rc = 0; + if (io_cfg == NULL || i2c_settings == NULL) { + CAM_ERR(CAM_SENSOR, + "Invalid args, io buf or i2c settings is NULL"); + return -EINVAL; + } + if (io_cfg->direction == CAM_BUF_OUTPUT) { rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], &buf_addr, &buf_size); -- GitLab From 710eb5214253030da5acea2bc3c9ce3c88cd4063 Mon Sep 17 00:00:00 2001 From: Suraj Dongre Date: Wed, 20 Nov 2019 22:23:37 -0800 Subject: [PATCH 096/295] msm: camera: jpeg: Increase number of jpeg contexts Fixed out of memory issue in triple camera usecase by increasing number of logical jpeg contexts. CRs-Fixed: 2587592 Change-Id: I25c99c0be8d3986bc11fbc2894a0dbf27c645d4e Signed-off-by: Suraj Dongre Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_jpeg/cam_jpeg_dev.c | 6 +++--- drivers/cam_jpeg/cam_jpeg_dev.h | 6 +++--- drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h | 3 +-- drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h | 4 +++- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/cam_jpeg/cam_jpeg_dev.c b/drivers/cam_jpeg/cam_jpeg_dev.c index 0a68ce997283..85da82cea7ba 100644 --- a/drivers/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/cam_jpeg/cam_jpeg_dev.c @@ -97,7 +97,7 @@ static int cam_jpeg_dev_remove(struct platform_device *pdev) int rc; int i; - for (i = 0; i < CAM_CTX_MAX; i++) { + for (i = 0; i < CAM_JPEG_CTX_MAX; i++) { rc = cam_jpeg_context_deinit(&g_jpeg_dev.ctx_jpeg[i]); if (rc) CAM_ERR(CAM_JPEG, "JPEG context %d deinit failed %d", @@ -135,7 +135,7 @@ static int cam_jpeg_dev_probe(struct platform_device *pdev) goto unregister; } - for (i = 0; i < CAM_CTX_MAX; i++) { + for (i = 0; i < CAM_JPEG_CTX_MAX; i++) { rc = cam_jpeg_context_init(&g_jpeg_dev.ctx_jpeg[i], &g_jpeg_dev.ctx[i], &node->hw_mgr_intf, @@ -147,7 +147,7 @@ static int cam_jpeg_dev_probe(struct platform_device *pdev) } } - rc = cam_node_init(node, &hw_mgr_intf, g_jpeg_dev.ctx, CAM_CTX_MAX, + rc = cam_node_init(node, &hw_mgr_intf, g_jpeg_dev.ctx, CAM_JPEG_CTX_MAX, CAM_JPEG_DEV_NAME); if (rc) { CAM_ERR(CAM_JPEG, "JPEG node init failed %d", rc); diff --git a/drivers/cam_jpeg/cam_jpeg_dev.h b/drivers/cam_jpeg/cam_jpeg_dev.h index 4961527de1a7..d07a1f94b425 100644 --- a/drivers/cam_jpeg/cam_jpeg_dev.h +++ b/drivers/cam_jpeg/cam_jpeg_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_JPEG_DEV_H_ @@ -24,8 +24,8 @@ struct cam_jpeg_dev { struct cam_subdev sd; struct cam_node *node; - struct cam_context ctx[CAM_CTX_MAX]; - struct cam_jpeg_context ctx_jpeg[CAM_CTX_MAX]; + struct cam_context ctx[CAM_JPEG_CTX_MAX]; + struct cam_jpeg_context ctx_jpeg[CAM_JPEG_CTX_MAX]; struct mutex jpeg_mutex; int32_t open_cnt; }; diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h index 1b93547fdf25..3deb9dd73b32 100644 --- a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h +++ b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_HW_INTF_H @@ -8,7 +8,6 @@ #include "cam_cpas_api.h" -#define CAM_JPEG_CTX_MAX 8 #define CAM_JPEG_DEV_PER_TYPE_MAX 1 #define CAM_JPEG_CMD_BUF_MAX_SIZE 128 diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h index 30c51f7cfcfd..b83a308f7d78 100644 --- a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h +++ b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_HW_MGR_INTF_H @@ -10,6 +10,8 @@ #include #include +#define CAM_JPEG_CTX_MAX 16 + int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, int *iommu_hdl); -- GitLab From cc746c8e83b2c52d66f75555b7781be0748076b5 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Fri, 13 Dec 2019 09:49:16 +0530 Subject: [PATCH 097/295] msm: camera: cpas: Reorder sequence of cleanup in cpas probe failure if cpas probe fails during initialization of soc resources soc data is being accessed after freeing the memory. This change handling the sequence on failure. CRs-Fixed: 2585085 Change-Id: Ia89b02bce9cfb6512b33f8e7366a552635317ccd Signed-off-by: Alok Pandey --- drivers/cam_cpas/cam_cpas_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 7d2ee82a093e..d451b28bda3f 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1885,10 +1885,10 @@ int cam_cpas_hw_probe(struct platform_device *pdev, cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client); client_cleanup: cam_cpas_util_client_cleanup(cpas_hw); + cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private); deinit_platform_res: cam_cpas_soc_deinit_resources(&cpas_hw->soc_info); release_workq: - cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private); flush_workqueue(cpas_core->work_queue); destroy_workqueue(cpas_core->work_queue); release_mem: -- GitLab From d3b891d15856e6a63da89acd6ace3fc5baf49f45 Mon Sep 17 00:00:00 2001 From: Prakasha Nayak Date: Thu, 12 Dec 2019 15:18:36 +0530 Subject: [PATCH 098/295] msm: camera: icp: Mapping fw error numbers with error names This change will print ICP error names based on error type. CRs-Fixed: 2456658 Change-Id: I975598a7404f7520912d7b3211b6baa249e7f238 Signed-off-by: Prakasha Nayak --- drivers/cam_icp/fw_inc/hfi_sys_defs.h | 6 ++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 95 +++++++++++++++++-- 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/drivers/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/cam_icp/fw_inc/hfi_sys_defs.h index 905b85a53633..f62e8cc99430 100644 --- a/drivers/cam_icp/fw_inc/hfi_sys_defs.h +++ b/drivers/cam_icp/fw_inc/hfi_sys_defs.h @@ -82,6 +82,12 @@ #define CAMERAICP_EHWVIOLATION 11 #define CAMERAICP_ECDMERROR 12 +/* HFI Specific errors. */ +#define CAMERAICP_HFI_ERR_COMMAND_SIZE 1000 +#define CAMERAICP_HFI_ERR_MESSAGE_SIZE 1001 +#define CAMERAICP_HFI_QUEUE_EMPTY 1002 +#define CAMERAICP_HFI_QUEUE_FULL 1003 + /* Core level commands */ /* IPE/BPS core Commands */ #define HFI_CMD_IPE_BPS_COMMON_START \ diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 26b43490b42e..f32a95e05d66 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -1955,6 +1955,70 @@ static int cam_icp_mgr_cleanup_ctx(struct cam_icp_hw_ctx_data *ctx_data) return 0; } +static const char *cam_icp_error_handle_id_to_type( + uint32_t error_handle) +{ + const char *name = NULL; + + switch (error_handle) { + case CAMERAICP_SUCCESS: + name = "SUCCESS"; + break; + case CAMERAICP_EFAILED: + name = "EFAILED"; + break; + case CAMERAICP_ENOMEMORY: + name = "ENOMEMORY"; + break; + case CAMERAICP_EBADSTATE: + name = "EBADSTATE"; + break; + case CAMERAICP_EBADPARM: + name = "EBADPARM"; + break; + case CAMERAICP_EBADITEM: + name = "EBADITEM"; + break; + case CAMERAICP_EINVALIDFORMAT: + name = "EINVALIDFORMAT"; + break; + case CAMERAICP_EUNSUPPORTED: + name = "EUNSUPPORTED"; + break; + case CAMERAICP_EOUTOFBOUND: + name = "EOUTOFBOUND"; + break; + case CAMERAICP_ETIMEDOUT: + name = "ETIMEDOUT"; + break; + case CAMERAICP_EABORTED: + name = "EABORTED"; + break; + case CAMERAICP_EHWVIOLATION: + name = "EHWVIOLATION"; + break; + case CAMERAICP_ECDMERROR: + name = "ECDMERROR"; + break; + case CAMERAICP_HFI_ERR_COMMAND_SIZE: + name = "HFI_ERR_COMMAND_SIZE"; + break; + case CAMERAICP_HFI_ERR_MESSAGE_SIZE: + name = "HFI_ERR_MESSAGE_SIZE"; + break; + case CAMERAICP_HFI_QUEUE_EMPTY: + name = "HFI_QUEUE_EMPTY"; + break; + case CAMERAICP_HFI_QUEUE_FULL: + name = "HFI_QUEUE_FULL"; + break; + default: + name = NULL; + break; + } + return name; +} + static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) { int i; @@ -2014,8 +2078,10 @@ static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) ctx_data->icp_dev_acquire_info->dev_type); else CAM_ERR(CAM_ICP, - "Done with error: %u on ctx_id %d dev %d for req %llu", + "Done with error: %u err_type= [%s] on ctx_id %d dev %d for req %llu", ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type), ctx_data->ctx_id, ctx_data->icp_dev_acquire_info->dev_type, request_id); @@ -2088,8 +2154,13 @@ static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr) ipe_config_ack = (struct hfi_msg_ipe_config *)(ioconfig_ack->msg_data); if (ipe_config_ack->rc) { - CAM_ERR(CAM_ICP, "rc = %d err = %u", - ipe_config_ack->rc, ioconfig_ack->err_type); + CAM_ERR(CAM_ICP, "rc = %d failed with\n" + "err_no = [%u] err_type = [%s]", + ipe_config_ack->rc, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); + return -EIO; } ctx_data = (struct cam_icp_hw_ctx_data *) @@ -2254,9 +2325,13 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); - CAM_DBG(CAM_ICP, - "received IPE/BPS MAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + CAM_DBG(CAM_ICP, "received IPE/BPS\n" + "MAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; case HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP: ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; @@ -2265,8 +2340,12 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); CAM_DBG(CAM_ICP, - "received IPE/BPS UNMAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + "received IPE/BPS UNMAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; default: CAM_ERR(CAM_ICP, "Invalid opcode : %u", -- GitLab From c4d2d17bddd75226e92e7f33301d2673fe04dea1 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Tue, 28 Jan 2020 15:06:27 +0530 Subject: [PATCH 099/295] msm: camera: tfe: Enable per frame register dump for rdi only context Rdi only context has only rdi resources, so update the check to support the rdi only context. Currently only camif resource register dump enabled. CRs-Fixed: 2611245 Change-Id: I3483a98db797fd5a0e096c3c5c28107f27cf2fe0 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 9641409fecf8..fbb71066c903 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) { -- GitLab From 70adc0a8aa204a24593ffee14d7053efdb7a9c54 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Wed, 29 Jan 2020 11:42:22 +0530 Subject: [PATCH 100/295] msm: camera: cdm: Protect cdm core status bits with mutex In stability test cases CDM Submit and CDM handle error can run in parallel causing abnormal behaviors. To prevent the error and submit bl running in parallel, status bit is protected with lock. CRs-Fixed: 2612240 Change-Id: I595ed6572e7f980d791ed9e1f147e6c23f2c7597 Signed-off-by: Gaurav Jindal --- drivers/cam_cdm/cam_cdm_hw_core.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index e27fc7befa9d..f2f193b8ae55 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -767,13 +767,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); @@ -1319,13 +1323,14 @@ int cam_hw_cdm_handle_error_info( 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); + set_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); + set_bit(CAM_CDM_FLUSH_HW_STATUS, &cdm_core->cdm_status); + rc = cam_cdm_read_hw_reg(cdm_hw, cdm_core->offsets->cmn_reg->current_bl_len, ¤t_bl_data); -- GitLab From 6273e78792ad571b1c8ab681c889f30f12ff9d8d Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 27 Jan 2020 13:09:12 +0530 Subject: [PATCH 101/295] msm: camera: cdm: correct the error check in cmd submit irq Correct the error check in cdm submit irq routine by using updated bl_depth value instead of hardcoded value. CRs-Fixed: 2605296 Change-Id: I267693ac5c8145fdf5c2dcf0fc5d80ce1e16b8a8 Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index e27fc7befa9d..ffdee1680d18 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -631,10 +631,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; } -- GitLab From 97193314840628422cf29c5104f3e81b7d9e6670 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Fri, 31 Jan 2020 17:38:53 +0530 Subject: [PATCH 102/295] msm: camera: ope: Fix unclock access during HW reset OPE reset HW as part of error handling and release client call can get invoked at the same time. This will lead to race between OPE reset hw and disabling of resources and finally in unclock access during reset OPE hw. Synchronize the reset as part of error handling and release callback. CRs-Fixed: 2611309 Change-Id: Ife14ee44b665d905b812447617bcc697dd685ce2 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 9 +++++++++ 1 file changed, 9 insertions(+) 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 070f67433502..b6491f8301ab 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 @@ -271,6 +271,14 @@ static int32_t cam_ope_mgr_process_msg(void *priv, void *data) /* 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, @@ -279,6 +287,7 @@ static int32_t cam_ope_mgr_process_msg(void *priv, void *data) CAM_ERR(CAM_OPE, "OPE Dev acquire failed: %d", rc); } + mutex_unlock(&ctx->ctx_mutex); return rc; } -- GitLab From 9bad51c2079379d58d693751c8e7b312addf827b Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 3 Feb 2020 16:53:41 +0530 Subject: [PATCH 103/295] msm: camera: ope: Program frame level settings after idle event For batch mode, add frame level settings for second frame onwards after waiting for idle event. CRs-Fixed: 2609059 Change-Id: Ibe174dd69327887a03914c871448cb573c5e7f80 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 122 ------------------- 1 file changed, 122 deletions(-) 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 8f934b09d7ff..2d062370d5e9 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 @@ -455,119 +455,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, @@ -1373,15 +1260,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, -- GitLab From 7daa5d9fde9324159a41ffbd01f3d36b7e06b777 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 14 Oct 2019 17:09:54 +0530 Subject: [PATCH 104/295] msm: camera: isp: LDAR Dump ISP information When user space detects an error or does not receive response for a request, Lets do a reset(LDAR) is triggered. Before LDAR, user space sends flush command to the kernel space. In order to debug the cause for this situation and to dump the information, user space sends a dump command to kernel space before sending flush. As a part of this command, it passes the culprit request id and the buffer into which the information can be dumped. Kernel space traverses across the drivers and find the culprit hw and dumps the relevant information in the buffer. This data is written to a file for offline processing. This commit dumps the IFE, CSID registers, LUT tables and context information, cmd buffers, timestamps information for submit, apply, RUP, epoch and buffdones of the last 20 requests. CRs-Fixed: 2612116 Change-Id: If83db59458c1e5ad778f3fa90cbc730122491c54 Signed-off-by: Gaurav Jindal --- drivers/cam_cdm/cam_cdm_util.c | 170 ++++++- drivers/cam_cdm/cam_cdm_util.h | 45 +- drivers/cam_isp/cam_isp_context.c | 446 +++++++++++++++++- drivers/cam_isp/cam_isp_context.h | 73 ++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 165 ++++++- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 4 +- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 67 +++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 41 +- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 3 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 29 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 29 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 29 +- .../vfe_hw/vfe_top/cam_vfe_top_common.h | 30 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 142 +++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h | 3 +- drivers/cam_utils/cam_soc_util.c | 294 +++++++++++- drivers/cam_utils/cam_soc_util.h | 59 ++- 17 files changed, 1576 insertions(+), 53 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_util.c b/drivers/cam_cdm/cam_cdm_util.c index 3f606ab45635..c9eee75f1c43 100644 --- a/drivers/cam_cdm/cam_cdm_util.c +++ b/drivers/cam_cdm/cam_cdm_util.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 @@ -823,3 +823,171 @@ void cam_cdm_util_dump_cmd_buf( } } while (buf_now <= cmd_buf_end); } + +static uint32_t cam_cdm_util_dump_reg_cont_cmd_v2( + uint32_t *cmd_buf_addr, + struct cam_cdm_cmd_buf_dump_info *dump_info) +{ + int i; + long ret; + uint8_t *dst; + size_t remain_len; + uint32_t *temp_ptr = cmd_buf_addr; + uint32_t *addr, *start; + uint32_t min_len; + struct cdm_regcontinuous_cmd *p_regcont_cmd; + struct cam_cdm_cmd_dump_header *hdr; + + p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr; + temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT); + ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT); + + min_len = (sizeof(uint32_t) * p_regcont_cmd->count) + + sizeof(struct cam_cdm_cmd_dump_header) + + (2 * sizeof(uint32_t)); + remain_len = dump_info->dst_max_size - dump_info->dst_offset; + + if (remain_len < min_len) { + CAM_WARN_RATE_LIMIT(CAM_CDM, + "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return ret; + } + + dst = (char *)dump_info->dst_start + dump_info->dst_offset; + hdr = (struct cam_cdm_cmd_dump_header *)dst; + scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_CONT:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header)); + start = addr; + *addr++ = p_regcont_cmd->offset; + *addr++ = p_regcont_cmd->count; + for (i = 0; i < p_regcont_cmd->count; i++) { + *addr = *temp_ptr; + temp_ptr++; + addr++; + ret++; + } + hdr->size = hdr->word_size * (addr - start); + dump_info->dst_offset += hdr->size + + sizeof(struct cam_cdm_cmd_dump_header); + + return ret; +} + +static uint32_t cam_cdm_util_dump_reg_random_cmd_v2( + uint32_t *cmd_buf_addr, + struct cam_cdm_cmd_buf_dump_info *dump_info) +{ + int i; + long ret; + uint8_t *dst; + uint32_t *temp_ptr = cmd_buf_addr; + uint32_t *addr, *start; + size_t remain_len; + uint32_t min_len; + struct cdm_regrandom_cmd *p_regrand_cmd; + struct cam_cdm_cmd_dump_header *hdr; + + p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr; + temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); + ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); + + min_len = (2 * sizeof(uint32_t) * p_regrand_cmd->count) + + sizeof(struct cam_cdm_cmd_dump_header) + sizeof(uint32_t); + remain_len = dump_info->dst_max_size - dump_info->dst_offset; + + if (remain_len < min_len) { + CAM_WARN_RATE_LIMIT(CAM_CDM, + "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return ret; + } + + dst = (char *)dump_info->dst_start + dump_info->dst_offset; + hdr = (struct cam_cdm_cmd_dump_header *)dst; + scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_RANDOM:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header)); + start = addr; + *addr++ = p_regrand_cmd->count; + for (i = 0; i < p_regrand_cmd->count; i++) { + addr[0] = temp_ptr[0] & CAM_CDM_REG_OFFSET_MASK; + addr[1] = temp_ptr[1]; + temp_ptr += 2; + addr += 2; + ret += 2; + } + hdr->size = hdr->word_size * (addr - start); + dump_info->dst_offset += hdr->size + + sizeof(struct cam_cdm_cmd_dump_header); + return ret; +} + +int cam_cdm_util_dump_cmd_bufs_v2( + struct cam_cdm_cmd_buf_dump_info *dump_info) +{ + uint32_t cmd; + uint32_t *buf_now; + int rc = 0; + + if (!dump_info || !dump_info->src_start || !dump_info->src_end || + !dump_info->dst_start) { + CAM_INFO(CAM_CDM, "Invalid args"); + return -EINVAL; + } + + buf_now = dump_info->src_start; + do { + if (dump_info->dst_offset >= dump_info->dst_max_size) { + CAM_WARN(CAM_CDM, + "Dump overshoot offset %zu size %zu", + dump_info->dst_offset, + dump_info->dst_max_size); + return -ENOSPC; + } + cmd = *buf_now; + cmd = cmd >> CAM_CDM_COMMAND_OFFSET; + + switch (cmd) { + case CAM_CDM_CMD_DMI: + case CAM_CDM_CMD_DMI_32: + case CAM_CDM_CMD_DMI_64: + buf_now += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); + break; + case CAM_CDM_CMD_REG_CONT: + buf_now += cam_cdm_util_dump_reg_cont_cmd_v2(buf_now, + dump_info); + break; + case CAM_CDM_CMD_REG_RANDOM: + buf_now += cam_cdm_util_dump_reg_random_cmd_v2(buf_now, + dump_info); + break; + case CAM_CDM_CMD_BUFF_INDIRECT: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_BUFF_INDIRECT); + break; + case CAM_CDM_CMD_GEN_IRQ: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_GEN_IRQ); + break; + case CAM_CDM_CMD_WAIT_EVENT: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_WAIT_EVENT); + break; + case CAM_CDM_CMD_CHANGE_BASE: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_CHANGE_BASE); + break; + case CAM_CDM_CMD_PERF_CTRL: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_PERF_CTRL); + break; + default: + CAM_ERR(CAM_CDM, "Invalid CMD: 0x%x", cmd); + buf_now++; + break; + } + } while (buf_now <= dump_info->src_end); + return rc; +} diff --git a/drivers/cam_cdm/cam_cdm_util.h b/drivers/cam_cdm/cam_cdm_util.h index 1eed75459e71..520e8354ed82 100644 --- a/drivers/cam_cdm/cam_cdm_util.h +++ b/drivers/cam_cdm/cam_cdm_util.h @@ -1,11 +1,14 @@ /* 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 _CAM_CDM_UTIL_H_ #define _CAM_CDM_UTIL_H_ +/* Max len for tag name for header while dumping cmd buffer*/ +#define CAM_CDM_CMD_TAG_MAX_LEN 32 + enum cam_cdm_command { CAM_CDM_CMD_UNUSED = 0x0, CAM_CDM_CMD_DMI = 0x1, @@ -178,6 +181,34 @@ uint32_t *(*cdm_write_wait_prefetch_disable)( uint32_t mask2); }; +/** + * struct cam_cdm_cmd_buf_dump_info; - Camera CDM dump info + * @dst_offset: dst offset + * @dst_max_size max size of destination buffer + * @src_start: source start address + * @src_end: source end address + * @dst_start: dst start address + */ +struct cam_cdm_cmd_buf_dump_info { + size_t dst_offset; + size_t dst_max_size; + uint32_t *src_start; + uint32_t *src_end; + uintptr_t dst_start; +}; + +/** + * struct cam_cdm_cmd_dump_header- Camera CDM dump header + * @tag: tag name for header + * @size: size of data + * @word_size: size of each word + */ +struct cam_cdm_cmd_dump_header { + uint8_t tag[CAM_CDM_CMD_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + /** * cam_cdm_util_log_cmd_bufs() * @@ -190,6 +221,18 @@ uint32_t *(*cdm_write_wait_prefetch_disable)( void cam_cdm_util_dump_cmd_buf( uint32_t *cmd_buffer_start, uint32_t *cmd_buffer_end); +/** + * cam_cdm_util_dump_cmd_bufs_v2() + * + * @brief: Util function to cdm command buffers + * to a buffer + * + * @dump_info: Information about source and destination buffers + * + * return SUCCESS/FAILURE + */ +int cam_cdm_util_dump_cmd_bufs_v2( + struct cam_cdm_cmd_buf_dump_info *dump_info); #endif /* _CAM_CDM_UTIL_H_ */ diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index e7236fa2d628..2431aef3dead 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -24,9 +24,9 @@ static const char isp_dev_name[] = "cam-isp"; static struct cam_isp_ctx_debug isp_ctx_debug; -#define INC_STATE_MONITOR_HEAD(head, ret) \ +#define INC_HEAD(head, max_entries, ret) \ div_u64_rem(atomic64_add_return(1, head),\ - CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, (ret)) + max_entries, (ret)) static int cam_isp_context_dump_active_request(void *data, unsigned long iova, uint32_t buf_info); @@ -34,6 +34,150 @@ static int cam_isp_context_dump_active_request(void *data, unsigned long iova, static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); +static const char *__cam_isp_evt_val_to_type( + uint32_t evt_id) +{ + switch (evt_id) { + case CAM_ISP_CTX_EVENT_SUBMIT: + return "SUBMIT"; + case CAM_ISP_CTX_EVENT_APPLY: + return "APPLY"; + case CAM_ISP_CTX_EVENT_EPOCH: + return "EPOCH"; + case CAM_ISP_CTX_EVENT_RUP: + return "RUP"; + case CAM_ISP_CTX_EVENT_BUFDONE: + return "BUFDONE"; + default: + return "CAM_ISP_EVENT_INVALID"; + } +} + +static void __cam_isp_ctx_update_event_record( + struct cam_isp_context *ctx_isp, + enum cam_isp_ctx_event event, + struct cam_ctx_request *req) +{ + int iterator = 0; + ktime_t cur_time; + struct cam_isp_ctx_req *req_isp; + + if (!ctx_isp) { + CAM_ERR(CAM_ISP, "Invalid Args"); + return; + } + switch (event) { + case CAM_ISP_CTX_EVENT_EPOCH: + case CAM_ISP_CTX_EVENT_RUP: + case CAM_ISP_CTX_EVENT_BUFDONE: + break; + case CAM_ISP_CTX_EVENT_SUBMIT: + case CAM_ISP_CTX_EVENT_APPLY: + if (!req) { + CAM_ERR(CAM_ISP, "Invalid arg for event %d", event); + return; + } + break; + default: + break; + } + + INC_HEAD(&ctx_isp->event_record_head[event], + CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES, &iterator); + cur_time = ktime_get(); + if (req) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + ctx_isp->event_record[event][iterator].req_id = + req->request_id; + req_isp->event_timestamp[event] = cur_time; + } else { + ctx_isp->event_record[event][iterator].req_id = 0; + } + ctx_isp->event_record[event][iterator].timestamp = cur_time; +} + +static int __cam_isp_ctx_dump_event_record( + struct cam_isp_context *ctx_isp, + uintptr_t cpu_addr, + size_t buf_len, + size_t *offset) +{ + int i, j; + int index; + size_t remain_len; + uint8_t *dst; + uint32_t oldest_entry, num_entries; + uint32_t min_len; + uint64_t *addr, *start; + uint64_t state_head; + struct timespec64 ts; + struct cam_isp_context_dump_header *hdr; + struct cam_isp_context_event_record *record; + + if (!cpu_addr || !buf_len || !offset || !ctx_isp) { + CAM_ERR(CAM_ISP, "Invalid args %pK %zu %pK %pK", + cpu_addr, buf_len, offset, ctx_isp); + return -EINVAL; + } + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) { + state_head = atomic64_read(&ctx_isp->event_record_head[i]); + + if (state_head == -1) { + return 0; + } else if (state_head < CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES) { + num_entries = state_head + 1; + oldest_entry = 0; + } else { + num_entries = CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES; + div_u64_rem(state_head + 1, + CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES, + &oldest_entry); + } + index = oldest_entry; + + if (buf_len <= *offset) { + CAM_WARN(CAM_ISP, + "Dump buffer overshoot len %zu offset %zu", + buf_len, *offset); + return -ENOSPC; + } + + min_len = sizeof(struct cam_isp_context_dump_header) + + ((num_entries * CAM_ISP_CTX_DUMP_EVENT_NUM_WORDS) * + sizeof(uint64_t)); + remain_len = buf_len - *offset; + + if (remain_len < min_len) { + CAM_WARN(CAM_ISP, + "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + dst = (uint8_t *)cpu_addr + *offset; + hdr = (struct cam_isp_context_dump_header *)dst; + scnprintf(hdr->tag, + CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, "ISP_EVT_%s:", + __cam_isp_evt_val_to_type(i)); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + + sizeof(struct cam_isp_context_dump_header)); + start = addr; + for (j = 0; j < num_entries; j++) { + record = &ctx_isp->event_record[i][index]; + ts = ktime_to_timespec64(record->timestamp); + *addr++ = record->req_id; + *addr++ = ts.tv_sec; + *addr++ = ts.tv_nsec/NSEC_PER_USEC; + index = (index + 1) % + CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES; + } + hdr->size = hdr->word_size * (addr - start); + *offset += hdr->size + + sizeof(struct cam_isp_context_dump_header); + } + return 0; +} + static void __cam_isp_ctx_update_state_monitor_array( struct cam_isp_context *ctx_isp, enum cam_isp_state_change_trigger trigger_type, @@ -41,7 +185,8 @@ static void __cam_isp_ctx_update_state_monitor_array( { int iterator; - INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head, &iterator); + INC_HEAD(&ctx_isp->state_monitor_head, + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, &iterator); ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state = ctx_isp->substate_activated; @@ -162,13 +307,19 @@ static int cam_isp_context_info_dump(void *context, return 0; } -static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) +static int cam_isp_ctx_dump_req( + struct cam_isp_ctx_req *req_isp, + uintptr_t cpu_addr, + size_t buf_len, + size_t *offset, + bool dump_to_buff) { int i = 0, rc = 0; size_t len = 0; uint32_t *buf_addr; uint32_t *buf_start, *buf_end; size_t remain_len = 0; + struct cam_cdm_cmd_buf_dump_info dump_info; for (i = 0; i < req_isp->num_cfg; i++) { rc = cam_packet_util_get_cmd_mem_addr( @@ -182,7 +333,7 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) CAM_ERR(CAM_ISP, "Invalid offset exp %u actual %u", req_isp->cfg[i].offset, (uint32_t)len); - return; + return rc; } remain_len = len - req_isp->cfg[i].offset; @@ -192,16 +343,33 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) "Invalid len exp %u remain_len %u", req_isp->cfg[i].len, (uint32_t)remain_len); - return; + return rc; } buf_start = (uint32_t *)((uint8_t *) buf_addr + req_isp->cfg[i].offset); buf_end = (uint32_t *)((uint8_t *) buf_start + req_isp->cfg[i].len - 1); - cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + if (dump_to_buff) { + if (!cpu_addr || !offset || !buf_len) { + CAM_ERR(CAM_ISP, "Invalid args"); + break; + } + dump_info.src_start = buf_start; + dump_info.src_end = buf_end; + dump_info.dst_start = cpu_addr; + dump_info.dst_offset = *offset; + dump_info.dst_max_size = buf_len; + rc = cam_cdm_util_dump_cmd_bufs_v2(&dump_info); + *offset = dump_info.dst_offset; + if (rc) + return rc; + } else { + cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + } } } + return rc; } static int __cam_isp_ctx_enqueue_request_in_order( @@ -210,6 +378,7 @@ static int __cam_isp_ctx_enqueue_request_in_order( struct cam_ctx_request *req_current; struct cam_ctx_request *req_prev; struct list_head temp_list; + struct cam_isp_context *ctx_isp; INIT_LIST_HEAD(&temp_list); spin_lock_bh(&ctx->lock); @@ -240,6 +409,9 @@ static int __cam_isp_ctx_enqueue_request_in_order( } } } + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_SUBMIT, req); spin_unlock_bh(&ctx->lock); return 0; } @@ -714,6 +886,8 @@ static int __cam_isp_ctx_handle_buf_done_for_request( __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_BUFDONE, req); return rc; } @@ -822,6 +996,8 @@ static int __cam_isp_ctx_reg_upd_in_applied_state( CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_RUP, req); } else { /* no io config, so the request is completed. */ list_add_tail(&req->list, &ctx->free_req_list); @@ -920,6 +1096,8 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( if (req->request_id > ctx_isp->reported_req_id) { request_id = req->request_id; ctx_isp->reported_req_id = request_id; + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, req); break; } } @@ -1085,7 +1263,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, /* Send SOF event as empty frame*/ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); goto end; } @@ -1130,7 +1309,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, } __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, req); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; CAM_DBG(CAM_ISP, "next Substate[%s]", __cam_isp_ctx_substate_val_to_type( @@ -1248,6 +1428,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( CAM_ERR(CAM_ISP, "ctx:%d No pending request.", ctx->ctx_id); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; goto end; @@ -1294,13 +1476,21 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( ctx_isp->reported_req_id = request_id; __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); - } else + + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, req); + } else { __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - } else + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); + } + } else { __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); + } ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; CAM_DBG(CAM_ISP, "next Substate[%s]", __cam_isp_ctx_substate_val_to_type( @@ -1390,7 +1580,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, req_isp = (struct cam_isp_ctx_req *) req_to_dump->req_priv; if (error_event_data->enable_req_dump) - cam_isp_ctx_dump_req(req_isp); + rc = cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false); __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req_to_dump->request_id); @@ -2058,6 +2248,8 @@ static int __cam_isp_ctx_apply_req_in_activated_state( __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED, req->request_id); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_APPLY, req); } end: return rc; @@ -2135,6 +2327,200 @@ static int __cam_isp_ctx_apply_req_in_bubble( return rc; } +static int __cam_isp_ctx_dump_req_info( + struct cam_context *ctx, + struct cam_ctx_request *req, + uintptr_t cpu_addr, + size_t buf_len, + size_t *offset) +{ + int i, rc; + uint8_t *dst; + int32_t *addr, *start; + uint32_t min_len; + size_t remain_len; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_context *ctx_isp; + struct cam_isp_context_dump_header *hdr; + + if (!req || !ctx || !offset || !cpu_addr || !buf_len) { + CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK %pK %zu", + req, ctx, offset, buf_len); + return -EINVAL; + } + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + ctx_isp = (struct cam_isp_context *)ctx->ctx_priv; + + if (buf_len <= *offset) { + CAM_WARN(CAM_ISP, "Dump buffer overshoot len %zu offset %zu", + buf_len, *offset); + return -ENOSPC; + } + + remain_len = buf_len - *offset; + min_len = sizeof(struct cam_isp_context_dump_header) + + (CAM_ISP_CTX_DUMP_REQUEST_NUM_WORDS * + req_isp->num_fence_map_out * + sizeof(int32_t)); + + if (remain_len < min_len) { + CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + + dst = (uint8_t *)cpu_addr + *offset; + hdr = (struct cam_isp_context_dump_header *)dst; + hdr->word_size = sizeof(int32_t); + scnprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, + "ISP_OUT_FENCE:"); + addr = (int32_t *)(dst + sizeof(struct cam_isp_context_dump_header)); + start = addr; + for (i = 0; i < req_isp->num_fence_map_out; i++) { + *addr++ = req_isp->fence_map_out[i].resource_handle; + *addr++ = req_isp->fence_map_out[i].sync_id; + } + hdr->size = hdr->word_size * (addr - start); + *offset += hdr->size + sizeof(struct cam_isp_context_dump_header); + rc = cam_isp_ctx_dump_req(req_isp, cpu_addr, buf_len, + offset, true); + return rc; +} + +static int __cam_isp_ctx_dump_in_top_state( + struct cam_context *ctx, + struct cam_req_mgr_dump_info *dump_info) +{ + int rc = 0; + bool dump_only_event_record = false; + size_t buf_len; + size_t remain_len; + uint8_t *dst; + ktime_t cur_time; + uint32_t min_len; + uint64_t diff; + uint64_t *addr, *start; + uintptr_t cpu_addr; + struct timespec64 ts; + struct cam_isp_context *ctx_isp; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_ctx_request *req_temp; + struct cam_hw_dump_args dump_args; + struct cam_isp_context_dump_header *hdr; + + spin_lock_bh(&ctx->lock); + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + if (req->request_id == dump_info->req_id) { + CAM_INFO(CAM_ISP, "isp dump active list req: %lld", + dump_info->req_id); + goto hw_dump; + } + } + list_for_each_entry_safe(req, req_temp, + &ctx->wait_req_list, list) { + if (req->request_id == dump_info->req_id) { + CAM_INFO(CAM_ISP, "isp dump wait list req: %lld", + dump_info->req_id); + goto hw_dump; + } + } + spin_unlock_bh(&ctx->lock); + return rc; +hw_dump: + rc = cam_mem_get_cpu_buf(dump_info->buf_handle, + &cpu_addr, &buf_len); + if (rc) { + CAM_ERR(CAM_ISP, "Invalid handle %u rc %d", + dump_info->buf_handle, rc); + spin_unlock_bh(&ctx->lock); + return rc; + } + if (buf_len <= dump_info->offset) { + spin_unlock_bh(&ctx->lock); + CAM_WARN(CAM_ISP, "Dump buffer overshoot len %zu offset %zu", + buf_len, dump_info->offset); + return -ENOSPC; + } + + remain_len = buf_len - dump_info->offset; + min_len = sizeof(struct cam_isp_context_dump_header) + + (CAM_ISP_CTX_DUMP_NUM_WORDS * sizeof(uint64_t)); + + if (remain_len < min_len) { + spin_unlock_bh(&ctx->lock); + CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + cur_time = ktime_get(); + diff = ktime_us_delta( + req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY], + cur_time); + if (diff < CAM_ISP_CTX_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_ISP, "req %lld found no error", + req->request_id); + dump_only_event_record = true; + } + dst = (uint8_t *)cpu_addr + dump_info->offset; + hdr = (struct cam_isp_context_dump_header *)dst; + scnprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, + "ISP_CTX_DUMP:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + + sizeof(struct cam_isp_context_dump_header)); + start = addr; + *addr++ = req->request_id; + ts = ktime_to_timespec64( + req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY]); + *addr++ = ts.tv_sec; + *addr++ = ts.tv_nsec/NSEC_PER_USEC; + ts = ktime_to_timespec64(cur_time); + *addr++ = ts.tv_sec; + *addr++ = ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_info->offset += hdr->size + + sizeof(struct cam_isp_context_dump_header); + + rc = __cam_isp_ctx_dump_event_record(ctx_isp, cpu_addr, + buf_len, &dump_info->offset); + if (rc) { + CAM_ERR(CAM_ISP, "Dump event fail %lld", + req->request_id); + spin_unlock_bh(&ctx->lock); + return rc; + } + if (dump_only_event_record) { + spin_unlock_bh(&ctx->lock); + return rc; + } + rc = __cam_isp_ctx_dump_req_info(ctx, req, cpu_addr, + buf_len, &dump_info->offset); + if (rc) { + CAM_ERR(CAM_ISP, "Dump Req info fail %lld", + req->request_id); + spin_unlock_bh(&ctx->lock); + return rc; + } + spin_unlock_bh(&ctx->lock); + + if (ctx->hw_mgr_intf->hw_dump) { + dump_args.offset = dump_info->offset; + dump_args.request_id = dump_info->req_id; + dump_args.buf_handle = dump_info->buf_handle; + dump_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + rc = ctx->hw_mgr_intf->hw_dump( + ctx->hw_mgr_intf->hw_mgr_priv, + &dump_args); + dump_info->offset = dump_args.offset; + } + return rc; +} + static int __cam_isp_ctx_flush_req(struct cam_context *ctx, struct list_head *req_list, struct cam_req_mgr_flush_request *flush_req) { @@ -2753,12 +3139,15 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( CAM_DBG(CAM_ISP, "next Substate[%s]", __cam_isp_ctx_substate_val_to_type( ctx_isp->substate_activated)); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_RUP, req); return 0; error: /* Send SOF event as idle frame*/ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_RUP, NULL); /* * There is no request in the pending list, move the sub state machine @@ -2918,6 +3307,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; struct cam_req_mgr_flush_request flush_req; + int i; if (ctx_isp->hw_ctx) { rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; @@ -2938,6 +3328,8 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); /* * Ideally, we should never have any active request here. * But we still add some sanity check code here to help the debug @@ -2967,6 +3359,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, struct cam_release_dev_cmd *cmd) { int rc = 0; + int i; struct cam_hw_release_args rel_arg; struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; @@ -2998,7 +3391,8 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx_isp->req_info.last_bufdone_req_id = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); - + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); /* * Ideally, we should never have any active request here. * But we still add some sanity check code here to help the debug @@ -3223,6 +3617,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) { int rc = 0; + int i; struct cam_hw_acquire_args param; struct cam_isp_resource *isp_res = NULL; struct cam_create_dev_hdl req_hdl_param; @@ -3335,6 +3730,8 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); kfree(isp_res); isp_res = NULL; @@ -3385,6 +3782,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, void *args) { int rc = 0; + int i; struct cam_acquire_hw_cmd_v1 *cmd = (struct cam_acquire_hw_cmd_v1 *)args; struct cam_hw_acquire_args param; @@ -3490,6 +3888,9 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); + trace_cam_context_state("ISP", ctx); CAM_DBG(CAM_ISP, "Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u", @@ -3799,6 +4200,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; + int i; struct cam_isp_start_args start_isp; struct cam_ctx_request *req; struct cam_isp_ctx_req *req_isp; @@ -3855,6 +4257,9 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); + /* * In case of CSID TPG we might receive SOF and RUP IRQs * before hw_mgr_intf->hw_start has returned. So move @@ -3885,7 +4290,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, ctx->state = CAM_CTX_READY; trace_cam_context_state("ISP", ctx); if (rc == -ETIMEDOUT) - cam_isp_ctx_dump_req(req_isp); + rc = cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false); list_del_init(&req->list); list_add(&req->list, &ctx->pending_req_list); goto end; @@ -4014,6 +4419,9 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( atomic_set(&ctx_isp->process_bubble, 0); atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); + CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u", ctx->state, ctx->ctx_id); @@ -4270,6 +4678,7 @@ static struct cam_ctx_ops .unlink = __cam_isp_ctx_unlink_in_acquired, .get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired, .flush_req = __cam_isp_ctx_flush_req_in_top_state, + .dump_req = __cam_isp_ctx_dump_in_top_state, }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, @@ -4286,6 +4695,7 @@ static struct cam_ctx_ops .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_ready, .flush_req = __cam_isp_ctx_flush_req_in_ready, + .dump_req = __cam_isp_ctx_dump_in_top_state, }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, @@ -4320,6 +4730,7 @@ static struct cam_ctx_ops .apply_req = __cam_isp_ctx_apply_req, .flush_req = __cam_isp_ctx_flush_req_in_top_state, .process_evt = __cam_isp_ctx_process_evt, + .dump_req = __cam_isp_ctx_dump_in_top_state, }, .irq_ops = __cam_isp_ctx_handle_irq_in_activated, .pagefault_ops = cam_isp_context_dump_active_request, @@ -4503,6 +4914,9 @@ int cam_isp_context_init(struct cam_isp_context *ctx, } atomic64_set(&ctx->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx->event_record_head[i], -1); + cam_isp_context_debug_register(); err: return rc; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 4e690251bf6c..99128fe0fab6 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.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 _CAM_ISP_CONTEXT_H_ @@ -33,6 +33,27 @@ */ #define CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES 40 +/* + * Threshold response time in us beyond which a request is not expected + * to be with IFE hw + */ +#define CAM_ISP_CTX_RESPONSE_TIME_THRESHOLD 100000 + +/* Number of words for dumping isp context */ +#define CAM_ISP_CTX_DUMP_NUM_WORDS 5 + +/* Number of words for dumping isp context events*/ +#define CAM_ISP_CTX_DUMP_EVENT_NUM_WORDS 3 + +/* Number of words for dumping request info*/ +#define CAM_ISP_CTX_DUMP_REQUEST_NUM_WORDS 2 + +/* Maximum entries in event record */ +#define CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES 20 + +/* Maximum length of tag while dumping */ +#define CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN 32 + /* forward declaration */ struct cam_isp_context; @@ -55,6 +76,19 @@ enum cam_isp_ctx_activated_substate { CAM_ISP_CTX_ACTIVATED_MAX, }; +/** + * enum cam_isp_ctx_event_type - events for a request + * + */ +enum cam_isp_ctx_event { + CAM_ISP_CTX_EVENT_SUBMIT, + CAM_ISP_CTX_EVENT_APPLY, + CAM_ISP_CTX_EVENT_EPOCH, + CAM_ISP_CTX_EVENT_RUP, + CAM_ISP_CTX_EVENT_BUFDONE, + CAM_ISP_CTX_EVENT_MAX +}; + /** * enum cam_isp_state_change_trigger - Different types of ISP events * @@ -109,6 +143,7 @@ struct cam_isp_ctx_irq_ops { * @bubble_report: Flag to track if bubble report is active on * current request * @hw_update_data: HW update data for this request + * @event_timestamp: Timestamp for different stage of request * @reapply: True if reapplying after bubble * */ @@ -125,6 +160,8 @@ struct cam_isp_ctx_req { uint32_t num_acked; int32_t bubble_report; struct cam_isp_prepare_hw_update_data hw_update_data; + ktime_t event_timestamp + [CAM_ISP_CTX_EVENT_MAX]; bool bubble_detected; bool reapply; }; @@ -160,8 +197,23 @@ struct cam_isp_context_state_monitor { struct cam_isp_context_req_id_info { int64_t last_bufdone_req_id; }; + /** * + * + * struct cam_isp_context_event_record - Information for last 20 Events + * for a request; Submit, Apply, EPOCH, RUP, Buf done. + * + * @req_id: Last applied request id + * @timestamp: Timestamp for the event + * + */ +struct cam_isp_context_event_record { + uint64_t req_id; + ktime_t timestamp; +}; + +/** * struct cam_isp_context - ISP context object * * @base: Common context object pointer @@ -185,6 +237,8 @@ struct cam_isp_context_req_id_info { * @state_monitor_head: Write index to the state monitoring array * @req_info Request id information about last buf done * @cam_isp_ctx_state_monitor: State monitoring array + * @event_record_head: Write index to the state monitoring array + * @event_record: Event record array * @rdi_only_context: Get context type information. * true, if context is rdi only context * @hw_acquired: Indicate whether HW resources are acquired @@ -218,6 +272,10 @@ struct cam_isp_context { struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; struct cam_isp_context_req_id_info req_info; + atomic64_t event_record_head[ + CAM_ISP_CTX_EVENT_MAX]; + struct cam_isp_context_event_record event_record[ + CAM_ISP_CTX_EVENT_MAX][CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES]; bool rdi_only_context; bool hw_acquired; bool init_received; @@ -226,6 +284,19 @@ struct cam_isp_context { uint32_t isp_device_type; }; +/** + * struct cam_isp_context_dump_header - ISP context dump header + * @tag: Tag name for the header + * @word_size: Size of word + * @size: Size of data + * + */ +struct cam_isp_context_dump_header { + uint8_t tag[CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + /** * cam_isp_context_init() * 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 739b594ba6fb..6fe984a17554 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 @@ -134,7 +134,9 @@ static int cam_ife_mgr_regspace_data_cb(uint32_t reg_base_type, static int cam_ife_mgr_handle_reg_dump(struct cam_ife_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; @@ -157,7 +159,9 @@ static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, rc = cam_soc_util_reg_dump_to_cmd_buf(ctx, ®_dump_buf_desc[i], ctx->applied_req_id, - cam_ife_mgr_regspace_data_cb); + cam_ife_mgr_regspace_data_cb, + 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", @@ -2423,7 +2427,8 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, cam_ife_mgr_handle_reg_dump(ctx, hw_update_data->reg_dump_buf_desc, hw_update_data->num_reg_dump_buf, - CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST); + CAM_ISP_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", @@ -5859,7 +5864,7 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) ctx->last_dump_flush_req_id = ctx->applied_req_id; rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, ctx->num_reg_dump_buf, - CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH); + CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH, NULL, false); if (rc) { CAM_ERR(CAM_ISP, "Reg dump on flush failed req id: %llu rc: %d", @@ -5875,7 +5880,7 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) ctx->last_dump_err_req_id = ctx->applied_req_id; rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, ctx->num_reg_dump_buf, - CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR); + CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR, NULL, false); if (rc) { CAM_ERR(CAM_ISP, "Reg dump on error failed req id: %llu rc: %d", @@ -5894,6 +5899,155 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) return rc; } +static int cam_ife_mgr_user_dump_hw( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_hw_dump_args *dump_args) +{ + int rc = 0; + struct cam_hw_soc_dump_args soc_dump_args; + + if (!ife_ctx || !dump_args) { + CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK", + ife_ctx, dump_args); + rc = -EINVAL; + goto end; + } + 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_ife_mgr_handle_reg_dump(ife_ctx, + ife_ctx->reg_dump_buf_desc, + ife_ctx->num_reg_dump_buf, + CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR, + &soc_dump_args, + true); + if (rc) { + CAM_ERR(CAM_ISP, + "Dump failed req: %lld handle %u offset %u", + dump_args->request_id, + dump_args->buf_handle, + dump_args->offset); + goto end; + } + dump_args->offset = soc_dump_args.offset; +end: + return rc; +} + +static int cam_ife_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_ife_hw_mgr_ctx *ife_ctx = (struct cam_ife_hw_mgr_ctx *) + dump_args->ctxt_to_hw_map; + int i; + int rc = 0; + + /* for some targets, information about the IFE 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 (ife_ctx->num_reg_dump_buf) { + cam_ife_mgr_user_dump_hw(ife_ctx, dump_args); + goto end; + } + + 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, &ife_ctx->res_list_ife_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_IFE_PIX_PATH_RES_RDI_0: + case CAM_IFE_PIX_PATH_RES_RDI_1: + case CAM_IFE_PIX_PATH_RES_RDI_2: + case CAM_IFE_PIX_PATH_RES_RDI_3: + if (ife_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_IFE_PIX_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, &ife_ctx->res_list_ife_src, 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->res_id) { + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + if (ife_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_VFE_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; +end: + CAM_DBG(CAM_ISP, "offset %u", dump_args->offset); + return rc; +} + static int cam_ife_mgr_cmd_get_sof_timestamp( struct cam_ife_hw_mgr_ctx *ife_ctx, uint64_t *time_stamp, @@ -6879,6 +7033,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) hw_mgr_intf->hw_config = cam_ife_mgr_config_hw; hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd; hw_mgr_intf->hw_reset = cam_ife_mgr_reset; + hw_mgr_intf->hw_dump = cam_ife_mgr_dump; if (iommu_hdl) *iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl; 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 fbb71066c903..02d727a29cad 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 @@ -141,7 +141,9 @@ static int cam_tfe_mgr_handle_reg_dump(struct cam_tfe_hw_mgr_ctx *ctx, rc = cam_soc_util_reg_dump_to_cmd_buf(ctx, ®_dump_buf_desc[i], ctx->applied_req_id, - cam_tfe_mgr_regspace_data_cb); + cam_tfe_mgr_regspace_data_cb, + NULL, + false); if (rc) { CAM_ERR(CAM_ISP, "Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %u", diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 0694287392b6..d2b5177d4e20 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -3741,6 +3741,70 @@ static int cam_ife_csid_set_csid_qcfa( return 0; } +static int cam_ife_csid_dump_hw( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + int i; + uint8_t *dst; + uint32_t *addr, *start; + uint32_t min_len; + uint32_t num_reg; + 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; + } + soc_info = &csid_hw->hw_info->soc_info; + 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; + } + min_len = soc_info->reg_map[0].size + + sizeof(struct cam_isp_hw_dump_header) + + sizeof(uint32_t); + 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; + } + 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); + CAM_DBG(CAM_ISP, "offset %zu", dump_args->offset); + return 0; +} + static int cam_ife_csid_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -3778,6 +3842,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED: rc = cam_ife_csid_set_csid_qcfa(csid_hw, cmd_args); break; + case CAM_ISP_HW_CMD_DUMP_HW: + rc = cam_ife_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); 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 483f85bc241e..ca30212ff6d6 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 @@ -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 _CAM_ISP_HW_H_ @@ -13,6 +13,8 @@ #include "cam_irq_controller.h" #include "cam_hw_intf.h" +/* Maximum length of tag while dumping */ +#define CAM_ISP_HW_DUMP_TAG_MAX_LEN 32 /* * struct cam_isp_timestamp: * @@ -111,6 +113,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE, CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, + CAM_ISP_HW_CMD_DUMP_HW, CAM_ISP_HW_CMD_MAX, }; @@ -251,4 +254,40 @@ struct cam_isp_hw_dual_isp_update_args { struct cam_isp_resource_node *res; struct cam_isp_dual_config *dual_cfg; }; + +/* + * struct cam_isp_hw_dump_args: + * + * @Brief: isp hw dump args + * + * @ req_id: request id + * @ cpu_addr: cpu address + * @ buf_len: buf len + * @ offset: offset of buffer + * @ ctxt_to_hw_map: ctx to hw map + */ +struct cam_isp_hw_dump_args { + uint64_t req_id; + uintptr_t cpu_addr; + size_t buf_len; + size_t offset; + void *ctxt_to_hw_map; +}; + +/** + * struct cam_isp_hw_dump_header - ISP context dump header + * + * @Brief: isp hw dump header + * + * @tag: Tag name for the header + * @word_size: Size of word + * @size: Size of data + * + */ +struct cam_isp_hw_dump_header { + uint8_t tag[CAM_ISP_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + #endif /* _CAM_ISP_HW_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index a9dbcf5d001f..8fdbbd33b897 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.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 @@ -593,6 +593,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_BW_CONTROL: case CAM_ISP_HW_CMD_CORE_CONFIG: case CAM_ISP_HW_CMD_BW_UPDATE_V2: + case CAM_ISP_HW_CMD_DUMP_HW: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 663bc247b27f..63df625221cc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.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 _CAM_VFE170_H_ @@ -144,6 +144,32 @@ static struct cam_vfe_rdi_reg_data vfe_170_rdi_2_data = { .reg_update_irq_mask = 0x80, }; +struct cam_vfe_top_dump_data vfe170_dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0x1164, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x397C, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, +}; + static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { .common_reg = &vfe170_top_common_reg, .camif_hw_info = { @@ -173,6 +199,7 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { CAM_VFE_RDI_VER_1_0, CAM_VFE_RDI_VER_1_0, }, + .dump_data = &vfe170_dump_data, }; static struct cam_irq_register_set vfe170_bus_irq_reg[3] = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index 6823b6386b91..4e9a1e232860 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.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_VFE175_H_ @@ -178,6 +178,32 @@ static struct cam_vfe_rdi_reg_data vfe_175_rdi_2_data = { .reg_update_irq_mask = 0x80, }; +struct cam_vfe_top_dump_data vfe175_dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0x1164, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x397C, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, +}; + static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { .common_reg = &vfe175_top_common_reg, .camif_hw_info = { @@ -209,6 +235,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { CAM_VFE_RDI_VER_1_0, CAM_VFE_CAMIF_LITE_VER_2_0, }, + .dump_data = &vfe175_dump_data, }; static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 8acd77d1f1e2..1a80dc7f8f2e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.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_VFE175_130_H_ @@ -226,6 +226,32 @@ static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_2_data = { .reg_update_irq_mask = 0x80, }; +struct cam_vfe_top_dump_data vfe175_130_dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0x1164, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x397C, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, +}; + static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { .common_reg = &vfe175_130_top_common_reg, .camif_hw_info = { @@ -263,6 +289,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { CAM_VFE_CAMIF_LITE_VER_2_0, CAM_VFE_IN_RD_VER_1_0, }, + .dump_data = &vfe175_130_dump_data, }; static struct cam_irq_register_set vfe175_130_bus_rd_irq_reg[1] = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h index 03be713e6068..55607b6d886f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.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_VFE_TOP_COMMON_H_ @@ -13,6 +13,10 @@ #include "cam_vfe_hw_intf.h" #include "cam_vfe_soc.h" +#define CAM_VFE_TOP_MAX_REG_DUMP_ENTRIES 70 + +#define CAM_VFE_TOP_MAX_LUT_DUMP_ENTRIES 6 + struct cam_vfe_top_priv_common { struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_MUX_MAX]; uint32_t num_mux; @@ -26,6 +30,30 @@ struct cam_vfe_top_priv_common { enum cam_vfe_bw_control_action axi_vote_control[CAM_VFE_TOP_MUX_MAX]; }; +struct cam_vfe_top_reg_dump_entry { + uint32_t reg_dump_start; + uint32_t reg_dump_end; +}; + +struct cam_vfe_top_lut_dump_entry { + uint32_t lut_word_size; + uint32_t lut_bank_sel; + uint32_t lut_addr_size; +}; + +struct cam_vfe_top_dump_data { + uint32_t num_reg_dump_entries; + uint32_t num_lut_dump_entries; + uint32_t dmi_cfg; + uint32_t dmi_addr; + uint32_t dmi_data_path_hi; + uint32_t dmi_data_path_lo; + struct cam_vfe_top_reg_dump_entry + reg_entry[CAM_VFE_TOP_MAX_REG_DUMP_ENTRIES]; + struct cam_vfe_top_lut_dump_entry + lut_entry[CAM_VFE_TOP_MAX_LUT_DUMP_ENTRIES]; +}; + int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private, struct cam_vfe_top_priv_common *top_common, bool start_stop); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index c5225c540722..6774be8cda3d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.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 @@ -19,6 +19,7 @@ struct cam_vfe_top_ver2_common_data { struct cam_hw_soc_info *soc_info; struct cam_hw_intf *hw_intf; struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_top_dump_data *dump_data; }; struct cam_vfe_top_ver2_priv { @@ -184,6 +185,140 @@ int cam_vfe_top_get_hw_caps(void *device_priv, return -EPERM; } +static int cam_vfe_hw_dump( + struct cam_vfe_top_ver2_priv *top_priv, + 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 val; + uint32_t num_reg; + void __iomem *reg_base; + uint32_t *addr, *start; + size_t remain_len; + uint32_t min_len; + struct cam_hw_soc_info *soc_info; + struct cam_vfe_top_dump_data *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) { + 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; + } + dump_data = top_priv->common_data.dump_data; + soc_info = top_priv->common_data.soc_info; + + /*Dump registers */ + for (i = 0; i < dump_data->num_reg_dump_entries; i++) + reg_dump_size += (dump_data->reg_entry[i].reg_dump_end - + dump_data->reg_entry[i].reg_dump_start); + /* + * We dump the offset as well, so the total size dumped becomes + * multiplied by 2 + */ + reg_dump_size *= 2; + for (i = 0; i < dump_data->num_lut_dump_entries; i++) + lut_dump_size += ((dump_data->lut_entry[i].lut_addr_size) * + (dump_data->lut_entry[i].lut_word_size/8)); + + /*Minimum len comprises of: + * soc_index + * lut_dump_size + reg_dump_size + sizeof dump_header + + * (num_lut_dump_entries--> represents number of banks) + */ + min_len = sizeof(uint32_t) + lut_dump_size + reg_dump_size + + sizeof(struct cam_isp_hw_dump_header) + + (dump_data->num_lut_dump_entries * sizeof(uint32_t)); + 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; + } + + 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, "VFE_REG:"); + addr = (uint32_t *)(dst + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + for (i = 0; i < dump_data->num_reg_dump_entries; i++) { + num_reg = (dump_data->reg_entry[i].reg_dump_end - + dump_data->reg_entry[i].reg_dump_start)/4; + reg_start_offset = dump_data->reg_entry[i].reg_dump_start; + reg_base = soc_info->reg_map[0].mem_base + reg_start_offset; + for (j = 0; j < num_reg; j++) { + addr[0] = soc_info->mem_block[0]->start + + reg_start_offset + (j*4); + addr[1] = cam_io_r(reg_base + (j*4)); + addr += 2; + } + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + + /*dump LUT*/ + for (i = 0; i < dump_data->num_lut_dump_entries; i++) { + + 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 = dump_data->lut_entry[i].lut_word_size/8; + addr = (uint32_t *)(dst + + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + *addr++ = dump_data->lut_entry[i].lut_bank_sel; + val = 0x100 | dump_data->lut_entry[i].lut_bank_sel; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + dump_data->dmi_cfg); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + dump_data->dmi_addr); + for (j = 0; j < dump_data->lut_entry[i].lut_addr_size; + j++) { + if (dump_data->lut_entry[i].lut_word_size == 64) { + addr[0] = cam_io_r( + soc_info->reg_map[0].mem_base + + dump_data->dmi_data_path_lo); + addr[1] = cam_io_r( + soc_info->reg_map[0].mem_base + + dump_data->dmi_data_path_hi); + addr += 2; + } else { + *addr = cam_io_r( + soc_info->reg_map[0].mem_base + + dump_data->dmi_data_path_lo); + addr++; + } + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + } + CAM_DBG(CAM_ISP, "offset %zu", dump_args->offset); + return 0; +} + int cam_vfe_top_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size) { @@ -505,6 +640,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_bw_control(soc_private, &top_priv->top_common, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_DUMP_HW: + rc = cam_vfe_hw_dump(top_priv, + cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); @@ -627,6 +766,7 @@ int cam_vfe_top_ver2_init( top_priv->common_data.hw_intf = hw_intf; top_priv->top_common.hw_idx = hw_intf->hw_idx; top_priv->common_data.common_reg = ver2_hw_info->common_reg; + top_priv->common_data.dump_data = ver2_hw_info->dump_data; return rc; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h index 961bf954aaa1..65d01da159ec 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.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 _CAM_VFE_TOP_VER2_H_ @@ -49,6 +49,7 @@ struct cam_vfe_top_ver2_hw_info { struct cam_vfe_camif_lite_ver2_hw_info camif_lite_hw_info; struct cam_vfe_rdi_ver2_hw_info rdi_hw_info; struct cam_vfe_fe_ver1_hw_info fe_hw_info; + struct cam_vfe_top_dump_data *dump_data; uint32_t num_mux; uint32_t mux_type[CAM_VFE_TOP_MUX_MAX]; }; diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 219d7569d0e2..ce80569ab0f9 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include @@ -2002,9 +2002,268 @@ static int cam_soc_util_dump_dmi_reg_range( return rc; } +static int cam_soc_util_dump_dmi_reg_range_user_buf( + struct cam_hw_soc_info *soc_info, + struct cam_dmi_read_desc *dmi_read, uint32_t base_idx, + struct cam_hw_soc_dump_args *dump_args) +{ + int i; + int rc; + size_t buf_len = 0; + uint8_t *dst; + size_t remain_len; + uint32_t min_len; + uint32_t *waddr, *start; + uintptr_t cpu_addr; + struct cam_hw_soc_dump_header *hdr; + + if (!soc_info || !dump_args || !dmi_read) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_args: %pK", + soc_info, dump_args); + rc = -EINVAL; + goto end; + } + + if (dmi_read->num_pre_writes > CAM_REG_DUMP_DMI_CONFIG_MAX || + dmi_read->num_post_writes > CAM_REG_DUMP_DMI_CONFIG_MAX) { + CAM_ERR(CAM_UTIL, + "Invalid number of requested writes, pre: %d post: %d", + dmi_read->num_pre_writes, dmi_read->num_post_writes); + rc = -EINVAL; + goto end; + } + + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &cpu_addr, &buf_len); + if (rc) { + CAM_ERR(CAM_UTIL, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + goto end; + } + + if (buf_len <= dump_args->offset) { + CAM_WARN(CAM_UTIL, "Dump offset overshoot offset %zu len %zu", + dump_args->offset, buf_len); + rc = -ENOSPC; + goto end; + } + remain_len = buf_len - dump_args->offset; + min_len = (dmi_read->num_pre_writes * 2 * sizeof(uint32_t)) + + (dmi_read->dmi_data_read.num_values * 2 * sizeof(uint32_t)) + + sizeof(uint32_t); + if (remain_len < min_len) { + CAM_WARN(CAM_UTIL, + "Dump Buffer exhaust read %d write %d remain %zu min %u", + dmi_read->dmi_data_read.num_values, + dmi_read->num_pre_writes, remain_len, + min_len); + rc = -ENOSPC; + goto end; + } + + dst = (uint8_t *)cpu_addr + dump_args->offset; + hdr = (struct cam_hw_soc_dump_header *)dst; + memset(hdr, 0, sizeof(struct cam_hw_soc_dump_header)); + scnprintf(hdr->tag, CAM_SOC_HW_DUMP_TAG_MAX_LEN, + "DMI_DUMP:"); + waddr = (uint32_t *)(dst + sizeof(struct cam_hw_soc_dump_header)); + start = waddr; + hdr->word_size = sizeof(uint32_t); + *waddr = soc_info->index; + waddr++; + for (i = 0; i < dmi_read->num_pre_writes; i++) { + if (dmi_read->pre_read_config[i].offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->pre_read_config[i].offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->pre_read_config[i].offset, + dmi_read->pre_read_config[i].value); + *waddr++ = dmi_read->pre_read_config[i].offset; + *waddr++ = dmi_read->pre_read_config[i].value; + } + + if (dmi_read->dmi_data_read.offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->dmi_data_read.offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + for (i = 0; i < dmi_read->dmi_data_read.num_values; i++) { + *waddr++ = dmi_read->dmi_data_read.offset; + *waddr++ = cam_soc_util_r_mb(soc_info, base_idx, + dmi_read->dmi_data_read.offset); + } + + for (i = 0; i < dmi_read->num_post_writes; i++) { + if (dmi_read->post_read_config[i].offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->post_read_config[i].offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->post_read_config[i].offset, + dmi_read->post_read_config[i].value); + } + hdr->size = (waddr - start) * hdr->word_size; + dump_args->offset += hdr->size + + sizeof(struct cam_hw_soc_dump_header); + +end: + return rc; +} + +static int cam_soc_util_dump_cont_reg_range_user_buf( + struct cam_hw_soc_info *soc_info, + struct cam_reg_range_read_desc *reg_read, + uint32_t base_idx, + struct cam_hw_soc_dump_args *dump_args) +{ + int i; + int rc = 0; + size_t buf_len; + uint8_t *dst; + size_t remain_len; + uint32_t min_len; + uint32_t *waddr, *start; + uintptr_t cpu_addr; + struct cam_hw_soc_dump_header *hdr; + + if (!soc_info || !dump_args || !reg_read) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_out_buffer: %pK reg_read: %pK", + soc_info, dump_args, reg_read); + rc = -EINVAL; + goto end; + } + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &cpu_addr, &buf_len); + if (rc) { + CAM_ERR(CAM_UTIL, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + goto end; + } + if (buf_len <= dump_args->offset) { + CAM_WARN(CAM_UTIL, "Dump offset overshoot %zu %zu", + dump_args->offset, buf_len); + rc = -ENOSPC; + goto end; + } + remain_len = buf_len - dump_args->offset; + min_len = (reg_read->num_values * 2 * sizeof(uint32_t)) + + sizeof(struct cam_hw_soc_dump_header) + sizeof(uint32_t); + if (remain_len < min_len) { + CAM_WARN(CAM_UTIL, + "Dump Buffer exhaust read_values %d remain %zu min %u", + reg_read->num_values, + remain_len, + min_len); + rc = -ENOSPC; + goto end; + } + dst = (uint8_t *)cpu_addr + dump_args->offset; + hdr = (struct cam_hw_soc_dump_header *)dst; + memset(hdr, 0, sizeof(struct cam_hw_soc_dump_header)); + scnprintf(hdr->tag, CAM_SOC_HW_DUMP_TAG_MAX_LEN, "%s_REG:", + soc_info->dev_name); + waddr = (uint32_t *)(dst + sizeof(struct cam_hw_soc_dump_header)); + start = waddr; + hdr->word_size = sizeof(uint32_t); + *waddr = soc_info->index; + waddr++; + for (i = 0; i < reg_read->num_values; i++) { + if ((reg_read->offset + (i * sizeof(uint32_t))) > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + (reg_read->offset + (i * sizeof(uint32_t))), + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + waddr[0] = reg_read->offset + (i * sizeof(uint32_t)); + waddr[1] = cam_soc_util_r(soc_info, base_idx, + (reg_read->offset + (i * sizeof(uint32_t)))); + waddr += 2; + } + hdr->size = (waddr - start) * hdr->word_size; + dump_args->offset += hdr->size + + sizeof(struct cam_hw_soc_dump_header); +end: + return rc; +} + +static int cam_soc_util_user_reg_dump( + struct cam_reg_dump_desc *reg_dump_desc, + struct cam_hw_soc_dump_args *dump_args, + struct cam_hw_soc_info *soc_info, + uint32_t reg_base_idx) +{ + int rc = 0; + int i; + struct cam_reg_read_info *reg_read_info = NULL; + + if (!dump_args || !reg_dump_desc || !soc_info) { + CAM_ERR(CAM_UTIL, + "Invalid input parameters %pK %pK %pK", + dump_args, reg_dump_desc, soc_info); + return -EINVAL; + } + for (i = 0; i < reg_dump_desc->num_read_range; i++) { + + reg_read_info = ®_dump_desc->read_range[i]; + if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_CONT_RANGE) { + rc = cam_soc_util_dump_cont_reg_range_user_buf( + soc_info, + ®_read_info->reg_read, + reg_base_idx, + dump_args); + } else if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_DMI) { + rc = cam_soc_util_dump_dmi_reg_range_user_buf( + soc_info, + ®_read_info->dmi_read, + reg_base_idx, + dump_args); + } else { + CAM_ERR(CAM_UTIL, + "Invalid Reg dump read type: %d", + reg_read_info->type); + rc = -EINVAL; + goto end; + } + + if (rc) { + CAM_ERR(CAM_UTIL, + "Reg range read failed rc: %d reg_base_idx: %d", + rc, reg_base_idx); + goto end; + } + } +end: + return rc; +} + int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id, - cam_soc_util_regspace_data_cb reg_data_cb) + cam_soc_util_regspace_data_cb reg_data_cb, + struct cam_hw_soc_dump_args *soc_dump_args, + bool user_triggered_dump) { int rc = 0, i, j; uintptr_t cpu_addr = 0; @@ -2148,12 +2407,6 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, goto end; } - dump_out_buf = (struct cam_reg_dump_out_buffer *) - (cmd_buf_start + - (uintptr_t)reg_dump_desc->dump_buffer_offset); - dump_out_buf->req_id = req_id; - dump_out_buf->bytes_written = 0; - reg_base_type = reg_dump_desc->reg_base_type; if (reg_base_type == 0 || reg_base_type > CAM_REG_DUMP_BASE_TYPE_CAMNOC) { @@ -2185,6 +2438,31 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, "Reg data callback success req_id: %llu base_type: %d base_idx: %d num_read_range: %d", req_id, reg_base_type, reg_base_idx, reg_dump_desc->num_read_range); + + /* If the dump request is triggered by user space + * buffer will be different from the buffer which is received + * in init packet. In this case, dump the data to the + * user provided buffer and exit. + */ + if (user_triggered_dump) { + rc = cam_soc_util_user_reg_dump(reg_dump_desc, + soc_dump_args, soc_info, reg_base_idx); + CAM_INFO(CAM_UTIL, + "%s reg_base_idx %d dumped offset %u", + soc_info->dev_name, reg_base_idx, + soc_dump_args->offset); + goto end; + } + + /* Below code is executed when data is dumped to the + * out buffer received in init packet + */ + dump_out_buf = (struct cam_reg_dump_out_buffer *) + (cmd_buf_start + + (uintptr_t)reg_dump_desc->dump_buffer_offset); + dump_out_buf->req_id = req_id; + dump_out_buf->bytes_written = 0; + for (j = 0; j < reg_dump_desc->num_read_range; j++) { CAM_DBG(CAM_UTIL, "Number of bytes written to cmd buffer: %u req_id: %llu", diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index a717b6b72817..aeaf1c6563ea 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SOC_UTIL_H_ @@ -41,6 +41,9 @@ #define DDR_TYPE_LPDDR5 8 #define DDR_TYPE_LPDDR5X 9 +/* Maximum length of tag while dumping */ +#define CAM_SOC_HW_DUMP_TAG_MAX_LEN 32 + /** * enum cam_vote_level - Enum for voting level * @@ -218,6 +221,34 @@ struct cam_hw_soc_info { void *soc_private; }; +/** + * struct cam_hw_soc_dump_header - SOC dump header + * + * @Brief: soc hw dump header + * + * @tag: Tag name for the header + * @word_size: Size of each word + * @size: Total size of dumped data + */ +struct cam_hw_soc_dump_header { + uint8_t tag[CAM_SOC_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + +/** + * struct cam_hw_soc_dump_args: SOC Dump args + * + * @request_id: Issue request id + * @offset: Buffer offset, updated as the informaton is dumped + * @buf_handle: Buffer handle of the out buffer + */ +struct cam_hw_soc_dump_args { + uint64_t request_id; + size_t offset; + uint32_t buf_handle; +}; + /* * CAM_SOC_GET_REG_MAP_START * @@ -636,19 +667,23 @@ typedef int (*cam_soc_util_regspace_data_cb)(uint32_t reg_base_type, /** * cam_soc_util_reg_dump_to_cmd_buf() * - * @brief: Camera SOC util for dumping sets of register ranges to - * to command buffer - * - * @ctx: Context info from specific hardware manager - * @cmd_desc: Command buffer descriptor - * @req_id: Last applied req id for which reg dump is required - * @reg_data_cb: Callback function to get reg space info based on type - * in command buffer - * - * @return: Success or Failure + * @brief: Camera SOC util for dumping sets of register ranges + * command buffer + * + * @ctx: Context info from specific hardware manager + * @cmd_desc: Command buffer descriptor + * @req_id: Last applied req id for which reg dump is required + * @reg_data_cb: Callback function to get reg space info based on type + * in command buffer + * @soc_dump_args: Dump buffer args to dump the soc information. + * @user_triggered_dump: Flag to indicate if the dump request is issued by + * user. + * @return: Success or Failure */ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id, - cam_soc_util_regspace_data_cb reg_data_cb); + cam_soc_util_regspace_data_cb reg_data_cb, + struct cam_hw_soc_dump_args *soc_dump_args, + bool user_triggered_dump); #endif /* _CAM_SOC_UTIL_H_ */ -- GitLab From 0c96fc99e26b04d23fc38061fe157473d2cbd3cc Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 3 Feb 2020 18:16:44 +0530 Subject: [PATCH 105/295] msm: camera: ope: Delay releasing of resources for last context OPE driver update the bandwidth as part of each release context. As part of last context it disabled the irq as well. But in some corner case, pending IRQ routines gets called very late as part of disable IRQ callback and causes unclock access. Hence delay the bw update for last context to avoid unclock access during pending IRQ callbacks. CRs-Fixed: 2611400 Change-Id: I6620b5fc218282af280eac41f276fccd7ff0c4b0 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 19 +++++++++--- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 31 +++++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) 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 070f67433502..692bfa244199 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 @@ -2433,10 +2433,6 @@ static int cam_ope_mgr_release_ctx(struct cam_ope_hw_mgr *hw_mgr, int ctx_id) hw_mgr->ctx[ctx_id].req_cnt = 0; cam_ope_put_free_ctx(hw_mgr, ctx_id); - rc = cam_ope_mgr_remove_bw(hw_mgr, ctx_id); - if (rc) - CAM_ERR(CAM_OPE, "OPE remove bw failed: %d", rc); - rc = cam_ope_mgr_ope_clk_remove(hw_mgr, ctx_id); if (rc) CAM_ERR(CAM_OPE, "OPE clk update failed: %d", rc); @@ -2509,6 +2505,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); 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 8f934b09d7ff..a32c597236d0 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) @@ -251,13 +273,6 @@ 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; } -- GitLab From 296fee45f5ff637d65a57e1e5643a2e34d306e2e Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 3 Feb 2020 16:43:49 +0530 Subject: [PATCH 106/295] msm: camera: isp: Set device enable flag after enable csid hardware Device enable flag is getting set after configuring the CSID csi rx and csid path configuration. If irq comes after configuring the csi rx hardware then irq handler is not handling as it is checking the device enable flag. So set device enable flag after enabling the hardware. CRs-Fixed: 2614498 Change-Id: I0e5a1f99ec4e2e4d3bd11274e2251f001223a651 Signed-off-by: Rishabh Jain --- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) 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 59450ae841d3..b723877f1a17 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 @@ -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. */ #include @@ -830,6 +830,7 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw *csid_hw) const struct cam_tfe_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; uint32_t i, val, clk_lvl; + unsigned long flags; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; @@ -902,6 +903,10 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw *csid_hw) if (rc) goto disable_soc; + spin_lock_irqsave(&csid_hw->spin_lock, flags); + csid_hw->device_enabled = 1; + spin_unlock_irqrestore(&csid_hw->spin_lock, flags); + return rc; disable_soc: @@ -1876,7 +1881,6 @@ static int cam_tfe_csid_init_hw(void *hw_priv, struct cam_hw_info *csid_hw_info; struct cam_isp_resource_node *res; const struct cam_tfe_csid_reg_offset *csid_reg; - unsigned long flags; if (!hw_priv || !init_args || (arg_size != sizeof(struct cam_isp_resource_node))) { @@ -1936,9 +1940,6 @@ static int cam_tfe_csid_init_hw(void *hw_priv, if (rc) cam_tfe_csid_disable_hw(csid_hw); - spin_lock_irqsave(&csid_hw->spin_lock, flags); - csid_hw->device_enabled = 1; - spin_unlock_irqrestore(&csid_hw->spin_lock, flags); end: mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; @@ -2465,16 +2466,6 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) 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 + -- GitLab From 9167e96beeace975b7d3f271a67bfdba7a2bc3a8 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Tue, 4 Feb 2020 22:48:24 +0530 Subject: [PATCH 107/295] msm: camera: isp: Increase default SOF freeze timeout Increase default SOF freeze timeout to 5 second. This will be updated based on additional timeout received in further requests. CRs-Fixed: 2612131 Change-Id: I6b2cb40ea288cb631acf429471a660f8dd4812b9 Signed-off-by: Rishabh Jain --- drivers/cam_req_mgr/cam_req_mgr_core.c | 4 ++-- drivers/cam_req_mgr/cam_req_mgr_core.h | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 1c3fa33961e7..25afc904b400 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -3665,7 +3665,7 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) if (control->ops == CAM_REQ_MGR_LINK_ACTIVATE) { /* 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 056b421ff81e..92c4c3d4599f 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_CORE_H_ #define _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 1000 -#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 -- GitLab From 39fc1ae37708ae3b85744f82bb3dfe88a08fa820 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Wed, 29 Jan 2020 14:10:55 -0800 Subject: [PATCH 108/295] msm: camera: smmu: Add map and unmap monitor Add map and unmap events in monitor array for each context bank and dump the last set of events whenever some smmu related issue happens. CRs-Fixed: 2538876 Change-Id: I18941e9a64ebd6828419e13471938bb32438122c Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_smmu/cam_smmu_api.c | 111 ++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 4 deletions(-) diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 1a7f122b8c04..0277391c048d 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -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. */ #include @@ -36,6 +36,11 @@ #define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK)) #define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK) +#define CAM_SMMU_MONITOR_MAX_ENTRIES 100 +#define CAM_SMMU_INC_MONITOR_HEAD(head, ret) \ + div_u64_rem(atomic64_add_return(1, head),\ + CAM_SMMU_MONITOR_MAX_ENTRIES, (ret)) + static int g_num_pf_handled = 4; module_param(g_num_pf_handled, int, 0644); @@ -94,6 +99,17 @@ struct secheap_buf_info { struct sg_table *table; }; +struct cam_smmu_monitor { + struct timespec64 timestamp; + bool is_map; + + /* map-unmap info */ + int ion_fd; + dma_addr_t paddr; + size_t len; + enum cam_smmu_region_id region_id; +}; + struct cam_context_bank_info { struct device *dev; struct iommu_domain *domain; @@ -143,6 +159,9 @@ struct cam_context_bank_info { /* discard iova - non-zero values are valid */ dma_addr_t discard_iova_start; size_t discard_iova_len; + + atomic64_t monitor_head; + struct cam_smmu_monitor monitor_entries[CAM_SMMU_MONITOR_MAX_ENTRIES]; }; struct cam_iommu_cb_set { @@ -265,6 +284,76 @@ static int cam_smmu_probe(struct platform_device *pdev); static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr); +static void cam_smmu_update_monitor_array( + struct cam_context_bank_info *cb_info, + bool is_map, + struct cam_dma_buff_info *mapping_info) +{ + int iterator; + + CAM_SMMU_INC_MONITOR_HEAD(&cb_info->monitor_head, &iterator); + + ktime_get_real_ts64(&cb_info->monitor_entries[iterator].timestamp); + + cb_info->monitor_entries[iterator].is_map = is_map; + cb_info->monitor_entries[iterator].ion_fd = mapping_info->ion_fd; + cb_info->monitor_entries[iterator].paddr = mapping_info->paddr; + cb_info->monitor_entries[iterator].len = mapping_info->len; + cb_info->monitor_entries[iterator].region_id = mapping_info->region_id; +} + +static void cam_smmu_dump_monitor_array( + struct cam_context_bank_info *cb_info) +{ + int i = 0; + int64_t state_head = 0; + uint32_t index, num_entries, oldest_entry; + uint64_t ms, tmp, hrs, min, sec; + struct timespec64 *ts = NULL; + + state_head = atomic64_read(&cb_info->monitor_head); + + if (state_head == -1) { + return; + } else if (state_head < CAM_SMMU_MONITOR_MAX_ENTRIES) { + num_entries = state_head; + oldest_entry = 0; + } else { + num_entries = CAM_SMMU_MONITOR_MAX_ENTRIES; + div_u64_rem(state_head + 1, + CAM_SMMU_MONITOR_MAX_ENTRIES, &oldest_entry); + } + + CAM_INFO(CAM_SMMU, + "========Dumping monitor information for cb %s===========", + cb_info->name[0]); + + index = oldest_entry; + + for (i = 0; i < num_entries; i++) { + ts = &cb_info->monitor_entries[index].timestamp; + tmp = ts->tv_sec; + ms = (ts->tv_nsec) / 1000000; + sec = do_div(tmp, 60); + min = do_div(tmp, 60); + hrs = do_div(tmp, 24); + + CAM_INFO(CAM_SMMU, + "**** %llu:%llu:%llu.%llu : Index[%d] [%s] : ion_fd=%d start=0x%x end=0x%x len=%u region=%d", + hrs, min, sec, ms, + index, + cb_info->monitor_entries[index].is_map ? "MAP" : "UNMAP", + cb_info->monitor_entries[index].ion_fd, + (void *)cb_info->monitor_entries[index].paddr, + ((uint64_t)cb_info->monitor_entries[index].paddr + + (uint64_t)cb_info->monitor_entries[index].len), + (unsigned int)cb_info->monitor_entries[index].len, + cb_info->monitor_entries[index].region_id); + + index = (index + 1) % CAM_SMMU_MONITOR_MAX_ENTRIES; + } +} + static void cam_smmu_page_fault_work(struct work_struct *work) { int j; @@ -327,7 +416,7 @@ static void cam_smmu_dump_cb_info(int idx) CAM_ERR(CAM_SMMU, "********** Context bank dump for %s **********", - cb_info->name); + cb_info->name[0]); CAM_ERR(CAM_SMMU, "Usage: shared_usage=%u io_usage=%u shared_free=%u io_free=%u", (unsigned int)cb_info->shared_mapping_size, @@ -347,6 +436,8 @@ static void cam_smmu_dump_cb_info(int idx) (unsigned int)mapping->len, mapping->region_id); } + + cam_smmu_dump_monitor_array(&iommu_cb_set.cb_info[idx]); } } @@ -1926,6 +2017,9 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + cam_smmu_update_monitor_array(&iommu_cb_set.cb_info[idx], true, + mapping_info); + return 0; } @@ -1951,6 +2045,9 @@ static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list); + cam_smmu_update_monitor_array(&iommu_cb_set.cb_info[idx], true, + mapping_info); + return 0; } @@ -1975,6 +2072,9 @@ static int cam_smmu_unmap_buf_and_remove_from_list( return -EINVAL; } + cam_smmu_update_monitor_array(&iommu_cb_set.cb_info[idx], false, + mapping_info); + CAM_DBG(CAM_SMMU, "region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", mapping_info->region_id, mapping_info->paddr, mapping_info->len, @@ -2934,6 +3034,7 @@ int cam_smmu_get_iova(int handle, int ion_fd, if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) { CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd); rc = -EINVAL; + cam_smmu_dump_cb_info(idx); goto get_addr_end; } @@ -3292,6 +3393,8 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, cb->is_fw_allocated = false; cb->is_secheap_allocated = false; + atomic64_set(&cb->monitor_head, -1); + /* Create a pool with 64K granularity for supporting shared memory */ if (cb->shared_support) { cb->shared_mem_pool = gen_pool_create( @@ -3625,7 +3728,7 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, cb->io_info.iova_start + cb->io_info.iova_len)) { CAM_ERR(CAM_SMMU, "[%s] : Incorrect Discard region specified [0x%x 0x%x] in [0x%x 0x%x]", - cb->name, + cb->name[0], cb->discard_iova_start, cb->discard_iova_start + cb->discard_iova_len, cb->io_info.iova_start, @@ -3636,7 +3739,7 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, CAM_INFO(CAM_SMMU, "[%s] : Discard region specified [0x%x 0x%x] in [0x%x 0x%x]", - cb->name, + cb->name[0], cb->discard_iova_start, cb->discard_iova_start + cb->discard_iova_len, cb->io_info.iova_start, -- GitLab From e110aec0bc74eb78ed7595b3a54504df538f4abb Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 28 Oct 2019 19:54:39 +0530 Subject: [PATCH 109/295] msm: camera: common: LDAR dump NRT devices information When user space detects an error or does not receive response for a request, Lets do a reset(LDAR) is triggered. Before LDAR, user space sends flush command to the kernel space. In order to debug the cause for this situation and to dump the information, user space sends a dump command to the kernel space before sending flush. As a part of this command, it passes the culprit request id and the buffer into which the information can be dumped. Kernel space traverses across the drivers and find the culprit hw and dumps the relevant information in the buffer. This data is written to a file for offline processing. This commit dumps the information for NRT devices; JPEG, LRME, FD and ICP. For LRME, FD, JPEG context information is dumped. FOR ICP, fw image is dumped. Change-Id: I123e9b8289521a40d88156ba9bd0003ad9602f01 CRs-Fixed: 2612116 Signed-off-by: Gaurav Jindal --- drivers/cam_fd/cam_fd_context.c | 16 +- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 135 +++++++++++++- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h | 10 +- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c | 81 ++++++++- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h | 34 +++- drivers/cam_icp/cam_icp_context.c | 17 +- drivers/cam_icp/icp_hw/a5_hw/a5_core.c | 55 +++++- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 111 ++++++++++++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 10 +- .../icp_hw_mgr/include/cam_a5_hw_intf.h | 3 +- .../icp_hw/include/cam_icp_hw_mgr_intf.h | 29 +++- drivers/cam_jpeg/cam_jpeg_context.c | 16 +- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 141 ++++++++++++++- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h | 10 +- .../jpeg_hw/include/cam_jpeg_hw_intf.h | 19 +- .../cam_jpeg_enc_hw_info_ver_4_2_0.h | 6 +- .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c | 83 ++++++++- .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h | 8 +- drivers/cam_lrme/cam_lrme_context.c | 18 +- .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 47 ++++- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c | 164 +++++++++++++++++- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h | 20 ++- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h | 21 ++- 23 files changed, 1032 insertions(+), 22 deletions(-) diff --git a/drivers/cam_fd/cam_fd_context.c b/drivers/cam_fd/cam_fd_context.c index ec6468f85dc0..99887d30242d 100644 --- a/drivers/cam_fd/cam_fd_context.c +++ b/drivers/cam_fd/cam_fd_context.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 @@ -117,6 +117,19 @@ static int __cam_fd_ctx_release_dev_in_activated(struct cam_context *ctx, return rc; } +static int __cam_fd_ctx_dump_dev_in_activated( + struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_FD, "Failed to dump device, rc=%d", rc); + + return rc; +} + static int __cam_fd_ctx_flush_dev_in_activated(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -198,6 +211,7 @@ static struct cam_ctx_ops .release_dev = __cam_fd_ctx_release_dev_in_activated, .config_dev = __cam_fd_ctx_config_dev_in_activated, .flush_dev = __cam_fd_ctx_flush_dev_in_activated, + .dump_dev = __cam_fd_ctx_dump_dev_in_activated, }, .crm_ops = {}, .irq_ops = __cam_fd_ctx_handle_irq_in_activated, diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index b33dfa699647..cfbb8840eb63 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.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 @@ -883,6 +883,7 @@ static int cam_fd_mgr_util_submit_frame(void *priv, void *data) hw_device->cur_hw_ctx = hw_ctx; hw_device->req_id = frame_req->request_id; mutex_unlock(&hw_device->lock); + frame_req->submit_timestamp = ktime_get(); rc = cam_fd_mgr_util_put_frame_req( &hw_mgr->frame_processing_list, &frame_req); @@ -1504,6 +1505,137 @@ static int cam_fd_mgr_hw_flush(void *hw_mgr_priv, return rc; } +static int cam_fd_mgr_hw_dump( + void *hw_mgr_priv, + void *hw_dump_args) +{ + int rc; + uint8_t *dst; + ktime_t cur_time; + size_t remain_len; + uint32_t min_len; + uint64_t diff; + uint64_t *addr, *start; + struct timespec64 cur_ts; + struct timespec64 req_ts; + struct cam_fd_hw_mgr *hw_mgr; + struct cam_hw_dump_args *dump_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_device *hw_device; + struct cam_fd_hw_dump_args fd_dump_args; + struct cam_fd_hw_dump_header *hdr; + struct cam_fd_mgr_frame_request *frame_req, *req_temp; + + hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + dump_args = (struct cam_hw_dump_args *)hw_dump_args; + if (!hw_mgr || !dump_args) { + CAM_ERR(CAM_FD, "Invalid args %pK %pK", + hw_mgr, dump_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)dump_args->ctxt_to_hw_map; + + if (!hw_ctx) { + CAM_ERR(CAM_FD, "Invalid ctx"); + return -EINVAL; + } + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_processing_list, list) { + if (frame_req->request_id == dump_args->request_id) + goto hw_dump; + } + + CAM_DBG(CAM_FD, "fd dump cannot find req %llu", + dump_args->request_id); + return rc; +hw_dump: + cur_time = ktime_get(); + diff = ktime_us_delta(frame_req->submit_timestamp, cur_time); + cur_ts = ktime_to_timespec64(cur_time); + req_ts = ktime_to_timespec64(frame_req->submit_timestamp); + if (diff < CAM_FD_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_FD, "No Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + return 0; + } + CAM_INFO(CAM_FD, "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &fd_dump_args.cpu_addr, &fd_dump_args.buf_len); + if (rc) { + CAM_ERR(CAM_FD, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + if (fd_dump_args.buf_len <= dump_args->offset) { + CAM_WARN(CAM_FD, "dump offset overshoot len %zu offset %zu", + fd_dump_args.buf_len, dump_args->offset); + return -ENOSPC; + } + remain_len = fd_dump_args.buf_len - dump_args->offset; + min_len = sizeof(struct cam_fd_hw_dump_header) + + (CAM_FD_HW_DUMP_NUM_WORDS * sizeof(uint64_t)); + + if (remain_len < min_len) { + CAM_WARN(CAM_FD, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + + dst = (uint8_t *)fd_dump_args.cpu_addr + dump_args->offset; + hdr = (struct cam_fd_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_FD_HW_DUMP_TAG_MAX_LEN, + "FD_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_fd_hw_dump_header)); + start = addr; + *addr++ = frame_req->request_id; + *addr++ = req_ts.tv_sec; + *addr++ = req_ts.tv_nsec/NSEC_PER_USEC; + *addr++ = cur_ts.tv_sec; + *addr++ = cur_ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_fd_hw_dump_header); + + fd_dump_args.request_id = dump_args->request_id; + fd_dump_args.offset = dump_args->offset; + if (hw_device->hw_intf->hw_ops.process_cmd) { + rc = hw_device->hw_intf->hw_ops.process_cmd( + hw_device->hw_intf->hw_priv, + CAM_FD_HW_CMD_HW_DUMP, + &fd_dump_args, + sizeof(struct + cam_fd_hw_dump_args)); + if (rc) { + CAM_ERR(CAM_FD, "Hw Dump cmd fails req %lld rc %d", + frame_req->request_id, rc); + return rc; + } + } + CAM_DBG(CAM_FD, "Offset before %zu after %zu", + dump_args->offset, fd_dump_args.offset); + dump_args->offset = fd_dump_args.offset; + return rc; +} + static int cam_fd_mgr_hw_stop(void *hw_mgr_priv, void *mgr_stop_args) { struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; @@ -1944,6 +2076,7 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, hw_mgr_intf->hw_write = NULL; hw_mgr_intf->hw_close = NULL; hw_mgr_intf->hw_flush = cam_fd_mgr_hw_flush; + hw_mgr_intf->hw_dump = cam_fd_mgr_hw_dump; return rc; diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h index 49bc5bbc1b07..bbbc77bef6a3 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FD_HW_MGR_H_ @@ -21,6 +21,12 @@ #define CAM_FD_HW_MAX 1 #define CAM_FD_WORKQ_NUM_TASK 10 +/* + * Response time threshold in ms beyond which a request is not expected to be + * with FD hw + */ +#define CAM_FD_RESPONSE_TIME_THRESHOLD 100000 + struct cam_fd_hw_mgr; /** @@ -100,6 +106,7 @@ struct cam_fd_device { * @hw_update_entries : HW update entries corresponding to this request * which needs to be submitted to HW through CDM * @num_hw_update_entries : Number of HW update entries + * @submit_timestamp : Time stamp for submit req with hw */ struct cam_fd_mgr_frame_request { struct list_head list; @@ -108,6 +115,7 @@ struct cam_fd_mgr_frame_request { struct cam_fd_hw_req_private hw_req_private; struct cam_hw_update_entry hw_update_entries[CAM_FD_MAX_HW_ENTRIES]; uint32_t num_hw_update_entries; + ktime_t submit_timestamp; }; /** diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index 93a7976bfebe..16a66c2a41ce 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.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 "cam_fd_hw_core.h" @@ -516,6 +516,80 @@ static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, return 0; } +static int cam_fd_hw_util_processcmd_hw_dump( + struct cam_hw_info *fd_hw, + void *args) +{ + int i, j; + uint8_t *dst; + uint32_t *addr, *start; + uint32_t num_reg, min_len; + uint64_t remain_len; + struct cam_hw_soc_info *soc_info; + struct cam_fd_hw_dump_header *hdr; + struct cam_fd_hw_dump_args *dump_args; + + if (!fd_hw || !args) { + CAM_ERR(CAM_FD, "Invalid args %pK %pK", + fd_hw, args); + return -EINVAL; + } + + mutex_lock(&fd_hw->hw_mutex); + + if (fd_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_INFO(CAM_FD, "power off state"); + mutex_unlock(&fd_hw->hw_mutex); + return 0; + } + + dump_args = (struct cam_fd_hw_dump_args *)args; + soc_info = &fd_hw->soc_info; + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_FD, "dump offset overshoot len %zu offset %zu", + dump_args->buf_len, dump_args->offset); + mutex_unlock(&fd_hw->hw_mutex); + return -ENOSPC; + } + + remain_len = dump_args->buf_len - dump_args->offset; + min_len = sizeof(struct cam_fd_hw_dump_header) + + soc_info->reg_map[0].size + sizeof(uint32_t); + + if (remain_len < min_len) { + CAM_WARN(CAM_FD, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + mutex_unlock(&fd_hw->hw_mutex); + return -ENOSPC; + } + + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_fd_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_FD_HW_DUMP_TAG_MAX_LEN, + "FD_REG:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_fd_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + + for (j = 0; j < soc_info->num_reg_map; j++) { + num_reg = soc_info->reg_map[j].size/4; + for (i = 0; i < num_reg; i++) { + *addr++ = soc_info->mem_block[j]->start + i*4; + *addr++ = cam_io_r(soc_info->reg_map[j].mem_base + + (i*4)); + } + } + + mutex_unlock(&fd_hw->hw_mutex); + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_fd_hw_dump_header); + CAM_DBG(CAM_FD, "%zu", dump_args->offset); + return 0; +} + irqreturn_t cam_fd_hw_irq(int irq_num, void *data) { struct cam_hw_info *fd_hw = (struct cam_hw_info *)data; @@ -1159,6 +1233,11 @@ int cam_fd_hw_process_cmd(void *hw_priv, uint32_t cmd_type, cmd_frame_results); break; } + case CAM_FD_HW_CMD_HW_DUMP: { + rc = cam_fd_hw_util_processcmd_hw_dump(fd_hw, + cmd_args); + break; + } default: break; } diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h index e35e5e520b7b..11ef1b913f91 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FD_HW_INTF_H_ @@ -24,6 +24,8 @@ #define CAM_FD_MAX_IO_BUFFERS 5 #define CAM_FD_MAX_HW_ENTRIES 5 +#define CAM_FD_HW_DUMP_TAG_MAX_LEN 32 +#define CAM_FD_HW_DUMP_NUM_WORDS 5 /** * enum cam_fd_hw_type - Enum for FD HW type @@ -81,12 +83,14 @@ enum cam_fd_hw_irq_type { * @CAM_FD_HW_CMD_UPDATE_SOC : Command to process soc update * @CAM_FD_HW_CMD_REGISTER_CALLBACK : Command to set hw mgr callback * @CAM_FD_HW_CMD_MAX : Indicates max cmd + * @CAM_FD_HW_CMD_HW_DUMP : Command to dump fd hw information */ enum cam_fd_hw_cmd_type { CAM_FD_HW_CMD_PRESTART, CAM_FD_HW_CMD_FRAME_DONE, CAM_FD_HW_CMD_UPDATE_SOC, CAM_FD_HW_CMD_REGISTER_CALLBACK, + CAM_FD_HW_CMD_HW_DUMP, CAM_FD_HW_CMD_MAX, }; @@ -279,4 +283,32 @@ struct cam_fd_hw_cmd_set_irq_cb { void *data; }; +/** + * struct cam_fd_hw_dump_args : Args for dump request + * + * @request_id : Issue request id + * @offset : offset of the buffer + * @buf_len : Length of target buffer + * @cpu_addr : start address of the target buffer + */ +struct cam_fd_hw_dump_args { + uint64_t request_id; + size_t offset; + size_t buf_len; + uintptr_t cpu_addr; +}; + +/** + * struct cam_fd_hw_dump_header : fd hw dump header + * + * @tag : fd hw dump header tag + * @size : Size of data + * @word_size : size of each word + */ +struct cam_fd_hw_dump_header { + uint8_t tag[CAM_FD_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + #endif /* _CAM_FD_HW_INTF_H_ */ diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 180ea7152a76..6a9f57b65f68 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.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 @@ -107,6 +107,19 @@ static int __cam_icp_start_dev_in_acquired(struct cam_context *ctx, return rc; } +static int __cam_icp_dump_dev_in_ready( + struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to dump device"); + + return rc; +} + static int __cam_icp_flush_dev_in_ready(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -230,6 +243,7 @@ static struct cam_ctx_ops .start_dev = __cam_icp_start_dev_in_acquired, .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, + .dump_dev = __cam_icp_dump_dev_in_ready, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, @@ -242,6 +256,7 @@ static struct cam_ctx_ops .release_dev = __cam_icp_release_dev_in_ready, .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, + .dump_dev = __cam_icp_dump_dev_in_ready, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c index e4cb645b7af0..1ac27511f7ac 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.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 @@ -235,6 +235,53 @@ static int32_t cam_a5_download_fw(void *device_priv) return rc; } +static int cam_a5_fw_dump( + struct cam_icp_hw_dump_args *dump_args, + struct cam_a5_device_core_info *core_info) +{ + u8 *dest; + u8 *src; + uint64_t size_required; + struct cam_icp_dump_header *hdr; + + if (!core_info || !dump_args) { + CAM_ERR(CAM_ICP, "invalid params %pK %pK", + core_info, dump_args); + return -EINVAL; + } + if (!core_info->fw_kva_addr || !dump_args->cpu_addr) { + CAM_ERR(CAM_ICP, "invalid params %pK, 0x%zx", + core_info->fw_kva_addr, dump_args->cpu_addr); + return -EINVAL; + } + + size_required = core_info->fw_buf_len + + sizeof(struct cam_icp_dump_header); + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_ICP, "Dump offset overshoot len %zu offset %zu", + dump_args->buf_len, dump_args->offset); + return -ENOSPC; + } + + if ((dump_args->buf_len - dump_args->offset) < size_required) { + CAM_WARN(CAM_ICP, "Dump buffer exhaust required %llu len %llu", + size_required, core_info->fw_buf_len); + return -ENOSPC; + } + + dest = (u8 *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_icp_dump_header *)dest; + scnprintf(hdr->tag, CAM_ICP_DUMP_TAG_MAX_LEN, "ICP_FW:"); + hdr->word_size = sizeof(u8); + hdr->size = core_info->fw_buf_len; + src = (u8 *)core_info->fw_kva_addr; + dest = (u8 *)dest + sizeof(struct cam_icp_dump_header); + memcpy_fromio(dest, src, core_info->fw_buf_len); + dump_args->offset += hdr->size + sizeof(struct cam_icp_dump_header); + return 0; +} + int cam_a5_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size) { @@ -543,6 +590,12 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, core_info->cpas_handle, &ahb_vote); break; } + case CAM_ICP_A5_CMD_HW_DUMP: { + struct cam_icp_hw_dump_args *dump_args = cmd_args; + + rc = cam_a5_fw_dump(dump_args, core_info); + break; + } default: break; } diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index f32a95e05d66..18bcdd8ac6e2 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -3980,6 +3980,7 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx); ctx_data->hfi_frame_process.fw_process_flag[idx] = true; + ctx_data->hfi_frame_process.submit_timestamp[idx] = ktime_get(); CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id, frame_info->io_config); @@ -5086,6 +5087,115 @@ static int cam_icp_mgr_enqueue_abort( return 0; } +static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args) +{ + int rc; + int i; + size_t remain_len; + uint8_t *dst; + uint32_t min_len; + uint64_t diff; + uint64_t *addr, *start; + struct timespec64 cur_ts; + struct timespec64 req_ts; + ktime_t cur_time; + struct cam_hw_intf *a5_dev_intf; + struct cam_icp_hw_mgr *hw_mgr; + struct cam_hw_dump_args *dump_args; + struct cam_icp_hw_ctx_data *ctx_data; + struct cam_icp_dump_header *hdr; + struct cam_icp_hw_dump_args icp_dump_args; + struct hfi_frame_process_info *frm_process; + + if ((!hw_priv) || (!hw_dump_args)) { + CAM_ERR(CAM_ICP, "Invalid params %pK %pK", + hw_priv, hw_dump_args); + return -EINVAL; + } + + dump_args = (struct cam_hw_dump_args *)hw_dump_args; + hw_mgr = hw_priv; + ctx_data = dump_args->ctxt_to_hw_map; + CAM_DBG(CAM_ICP, "Req %lld", dump_args->request_id); + frm_process = &ctx_data->hfi_frame_process; + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) { + if ((frm_process->request_id[i] == + dump_args->request_id) && + frm_process->fw_process_flag[i]) + goto hw_dump; + } + return 0; +hw_dump: + cur_time = ktime_get(); + diff = ktime_us_delta(frm_process->submit_timestamp[i], cur_time); + cur_ts = ktime_to_timespec64(cur_time); + req_ts = ktime_to_timespec64(frm_process->submit_timestamp[i]); + + if (diff < CAM_ICP_CTX_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_ICP, "No Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + return 0; + } + + CAM_INFO(CAM_ICP, "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &icp_dump_args.cpu_addr, &icp_dump_args.buf_len); + if (rc) { + CAM_ERR(CAM_ICP, "Invalid addr %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + if (icp_dump_args.buf_len <= dump_args->offset) { + CAM_WARN(CAM_ICP, "dump buffer overshoot len %zu offset %zu", + icp_dump_args.buf_len, dump_args->offset); + return -ENOSPC; + } + + remain_len = icp_dump_args.buf_len - dump_args->offset; + min_len = sizeof(struct cam_icp_dump_header) + + (CAM_ICP_DUMP_NUM_WORDS * sizeof(uint64_t)); + + if (remain_len < min_len) { + CAM_WARN(CAM_ICP, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + + dst = (uint8_t *)icp_dump_args.cpu_addr + dump_args->offset; + hdr = (struct cam_icp_dump_header *)dst; + scnprintf(hdr->tag, CAM_ICP_DUMP_TAG_MAX_LEN, "ICP_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_icp_dump_header)); + start = addr; + *addr++ = frm_process->request_id[i]; + *addr++ = req_ts.tv_sec; + *addr++ = req_ts.tv_nsec/NSEC_PER_USEC; + *addr++ = cur_ts.tv_sec; + *addr++ = cur_ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += (hdr->size + sizeof(struct cam_icp_dump_header)); + /* Dumping the fw image*/ + icp_dump_args.offset = dump_args->offset; + a5_dev_intf = hw_mgr->a5_dev_intf; + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_HW_DUMP, &icp_dump_args, + sizeof(struct cam_icp_hw_dump_args)); + CAM_DBG(CAM_ICP, "Offset before %zu after %zu", + dump_args->offset, icp_dump_args.offset); + dump_args->offset = icp_dump_args.offset; + return rc; +} + static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; @@ -5898,6 +6008,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, hw_mgr_intf->hw_close = cam_icp_mgr_hw_close_u; hw_mgr_intf->hw_flush = cam_icp_mgr_hw_flush; hw_mgr_intf->hw_cmd = cam_icp_mgr_cmd; + hw_mgr_intf->hw_dump = cam_icp_mgr_hw_dump; icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE; mutex_init(&icp_hw_mgr.hw_mgr_mutex); diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 8cab9a80cd30..c438d438e892 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.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 CAM_ICP_HW_MGR_H @@ -67,6 +67,12 @@ /* Current appliacble vote paths, based on number of UAPI definitions */ #define CAM_ICP_MAX_PER_PATH_VOTES 6 +/* + * Response time threshold in ms beyond which a request is not expected + * to be with ICP hw + */ +#define CAM_ICP_CTX_RESPONSE_TIME_THRESHOLD 300000 + /** * struct icp_hfi_mem_info * @qtbl: Memory info of queue table @@ -171,6 +177,7 @@ struct cam_icp_clk_bw_req_internal_v2 { * @clk_info: Clock information for a request * @clk_info_v2: Clock info for AXI bw voting v2 * @frame_info: information needed to process request + * @submit_timestamp: Submit timestamp to hw */ struct hfi_frame_process_info { struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX]; @@ -186,6 +193,7 @@ struct hfi_frame_process_info { struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX]; struct cam_icp_clk_bw_req_internal_v2 clk_info_v2[CAM_FRAME_CMD_MAX]; struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX]; + ktime_t submit_timestamp[CAM_FRAME_CMD_MAX]; }; /** diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h index af80a2eac15d..c3fefdc09ba9 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_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 CAM_A5_HW_INTF_H @@ -27,6 +27,7 @@ enum cam_icp_a5_cmd_type { CAM_ICP_A5_CMD_UBWC_CFG, CAM_ICP_A5_CMD_PC_PREP, CAM_ICP_A5_CMD_CLK_UPDATE, + CAM_ICP_A5_CMD_HW_DUMP, CAM_ICP_A5_CMD_MAX, }; diff --git a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index d87c7ef238df..84129cba7e19 100644 --- a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_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 CAM_ICP_HW_MGR_INTF_H @@ -27,6 +27,9 @@ #define CAM_ICP_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_ALL #define CAM_ICP_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_READ +#define CAM_ICP_DUMP_TAG_MAX_LEN 32 +#define CAM_ICP_DUMP_NUM_WORDS 5 + int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, int *iommu_hdl); @@ -44,4 +47,28 @@ struct cam_icp_cpas_vote { uint32_t axi_vote_valid; }; +/** + * struct cam_icp_hw_dump_args + * @cpu_addr: kernel vaddr + * @buf_len: buffer length + * @offset: offset + */ +struct cam_icp_hw_dump_args { + uintptr_t cpu_addr; + size_t buf_len; + size_t offset; +}; + +/** + * struct cam_icp_dump_header + * @tag: tag of the packet + * @size: size of data in packet + * @word_size: size of each word in packet + */ +struct cam_icp_dump_header { + uint8_t tag[CAM_ICP_DUMP_TAG_MAX_LEN]; + uint64_t size; + int32_t word_size; +}; + #endif /* CAM_ICP_HW_MGR_INTF_H */ diff --git a/drivers/cam_jpeg/cam_jpeg_context.c b/drivers/cam_jpeg/cam_jpeg_context.c index b16a9dfed011..b28f8b667239 100644 --- a/drivers/cam_jpeg/cam_jpeg_context.c +++ b/drivers/cam_jpeg/cam_jpeg_context.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 @@ -83,6 +83,19 @@ static int __cam_jpeg_ctx_release_dev_in_acquired(struct cam_context *ctx, return rc; } +static int __cam_jpeg_ctx_dump_dev_in_acquired( + struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to dump device, rc=%d", rc); + + return rc; +} + static int __cam_jpeg_ctx_flush_dev_in_acquired(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -145,6 +158,7 @@ static struct cam_ctx_ops .config_dev = __cam_jpeg_ctx_config_dev_in_acquired, .stop_dev = __cam_jpeg_ctx_stop_dev_in_acquired, .flush_dev = __cam_jpeg_ctx_flush_dev_in_acquired, + .dump_dev = __cam_jpeg_ctx_dump_dev_in_acquired, }, .crm_ops = { }, .irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired, diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index b2b1a47ea31d..24511b904da0 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.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 @@ -488,6 +488,7 @@ static int cam_jpeg_mgr_process_cmd(void *priv, void *data) rc); goto end_callcb; } + p_cfg_req->submit_timestamp = ktime_get(); mutex_unlock(&hw_mgr->hw_mgr_mutex); return rc; @@ -1491,6 +1492,143 @@ static int cam_jpeg_init_devices(struct device_node *of_node, return rc; } +static int cam_jpeg_mgr_hw_dump(void *hw_mgr_priv, void *dump_hw_args) +{ + int rc; + uint8_t *dst; + ktime_t cur_time; + size_t remain_len; + uint32_t min_len; + uint32_t dev_type; + uint64_t diff; + uint64_t *addr, *start; + struct timespec64 cur_ts; + struct timespec64 req_ts; + struct cam_jpeg_hw_mgr *hw_mgr; + struct cam_hw_dump_args *dump_args; + struct cam_jpeg_hw_cfg_req *p_cfg_req; + struct cam_jpeg_hw_ctx_data *ctx_data; + struct cam_jpeg_hw_dump_args jpeg_dump_args; + struct cam_jpeg_hw_dump_header *hdr; + + if (!hw_mgr_priv || !dump_hw_args) { + CAM_ERR(CAM_JPEG, "Invalid args %pK %pK", + hw_mgr_priv, dump_hw_args); + return -EINVAL; + } + + hw_mgr = hw_mgr_priv; + dump_args = (struct cam_hw_dump_args *)dump_hw_args; + ctx_data = (struct cam_jpeg_hw_ctx_data *)dump_args->ctxt_to_hw_map; + + if (!ctx_data) { + CAM_ERR(CAM_JPEG, "Invalid context"); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + if (true == hw_mgr->device_in_use[dev_type][0]) { + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (p_cfg_req && p_cfg_req->req_id == + (uintptr_t)dump_args->request_id) + goto hw_dump; + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return 0; + +hw_dump: + cur_time = ktime_get(); + diff = ktime_us_delta(p_cfg_req->submit_timestamp, cur_time); + cur_ts = ktime_to_timespec64(cur_time); + req_ts = ktime_to_timespec64(p_cfg_req->submit_timestamp); + + if (diff < CAM_JPEG_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_JPEG, + "No error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return 0; + } + + CAM_INFO(CAM_JPEG, + "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &jpeg_dump_args.cpu_addr, &jpeg_dump_args.buf_len); + if (rc) { + CAM_ERR(CAM_JPEG, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -rc; + } + + if (jpeg_dump_args.buf_len <= dump_args->offset) { + CAM_WARN(CAM_JPEG, "dump offset overshoot len %zu offset %zu", + jpeg_dump_args.buf_len, dump_args->offset); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -ENOSPC; + } + + remain_len = jpeg_dump_args.buf_len - dump_args->offset; + min_len = sizeof(struct cam_jpeg_hw_dump_header) + + (CAM_JPEG_HW_DUMP_NUM_WORDS * sizeof(uint64_t)); + if (remain_len < min_len) { + CAM_WARN(CAM_JPEG, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -ENOSPC; + } + + dst = (uint8_t *)jpeg_dump_args.cpu_addr + dump_args->offset; + hdr = (struct cam_jpeg_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_JPEG_HW_DUMP_TAG_MAX_LEN, + "JPEG_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_jpeg_hw_dump_header)); + start = addr; + *addr++ = dump_args->request_id; + *addr++ = req_ts.tv_sec; + *addr++ = req_ts.tv_nsec/NSEC_PER_USEC; + *addr++ = cur_ts.tv_sec; + *addr++ = cur_ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_jpeg_hw_dump_header); + jpeg_dump_args.request_id = dump_args->request_id; + jpeg_dump_args.offset = dump_args->offset; + + if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_HW_DUMP, + &jpeg_dump_args, sizeof(jpeg_dump_args)); + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_DBG(CAM_JPEG, "Offset before %u after %u", + dump_args->offset, jpeg_dump_args.offset); + dump_args->offset = jpeg_dump_args.offset; + return rc; +} + static int cam_jpeg_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -1544,6 +1682,7 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, hw_mgr_intf->hw_flush = cam_jpeg_mgr_hw_flush; hw_mgr_intf->hw_stop = cam_jpeg_mgr_hw_stop; hw_mgr_intf->hw_cmd = cam_jpeg_mgr_cmd; + hw_mgr_intf->hw_dump = cam_jpeg_mgr_hw_dump; mutex_init(&g_jpeg_hw_mgr.hw_mgr_mutex); spin_lock_init(&g_jpeg_hw_mgr.hw_mgr_lock); diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h index e482c11a82bd..3a00e424ebc9 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_HW_MGR_H @@ -21,6 +21,12 @@ #define CAM_JPEG_WORKQ_TASK_MSG_TYPE 2 #define CAM_JPEG_HW_CFG_Q_MAX 50 +/* + * Response time threshold in ms beyond which a request is not expected + * to be with JPEG hw + */ +#define CAM_JPEG_RESPONSE_TIME_THRESHOLD 100000 + /** * struct cam_jpeg_process_frame_work_data_t * @@ -69,12 +75,14 @@ struct cam_jpeg_hw_cdm_info_t { * @hw_cfg_args: Hw config args * @dev_type: Dev type for cfg request * @req_id: Request Id + * @submit_timestamp: Timestamp of submitting request */ struct cam_jpeg_hw_cfg_req { struct list_head list; struct cam_hw_config_args hw_cfg_args; uint32_t dev_type; uintptr_t req_id; + ktime_t submit_timestamp; }; /** diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h index 3deb9dd73b32..df552c4d04cf 100644 --- a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h +++ b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_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 CAM_JPEG_HW_INTF_H @@ -15,6 +15,9 @@ #define JPEG_VOTE 640000000 +#define CAM_JPEG_HW_DUMP_TAG_MAX_LEN 32 +#define CAM_JPEG_HW_DUMP_NUM_WORDS 5 + enum cam_jpeg_hw_type { CAM_JPEG_DEV_ENC, CAM_JPEG_DEV_DMA, @@ -27,9 +30,23 @@ struct cam_jpeg_set_irq_cb { uint32_t b_set_cb; }; +struct cam_jpeg_hw_dump_args { + uint64_t request_id; + uintptr_t cpu_addr; + size_t offset; + size_t buf_len; +}; + +struct cam_jpeg_hw_dump_header { + uint8_t tag[CAM_JPEG_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + enum cam_jpeg_cmd_type { CAM_JPEG_CMD_CDM_CFG, CAM_JPEG_CMD_SET_IRQ_CB, + CAM_JPEG_CMD_HW_DUMP, CAM_JPEG_CMD_MAX, }; diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h index e610a9e7ee03..b75998bc586c 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.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 CAM_JPEG_ENC_HW_INFO_TITAN170_H @@ -66,6 +66,10 @@ static struct cam_jpeg_enc_device_hw_info cam_jpeg_enc_hw_info = { .resetdone = CAM_JPEG_HW_MASK_COMP_RESET_ACK, .iserror = CAM_JPEG_HW_MASK_COMP_ERR, .stopdone = CAM_JPEG_HW_IRQ_STATUS_STOP_DONE_MASK, + }, + .reg_dump = { + .start_offset = 0x0, + .end_offset = 0x33C, } }; 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 4830bf58e89e..b9329a8173e5 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 @@ -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 @@ -378,6 +378,81 @@ int cam_jpeg_enc_stop_hw(void *data, return 0; } +int cam_jpeg_enc_hw_dump( + struct cam_hw_info *jpeg_enc_dev, + struct cam_jpeg_hw_dump_args *dump_args) +{ + + int i; + uint8_t *dst; + uint32_t *addr, *start; + uint32_t num_reg, min_len; + uint32_t reg_start_offset; + size_t remain_len; + struct cam_hw_soc_info *soc_info; + struct cam_jpeg_hw_dump_header *hdr; + struct cam_jpeg_enc_device_hw_info *hw_info; + struct cam_jpeg_enc_device_core_info *core_info; + + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mutex_lock(&core_info->core_mutex); + 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); + mutex_unlock(&core_info->core_mutex); + return -EINVAL; + } + + spin_unlock(&jpeg_enc_dev->hw_lock); + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_JPEG, "dump buffer overshoot %zu %zu", + dump_args->buf_len, dump_args->offset); + mutex_unlock(&core_info->core_mutex); + return -ENOSPC; + } + + remain_len = dump_args->buf_len - dump_args->offset; + min_len = sizeof(struct cam_jpeg_hw_dump_header) + + soc_info->reg_map[0].size + sizeof(uint32_t); + if (remain_len < min_len) { + CAM_WARN(CAM_JPEG, "dump buffer exhaust %zu %u", + remain_len, min_len); + mutex_unlock(&core_info->core_mutex); + return -ENOSPC; + } + + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_jpeg_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_JPEG_HW_DUMP_TAG_MAX_LEN, + "JPEG_REG:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_jpeg_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + num_reg = (hw_info->reg_dump.end_offset - + hw_info->reg_dump.start_offset)/4; + reg_start_offset = hw_info->reg_dump.start_offset; + for (i = 0; i < num_reg; i++) { + *addr++ = soc_info->mem_block[0]->start + + reg_start_offset + i*4; + *addr++ = cam_io_r(soc_info->reg_map[0].mem_base + (i*4)); + } + + mutex_unlock(&core_info->core_mutex); + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_jpeg_hw_dump_header); + CAM_DBG(CAM_JPEG, "offset %zu", dump_args->offset); + + return 0; +} + int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -418,6 +493,12 @@ int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, rc = 0; break; } + case CAM_JPEG_CMD_HW_DUMP: + { + rc = cam_jpeg_enc_hw_dump(jpeg_enc_dev, + cmd_args); + break; + } default: rc = -EINVAL; break; diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h index df9341c90c77..ca83dccb193f 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.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 CAM_JPEG_ENC_CORE_H @@ -39,10 +39,16 @@ struct cam_jpeg_enc_int_status { uint32_t stopdone; }; +struct cam_jpeg_enc_reg_dump { + uint32_t start_offset; + uint32_t end_offset; +}; + struct cam_jpeg_enc_device_hw_info { struct cam_jpeg_enc_reg_offsets reg_offset; struct cam_jpeg_enc_regval reg_val; struct cam_jpeg_enc_int_status int_status; + struct cam_jpeg_enc_reg_dump reg_dump; }; enum cam_jpeg_enc_core_state { diff --git a/drivers/cam_lrme/cam_lrme_context.c b/drivers/cam_lrme/cam_lrme_context.c index fa544c7a089e..857aab9dd476 100644 --- a/drivers/cam_lrme/cam_lrme_context.c +++ b/drivers/cam_lrme/cam_lrme_context.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 @@ -86,6 +86,21 @@ static int __cam_lrme_ctx_config_dev_in_activated(struct cam_context *ctx, return rc; } +static int __cam_lrme_ctx_dump_dev_in_activated( + struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_LRME, "Failed to dump device"); + + return rc; +} + static int __cam_lrme_ctx_flush_dev_in_activated(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -199,6 +214,7 @@ static struct cam_ctx_ops .release_dev = __cam_lrme_ctx_release_dev_in_activated, .stop_dev = __cam_lrme_ctx_stop_dev_in_activated, .flush_dev = __cam_lrme_ctx_flush_dev_in_activated, + .dump_dev = __cam_lrme_ctx_dump_dev_in_activated, }, .crm_ops = {}, .irq_ops = __cam_lrme_ctx_handle_irq_in_activated, diff --git a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 40700bbce9e0..537fc48a619e 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.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 @@ -649,6 +649,50 @@ static int cam_lrme_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args) return rc; } +static int cam_lrme_mgr_hw_dump(void *hw_mgr_priv, void *hw_dump_args) +{ + struct cam_hw_dump_args *dump_args = hw_dump_args; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_lrme_device *hw_device; + int rc = 0; + uint32_t device_index; + struct cam_lrme_hw_dump_args lrme_dump_args; + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(dump_args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + CAM_DBG(CAM_LRME, "Start device index %d", device_index); + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to get hw device"); + return rc; + } + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &lrme_dump_args.cpu_addr, + &lrme_dump_args.buf_len); + if (rc) { + CAM_ERR(CAM_LRME, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + lrme_dump_args.offset = dump_args->offset; + lrme_dump_args.request_id = dump_args->request_id; + + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_DUMP, + &lrme_dump_args, + sizeof(struct cam_lrme_hw_dump_args)); + CAM_DBG(CAM_LRME, "Offset before %zu after %zu", + dump_args->offset, lrme_dump_args.offset); + dump_args->offset = lrme_dump_args.offset; + return rc; +} + static int cam_lrme_mgr_hw_flush(void *hw_mgr_priv, void *hw_flush_args) { int rc = 0, i; struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; @@ -1147,6 +1191,7 @@ int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, hw_mgr_intf->hw_flush = cam_lrme_mgr_hw_flush; g_lrme_hw_mgr.event_cb = cam_lrme_dev_buf_done_cb; + hw_mgr_intf->hw_dump = cam_lrme_mgr_hw_dump; cam_lrme_mgr_create_debugfs_entry(); diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c index 1d92554c76ea..dc4df1c57931 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -1,8 +1,9 @@ // 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 #include "cam_lrme_hw_core.h" #include "cam_lrme_hw_soc.h" #include "cam_smmu_api.h" @@ -21,6 +22,159 @@ static void cam_lrme_dump_registers(void __iomem *base) cam_io_dump(base, 0x900, (0x928 - 0x900) / 0x4); } +static int cam_lrme_dump_regs_to_buf( + struct cam_lrme_frame_request *req, + struct cam_hw_info *lrme_hw, + struct cam_lrme_hw_dump_args *dump_args) +{ + int i; + uint8_t *dst; + uint32_t *addr, *start; + uint32_t num_reg, min_len; + size_t remain_len; + struct cam_hw_soc_info *soc_info; + struct cam_lrme_hw_dump_header *hdr; + + if (!lrme_hw || !req || !dump_args) { + CAM_ERR(CAM_LRME, "Invalid params %pK, %pK, %pK", + lrme_hw, req, dump_args); + return -EINVAL; + } + soc_info = &lrme_hw->soc_info; + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_LRME, "dump buffer overshoot len %zu offset %zu", + dump_args->buf_len, dump_args->offset); + return -ENOSPC; + } + remain_len = dump_args->buf_len - dump_args->offset; + min_len = sizeof(struct cam_lrme_hw_dump_header) + + soc_info->reg_map[0].size + sizeof(uint32_t); + + if (remain_len < min_len) { + CAM_WARN(CAM_LRME, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_lrme_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_LRME_HW_DUMP_TAG_MAX_LEN, + "LRME_REG:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_lrme_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + num_reg = soc_info->reg_map[0].size/4; + for (i = 0; i < num_reg; i++) { + *addr++ = soc_info->mem_block[0]->start + (i*4); + *addr++ = cam_io_r(soc_info->reg_map[0].mem_base + (i*4)); + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_lrme_hw_dump_header); + CAM_DBG(CAM_LRME, "offset %zu", dump_args->offset); + return 0; +} + +static int cam_lrme_hw_dump( + struct cam_hw_info *lrme_hw, + struct cam_lrme_hw_dump_args *dump_args) +{ + uint8_t *dst; + ktime_t cur_time; + size_t remain_len; + uint32_t min_len; + uint64_t diff; + uint64_t *addr, *start; + struct timespec64 cur_ts; + struct timespec64 req_ts; + struct cam_lrme_core *lrme_core; + struct cam_lrme_frame_request *req = NULL; + struct cam_lrme_hw_dump_header *hdr; + + 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"); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + + if (lrme_core->req_submit && + lrme_core->req_submit->req_id == dump_args->request_id) + req = lrme_core->req_submit; + else if (lrme_core->req_proc && + lrme_core->req_proc->req_id == dump_args->request_id) + req = lrme_core->req_proc; + + if (!req) { + CAM_DBG(CAM_LRME, "LRME req %lld not with hw", + dump_args->request_id); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + cur_time = ktime_get(); + diff = ktime_us_delta(req->submit_timestamp, cur_time); + cur_ts = ktime_to_timespec64(cur_time); + req_ts = ktime_to_timespec64(req->submit_timestamp); + + if (diff < CAM_LRME_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_LRME, "No error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + CAM_INFO(CAM_LRME, "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_LRME, "dump buffer overshoot len %zu offset %zu", + dump_args->buf_len, dump_args->offset); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + remain_len = dump_args->buf_len - dump_args->offset; + min_len = sizeof(struct cam_lrme_hw_dump_header) + + (CAM_LRME_HW_DUMP_NUM_WORDS * sizeof(uint64_t)); + + if (remain_len < min_len) { + CAM_WARN(CAM_LRME, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_lrme_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_LRME_HW_DUMP_TAG_MAX_LEN, + "LRME_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_lrme_hw_dump_header)); + start = addr; + *addr++ = req->req_id; + *addr++ = req_ts.tv_sec; + *addr++ = req_ts.tv_nsec/NSEC_PER_USEC; + *addr++ = cur_ts.tv_sec; + *addr++ = cur_ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_lrme_hw_dump_header); + cam_lrme_dump_regs_to_buf(req, lrme_hw, dump_args); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; +} + static void cam_lrme_cdm_write_reg_val_pair(uint32_t *buffer, uint32_t *index, uint32_t reg_offset, uint32_t reg_value) { @@ -959,6 +1113,8 @@ int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, goto error; } + frame_req->submit_timestamp = ktime_get(); + switch (lrme_core->state) { case CAM_LRME_CORE_STATE_PROCESSING: lrme_core->state = CAM_LRME_CORE_STATE_REQ_PROC_PEND; @@ -1268,6 +1424,12 @@ int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type, break; } + case CAM_LRME_HW_CMD_DUMP: { + struct cam_lrme_hw_dump_args *dump_args = + (struct cam_lrme_hw_dump_args *)cmd_args; + rc = cam_lrme_hw_dump(lrme_hw, dump_args); + break; + } default: break; } diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h index accb5a8b5827..4c9386c9f046 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_LRME_HW_CORE_H_ @@ -35,6 +35,10 @@ #define CAM_LRME_MAX_REG_PAIR_NUM 60 +#define CAM_LRME_RESPONSE_TIME_THRESHOLD 100000 +#define CAM_LRME_HW_DUMP_TAG_MAX_LEN 32 +#define CAM_LRME_HW_DUMP_NUM_WORDS 5 + /** * enum cam_lrme_irq_set * @@ -432,6 +436,20 @@ struct cam_lrme_hw_info { struct cam_lrme_titan_reg titan_reg; }; +/** + * struct cam_lrme_hw_dump_header : LRME hw dump header + * + * @tag : LRME hw dump header tag + * @size : Size of data + * @word_size : size of each word + */ + +struct cam_lrme_hw_dump_header { + uint8_t tag[CAM_LRME_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + int cam_lrme_hw_process_irq(void *priv, void *data); int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, uint32_t arg_size); diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h index b74d53700419..cd4d64b18f67 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_LRME_HW_INTF_H_ @@ -59,12 +59,14 @@ enum cam_lrme_cb_type { * @CAM_LRME_HW_CMD_REGISTER_CB : register HW manager callback * @CAM_LRME_HW_CMD_SUBMIT : Submit frame to HW * @CAM_LRME_HW_CMD_DUMP_REGISTER : dump register values + * @CAM_LRME_HW_CMD_DUMP : dump register values to buffer */ enum cam_lrme_hw_cmd_type { CAM_LRME_HW_CMD_PREPARE_HW_UPDATE, CAM_LRME_HW_CMD_REGISTER_CB, CAM_LRME_HW_CMD_SUBMIT, CAM_LRME_HW_CMD_DUMP_REGISTER, + CAM_LRME_HW_CMD_DUMP, }; /** @@ -87,6 +89,7 @@ enum cam_lrme_hw_reset_type { * @hw_device : Pointer to HW device * @hw_update_entries : List of hw_update_entries * @num_hw_update_entries : number of hw_update_entries + * @submit_timestamp : timestamp of submitting request with hw */ struct cam_lrme_frame_request { struct list_head frame_list; @@ -95,6 +98,7 @@ struct cam_lrme_frame_request { struct cam_lrme_device *hw_device; struct cam_hw_update_entry hw_update_entries[CAM_LRME_MAX_HW_ENTRIES]; uint32_t num_hw_update_entries; + ktime_t submit_timestamp; }; /** @@ -192,4 +196,19 @@ struct cam_lrme_hw_submit_args { struct cam_lrme_frame_request *frame_req; }; +/** + * struct cam_lrme_hw_dump_args : Args for dump request + * + * @request_id : Issue request id + * @cpu_addr : start address of the target buffer + * @offset : offset of the buffer + * @buf_len : Length of target buffer + */ +struct cam_lrme_hw_dump_args { + uint64_t request_id; + uintptr_t cpu_addr; + size_t offset; + size_t buf_len; +}; + #endif /* _CAM_LRME_HW_INTF_H_ */ -- GitLab From 3c73bff0b290ffd59cd07f591289b59d4a334212 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 9 Jan 2020 12:01:18 -0800 Subject: [PATCH 110/295] msm: camera: ife: Look into next request if res not found In cases where IRQ delays or overlap happens, the IRQ we get for the resource may belong to the 2nd request in the queue. If the IRQ resource is not found in top request, look into the second request as well. CRs-Fixed: 2600457 Change-Id: Ida2665a00169463e2f146de1cfa6be076d8c7d72 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_isp/cam_isp_context.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index e7236fa2d628..0ada1bdca471 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -576,10 +576,28 @@ static int __cam_isp_ctx_handle_buf_done_for_request( } if (j == req_isp->num_fence_map_out) { - CAM_ERR(CAM_ISP, - "Can not find matching lane handle 0x%x!", - done->resource_handle[i]); - rc = -EINVAL; + if (done_next_req) { + /* + * If not found in current request, it could be + * belonging to next request, This can happen if + * IRQ delay happens. + */ + CAM_WARN(CAM_ISP, + "BUF_DONE for res 0x%x not found in Req %lld ", + __cam_isp_resource_handle_id_to_type( + done->resource_handle[i]), + req->request_id); + + done_next_req->resource_handle + [done_next_req->num_handles++] = + done->resource_handle[i]; + } else { + CAM_ERR(CAM_ISP, + "Can not find matching lane handle 0x%x! in Req %lld", + done->resource_handle[i], + req->request_id); + rc = -EINVAL; + } continue; } -- GitLab From 78ee8f12b3618a34984646bd07405e48960c5f27 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Tue, 10 Dec 2019 14:11:48 -0800 Subject: [PATCH 111/295] msm: camera: cpas: Remove votes on enable_soc failure If enabling soc resources has failed, remove the votes that were voted for this client. CRs-Fixed: 2585080 Change-Id: I05f460e93a1bf7b96a99dd32f3fd03dbde5b094f Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_cpas/cam_cpas_hw.c | 48 +++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 6f6386be82ae..c3a0c27ca88b 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1101,6 +1101,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, struct cam_cpas_hw_cmd_start *cmd_hw_start; struct cam_cpas_client *cpas_client; struct cam_ahb_vote *ahb_vote; + struct cam_ahb_vote remove_ahb; struct cam_axi_vote axi_vote = {0}; enum cam_vote_level applied_level = CAM_SVS_VOTE; int rc, i = 0; @@ -1162,7 +1163,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, CAM_ERR(CAM_CPAS, "client=[%d] is not registered", client_indx); rc = -EPERM; - goto done; + goto error; } if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { @@ -1170,7 +1171,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, client_indx, cpas_client->data.identifier, cpas_client->data.cell_index); rc = -EPERM; - goto done; + goto error; } CAM_DBG(CAM_CPAS, @@ -1181,7 +1182,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, ahb_vote, &applied_level); if (rc) - goto done; + goto error; cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Vote", &axi_vote); @@ -1202,7 +1203,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, if (rc) { CAM_ERR(CAM_CPAS, "Unable to create or translate paths rc: %d", rc); - goto done; + goto remove_ahb_vote; } cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Translated Vote", @@ -1211,7 +1212,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); if (rc) - goto done; + goto remove_ahb_vote; if ((soc_private->cx_ipeak_gpu_limit) && (!cpas_core->streamon_clients)) { @@ -1225,7 +1226,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, kgsl_pwr_limits_del( soc_private->gpu_pwr_limit); soc_private->gpu_pwr_limit = NULL; - goto done; + goto remove_axi_vote; } } } @@ -1233,7 +1234,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, if (cpas_core->streamon_clients == 0) { rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, true); if (rc) - goto done; + goto remove_axi_vote; atomic_set(&cpas_core->irq_count, 1); rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, @@ -1241,7 +1242,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, if (rc) { atomic_set(&cpas_core->irq_count, 0); CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc); - goto done; + goto remove_axi_vote; } if (cpas_core->internal_ops.power_on) { @@ -1253,7 +1254,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, CAM_ERR(CAM_CPAS, "failed in power_on settings rc=%d", rc); - goto done; + goto remove_axi_vote; } } CAM_DBG(CAM_CPAS, "irq_count=%d\n", @@ -1267,7 +1268,34 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, CAM_DBG(CAM_CPAS, "client=[%d][%s][%d] streamon_clients=%d", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, cpas_core->streamon_clients); -done: + + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; + +remove_axi_vote: + memset(&axi_vote, 0x0, sizeof(struct cam_axi_vote)); + rc = cam_cpas_util_create_vote_all_paths(cpas_client, &axi_vote); + if (rc) + CAM_ERR(CAM_CPAS, "Unable to create per path votes rc: %d", rc); + + cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start fail Vote", + &axi_vote); + + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_client, &axi_vote); + if (rc) + CAM_ERR(CAM_CPAS, "Unable remove votes rc: %d", rc); + +remove_ahb_vote: + remove_ahb.type = CAM_VOTE_ABSOLUTE; + remove_ahb.vote.level = CAM_SUSPEND_VOTE; + rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, + &remove_ahb, NULL); + if (rc) + CAM_ERR(CAM_CPAS, "Removing AHB vote failed, rc=%d", rc); + +error: mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return rc; -- GitLab From 1cb60f43efd12dcea8ed8c1bac99fb5fc0204c24 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 29 Aug 2019 12:35:25 -0700 Subject: [PATCH 112/295] msm: camera: isp: Add trace events across ISP Add trace events for IRQ's on IFE top side and IFE BUS side in top half. These traces when enabled will help to gather relative timing information of the IRQ's with systrace. CRs-Fixed: 2538876 Change-Id: I856a9df1978f90e260da7c62cadf02fa2fe53202 Signed-off-by: Vishalsingh Hajeri Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_cdm/cam_cdm_hw_core.c | 7 ++++++ drivers/cam_isp/cam_isp_context.c | 20 ++++++++++++++-- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile | 1 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 24 ++++++++++++++++++- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile | 1 + .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 22 +++++++++++++++++ drivers/cam_utils/cam_trace.h | 23 ++++++++++++++++++ 7 files changed, 95 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index f207e4f998c3..3864749278ee 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -22,6 +22,7 @@ #include "cam_cdm_hw_reg_1_1.h" #include "cam_cdm_hw_reg_1_2.h" #include "cam_cdm_hw_reg_2_0.h" +#include "cam_trace.h" #define CAM_CDM_BL_FIFO_WAIT_TIMEOUT 2000 #define CAM_CDM_DBG_GEN_IRQ_USR_DATA 0xff @@ -691,6 +692,8 @@ int cam_hw_cdm_submit_gen_irq( rc = -EIO; } + trace_cam_log_event("CDM_START", "CDM_START_IRQ", req->data->cookie, 0); + end: return rc; } @@ -1162,6 +1165,10 @@ 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", + 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)) { diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index e7236fa2d628..0d4608d739ff 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -524,15 +524,26 @@ static void __cam_isp_ctx_handle_buf_done_fail_log( "Resource Handles that fail to generate buf_done in prev frame"); for (i = 0; i < req_isp->num_fence_map_out; i++) { if (req_isp->fence_map_out[i].sync_id != -1) { - if (isp_device_type == CAM_IFE_DEVICE_TYPE) + if (isp_device_type == CAM_IFE_DEVICE_TYPE) { handle_type = __cam_isp_resource_handle_id_to_type( req_isp->fence_map_out[i].resource_handle); - else + + trace_cam_log_event("Buf_done Congestion", + __cam_isp_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle), + request_id, req_isp->fence_map_out[i].sync_id); + } else { handle_type = __cam_isp_tfe_resource_handle_id_to_type( req_isp->fence_map_out[i].resource_handle); + trace_cam_log_event("Buf_done Congestion", + __cam_isp_tfe_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle), + request_id, req_isp->fence_map_out[i].sync_id); + } + CAM_WARN(CAM_ISP, "Resource_Handle: [%s][0x%x] Sync_ID: [0x%x]", handle_type, @@ -597,6 +608,9 @@ static int __cam_isp_ctx_handle_buf_done_for_request( "Duplicate BUF_DONE for req %lld : i=%d, j=%d, res=%s", req->request_id, i, j, handle_type); + trace_cam_log_event("Duplicate BufDone", + handle_type, req->request_id, ctx->ctx_id); + if (done_next_req) { done_next_req->resource_handle [done_next_req->num_handles++] = @@ -1108,6 +1122,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, CAM_WARN(CAM_ISP, "Notify CRM about Bubble req %lld frame %lld, ctx %u", req->request_id, ctx_isp->frame_id, ctx->ctx_id); + trace_cam_log_event("Bubble", "Rcvd epoch in applied state", + req->request_id, ctx->ctx_id); ctx->ctx_crm_intf->notify_err(¬ify); atomic_set(&ctx_isp->process_bubble, 1); } else { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile index d5ab83c81dd7..aa3fb1c74358 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile @@ -3,6 +3,7 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 116cf7205875..7ad42e8480bd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -21,8 +21,10 @@ #include "cam_vfe_soc.h" #include "cam_debug_util.h" #include "cam_cpas_api.h" +#include "cam_trace.h" static const char drv_name[] = "vfe_bus"; +static char rup_controller_name[32] = ""; #define CAM_VFE_BUS_VER3_IRQ_REG0 0 #define CAM_VFE_BUS_VER3_IRQ_REG1 1 @@ -916,6 +918,7 @@ static int cam_vfe_bus_ver3_handle_rup_top_half(uint32_t evt_id, struct cam_isp_resource_node *vfe_out = NULL; struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; struct cam_vfe_bus_irq_evt_payload *evt_payload; + uint32_t irq_status; vfe_out = th_payload->handler_priv; if (!vfe_out) { @@ -944,6 +947,12 @@ static int cam_vfe_bus_ver3_handle_rup_top_half(uint32_t evt_id, evt_payload->evt_id = evt_id; for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + irq_status = + th_payload->evt_status_arr[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + + trace_cam_log_event("RUP", "RUP_IRQ", irq_status, 0); + th_payload->evt_payload_priv = evt_payload; return rc; @@ -2238,6 +2247,8 @@ static int cam_vfe_bus_ver3_handle_vfe_out_done_top_half(uint32_t evt_id, struct cam_isp_resource_node *vfe_out = NULL; struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; struct cam_vfe_bus_irq_evt_payload *evt_payload; + struct cam_vfe_bus_ver3_comp_grp_data *resource_data; + uint32_t status_0; vfe_out = th_payload->handler_priv; if (!vfe_out) { @@ -2246,6 +2257,7 @@ static int cam_vfe_bus_ver3_handle_vfe_out_done_top_half(uint32_t evt_id, } rsrc_data = vfe_out->res_priv; + resource_data = rsrc_data->comp_grp->res_priv; CAM_DBG(CAM_ISP, "VFE:%d Bus IRQ status_0: 0x%X status_1: 0x%X", rsrc_data->common_data->core_index, @@ -2274,6 +2286,17 @@ static int cam_vfe_bus_ver3_handle_vfe_out_done_top_half(uint32_t evt_id, th_payload->evt_payload_priv = evt_payload; + status_0 = th_payload->evt_status_arr[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + + if (status_0 & BIT(resource_data->comp_grp_type + + rsrc_data->common_data->comp_done_shift)) { + trace_cam_log_event("bufdone", "bufdone_IRQ", + status_0, resource_data->comp_grp_type); + } + + if (status_0 & 0x1) + trace_cam_log_event("UnexpectedRUP", "RUP_IRQ", status_0, 40); + CAM_DBG(CAM_ISP, "Exit"); return rc; } @@ -3725,7 +3748,6 @@ int cam_vfe_bus_ver3_init( struct cam_vfe_bus *vfe_bus_local; struct cam_vfe_bus_ver3_hw_info *ver3_hw_info = bus_hw_info; struct cam_vfe_soc_private *soc_private = NULL; - char rup_controller_name[12] = ""; CAM_DBG(CAM_ISP, "Enter"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile index 2ab4651e4271..08b95ac27209 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile @@ -4,6 +4,7 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 12cdcb19f2c0..622c8548bb52 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -18,6 +18,7 @@ #include "cam_debug_util.h" #include "cam_cdm_util.h" #include "cam_cpas_api.h" +#include "cam_trace.h" #define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 @@ -1192,6 +1193,27 @@ static int cam_vfe_camif_ver3_handle_irq_top_half(uint32_t evt_id, th_payload->evt_payload_priv = evt_payload; + if (th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->sof_irq_mask) { + trace_cam_log_event("SOF", "TOP_HALF", + th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1], + camif_node->hw_intf->hw_idx); + } + + if (th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->epoch0_irq_mask) { + trace_cam_log_event("EPOCH0", "TOP_HALF", + th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1], + camif_node->hw_intf->hw_idx); + } + + if (th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->eof_irq_mask) { + trace_cam_log_event("EOF", "TOP_HALF", + th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1], + camif_node->hw_intf->hw_idx); + } + CAM_DBG(CAM_ISP, "Exit"); return rc; } diff --git a/drivers/cam_utils/cam_trace.h b/drivers/cam_utils/cam_trace.h index 838997590771..c564b1582a3a 100644 --- a/drivers/cam_utils/cam_trace.h +++ b/drivers/cam_utils/cam_trace.h @@ -63,6 +63,29 @@ TRACE_EVENT(cam_isp_activated_irq, ) ); +TRACE_EVENT(cam_log_event, + TP_PROTO(const char *string1, const char *string2, + uint64_t val1, uint64_t val2), + TP_ARGS(string1, string2, val1, val2), + TP_STRUCT__entry( + __string(string1, string1) + __string(string2, string2) + __field(uint64_t, val1) + __field(uint64_t, val2) + ), + TP_fast_assign( + __assign_str(string1, string1); + __assign_str(string2, string2); + __entry->val1 = val1; + __entry->val2 = val2; + ), + TP_printk( + "%s: %s val1=%llu val2=%llu", + __get_str(string1), __get_str(string2), + __entry->val1, __entry->val2 + ) +); + TRACE_EVENT(cam_icp_fw_dbg, TP_PROTO(char *dbg_message, uint64_t timestamp), TP_ARGS(dbg_message, timestamp), -- GitLab From f1eeda6ff9462ee92d2d1f3bdfd71ab3b9d7923d Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Wed, 11 Dec 2019 13:31:46 -0800 Subject: [PATCH 113/295] msm: camera: smmu: Profile time taken for map, unmap Add debugging capability to profile ion alloc, smmu map and unmap calls. Enable below debugfs settings to get the traces with corresponding latencies. Alloc : echo 1 > /sys/kernel/debug/camera_memmgr/alloc_profile_enable Map, Unmap : echo 1 > /sys/kernel/debug/camera_smmu/map_profile_enable Capture the profiling numbers in traces. CRs-Fixed: 2538876 Change-Id: I92dc58416a9febc77a7836b8f7b1523b547c128f Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_req_mgr/cam_mem_mgr.c | 45 +++++++++++++++++++++++++++-- drivers/cam_req_mgr/cam_mem_mgr.h | 4 +++ drivers/cam_smmu/Makefile | 1 + drivers/cam_smmu/cam_smmu_api.c | 40 ++++++++++++++++++++++++- drivers/cam_utils/cam_common_util.h | 19 ++++++++++++ 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index eef1583451ba..ae0f167e189f 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -10,11 +10,14 @@ #include #include #include +#include #include "cam_req_mgr_util.h" #include "cam_mem_mgr.h" #include "cam_smmu_api.h" #include "cam_debug_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" static struct cam_mem_table tbl; static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED); @@ -116,6 +119,29 @@ static int cam_mem_util_unmap_cpu_va(struct dma_buf *dmabuf, return rc; } +static int cam_mem_mgr_create_debug_fs(void) +{ + tbl.dentry = debugfs_create_dir("camera_memmgr", NULL); + if (!tbl.dentry) { + CAM_ERR(CAM_MEM, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_bool("alloc_profile_enable", + 0644, + tbl.dentry, + &tbl.alloc_profile_enable)) { + CAM_ERR(CAM_MEM, + "failed to create alloc_profile_enable"); + goto err; + } + + return 0; +err: + debugfs_remove_recursive(tbl.dentry); + return -ENOMEM; +} + int cam_mem_mgr_init(void) { int i; @@ -141,6 +167,8 @@ int cam_mem_mgr_init(void) atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_INITIALIZED); + cam_mem_mgr_create_debug_fs(); + return 0; } @@ -375,12 +403,17 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, { struct dma_buf *dmabuf = NULL; int rc = 0; + struct timespec64 ts1, ts2; + long microsec = 0; if (!buf || !fd) { CAM_ERR(CAM_MEM, "Invalid params, buf=%pK, fd=%pK", buf, fd); return -EINVAL; } + if (tbl.alloc_profile_enable) + CAM_GET_TIMESTAMP(ts1); + *buf = ion_alloc(len, heap_id_mask, flags); if (IS_ERR_OR_NULL(*buf)) return -ENOMEM; @@ -403,6 +436,13 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, rc = -EINVAL; } + if (tbl.alloc_profile_enable) { + CAM_GET_TIMESTAMP(ts2); + CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts1, ts2, microsec); + trace_cam_log_event("IONAllocProfile", "size and time in micro", + len, microsec); + } + return rc; get_fd_fail: @@ -639,8 +679,9 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) if (rc) { CAM_ERR(CAM_MEM, - "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", - cmd->flags, fd, region, cmd->num_hdl, rc); + "Failed in map_hw_va, len=%llu, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + cmd->len, cmd->flags, fd, region, + cmd->num_hdl, rc); goto map_hw_fail; } } diff --git a/drivers/cam_req_mgr/cam_mem_mgr.h b/drivers/cam_req_mgr/cam_mem_mgr.h index 6ce30db66fe3..415639a67172 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.h +++ b/drivers/cam_req_mgr/cam_mem_mgr.h @@ -65,12 +65,16 @@ struct cam_mem_buf_queue { * @bitmap: bitmap of the mem mgr utility * @bits: max bits of the utility * @bufq: array of buffers + * @dentry: Debugfs entry + * @alloc_profile_enable: Whether to enable alloc profiling */ struct cam_mem_table { struct mutex m_lock; void *bitmap; size_t bits; struct cam_mem_buf_queue bufq[CAM_MEM_BUFQ_MAX]; + struct dentry *dentry; + bool alloc_profile_enable; }; /** diff --git a/drivers/cam_smmu/Makefile b/drivers/cam_smmu/Makefile index b674b48ceb2d..2968a7a1e2af 100644 --- a/drivers/cam_smmu/Makefile +++ b/drivers/cam_smmu/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 1a7f122b8c04..79c8d5210fc7 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -21,6 +21,8 @@ #include #include "cam_smmu_api.h" #include "cam_debug_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" #define SHARED_MEM_POOL_GRANULARITY 16 @@ -155,6 +157,7 @@ struct cam_iommu_cb_set { u32 non_fatal_fault; struct dentry *dentry; bool cb_dump_enable; + bool map_profile_enable; }; static const struct of_device_id msm_cam_smmu_dt_match[] = { @@ -1746,6 +1749,8 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, size_t size = 0; uint32_t iova = 0; int rc = 0; + struct timespec64 ts1, ts2; + long microsec = 0; if (IS_ERR_OR_NULL(buf)) { rc = PTR_ERR(buf); @@ -1760,6 +1765,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, goto err_out; } + if (iommu_cb_set.map_profile_enable) + CAM_GET_TIMESTAMP(ts1); + attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev); if (IS_ERR_OR_NULL(attach)) { rc = PTR_ERR(attach); @@ -1819,7 +1827,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, table = dma_buf_map_attachment(attach, dma_dir); if (IS_ERR_OR_NULL(table)) { rc = PTR_ERR(table); - CAM_ERR(CAM_SMMU, "Error: dma map attachment failed"); + CAM_ERR(CAM_SMMU, + "Error: dma map attachment failed, size=%zu", + buf->size); goto err_detach; } @@ -1836,6 +1846,13 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, "iova=%pK, region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", iova, region_id, *paddr_ptr, *len_ptr, attach->dma_map_attrs); + if (iommu_cb_set.map_profile_enable) { + CAM_GET_TIMESTAMP(ts2); + CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts1, ts2, microsec); + trace_cam_log_event("SMMUMapProfile", "size and time in micro", + *len_ptr, microsec); + } + if (table->sgl) { CAM_DBG(CAM_SMMU, "DMA buf: %pK, device: %pK, attach: %pK, table: %pK", @@ -1962,6 +1979,8 @@ static int cam_smmu_unmap_buf_and_remove_from_list( int rc; size_t size; struct iommu_domain *domain; + struct timespec64 ts1, ts2; + long microsec = 0; if ((!mapping_info->buf) || (!mapping_info->table) || (!mapping_info->attach)) { @@ -1980,6 +1999,9 @@ static int cam_smmu_unmap_buf_and_remove_from_list( mapping_info->region_id, mapping_info->paddr, mapping_info->len, mapping_info->attach->dma_map_attrs); + if (iommu_cb_set.map_profile_enable) + CAM_GET_TIMESTAMP(ts1); + if (mapping_info->region_id == CAM_SMMU_REGION_SHARED) { CAM_DBG(CAM_SMMU, "Removing SHARED buffer paddr = %pK, len = %zu", @@ -2016,6 +2038,13 @@ static int cam_smmu_unmap_buf_and_remove_from_list( dma_buf_detach(mapping_info->buf, mapping_info->attach); dma_buf_put(mapping_info->buf); + if (iommu_cb_set.map_profile_enable) { + CAM_GET_TIMESTAMP(ts2); + CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts1, ts2, microsec); + trace_cam_log_event("SMMUUnmapProfile", + "size and time in micro", mapping_info->len, microsec); + } + mapping_info->buf = NULL; list_del_init(&mapping_info->list); @@ -3779,6 +3808,15 @@ static int cam_smmu_create_debug_fs(void) goto err; } + if (!debugfs_create_bool("map_profile_enable", + 0644, + iommu_cb_set.dentry, + &iommu_cb_set.map_profile_enable)) { + CAM_ERR(CAM_SMMU, + "failed to create map_profile_enable"); + goto err; + } + return 0; err: debugfs_remove_recursive(iommu_cb_set.dentry); diff --git a/drivers/cam_utils/cam_common_util.h b/drivers/cam_utils/cam_common_util.h index e202bae5b761..ebe75f6eb5e9 100644 --- a/drivers/cam_utils/cam_common_util.h +++ b/drivers/cam_utils/cam_common_util.h @@ -14,6 +14,25 @@ #define PTR_TO_U64(ptr) ((uint64_t)(uintptr_t)ptr) #define U64_TO_PTR(ptr) ((void *)(uintptr_t)ptr) +#define CAM_GET_TIMESTAMP(timestamp) ktime_get_real_ts64(&(timestamp)) +#define CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts_start, ts_end, diff_microsec) \ +({ \ + diff_microsec = 0; \ + if (ts_end.tv_nsec >= ts_start.tv_nsec) { \ + diff_microsec = \ + (ts_end.tv_nsec - ts_start.tv_nsec) / 1000; \ + diff_microsec += \ + (ts_end.tv_sec - ts_start.tv_sec) * 1000 * 1000; \ + } else { \ + diff_microsec = \ + (ts_end.tv_nsec + \ + (1000*1000*1000 - ts_start.tv_nsec)) / 1000; \ + diff_microsec += \ + (ts_end.tv_sec - ts_start.tv_sec - 1) * 1000 * 1000; \ + } \ +}) + + /** * cam_common_util_get_string_index() * -- GitLab From fb113f780366263a999ca689a493d5228fad48fc Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Fri, 7 Feb 2020 15:13:18 +0530 Subject: [PATCH 114/295] msm: camera: ope: Clear comp events before each request If there is a stale entry of any event in the CDM, it will end the wait of same event in next request. So, clearing the comp events before each request. CRs-Fixed: 2611231 Change-Id: I252ee5edaea1cda34dc48343dd6bc865b490e977 Signed-off-by: Rishabh Jain --- drivers/cam_cdm/cam_cdm_util.c | 31 ++++++++++++++++++++ drivers/cam_cdm/cam_cdm_util.h | 15 ++++++++++ drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 7 +++++ 3 files changed, 53 insertions(+) diff --git a/drivers/cam_cdm/cam_cdm_util.c b/drivers/cam_cdm/cam_cdm_util.c index c9eee75f1c43..117680a5f8a0 100644 --- a/drivers/cam_cdm/cam_cdm_util.c +++ b/drivers/cam_cdm/cam_cdm_util.c @@ -168,6 +168,15 @@ struct cdm_wait_comp_event_cmd { unsigned int mask2; } __attribute__((__packed__)); +struct cdm_clear_comp_event_cmd { + unsigned int reserved : 8; + unsigned int id : 8; + unsigned int id_reserved: 8; + unsigned int cmd : 8; + unsigned int mask1; + unsigned int mask2; +} __attribute__((__packed__)); + struct cdm_prefetch_disable_event_cmd { unsigned int reserved : 8; unsigned int id : 8; @@ -223,6 +232,11 @@ uint32_t cdm_required_size_comp_wait(void) return cdm_get_cmd_header_size(CAM_CDM_COMP_WAIT); } +uint32_t cdm_required_size_clear_comp_event(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CLEAR_COMP_WAIT); +} + uint32_t cdm_required_size_prefetch_disable(void) { return cdm_get_cmd_header_size(CAM_CDM_WAIT_PREFETCH_DISABLE); @@ -382,6 +396,21 @@ uint32_t *cdm_write_wait_comp_event( return pCmdBuffer; } +uint32_t *cdm_write_clear_comp_event( + uint32_t *pCmdBuffer, uint32_t mask1, uint32_t mask2) +{ + struct cdm_clear_comp_event_cmd *pHeader = + (struct cdm_clear_comp_event_cmd *)pCmdBuffer; + + pHeader->cmd = CAM_CDM_CLEAR_COMP_WAIT; + pHeader->mask1 = mask1; + pHeader->mask2 = mask2; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CLEAR_COMP_WAIT); + + return pCmdBuffer; +} + uint32_t *cdm_write_wait_prefetch_disable( uint32_t *pCmdBuffer, uint32_t id, @@ -412,6 +441,7 @@ struct cam_cdm_utils_ops CDM170_ops = { cdm_required_size_wait_event, cdm_required_size_changebase, cdm_required_size_comp_wait, + cdm_required_size_clear_comp_event, cdm_required_size_prefetch_disable, cdm_offsetof_dmi_addr, cdm_offsetof_indirect_addr, @@ -423,6 +453,7 @@ struct cam_cdm_utils_ops CDM170_ops = { cdm_write_wait_event, cdm_write_changebase, cdm_write_wait_comp_event, + cdm_write_clear_comp_event, cdm_write_wait_prefetch_disable, }; diff --git a/drivers/cam_cdm/cam_cdm_util.h b/drivers/cam_cdm/cam_cdm_util.h index 520e8354ed82..750a98a6de05 100644 --- a/drivers/cam_cdm/cam_cdm_util.h +++ b/drivers/cam_cdm/cam_cdm_util.h @@ -63,6 +63,10 @@ enum cam_cdm_command { * in dwords. * @return Size in dwords * + * @cdm_required_size_clear_comp_event: Calculates the size of clear-comp-event + * command in dwords. + * @return Size in dwords + * * @cdm_required_size_changebase: Calculates the size of a change-base command * in dwords. * @return Size in dwords @@ -121,6 +125,12 @@ enum cam_cdm_command { * @pCmdBuffer: Pointer to command buffer * @mask1: This value decides which comp events to wait (0 - 31). * @mask2: This value decides which comp events to wait (32 - 65). + * + * @cdm_write_clear_comp_event: Writes a clear comp event cmd into the + * command buffer. + * @pCmdBuffer: Pointer to command buffer + * @mask1: This value decides which comp events to clear (0 - 31). + * @mask2: This value decides which comp events to clear (32 - 65). */ struct cam_cdm_utils_ops { uint32_t (*cdm_get_cmd_header_size)(unsigned int command); @@ -132,6 +142,7 @@ uint32_t (*cdm_required_size_genirq)(void); uint32_t (*cdm_required_size_wait_event)(void); uint32_t (*cdm_required_size_changebase)(void); uint32_t (*cdm_required_size_comp_wait)(void); +uint32_t (*cdm_required_size_clear_comp_event)(void); uint32_t (*cdm_required_size_prefetch_disable)(void); uint32_t (*cdm_offsetof_dmi_addr)(void); uint32_t (*cdm_offsetof_indirect_addr)(void); @@ -174,6 +185,10 @@ uint32_t *(*cdm_write_wait_comp_event)( uint32_t *pCmdBuffer, uint32_t mask1, uint32_t mask2); +uint32_t *(*cdm_write_clear_comp_event)( + uint32_t *pCmdBuffer, + uint32_t mask1, + uint32_t mask2); uint32_t *(*cdm_write_wait_prefetch_disable)( uint32_t *pCmdBuffer, uint32_t id, 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 8f934b09d7ff..7ef6ece6b976 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 @@ -1282,6 +1282,9 @@ static int cam_ope_dev_create_kmd_buf_nrt(struct cam_ope_hw_mgr *hw_mgr, cdm_ops = ctx_data->ope_cdm.cdm_ops; + kmd_buf = cdm_ops->cdm_write_clear_comp_event(kmd_buf, + OPE_WAIT_COMP_IDLE|OPE_WAIT_COMP_RUP, 0x0); + /* Frame 0 DB */ kmd_buf = ope_create_frame_cmd(hw_mgr, ctx_data, req_idx, @@ -1364,6 +1367,8 @@ static int cam_ope_dev_create_kmd_buf_batch(struct cam_ope_hw_mgr *hw_mgr, (kmd_buf_offset / sizeof(len)); cdm_kmd_start_addr = kmd_buf; cdm_ops = ctx_data->ope_cdm.cdm_ops; + kmd_buf = cdm_ops->cdm_write_clear_comp_event(kmd_buf, + OPE_WAIT_COMP_IDLE|OPE_WAIT_COMP_RUP, 0x0); for (i = 0; i < frm_proc->batch_size; i++) { wr_cdm_info = @@ -1500,6 +1505,8 @@ static int cam_ope_dev_create_kmd_buf(struct cam_ope_hw_mgr *hw_mgr, CAM_DBG(CAM_OPE, "kmd_buf:%x req_idx:%d req_id:%lld offset:%d", kmd_buf, req_idx, ope_request->request_id, kmd_buf_offset); + kmd_buf = cdm_ops->cdm_write_clear_comp_event(kmd_buf, + OPE_WAIT_COMP_IDLE|OPE_WAIT_COMP_RUP, 0x0); /* Frame 0 DB */ kmd_buf = ope_create_frame_cmd(hw_mgr, ctx_data, req_idx, -- GitLab From e4d401666b1280807e370c7dcb03cf8bdb62269e Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Fri, 7 Feb 2020 18:49:07 +0530 Subject: [PATCH 115/295] msm: camera: ope: Start context timer on receiving new request Restart the context timer on receiving new request, if stopped due to idleness of the context. CRs-Fixed: 2617511 Change-Id: If8e3d1412cb7ad6195a7e2fa55b7ed456f4a4321 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b6491f8301ab..838e904eb91b 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 @@ -2707,7 +2707,7 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, get_monotonic_boottime64(&ts); ctx_data->last_req_time = (uint64_t)((ts.tv_sec * 1000000000) + ts.tv_nsec); - cam_ope_req_timer_reset(ctx_data); + cam_ope_req_timer_modify(ctx_data, OPE_REQUEST_TIMEOUT); set_bit(request_idx, ctx_data->bitmap); ctx_data->req_list[request_idx] = kzalloc(sizeof(struct cam_ope_request), GFP_KERNEL); -- GitLab From b48f2fea630b6e22885d9ff90bf4f9b323e7a304 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Tue, 17 Dec 2019 15:21:45 +0530 Subject: [PATCH 116/295] msm: camera: isp: Mask unused rdi interrupts Enable rdi interrupts from the required sources only, other unused interrupts from rdi sources should be masked. Also in the case where multiple rdi has been acquired in same context interrupts from only one of them should be enabled. CRs-Fixed: 2590476 Change-Id: Icd074d1566db0b758d25c7b127402b424e48efd9 Signed-off-by: Tejas Prajapati --- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index 7aaacde775f4..a0e7741e5505 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -212,7 +212,7 @@ static int cam_vfe_rdi_resource_start( struct cam_vfe_mux_rdi_data *rsrc_data; int rc = 0; uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; - uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t rdi_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; if (!rdi_res) { CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); @@ -230,10 +230,6 @@ static int cam_vfe_rdi_resource_start( rsrc_data->rdi_common_reg_data->error_irq_mask0; err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = rsrc_data->rdi_common_reg_data->error_irq_mask1; - irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = - rsrc_data->rdi_common_reg_data->subscribe_irq_mask0; - irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = - rsrc_data->rdi_common_reg_data->subscribe_irq_mask1; rdi_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; @@ -261,11 +257,19 @@ static int cam_vfe_rdi_resource_start( if (!rdi_res->rdi_only_ctx) goto end; + rdi_irq_mask[0] = + (rsrc_data->reg_data->reg_update_irq_mask | + rsrc_data->reg_data->sof_irq_mask); + + CAM_DBG(CAM_ISP, "RDI%d irq_mask 0x%x", + rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0, + rdi_irq_mask[0]); + if (!rsrc_data->irq_handle) { rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, CAM_IRQ_PRIORITY_1, - irq_mask, + rdi_irq_mask, rdi_res, rdi_res->top_half_handler, rdi_res->bottom_half_handler, -- GitLab From 2ff81a2f0780eab262975cb0bd54f9879708776e Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 19 Dec 2019 12:55:45 +0530 Subject: [PATCH 117/295] msm: camera: isp: Update unlink handling to avoid race Expire timer after destroying workqueues so that we do not refer to watchdog timer while the link is getting unlinked from session handle. CRs-Fixed: 2585098 Change-Id: Ife2450ae66bd52ec704ac7d593b2daaeb20ba54d Signed-off-by: Vikram Sharma --- drivers/cam_req_mgr/cam_req_mgr_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 5e3015118d94..91e3ee1cdc4d 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3149,12 +3149,13 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) } mutex_lock(&link->lock); - /* Destroy timer of link */ - crm_timer_exit(&link->watchdog); /* Destroy workq of link */ cam_req_mgr_workq_destroy(&link->workq); + /* Destroy timer of link */ + crm_timer_exit(&link->watchdog); + /* Cleanup request tables and unlink devices */ __cam_req_mgr_destroy_link_info(link); -- GitLab From 1a907824ee4e62a57f5e22ea93b85f75785198e2 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Fri, 20 Dec 2019 12:51:16 +0530 Subject: [PATCH 118/295] msm: camera: csiphy: Add combo phy settings for csiphy v1.2.2.2 As per HPG revision L, there's a difference in the DPHY combo-mode sequence settings between lito v1 and v2. This change adds a separate sequence for lito v2, csiphy version 1.2.2.2. CRs-Fixed: 2591712 Change-Id: Ic535bd2c98f47c33aa689d0e1bfe07d7dac8d9a2 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/cam_csiphy_soc.c | 22 ++++ .../include/cam_csiphy_1_2_2_hwreg.h | 115 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h 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 c5a8033aaffb..3c1c01337bda 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -9,6 +9,7 @@ #include "include/cam_csiphy_1_0_hwreg.h" #include "include/cam_csiphy_1_2_hwreg.h" #include "include/cam_csiphy_1_2_1_hwreg.h" +#include "include/cam_csiphy_1_2_2_hwreg.h" #include "include/cam_csiphy_2_0_hwreg.h" #define CSIPHY_DIVISOR_16 16 @@ -310,6 +311,27 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->clk_lane = 0; csiphy_dev->ctrl_reg->data_rates_settings_table = &data_rate_delta_table_1_2; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.2.2.2")) { + /* settings for lito v2 */ + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_2_2_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_2_reg; + 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_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->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->hw_version = CSIPHY_VERSION_V12; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_1_2; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v2.0")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; 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 new file mode 100644 index 000000000000..dd88ba7cca38 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_2_2_HWREG_H_ +#define _CAM_CSIPHY_1_2_2_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_t +csiphy_2ph_v1_2_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_1_2_2_HWREG_H_ */ -- GitLab From a01c314effbdea6072982c3b33d0c45402fa2af0 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Tue, 17 Dec 2019 12:44:44 +0530 Subject: [PATCH 119/295] msm: camera: sync: correcting atomic read operation This change rectifies the reading of atomic variable. CRs-Fixed: 2591537 Change-Id: I13c289bc00a07d5c2289e2e3f13245bbc521d4ee Signed-off-by: Alok Pandey --- drivers/cam_sync/cam_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index 33b14f17ceb7..5f205361d1e9 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -38,7 +38,7 @@ static void cam_sync_print_fence_table(void) sync_dev->sync_table[idx].name, sync_dev->sync_table[idx].type, sync_dev->sync_table[idx].state, - sync_dev->sync_table[idx].ref_cnt); + atomic_read(&sync_dev->sync_table[idx].ref_cnt)); spin_unlock_bh(&sync_dev->row_spinlocks[idx]); } } -- GitLab From 7bfa9f70249384e63be076b7484e59d94a831450 Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Mon, 3 Feb 2020 12:42:03 +0530 Subject: [PATCH 120/295] msm: camera: csiphy: Update phy sequence for bengal Toggle reset register in common and reset programming sequence. CRs-Fixed: 2615460 Change-Id: Iba17fa3b2014be0bc27236169cf8456a7f8ededd Signed-off-by: Tony Lijo Jose --- .../cam_csiphy/include/cam_csiphy_2_0_hwreg.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h index cbd0dc582b32..9549919e2ea7 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_2_0_HWREG_H_ @@ -12,8 +12,8 @@ struct csiphy_reg_parms_t csiphy_v2_0 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 6, - .csiphy_reset_array_size = 3, + .csiphy_common_array_size = 8, + .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 15, .csiphy_3ph_config_array_size = 17, .csiphy_2ph_clock_lane = 0x1, @@ -24,6 +24,8 @@ struct csiphy_reg_t csiphy_common_reg_2_0[] = { {0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x06, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x00, 0x00, CSIPHY_2PH_REGS}, {0x0364, 0x00, 0x00, CSIPHY_2PH_REGS}, {0x0564, 0x00, 0x00, CSIPHY_2PH_REGS}, @@ -33,6 +35,8 @@ struct csiphy_reg_t csiphy_reset_reg_2_0[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; struct csiphy_reg_t csiphy_irq_reg_2_0[] = { -- GitLab From 0639c9b63c77ce026071aed994c61c458d866a30 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Sat, 8 Feb 2020 00:14:55 +0530 Subject: [PATCH 121/295] msm: camera: tfe: Reduce stack size during set axi bw Add change to move static memory allocation to dynamic to reduce stack usage during set axi bw in tfe driver. CRs-Fixed: 2615123 Change-Id: I5c60cd65fc458111daa29c3ba1a1f496248c653c Signed-off-by: Alok Chauhan --- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) 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 70d40eb6a3b1..994ad12ad709 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 @@ -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. */ #include @@ -974,7 +974,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; @@ -990,6 +990,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) { @@ -1001,10 +1007,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( @@ -1013,31 +1020,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; @@ -1049,18 +1056,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); @@ -1074,7 +1082,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; } } @@ -1115,6 +1124,9 @@ static int cam_tfe_top_set_axi_bw_vote( } } +free_mem: + kzfree(agg_vote); + agg_vote = NULL; return rc; } -- GitLab From 65455a7eee3a219ea7a1b06b64c2839b50bc40b8 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 10 Feb 2020 14:58:44 +0530 Subject: [PATCH 122/295] msm: camera: cdm: Check for HW state before dumping registers In case of page fault, check for cdm hardware state before dumping registers. CRs-Fixed: 2614680 Change-Id: I509cdd7d53e75a39199129806a7391f0142737d8 Signed-off-by: Rishabh Jain --- drivers/cam_cdm/cam_cdm_hw_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index f207e4f998c3..690cfd083c79 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1086,7 +1086,10 @@ 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) + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + 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); -- GitLab From 4bce1271b2a3dc460a5153275d32f4c48cf33181 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Sat, 8 Feb 2020 20:14:34 +0530 Subject: [PATCH 123/295] msm: camera: ope: Reduce stack footprint during acquire Add changes to allocate memory dynamically to reduce stack sizes during OPE acquire hardware. CRs-Fixed: 2616315 Change-Id: I71605a09502e7426329b9dc89c54ba7b5a6144d8 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 78 ++++++++++++-------- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 37 ++++++---- 2 files changed, 69 insertions(+), 46 deletions(-) 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 276cce1740f4..eca4a7e382b0 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 @@ -2117,10 +2117,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)) { @@ -2201,34 +2201,38 @@ 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")); + cdm_acquire = kzalloc(sizeof(struct cam_cdm_acquire_data), GFP_KERNEL); + if (!cdm_acquire) { + CAM_ERR(CAM_ISP, "Out of memory"); + goto ope_dev_acquire_failed; + } + 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; + 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; + cdm_acquire->priority = CAM_CDM_BL_FIFO_0; else - goto ope_dev_acquire_failed; + 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]; + 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); + 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; + ctx->ope_cdm.cdm_ops = cdm_acquire->ops; + ctx->ope_cdm.cdm_handle = cdm_acquire->handle; - rc = cam_cdm_stream_on(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; @@ -2245,25 +2249,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; } } @@ -2281,10 +2290,12 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) 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); + cam_cdm_release(cdm_acquire->handle); ctx->ope_cdm.cdm_ops = NULL; ctx->ope_cdm.cdm_handle = 0; cdm_acquire_failed: @@ -2296,6 +2307,9 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) CAM_ERR(CAM_OPE, "OPE Dev release failed"); } +free_cdm_acquire: + kzfree(cdm_acquire); + cdm_acquire = NULL; ope_dev_acquire_failed: if (!hw_mgr->ope_ctx_cnt) { irq_cb.ope_hw_mgr_cb = NULL; 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 ed9b797700e5..a0b695fa85dd 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 @@ -171,7 +171,7 @@ 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; @@ -192,30 +192,36 @@ int cam_ope_init_hw(void *device_priv, } 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); - goto end; + goto free_cpas_vote; } core_info->cpas_start = true; @@ -233,7 +239,7 @@ int cam_ope_init_hw(void *device_priv, if (rc) goto process_init_failed; else - goto end; + goto free_cpas_vote; process_init_failed: if (cam_ope_disable_soc_resources(soc_info, core_info->clk_enable)) @@ -243,6 +249,9 @@ int cam_ope_init_hw(void *device_priv, 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; } -- GitLab From 6c21f0c7922eebca3d9e412b0286a865ead246ff Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 10 Feb 2020 17:27:38 +0530 Subject: [PATCH 124/295] msm: camera: tfe: Disable clock if tfe2 is not supported Depending upon the variant, tfe2 may be fused. If tfe2 is fused, disable the CSID SOC resources. CRs-Fixed: 2618848 Change-Id: I55ed323db269b3e3c6e2a1c2690ee14f28d5ad3c Signed-off-by: Gaurav Jindal --- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) 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 59450ae841d3..3d3af7dc1b2e 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 @@ -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. */ #include @@ -2744,7 +2744,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; } } -- GitLab From 08d329c5ce84cd0083f19b68ceba07a2d4a45586 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Tue, 11 Feb 2020 17:21:09 +0530 Subject: [PATCH 125/295] msm: camera: cdm: Avoid cdm pause incase of BL submit BL submit and handle error callback can run in parallel. Handle error callback do ope cdm pause and can cause issue if BL submit callback come at the same time. CRs-Fixed: 2620486 Change-Id: I9d803775a67f8d7d5a94cb6d8d2648794cd661de Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index f207e4f998c3..6c292da186a1 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1334,6 +1334,9 @@ int cam_hw_cdm_handle_error_info( 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_enable_core(cdm_hw, false); + rc = cam_cdm_read_hw_reg(cdm_hw, cdm_core->offsets->cmn_reg->current_bl_len, ¤t_bl_data); @@ -1445,9 +1448,6 @@ 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; -- GitLab From 70b07a6f51b2811cfd6ebdbb48eea34643f9a671 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 10 Feb 2020 15:36:50 +0530 Subject: [PATCH 126/295] msm: camera: tfe: Optimize CSID IRQ logging CSID error IRQ logs can sometimes lead to stability issues especially if the serial logs are enabled. Optimize the CSID error IRQ logs. Also make the Reset IRQ logs debugfs based. Change-Id: Ic0e0a297fd75523634f84dbf7d7f2bee5a2ff78c CRs-Fixed: 2616316 Signed-off-by: Gaurav Jindal --- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 89 ++++++++++++++----- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.h | 3 +- 2 files changed, 70 insertions(+), 22 deletions(-) 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 59450ae841d3..eb6149569d2d 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 @@ -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. */ #include @@ -1834,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); @@ -1853,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); @@ -2345,7 +2348,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; @@ -2402,14 +2405,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]) @@ -2456,25 +2451,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 + @@ -2590,6 +2589,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 */ @@ -2621,10 +2637,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); @@ -2647,12 +2677,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; 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 f706bbaefd05..c0c3532bcc82 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 @@ -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_TFE_CSID_HW_H_ @@ -65,6 +65,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 { -- GitLab From 8394641987ab4de803e23670079e012dbaaaf4ae Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Mon, 23 Dec 2019 11:42:09 +0800 Subject: [PATCH 127/295] msm: camera: sensor: Fix an operator error - Fix an operator error in cam_sensor_flush_request CRs-Fixed: 2591694 Change-Id: I39a8b29f83db55d2a930dd5ccd2b765517e2c1d6 Signed-off-by: Depeng Shao --- drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 6902122b3f66..37f62fe95246 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.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 @@ -1319,8 +1319,8 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) } mutex_lock(&(s_ctrl->cam_sensor_mutex)); - if (s_ctrl->sensor_state != CAM_SENSOR_START || - s_ctrl->sensor_state != CAM_SENSOR_CONFIG) { + if ((s_ctrl->sensor_state != CAM_SENSOR_START) && + (s_ctrl->sensor_state != CAM_SENSOR_CONFIG)) { mutex_unlock(&(s_ctrl->cam_sensor_mutex)); return rc; } -- GitLab From 33d94b55de5eb2a5f47d4bebb2a96801b8f40405 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 7 Nov 2019 18:54:27 -0800 Subject: [PATCH 128/295] msm: camera: icp: Enable hang dump on failure In case user does not set any dump lvl, KMD will set to dump on failure as default. CRs-Fixed: 2579908 Change-Id: I036e91f5daceedf575815e7569c0e90c04f8de52 Signed-off-by: Karthik Anantha Ram --- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 18bcdd8ac6e2..94497f4f16fc 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.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 @@ -1890,6 +1890,8 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) goto err; } + /* Set default hang dump lvl */ + icp_hw_mgr.a5_fw_dump_lvl = HFI_FW_DUMP_ON_FAILURE; return rc; err: debugfs_remove_recursive(icp_hw_mgr.dentry); -- GitLab From 120973d479d703f6d0c11507bf4503e1cf10e374 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 8 Nov 2019 17:45:22 -0800 Subject: [PATCH 129/295] msm: camera: icp: Dump patching info in case of page faults Currently as part of the page fault handler we only dump the io_bufs. This change dumps all the patched addresses for this request as well. CRs-Fixed: 2579908 Change-Id: If5deec0ad3a8aec82824ef55366084c31a037515 Signed-off-by: Karthik Anantha Ram --- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 2 + drivers/cam_utils/cam_packet_util.c | 55 ++++++++++++++++++- drivers/cam_utils/cam_packet_util.h | 16 +++++- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 94497f4f16fc..f0bf17855753 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -4743,6 +4743,8 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, } } + cam_packet_dump_patch_info(packet, icp_hw_mgr.iommu_hdl, + icp_hw_mgr.iommu_sec_hdl); } static int cam_icp_mgr_config_stream_settings( diff --git a/drivers/cam_utils/cam_packet_util.c b/drivers/cam_utils/cam_packet_util.c index 4eadee666219..1569d5dbafa6 100644 --- a/drivers/cam_utils/cam_packet_util.c +++ b/drivers/cam_utils/cam_packet_util.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 @@ -154,6 +154,59 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, return rc; } +void cam_packet_dump_patch_info(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl) +{ + struct cam_patch_desc *patch_desc = NULL; + dma_addr_t iova_addr; + size_t dst_buf_len; + size_t src_buf_size; + int i, rc = 0; + int32_t hdl; + uintptr_t cpu_addr = 0; + uint32_t *dst_cpu_addr; + uint64_t value = 0; + + patch_desc = (struct cam_patch_desc *) + ((uint32_t *) &packet->payload + + packet->patch_offset/4); + + for (i = 0; i < packet->num_patches; i++) { + hdl = cam_mem_is_secure_buf(patch_desc[i].src_buf_hdl) ? + sec_mmu_hdl : iommu_hdl; + rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl, + hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, + "unable to get src buf address for hdl 0x%x", + hdl); + return; + } + + rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl, + &cpu_addr, &dst_buf_len); + if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) { + CAM_ERR(CAM_UTIL, "unable to get dst buf address"); + return; + } + + dst_cpu_addr = (uint32_t *)cpu_addr; + dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr + + patch_desc[i].dst_offset); + value = *((uint64_t *)dst_cpu_addr); + CAM_INFO(CAM_UTIL, + "i = %d src_buf 0x%llx src_hdl 0x%x src_buf_with_offset 0x%llx size 0x%llx dst %p dst_offset %u dst_hdl 0x%x value 0x%llx", + i, iova_addr, patch_desc[i].src_buf_hdl, + (iova_addr + patch_desc[i].src_offset), + src_buf_size, dst_cpu_addr, + patch_desc[i].dst_offset, + patch_desc[i].dst_buf_hdl, value); + + if (!(*dst_cpu_addr)) + CAM_ERR(CAM_ICP, "Null at dst addr %p", dst_cpu_addr); + } +} + int cam_packet_util_process_patches(struct cam_packet *packet, int32_t iommu_hdl, int32_t sec_mmu_hdl) { diff --git a/drivers/cam_utils/cam_packet_util.h b/drivers/cam_utils/cam_packet_util.h index d5fc8f70ec07..62866a962cc6 100644 --- a/drivers/cam_utils/cam_packet_util.h +++ b/drivers/cam_utils/cam_packet_util.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 _CAM_PACKET_UTIL_H_ @@ -86,6 +86,20 @@ int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc); int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, struct cam_kmd_buf_info *kmd_buf_info); +/** + * cam_packet_dump_patch_info() + * + * @brief: Dump patch info in case of page fault + * + * @packet: Input packet containing Command Buffers and Patches + * @iommu_hdl: IOMMU handle of the HW Device that received the packet + * @sec_iommu_hdl: Secure IOMMU handle of the HW Device that + * received the packet + * + */ +void cam_packet_dump_patch_info(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl); + /** * cam_packet_util_process_patches() * -- GitLab From 6a9dc2d870d3872fa8975e9de3f236984323ae34 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 9 Sep 2019 22:54:06 -0700 Subject: [PATCH 130/295] msm: camera: isp: Add support to obtain frame index This change captures the frame index as part of the IFE top register space at every epoch event. The index is then notified to userspace as part of shutter notification. CRs-Fixed: 2524308 Change-Id: Iac510c452f9ceda86e9f7d69528f22f81e614974 Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/cam_isp_context.c | 44 +++++++++++++---- drivers/cam_isp/cam_isp_context.h | 45 +++++++++-------- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 48 +++++++++++-------- .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 3 +- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 2 + .../isp_hw/include/cam_vfe_hw_intf.h | 4 ++ .../isp_hw/vfe_hw/vfe17x/cam_vfe480.h | 5 +- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 28 ++++++++++- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.h | 3 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h | 4 +- 10 files changed, 131 insertions(+), 55 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 7ea77b7fbcc1..cd0a0f8ae95a 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -629,6 +629,7 @@ static void __cam_isp_ctx_send_sof_boot_timestamp( req_msg.u.frame_msg.timestamp = ctx_isp->boot_timestamp; req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; req_msg.u.frame_msg.sof_status = sof_event_status; + req_msg.u.frame_msg.frame_id_meta = ctx_isp->frame_id_meta; CAM_DBG(CAM_ISP, "request id:%lld frame number:%lld boot time stamp:0x%llx", @@ -656,6 +657,7 @@ static void __cam_isp_ctx_send_sof_timestamp( req_msg.u.frame_msg.timestamp = ctx_isp->sof_timestamp_val; req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; req_msg.u.frame_msg.sof_status = sof_event_status; + req_msg.u.frame_msg.frame_id_meta = ctx_isp->frame_id_meta; CAM_DBG(CAM_ISP, "request id:%lld frame number:%lld SOF time stamp:0x%llx", @@ -1040,11 +1042,20 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( struct cam_isp_context *ctx_isp, void *evt_data) { int rc = 0; + uint64_t request_id = 0; struct cam_req_mgr_trigger_notify notify; struct cam_context *ctx = ctx_isp->base; struct cam_ctx_request *req; struct cam_isp_ctx_req *req_isp; - uint64_t request_id = 0; + struct cam_isp_hw_epoch_event_data *epoch_done_event_data = + (struct cam_isp_hw_epoch_event_data *)evt_data; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "invalid event data"); + return -EINVAL; + } + + ctx_isp->frame_id_meta = epoch_done_event_data->frame_id_meta; /* * notify reqmgr with sof signal. Note, due to scheduling delay @@ -1261,11 +1272,19 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, void *evt_data) { - struct cam_ctx_request *req; - struct cam_isp_ctx_req *req_isp; - struct cam_context *ctx = ctx_isp->base; - uint64_t request_id = 0; + uint64_t request_id = 0; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_epoch_event_data *epoch_done_event_data = + (struct cam_isp_hw_epoch_event_data *)evt_data; + if (!evt_data) { + CAM_ERR(CAM_ISP, "invalid event data"); + return -EINVAL; + } + + ctx_isp->frame_id_meta = epoch_done_event_data->frame_id_meta; if (list_empty(&ctx->wait_req_list)) { /* * If no wait req in epoch, this is an error case. @@ -1426,10 +1445,19 @@ static int __cam_isp_ctx_buf_done_in_bubble( static int __cam_isp_ctx_epoch_in_bubble_applied( struct cam_isp_context *ctx_isp, void *evt_data) { - struct cam_ctx_request *req; - struct cam_isp_ctx_req *req_isp; - struct cam_context *ctx = ctx_isp->base; uint64_t request_id = 0; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_epoch_event_data *epoch_done_event_data = + (struct cam_isp_hw_epoch_event_data *)evt_data; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "invalid event data"); + return -EINVAL; + } + + ctx_isp->frame_id_meta = epoch_done_event_data->frame_id_meta; /* * This means we missed the reg upd ack. So we need to diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 99128fe0fab6..78e2db92f0b1 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -218,6 +218,8 @@ struct cam_isp_context_event_record { * * @base: Common context object pointer * @frame_id: Frame id tracking for the isp context + * @frame_id_meta: Frame id read every epoch for the ctx + * meta from the sensor * @substate_actiavted: Current substate for the activated state. * @process_bubble: Atomic variable to check if ctx is still * processing bubble. @@ -249,27 +251,28 @@ struct cam_isp_context_event_record { * */ struct cam_isp_context { - struct cam_context *base; - - int64_t frame_id; - enum cam_isp_ctx_activated_substate substate_activated; - atomic_t process_bubble; - uint32_t bubble_frame_cnt; - struct cam_ctx_ops *substate_machine; - struct cam_isp_ctx_irq_ops *substate_machine_irq; - - struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; - struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX]; - - void *hw_ctx; - uint64_t sof_timestamp_val; - uint64_t boot_timestamp; - int32_t active_req_cnt; - int64_t reported_req_id; - uint32_t subscribe_event; - int64_t last_applied_req_id; - atomic64_t state_monitor_head; - struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ + struct cam_context *base; + + int64_t frame_id; + uint32_t frame_id_meta; + uint32_t substate_activated; + atomic_t process_bubble; + uint32_t bubble_frame_cnt; + struct cam_ctx_ops *substate_machine; + struct cam_isp_ctx_irq_ops *substate_machine_irq; + + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX]; + + void *hw_ctx; + uint64_t sof_timestamp_val; + uint64_t boot_timestamp; + int32_t active_req_cnt; + int64_t reported_req_id; + uint32_t subscribe_event; + int64_t last_applied_req_id; + atomic64_t state_monitor_head; + struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; struct cam_isp_context_req_id_info req_info; atomic64_t event_record_head[ 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 6fe984a17554..e94664879573 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 @@ -4769,29 +4769,36 @@ static int cam_isp_blob_core_cfg_update( list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { clk_rate = 0; - if (!hw_mgr_res->hw_res[i] || - hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF) + if (!hw_mgr_res->hw_res[i]) continue; - hw_intf = hw_mgr_res->hw_res[i]->hw_intf; - if (hw_intf && hw_intf->hw_ops.process_cmd) { - vfe_core_config.node_res = - hw_mgr_res->hw_res[i]; + if ((hw_mgr_res->res_id == + CAM_ISP_HW_VFE_IN_CAMIF) || + (hw_mgr_res->res_id == + CAM_ISP_HW_VFE_IN_PDLIB)) { + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + vfe_core_config.node_res = + hw_mgr_res->hw_res[i]; - memcpy(&vfe_core_config.core_config, - core_config, - sizeof(struct cam_isp_core_config)); + memcpy(&vfe_core_config.core_config, + core_config, + sizeof( + struct cam_isp_core_config)); - rc = hw_intf->hw_ops.process_cmd( - hw_intf->hw_priv, - CAM_ISP_HW_CMD_CORE_CONFIG, - &vfe_core_config, - sizeof( - struct cam_vfe_core_config_args)); - if (rc) - CAM_ERR(CAM_ISP, "Core cfg parse fail"); - } else { - CAM_WARN(CAM_ISP, "NULL hw_intf!"); + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CORE_CONFIG, + &vfe_core_config, + sizeof( + struct cam_vfe_core_config_args) + ); + if (rc) + CAM_ERR(CAM_ISP, + "Core cfg parse fail"); + } else { + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } } } } @@ -6520,6 +6527,9 @@ static int cam_ife_hw_mgr_handle_hw_epoch( if (!rc) { if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) break; + + epoch_done_event_data.frame_id_meta = + event_info->th_reg_val; ife_hw_irq_epoch_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_EPOCH, &epoch_done_event_data); } diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index a0c0e60a30a4..86b47da0b313 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -170,10 +170,11 @@ struct cam_isp_hw_reg_update_event_data { * struct cam_isp_hw_epoch_event_data - Event payload for CAM_HW_EVENT_EPOCH * * @timestamp: Time stamp for the epoch event - * + * @frame_id_meta: Frame id value corresponding to this frame */ struct cam_isp_hw_epoch_event_data { uint64_t timestamp; + uint32_t frame_id_meta; }; /** 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 ca30212ff6d6..5fd1172a4033 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 @@ -177,6 +177,7 @@ struct cam_isp_resource_node { * @res_id: Unique resource ID * @hw_idx: IFE hw index * @err_type: Error type if any + * @th_reg_val: Any critical register value captured during th * */ struct cam_isp_hw_event_info { @@ -184,6 +185,7 @@ struct cam_isp_hw_event_info { uint32_t res_id; uint32_t hw_idx; uint32_t err_type; + uint32_t th_reg_val; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index a1d1c6a60881..e4f86edaf5e6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -259,11 +259,15 @@ struct cam_vfe_bw_control_args { * @list: list_head node for the payload * @irq_reg_val: IRQ and Error register values, read when IRQ was * handled + * @th_reg_val: Value of any critical register that needs to be + * read at th to avoid any latencies in bh processing + * * @ts: Timestamp */ struct cam_vfe_top_irq_evt_payload { struct list_head list; uint32_t irq_reg_val[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t th_reg_val; struct cam_isp_timestamp ts; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h index ae65df7c1126..0cd59de02f46 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.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. */ @@ -77,6 +77,7 @@ static struct cam_vfe_camif_ver3_reg_data vfe_480_camif_reg_data = { .error_irq_mask0 = 0x82000200, .error_irq_mask2 = 0x30301F80, .subscribe_irq_mask1 = 0x00000007, + .frame_id_irq_mask = 0x400, .enable_diagnostic_hw = 0x1, .pp_camif_cfg_en_shift = 0, .pp_camif_cfg_ife_out_en_shift = 8, @@ -101,7 +102,7 @@ static struct cam_vfe_top_ver3_reg_offset_common vfe480_top_common_reg = { .ahb_cgc_ovd = 0x00000024, .noc_cgc_ovd = 0x00000028, .trigger_cdm_events = 0x00000090, - .sbi_frame_idx = 0x00000110, + .custom_frame_idx = 0x00000110, .dsp_status = 0x0000007C, .diag_config = 0x00000064, .diag_sensor_status_0 = 0x00000068, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 622c8548bb52..03dcf8cedbc3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -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. */ #include @@ -503,6 +503,9 @@ static int cam_vfe_camif_ver3_resource_start( irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = rsrc_data->reg_data->sof_irq_mask; + if (rsrc_data->cam_common_cfg.input_mux_sel_pp & 0x3) + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->frame_id_irq_mask; if (!rsrc_data->sof_irq_handle) { rsrc_data->sof_irq_handle = cam_irq_controller_subscribe_irq( @@ -1187,10 +1190,21 @@ static int cam_vfe_camif_ver3_handle_irq_top_half(uint32_t evt_id, } cam_isp_hw_get_timestamp(&evt_payload->ts); + evt_payload->th_reg_val = 0; for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + /* Read frame_id meta at every epoch if custom hw is enabled */ + if (evt_payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->epoch0_irq_mask) { + if ((camif_priv->common_reg->custom_frame_idx) && + (camif_priv->cam_common_cfg.input_mux_sel_pp & 0x3)) + evt_payload->th_reg_val = cam_io_r_mb( + camif_priv->mem_base + + camif_priv->common_reg->custom_frame_idx); + } + th_payload->evt_payload_priv = evt_payload; if (th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1] @@ -1227,6 +1241,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; + uint32_t val = 0; int i = 0; if (!handler_priv || !evt_payload_priv) { @@ -1246,6 +1261,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, evt_info.hw_idx = camif_node->hw_intf->hw_idx; evt_info.res_id = camif_node->res_id; evt_info.res_type = camif_node->res_type; + evt_info.th_reg_val = 0; if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] & camif_priv->reg_data->sof_irq_mask) { @@ -1276,6 +1292,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] & camif_priv->reg_data->epoch0_irq_mask) { CAM_DBG(CAM_ISP, "VFE:%d Received EPOCH", evt_info.hw_idx); + evt_info.th_reg_val = payload->th_reg_val; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1311,6 +1328,15 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, cam_vfe_camif_ver3_reg_dump(camif_node); } + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + & camif_priv->reg_data->frame_id_irq_mask) { + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->custom_frame_idx); + CAM_DBG(CAM_ISP, + "VFE:%d Frame id change to: %u", evt_info.hw_idx, + val); + } + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { CAM_ERR(CAM_ISP, "VFE:%d Violation", evt_info.hw_idx); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h index 40d8e40ae852..303a9e5b0a6a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.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_VFE_CAMIF_VER3_H_ @@ -52,6 +52,7 @@ struct cam_vfe_camif_ver3_reg_data { uint32_t error_irq_mask0; uint32_t error_irq_mask2; uint32_t subscribe_irq_mask1; + uint32_t frame_id_irq_mask; uint32_t enable_diagnostic_hw; uint32_t pp_camif_cfg_en_shift; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h index 14c96097cdf6..4a24ba6ddf76 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.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_VFE_TOP_VER3_H_ @@ -41,7 +41,7 @@ struct cam_vfe_top_ver3_reg_offset_common { uint32_t reg_update_cmd; uint32_t trigger_cdm_events; uint32_t violation_status; - uint32_t sbi_frame_idx; + uint32_t custom_frame_idx; uint32_t dsp_status; uint32_t diag_config; uint32_t diag_sensor_status_0; -- GitLab From f53584d10c13058f8b6c06d26b520227a01dceda Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 19 Nov 2019 13:40:02 -0800 Subject: [PATCH 131/295] msm: camera: reqmgr: Add uapi for new v4l2 event type Add event type to be notify custom events from the custom driver. Also adds a new custom message definition. CRs-Fixed: 2569823 Change-Id: I2ff701e79949ac3a467cbfe0c704065dbf0dc759 Signed-off-by: Karthik Anantha Ram --- include/uapi/media/cam_req_mgr.h | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 7528557a8423..d876f21575bb 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_LINUX_CAM_REQ_MGR_H @@ -53,6 +53,7 @@ #define V4L_EVENT_CAM_REQ_MGR_SOF 0 #define V4L_EVENT_CAM_REQ_MGR_ERROR 1 #define V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS 2 +#define V4L_EVENT_CAM_REQ_MGR_CUSTOM_EVT 3 /* SOF Event status */ #define CAM_REQ_MGR_SOF_EVENT_SUCCESS 0 @@ -463,11 +464,29 @@ struct cam_req_mgr_frame_msg { uint32_t reserved; }; +/** + * struct cam_req_mgr_custom_msg + * @custom_type: custom type + * @request_id: request id of the frame + * @frame_id: frame id of the frame + * @timestamp: timestamp of the frame + * @link_hdl: link handle associated with this message + * @custom_data: custom data + */ +struct cam_req_mgr_custom_msg { + uint32_t custom_type; + uint64_t request_id; + uint64_t frame_id; + uint64_t timestamp; + int32_t link_hdl; + uint64_t custom_data; +}; + /** * struct cam_req_mgr_message * @session_hdl: session to which the frame belongs to * @reserved: reserved field - * @u: union which can either be error or frame message + * @u: union which can either be error/frame/custom message */ struct cam_req_mgr_message { int32_t session_hdl; @@ -475,6 +494,7 @@ struct cam_req_mgr_message { union { struct cam_req_mgr_error_msg err_msg; struct cam_req_mgr_frame_msg frame_msg; + struct cam_req_mgr_custom_msg custom_msg; } u; }; #endif /* __UAPI_LINUX_CAM_REQ_MGR_H */ -- GitLab From 9123e2e677cbc6679e29ad3fcfcf07adecc887e8 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 6 Jan 2020 15:11:49 -0800 Subject: [PATCH 132/295] msm: camera: custom: Disable overflow recovery This change disables overflow recovery/detection for custom CSID. Currently for QCOM CSID we enable overflow detection and freeze on overflow. But for custom HW the CSID needs to be free running, custom HW will take care of handling any backpressure from IFE pipeline/DDR. There is no need to backpressure to CSID in case of custom HW. CRs-Fixed: 2524308 Change-Id: I5de62eea0e87674d7ac24bb5ad2f11ff2a5a6b7c Signed-off-by: Karthik Anantha Ram --- .../cam_custom_csid/cam_custom_csid480.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h index a55bb002ffc2..da98ebf104c7 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.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_CUSTOM_CSID_480_H_ @@ -56,7 +56,7 @@ static struct cam_ife_csid_udi_reg_offset .csid_udi_byte_cntr_pong_addr = 0x2e4, /* configurations */ .ccif_violation_en = 1, - .overflow_ctrl_en = 1, + .overflow_ctrl_en = 0, }; static struct cam_ife_csid_udi_reg_offset @@ -105,7 +105,7 @@ static struct cam_ife_csid_udi_reg_offset .csid_udi_byte_cntr_pong_addr = 0x3e4, /* configurations */ .ccif_violation_en = 1, - .overflow_ctrl_en = 1, + .overflow_ctrl_en = 0, }; static struct cam_ife_csid_udi_reg_offset @@ -155,7 +155,7 @@ static struct cam_ife_csid_udi_reg_offset .csid_udi_byte_cntr_pong_addr = 0x4e4, /* configurations */ .ccif_violation_en = 1, - .overflow_ctrl_en = 1, + .overflow_ctrl_en = 0, }; static struct cam_ife_csid_csi2_rx_reg_offset -- GitLab From 464238bf52764c089cb077a495402b3a8636e31b Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Wed, 12 Feb 2020 14:46:15 +0530 Subject: [PATCH 133/295] msm: camera: ope: Move request id validity check outside of lock In some corner cases, flush request and cdm callback can run in parallel. This may lead to data curruption in cdm callback if bl request gets freed by flush. As lock is also part of corrupted data structure hence move the request validity check outside of lock in cdm callback to prevent this issue. CRs-Fixed: 2615308 Change-Id: I2b166eb491e394000a63d0fe4e6d001ba3ddef76 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 276cce1740f4..342d05fbe8e8 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 @@ -1190,15 +1190,15 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, CAM_DBG(CAM_OPE, "CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", handle, userdata, status, cookie); - ctx = userdata; - - mutex_lock(&ctx->ctx_mutex); - if (cookie >= CAM_CTX_REQ_MAX) { CAM_ERR(CAM_OPE, "Invalid reqIdx = %llu", cookie); - goto end; + return; } + ctx = userdata; + + mutex_lock(&ctx->ctx_mutex); + if (!test_bit(cookie, ctx->bitmap)) { CAM_INFO(CAM_OPE, "Request not present reqIdx = %d", cookie); goto end; -- GitLab From 34daeb943e0ba59a4cb1aa74a29044579e9d1f89 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Tue, 18 Feb 2020 10:42:21 +0530 Subject: [PATCH 134/295] msm: camera: tfe: Correct the tfe hw manager dump logic If tfe acquire fails, tfe hardware manager dumps the current acquired context resource information. Correct this dump logic to dump the proper resource information. CRs-Fixed: 2623360 Change-Id: Ifbcf53483dd674c3084040b851eadd5d6377bff3 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) 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 02d727a29cad..a387736ea3bb 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 @@ -679,7 +679,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, @@ -694,7 +694,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, @@ -1233,7 +1233,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; } @@ -1657,7 +1657,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; } } @@ -1667,7 +1668,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; } } @@ -1675,14 +1677,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; } -- GitLab From 3c47df1dc85f9f81411743e370e612f4e4a9b46e Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 17 Feb 2020 19:19:05 +0530 Subject: [PATCH 135/295] msm: camera: ope: Synchronize flush and submit BLs In stability, Flush and submit can run in parallel. This can cause submit to fail for a given request. Avoid submitted new request if it is lesss than last flush request. CRs-Fixed: 2622981 Change-Id: Idf94e39d8cd74f25cc05c8211301e9c172b8a88a Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 29 ++++++++++++++++++--- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 2 ++ 2 files changed, 28 insertions(+), 3 deletions(-) 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 8adbe52a6f40..607e265cc1be 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 @@ -97,6 +97,17 @@ static int cam_ope_mgr_process_cmd(void *priv, void *data) CAM_DBG(CAM_OPE, "cam_cdm_submit_bls: handle = %u", ctx_data->ope_cdm.cdm_handle); + + 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); + 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) @@ -2454,6 +2465,7 @@ 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); @@ -2842,8 +2854,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); @@ -2902,6 +2915,12 @@ 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; @@ -2995,6 +3014,7 @@ static int cam_ope_mgr_flush_all(struct cam_ope_ctx *ctx_data, rc = cam_cdm_flush_hw(ctx_data->ope_cdm.cdm_handle); + mutex_lock(&hw_mgr->hw_mgr_mutex); mutex_lock(&ctx_data->ctx_mutex); for (i = 0; i < hw_mgr->num_ope; i++) { rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( @@ -3017,6 +3037,7 @@ static int cam_ope_mgr_flush_all(struct cam_ope_ctx *ctx_data, clear_bit(i, ctx_data->bitmap); } mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); return rc; } @@ -3044,8 +3065,10 @@ 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); + 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); switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: 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 c8a60215ab66..8e8ec020f575 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 @@ -439,6 +439,7 @@ struct cam_ope_cdm { * @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; @@ -460,6 +461,7 @@ struct cam_ope_ctx { 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; }; /** -- GitLab From dfb3fc66e34e9be431e626533aed67c8272c50c0 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 17 Feb 2020 20:35:26 +0530 Subject: [PATCH 136/295] msm: camera: cdm: Protect cdm reset status CDM reset and submit BL callbacks can run in parallel. As submit BL callback is relying on cdm reset bit status so this condition can fail incase CDM reset also run in parallel. Protect cdm reset bit status by lock. CRs-Fixed: 2622981 Change-Id: Iecf001fd8d3861d7a96428c4013fc2e6fd16bad0 Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 91ca4f2561cd..0e7036780796 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1269,12 +1269,12 @@ int cam_hw_cdm_reset_hw(struct cam_hw_info *cdm_hw, uint32_t handle) 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); + reinit_completion(&cdm_core->reset_complete); + 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)); @@ -1336,11 +1336,10 @@ int cam_hw_cdm_handle_error_info( cdm_core = (struct cam_cdm *)cdm_hw->core_info; - 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); + 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); -- GitLab From 40db69163bbe4bf662ace7010f4ca761b930d255 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 17 Feb 2020 23:59:08 +0530 Subject: [PATCH 137/295] msm: camera: cdm: Handle cdm deinit sequence properly As per recommendation, cdm reset should be done before cdm power collapse to make sure it is in proper state. CRs-Fixed: 2604473 Change-Id: I35994e0f415b58ce1adad2a208e5fa83f46a3c62 Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 46 +++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 0e7036780796..2adb11ea2c1c 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1587,13 +1587,55 @@ 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; 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; + + /*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); + reinit_completion(&cdm_core->reset_complete); + + 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); + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); if (rc) { CAM_ERR(CAM_CDM, "disable platform failed"); -- GitLab From 16a8981b1cf786060248b71e73f60ccb98219477 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Wed, 19 Feb 2020 16:29:45 +0530 Subject: [PATCH 138/295] msm: camera: tfe: Reduce reset timeout to 100ms Reduce reset timeout to 100ms and also added converting msec to jiffies logic for this 100ms reset timeout value. CRs-Fixed: 2624883 Change-Id: Ibb4841bf45ee505b33480ef32445754095870f0d Signed-off-by: Shravya Samala --- drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 994ad12ad709..b57b17265c2c 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 @@ -2212,8 +2212,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); -- GitLab From 8850eb548e8db4226bb33b1ad227857b7efe78b1 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Wed, 18 Dec 2019 15:53:50 -0800 Subject: [PATCH 139/295] msm: camera: sensor: Add Init setting retry in case cci is resetting If any subdev is reporting Nack, cci hardware gets into resetting. During resetting if sensor tries to apply Init setting, it fails. This change adds retry for INIT setting to reapply after sometime. CRs-Fixed: 2598605 Change-Id: Iff13014d74abe6aebaec6cd428811de9d865f090 Signed-off-by: Jigarkumar Zala --- .../cam_actuator/cam_actuator_core.c | 15 ++++++++++--- .../cam_flash/cam_flash_core.c | 10 +++++++++ .../cam_sensor_module/cam_ois/cam_ois_core.c | 14 ++++++++++-- .../cam_sensor/cam_sensor_core.c | 22 +++++++++++++++---- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c index d886d8ebaecb..0b6e25572e90 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.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 @@ -957,10 +957,19 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, ACT_APPLY_SETTINGS_NOW) { rc = cam_actuator_apply_settings(a_ctrl, &a_ctrl->i2c_data.init_settings); + if ((rc == -EAGAIN) && + (a_ctrl->io_master_info.master_type == CCI_MASTER)) { + CAM_WARN(CAM_ACTUATOR, + "CCI HW is in resetting mode:: Reapplying Init settings"); + usleep_range(1000, 1010); + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.init_settings); + } + if (rc < 0) CAM_ERR(CAM_ACTUATOR, - "Cannot apply Update settings"); - + "Failed to apply Init settings: rc = %d", + rc); /* Delete the request even if the apply is failed */ rc = delete_request(&a_ctrl->i2c_data.init_settings); if (rc < 0) { 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 daa55420becf..0e1440d13b46 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -662,6 +662,16 @@ int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, list) { rc = cam_sensor_util_i2c_apply_setting (&(fctrl->io_master_info), i2c_list); + if ((rc == -EAGAIN) && + (fctrl->io_master_info.master_type == + CCI_MASTER)) { + CAM_WARN(CAM_FLASH, + "CCI HW is in reset mode: Reapplying Init settings"); + usleep_range(1000, 1010); + rc = cam_sensor_util_i2c_apply_setting + (&(fctrl->io_master_info), i2c_list); + } + if (rc) { CAM_ERR(CAM_FLASH, "Failed to apply init settings: %d", diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 8ced8a28c309..6a1ccbd4aa11 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.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 @@ -586,8 +586,18 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) } rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_init_data); + if ((rc == -EAGAIN) && + (o_ctrl->io_master_info.master_type == CCI_MASTER)) { + CAM_WARN(CAM_OIS, + "CCI HW is restting: Reapplying INIT settings"); + usleep_range(1000, 1010); + rc = cam_ois_apply_settings(o_ctrl, + &o_ctrl->i2c_init_data); + } if (rc < 0) { - CAM_ERR(CAM_OIS, "Cannot apply Init settings"); + CAM_ERR(CAM_OIS, + "Cannot apply Init settings: rc = %d", + rc); goto pwr_dwn; } diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 37f62fe95246..696bbd3b90cb 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -644,7 +644,7 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, void *arg) { - int rc = 0; + int rc = 0, pkt_opcode = 0; struct cam_control *cmd = (struct cam_control *)arg; struct cam_sensor_power_ctrl_t *power_info = &s_ctrl->sensordata->power_info; @@ -932,14 +932,28 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, if (s_ctrl->i2c_data.init_settings.is_settings_valid && (s_ctrl->i2c_data.init_settings.request_id == 0)) { + pkt_opcode = + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG; rc = cam_sensor_apply_settings(s_ctrl, 0, - CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG); - + pkt_opcode); + + if ((rc == -EAGAIN) && + (s_ctrl->io_master_info.master_type == CCI_MASTER)) { + /* If CCI hardware is resetting we need to wait + * for sometime before reapply + */ + CAM_WARN(CAM_SENSOR, + "Reapplying the Init settings due to cci hw reset"); + usleep_range(1000, 1010); + rc = cam_sensor_apply_settings(s_ctrl, 0, + pkt_opcode); + } s_ctrl->i2c_data.init_settings.request_id = -1; if (rc < 0) { CAM_ERR(CAM_SENSOR, - "cannot apply init settings"); + "cannot apply init settings rc= %d", + rc); delete_request(&s_ctrl->i2c_data.init_settings); goto release_mutex; } -- GitLab From 975b3600974f4b47b20636b487107db61ada5fc2 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Tue, 18 Feb 2020 17:37:10 +0530 Subject: [PATCH 140/295] msm: camera: ope: Fix hang detection There is some inaccuracy in timer due to low HZ value. Due to which, sometime we are treating real hang as false alarm. This results into LDAR due to no response from kernel. Taking error margin into consideration while taking decission related to false alarm based on time. CRs-Fixed: 2621928 Change-Id: I3285e18094863903329057eb44f677d62ad1bff0 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8adbe52a6f40..bbb9a937d7c7 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 @@ -326,7 +326,7 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) ts_ns = (uint64_t)((ts.tv_sec * 1000000000) + ts.tv_nsec); if (ts_ns - ctx_data->last_req_time < - OPE_REQUEST_TIMEOUT * 1000000) { + ((OPE_REQUEST_TIMEOUT - OPE_REQUEST_TIMEOUT / 10) * 1000000)) { mutex_unlock(&ctx_data->ctx_mutex); return 0; } -- GitLab From 3de05cba2fdb02187a2d72e856b3341a7c73844e Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Thu, 20 Feb 2020 13:04:55 +0530 Subject: [PATCH 141/295] msm: camera: ope: Make non-fatal logs as debug and info logs Make non-fatal logs as debug and info logs. CRs-Fixed: 2607887 Change-Id: I746b4da8b0cd29f42369ed3d976fa39d8a999b19 Signed-off-by: Shravya Samala --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 63 ++++++++++++++----- .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 2 +- 2 files changed, 47 insertions(+), 18 deletions(-) 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 607e265cc1be..e9dd19023ce7 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 @@ -1198,27 +1198,30 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, return; } - CAM_DBG(CAM_OPE, "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_INFO(CAM_OPE, "Request not present reqIdx = %d", cookie); + 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]; + 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", + ope_req->request_id, ctx->ctx_id); + 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; @@ -1238,8 +1241,9 @@ 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); rc = cam_ope_mgr_reset_hw(); @@ -1364,9 +1368,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, @@ -2299,6 +2307,7 @@ 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: @@ -2716,14 +2725,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; } @@ -2731,7 +2744,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; } @@ -2749,6 +2763,8 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, 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; @@ -2761,6 +2777,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; @@ -2770,7 +2788,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; } @@ -2778,7 +2798,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; } @@ -2786,7 +2808,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; } @@ -2794,7 +2818,9 @@ 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; @@ -2804,6 +2830,8 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, 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: @@ -2925,7 +2953,8 @@ static int cam_ope_mgr_config_hw(void *hw_priv, void *hw_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); 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 8422e3dcc862..d58d4dd5e94a 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 @@ -820,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) == -- GitLab From c928f229e3c84ac30cbe882f4e8364753a709b8c Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Fri, 21 Feb 2020 10:04:10 +0530 Subject: [PATCH 142/295] msm: camera: tfe: set overflow pending bit to zero after HW reset In dual tfe case,in flush operation, while stopping tfe hardwares a race condition can occur on one tfe while other got stopped, this will result in overflow condition for this tfe. This overflow error will set overflow pending bit set for the hardware manager context. After stop, tfe reset hw will be performed. Set the overflow pending bit to zero after hw reset. CRs-Fixed: 2624562 Change-Id: I780212c3cae1f96207b457cba3cfae8af7be843f Signed-off-by: Shravya Samala --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 1 + 1 file changed, 1 insertion(+) 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 a387736ea3bb..322d75fe0f30 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 @@ -3017,6 +3017,7 @@ static int cam_tfe_mgr_reset(void *hw_mgr_priv, void *hw_reset_args) } } + atomic_set(&ctx->overflow_pending, 0); end: return rc; } -- GitLab From 207db39162222c8462ae1debba491a14fa35f22e Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Thu, 20 Feb 2020 12:25:17 +0530 Subject: [PATCH 143/295] msm: camera: ope: Do not disable CDM during error handling Currently, CDM is paused and disabled during error handling. Due to which, there is a possiblity of HW going to error state. Avoiding disable of CDM while pausing during error handling. CRs-Fixed: 2624707 Change-Id: I8b0bdf8dc1bb777a086026c0f28b1c04b5342a3c Signed-off-by: Rishabh Jain --- drivers/cam_cdm/cam_cdm_hw_core.c | 33 +++++++++++++------------------ 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 715ee808510e..15a816a7bfa4 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -128,26 +128,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; } @@ -309,7 +304,7 @@ void cam_hw_cdm_dump_core_debug_registers( CAM_ERR(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_hw_cdm_pause_core(cdm_hw, true); cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->debug_status, @@ -378,8 +373,8 @@ 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); + /* Resume CDM back */ + cam_hw_cdm_pause_core(cdm_hw, false); } enum cam_cdm_arbitration cam_cdm_get_arbitration_type( @@ -1344,7 +1339,7 @@ int cam_hw_cdm_handle_error_info( 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_enable_core(cdm_hw, false); + cam_hw_cdm_pause_core(cdm_hw, true); rc = cam_cdm_read_hw_reg(cdm_hw, cdm_core->offsets->cmn_reg->current_bl_len, -- GitLab From 2ab1fc0d40002e239041f849ead60596ab74ba7e Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Tue, 14 Jan 2020 15:53:54 -0800 Subject: [PATCH 144/295] msm: camera: req_mgr: Reduce maximum attempts to apply request This change reduces the maximum attempts to apply a particular request from three to two. After two failed attempts to apply to ISP device, IRQs for ISP device will be overlapped from two requests. Thereafter apply request at every alternate frame will fail without a chance of recovery. Therefore we must notify userspace to trigger recover on the link. CRs-Fixed: 2606911 Change-Id: I526bb837a496fe1e67786b854c5afb062dddb918 Signed-off-by: Venkat Chinta --- drivers/cam_req_mgr/cam_req_mgr_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index a52a652d1d6a..09f95e7072ed 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -34,7 +34,7 @@ #define MAXIMUM_LINKS_PER_SESSION 4 -#define MAXIMUM_RETRY_ATTEMPTS 3 +#define MAXIMUM_RETRY_ATTEMPTS 2 #define VERSION_1 1 #define VERSION_2 2 -- GitLab From 783df236ff15bd363f663ecd462916b104236b15 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 19 Dec 2019 16:00:05 -0800 Subject: [PATCH 145/295] msm: camera: ife: Disable clock gating at top Clock gating must be disabled at top level initialize hardware routine as VFE is reset after resource level initialize hardware routine. CRs-Fixed: 2590331 Change-Id: I5c51c402a3a6076f056368493b774daa199228aa Signed-off-by: Venkat Chinta --- .../isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 14 -------------- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 03dcf8cedbc3..e4187935b2b0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -293,20 +293,6 @@ static int cam_vfe_camif_ver3_resource_init( "failed to enable dsp clk, rc = %d", rc); } - /* All auto clock gating disabled by default */ - CAM_INFO(CAM_ISP, "overriding clock gating"); - cam_io_w_mb(0xFFFFFFFF, camif_data->mem_base + - camif_data->common_reg->core_cgc_ovd_0); - - cam_io_w_mb(0xFF, camif_data->mem_base + - camif_data->common_reg->core_cgc_ovd_1); - - cam_io_w_mb(0x1, camif_data->mem_base + - camif_data->common_reg->ahb_cgc_ovd); - - cam_io_w_mb(0x1, camif_data->mem_base + - camif_data->common_reg->noc_cgc_ovd); - return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index 743950bd01bc..2bd393fc97a8 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -222,9 +222,24 @@ int cam_vfe_top_ver3_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size) { struct cam_vfe_top_ver3_priv *top_priv = device_priv; + struct cam_vfe_top_ver3_common_data common_data = top_priv->common_data; top_priv->hw_clk_rate = 0; + /* Disable clock gating at IFE top */ + CAM_INFO(CAM_ISP, "Disable clock gating at IFE top"); + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->core_cgc_ovd_0, 0xFFFFFFFF); + + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->core_cgc_ovd_1, 0xFF); + + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->ahb_cgc_ovd, 0x1); + + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->noc_cgc_ovd, 0x1); + return 0; } -- GitLab From 43b257b29fed7a3f5a295cf4fb9304192843b26d Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Tue, 14 Jan 2020 14:44:43 +0530 Subject: [PATCH 146/295] msm: camera: req_mgr: Update link activate/deactivate to avoid race When cam request manager gets a request to deactivate a link, we do pause for each of the device for that link. There is a race here in current scenario that workqueues can be scheduled even after the link has been deactivated. This can lead to unexpected behavior. This change has updated the activate and deactivate handling to take care of the race. CRs-Fixed: 2601863 Change-Id: I7ff03c74c240fc3250618db518d586531d87369f Signed-off-by: Vikram Sharma --- drivers/cam_req_mgr/cam_req_mgr_core.c | 94 +++++++++++++++----------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 5629218b4cb4..e1db980c78b9 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -535,32 +535,40 @@ static void __cam_req_mgr_validate_crm_wd_timer( CAM_DBG(CAM_CRM, "rd_idx: %d idx: %d current_frame_timeout: %d ms", in_q->rd_idx, idx, current_frame_timeout); - - if ((next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT) > - link->watchdog->expires) { - CAM_DBG(CAM_CRM, - "Modifying wd timer expiry from %d ms to %d ms", - link->watchdog->expires, - (next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); - crm_timer_modify(link->watchdog, - next_frame_timeout + - CAM_REQ_MGR_WATCHDOG_TIMEOUT); - } else if (current_frame_timeout) { - CAM_DBG(CAM_CRM, - "Reset wd timer to current frame from %d ms to %d ms", - link->watchdog->expires, - (current_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); - crm_timer_modify(link->watchdog, - current_frame_timeout + - CAM_REQ_MGR_WATCHDOG_TIMEOUT); - } else if (link->watchdog->expires > - CAM_REQ_MGR_WATCHDOG_TIMEOUT) { - CAM_DBG(CAM_CRM, - "Reset wd timer to default from %d ms to %d ms", - link->watchdog->expires, CAM_REQ_MGR_WATCHDOG_TIMEOUT); - crm_timer_modify(link->watchdog, - CAM_REQ_MGR_WATCHDOG_TIMEOUT); + spin_lock_bh(&link->link_state_spin_lock); + if (link->watchdog) { + if ((next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT) > + link->watchdog->expires) { + CAM_DBG(CAM_CRM, + "Modifying wd timer expiry from %d ms to %d ms", + link->watchdog->expires, + (next_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + next_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (current_frame_timeout) { + CAM_DBG(CAM_CRM, + "Reset wd timer to frame from %d ms to %d ms", + link->watchdog->expires, + (current_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + current_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (link->watchdog->expires > + CAM_REQ_MGR_WATCHDOG_TIMEOUT) { + CAM_DBG(CAM_CRM, + "Reset wd timer to default from %d ms to %d ms", + link->watchdog->expires, + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + crm_timer_modify(link->watchdog, + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } + } else { + CAM_WARN(CAM_CRM, "Watchdog timer exited already"); } + spin_unlock_bh(&link->link_state_spin_lock); } /** @@ -1720,6 +1728,14 @@ static int __cam_req_mgr_process_sof_freeze(void *priv, void *data) link = (struct cam_req_mgr_core_link *)priv; session = (struct cam_req_mgr_core_session *)link->parent; + spin_lock_bh(&link->link_state_spin_lock); + if ((link->watchdog) && (link->watchdog->pause_timer)) { + CAM_INFO(CAM_CRM, "Watchdog Paused"); + spin_unlock_bh(&link->link_state_spin_lock); + return rc; + } + spin_unlock_bh(&link->link_state_spin_lock); + CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x", session->session_hdl, link->link_hdl); @@ -1764,9 +1780,6 @@ static void __cam_req_mgr_sof_freeze(struct timer_list *timer_data) link = (struct cam_req_mgr_core_link *)timer->parent; - if (link->watchdog->pause_timer) - return; - task = cam_req_mgr_workq_get_task(link->workq); if (!task) { CAM_ERR(CAM_CRM, "No empty task"); @@ -2753,11 +2766,9 @@ static int cam_req_mgr_cb_notify_timer( rc = -EPERM; goto end; } - spin_unlock_bh(&link->link_state_spin_lock); - - - if (!timer_data->state) + if ((link->watchdog) && (!timer_data->state)) link->watchdog->pause_timer = true; + spin_unlock_bh(&link->link_state_spin_lock); end: return rc; @@ -2865,7 +2876,7 @@ static int cam_req_mgr_cb_notify_trigger( goto end; } - if (link->watchdog->pause_timer) + if ((link->watchdog) && (link->watchdog->pause_timer)) link->watchdog->pause_timer = false; crm_timer_reset(link->watchdog); @@ -3152,14 +3163,15 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) /* Destroy workq of link */ cam_req_mgr_workq_destroy(&link->workq); - + spin_lock_bh(&link->link_state_spin_lock); /* Destroy timer of link */ crm_timer_exit(&link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); /* Cleanup request tables and unlink devices */ __cam_req_mgr_destroy_link_info(link); - /* Free memory holding data of linked devs */ + __cam_req_mgr_destroy_subdev(link->l_dev); /* Destroy the link handle */ @@ -3787,6 +3799,9 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) mutex_lock(&link->lock); if (control->ops == CAM_REQ_MGR_LINK_ACTIVATE) { + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + spin_unlock_bh(&link->link_state_spin_lock); /* Start SOF watchdog timer */ rc = crm_timer_init(&link->watchdog, CAM_REQ_MGR_WATCHDOG_TIMEOUT_DEFAULT, link, @@ -3808,10 +3823,6 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) dev->ops->process_evt(&evt_data); } } else if (control->ops == CAM_REQ_MGR_LINK_DEACTIVATE) { - /* Destroy SOF watchdog timer */ - spin_lock_bh(&link->link_state_spin_lock); - crm_timer_exit(&link->watchdog); - spin_unlock_bh(&link->link_state_spin_lock); /* notify nodes */ for (j = 0; j < link->num_devs; j++) { dev = &link->l_dev[j]; @@ -3822,6 +3833,11 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) if (dev->ops && dev->ops->process_evt) dev->ops->process_evt(&evt_data); } + /* Destroy SOF watchdog timer */ + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_IDLE; + crm_timer_exit(&link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); } else { CAM_ERR(CAM_CRM, "Invalid link control command"); rc = -EINVAL; -- GitLab From 983037614b26c87fc9a434b85e57086f8cf824d5 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 8 Jan 2020 19:04:51 -0800 Subject: [PATCH 147/295] msm: camera: custom: Add support for immediate stop Add support for immediate stop and reset during flush for custom HW. CRs-Fixed: 2585745 Change-Id: I542ac02f8d99c194efa498bc07dffae7879a6c8a Signed-off-by: Karthik Anantha Ram --- drivers/cam_cust/cam_custom_context.c | 227 +++++++++++++----- .../cam_custom_hw_mgr/cam_custom_hw_mgr.c | 99 +++++++- 2 files changed, 268 insertions(+), 58 deletions(-) diff --git a/drivers/cam_cust/cam_custom_context.c b/drivers/cam_cust/cam_custom_context.c index 3e69ebd15109..25e092841cef 100644 --- a/drivers/cam_cust/cam_custom_context.c +++ b/drivers/cam_cust/cam_custom_context.c @@ -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. */ #include @@ -24,6 +24,10 @@ static const char custom_dev_name[] = "cam-custom"; static int __cam_custom_ctx_handle_irq_in_activated( void *context, uint32_t evt_id, void *evt_data); +static int __cam_custom_ctx_start_dev_in_ready( + struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); + + static int __cam_custom_ctx_enqueue_request_in_order( struct cam_context *ctx, struct cam_ctx_request *req) { @@ -131,22 +135,104 @@ static int __cam_custom_ctx_flush_req(struct cam_context *ctx, return 0; } +static int __cam_custom_ctx_unlink_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + + return 0; +} + +static int __cam_custom_ctx_unlink_in_ready(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->state = CAM_CTX_ACQUIRED; + + return 0; +} + +static int __cam_custom_ctx_get_dev_info_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_device_info *dev_info) +{ + dev_info->dev_hdl = ctx->dev_hdl; + strlcpy(dev_info->name, CAM_CUSTOM_DEV_NAME, sizeof(dev_info->name)); + dev_info->dev_id = CAM_REQ_MGR_DEVICE_CUSTOM_HW; + dev_info->p_delay = 1; + dev_info->trigger = CAM_TRIGGER_POINT_SOF; + + return 0; +} + static int __cam_custom_ctx_flush_req_in_top_state( struct cam_context *ctx, struct cam_req_mgr_flush_request *flush_req) { int rc = 0; + struct cam_custom_context *custom_ctx; + struct cam_hw_reset_args reset_args; + struct cam_hw_stop_args stop_args; + struct cam_custom_stop_args custom_stop; + + custom_ctx = + (struct cam_custom_context *) ctx->ctx_priv; + + CAM_DBG(CAM_CUSTOM, "Flushing pending list"); + spin_lock_bh(&ctx->lock); + __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + spin_unlock_bh(&ctx->lock); if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + if (ctx->state <= CAM_CTX_READY) { + ctx->state = CAM_CTX_ACQUIRED; + goto end; + } + + spin_lock_bh(&ctx->lock); + ctx->state = CAM_CTX_FLUSHED; + spin_unlock_bh(&ctx->lock); + CAM_INFO(CAM_CUSTOM, "Last request id to flush is %lld", flush_req->req_id); ctx->last_flush_req = flush_req->req_id; - } - spin_lock_bh(&ctx->lock); - rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); - spin_unlock_bh(&ctx->lock); + /* stop hw first */ + if (ctx->hw_mgr_intf->hw_stop) { + custom_stop.stop_only = true; + stop_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + stop_args.args = (void *) &custom_stop; + rc = ctx->hw_mgr_intf->hw_stop( + ctx->hw_mgr_intf->hw_mgr_priv, &stop_args); + if (rc) + CAM_ERR(CAM_CUSTOM, + "HW stop failed in flush rc %d", rc); + } + + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->wait_req_list)) + __cam_custom_ctx_flush_req(ctx, &ctx->wait_req_list, + flush_req); + if (!list_empty(&ctx->active_req_list)) + __cam_custom_ctx_flush_req(ctx, &ctx->active_req_list, + flush_req); + + custom_ctx->active_req_cnt = 0; + spin_unlock_bh(&ctx->lock); + + reset_args.ctxt_to_hw_map = custom_ctx->hw_ctx; + rc = ctx->hw_mgr_intf->hw_reset(ctx->hw_mgr_intf->hw_mgr_priv, + &reset_args); + if (rc) + CAM_ERR(CAM_CUSTOM, + "Reset HW failed in flush rc %d", rc); + + custom_ctx->init_received = false; + } + +end: return rc; } @@ -170,34 +256,27 @@ static int __cam_custom_ctx_flush_req_in_ready( return rc; } -static int __cam_custom_ctx_unlink_in_ready(struct cam_context *ctx, - struct cam_req_mgr_core_dev_link_setup *unlink) -{ - ctx->link_hdl = -1; - ctx->ctx_crm_intf = NULL; - ctx->state = CAM_CTX_ACQUIRED; - - return 0; -} - static int __cam_custom_stop_dev_core( struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd) { int rc = 0; uint32_t i; struct cam_custom_context *ctx_custom = - (struct cam_custom_context *) ctx->ctx_priv; - struct cam_ctx_request *req; - struct cam_custom_dev_ctx_req *req_custom; - struct cam_hw_stop_args stop; - - if (ctx_custom->hw_ctx) { + (struct cam_custom_context *) ctx->ctx_priv; + struct cam_ctx_request *req; + struct cam_custom_dev_ctx_req *req_custom; + struct cam_hw_stop_args stop; + struct cam_custom_stop_args custom_stop; + + if ((ctx->state != CAM_CTX_FLUSHED) && (ctx_custom->hw_ctx) && + (ctx->hw_mgr_intf->hw_stop)) { + custom_stop.stop_only = false; stop.ctxt_to_hw_map = ctx_custom->hw_ctx; - - stop.args = NULL; - if (ctx->hw_mgr_intf->hw_stop) - ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + stop.args = (void *) &custom_stop; + rc = ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, &stop); + if (rc) + CAM_ERR(CAM_CUSTOM, "HW stop failed rc %d", rc); } while (!list_empty(&ctx->pending_req_list)) { @@ -752,7 +831,9 @@ static int __cam_custom_ctx_config_dev(struct cam_context *ctx, CAM_ERR(CAM_CUSTOM, "Recevied INIT pkt in wrong state"); } } else { - if (ctx->state >= CAM_CTX_READY && ctx->ctx_crm_intf->add_req) { + if ((ctx->state != CAM_CTX_FLUSHED) && + (ctx->state >= CAM_CTX_READY) && + (ctx->ctx_crm_intf->add_req)) { add_req.link_hdl = ctx->link_hdl; add_req.dev_hdl = ctx->dev_hdl; add_req.req_id = req->request_id; @@ -796,6 +877,44 @@ static int __cam_custom_ctx_config_dev(struct cam_context *ctx, } +static int __cam_custom_ctx_config_dev_in_flushed(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + struct cam_start_stop_dev_cmd start_cmd; + struct cam_custom_context *custom_ctx = + (struct cam_custom_context *) ctx->ctx_priv; + + if (!custom_ctx->hw_acquired) { + CAM_ERR(CAM_CUSTOM, "HW is not acquired, reject packet"); + rc = -EINVAL; + goto end; + } + + rc = __cam_custom_ctx_config_dev(ctx, cmd); + if (rc) + goto end; + + if (!custom_ctx->init_received) { + CAM_WARN(CAM_CUSTOM, + "Received update packet in flushed state, skip start"); + goto end; + } + + start_cmd.dev_handle = cmd->dev_handle; + start_cmd.session_handle = cmd->session_handle; + rc = __cam_custom_ctx_start_dev_in_ready(ctx, &start_cmd); + if (rc) + CAM_ERR(CAM_CUSTOM, + "Failed to re-start HW after flush rc: %d", rc); + else + CAM_INFO(CAM_CUSTOM, + "Received init after flush. Re-start HW complete."); + +end: + return rc; +} + static int __cam_custom_ctx_config_dev_in_acquired(struct cam_context *ctx, struct cam_config_dev_cmd *cmd) { @@ -835,32 +954,11 @@ static int __cam_custom_ctx_link_in_acquired(struct cam_context *ctx, return 0; } -static int __cam_custom_ctx_unlink_in_acquired(struct cam_context *ctx, - struct cam_req_mgr_core_dev_link_setup *unlink) -{ - ctx->link_hdl = -1; - ctx->ctx_crm_intf = NULL; - - return 0; -} - -static int __cam_custom_ctx_get_dev_info_in_acquired(struct cam_context *ctx, - struct cam_req_mgr_device_info *dev_info) -{ - dev_info->dev_hdl = ctx->dev_hdl; - strlcpy(dev_info->name, CAM_CUSTOM_DEV_NAME, sizeof(dev_info->name)); - dev_info->dev_id = CAM_REQ_MGR_DEVICE_CUSTOM_HW; - dev_info->p_delay = 1; - dev_info->trigger = CAM_TRIGGER_POINT_SOF; - - return 0; -} - static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; - struct cam_hw_config_args hw_config; + struct cam_custom_start_args custom_start; struct cam_ctx_request *req; struct cam_custom_dev_ctx_req *req_custom; struct cam_custom_context *ctx_custom = @@ -889,16 +987,20 @@ static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx, goto end; } - hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx; - hw_config.request_id = req->request_id; - hw_config.hw_update_entries = req_custom->cfg; - hw_config.num_hw_update_entries = req_custom->num_cfg; - hw_config.priv = &req_custom->hw_update_data; - hw_config.init_packet = 1; + custom_start.hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx; + custom_start.hw_config.request_id = req->request_id; + custom_start.hw_config.hw_update_entries = req_custom->cfg; + custom_start.hw_config.num_hw_update_entries = req_custom->num_cfg; + custom_start.hw_config.priv = &req_custom->hw_update_data; + custom_start.hw_config.init_packet = 1; + if (ctx->state == CAM_CTX_FLUSHED) + custom_start.start_only = true; + else + custom_start.start_only = false; ctx->state = CAM_CTX_ACTIVATED; rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, - &hw_config); + &custom_start); if (rc) { /* HW failure. User need to clean up the resource */ CAM_ERR(CAM_CUSTOM, "Start HW failed"); @@ -1064,7 +1166,20 @@ static struct cam_ctx_ops .pagefault_ops = NULL, }, /* Flushed */ - {}, + { + .ioctl_ops = { + .stop_dev = __cam_custom_stop_dev_in_activated, + .release_dev = + __cam_custom_ctx_release_dev_in_activated, + .config_dev = __cam_custom_ctx_config_dev_in_flushed, + .release_hw = + __cam_custom_ctx_release_hw_in_activated_state, + }, + .crm_ops = { + .unlink = __cam_custom_ctx_unlink_in_ready, + }, + .irq_ops = NULL, + }, /* Activated */ { .ioctl_ops = { diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c index f2e5a1ff3407..2fed429ad13a 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c @@ -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. */ #include @@ -220,6 +220,7 @@ static int cam_custom_hw_mgr_stop_hw_res( static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) { int rc = 0; + struct cam_custom_stop_args *custom_args; struct cam_hw_stop_args *stop_args = stop_hw_args; struct cam_custom_hw_mgr_res *hw_mgr_res; struct cam_custom_hw_mgr_ctx *ctx; @@ -229,6 +230,7 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) return -EINVAL; } + custom_args = (struct cam_custom_stop_args *)stop_args->args; ctx = (struct cam_custom_hw_mgr_ctx *) stop_args->ctxt_to_hw_map; @@ -261,6 +263,9 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) /* stop custom hw here */ + if (custom_args->stop_only) + goto end; + /* Deinit custom cid here */ list_for_each_entry(hw_mgr_res, &ctx->res_list_custom_cid, list) { @@ -282,6 +287,7 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) /* deinit custom rsrc */ +end: return rc; } @@ -357,13 +363,19 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, struct cam_hw_stop_args stop_args; struct cam_custom_hw_mgr_res *hw_mgr_res; struct cam_custom_hw_mgr_ctx *ctx; + struct cam_custom_stop_args custom_stop_args; + struct cam_custom_start_args *custom_args; if (!hw_mgr_priv || !start_hw_args) { CAM_ERR(CAM_CUSTOM, "Invalid arguments"); return -EINVAL; } - hw_config = (struct cam_hw_config_args *)start_hw_args; + custom_args = + (struct cam_custom_start_args *)start_hw_args; + + hw_config = (struct cam_hw_config_args *) + &custom_args->hw_config; ctx = (struct cam_custom_hw_mgr_ctx *) hw_config->ctxt_to_hw_map; @@ -375,6 +387,9 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, CAM_DBG(CAM_CUSTOM, "Enter... ctx id:%d", ctx->ctx_index); + if (custom_args->start_only) + goto start_only; + /* Init custom cid */ list_for_each_entry(hw_mgr_res, &ctx->res_list_custom_cid, list) { @@ -402,6 +417,8 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, /* Apply init config */ +start_only: + /* Start custom HW first */ if (rc < 0) goto err; @@ -432,6 +449,8 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, return 0; err: + custom_stop_args.stop_only = false; + stop_args.args = (void *) &custom_stop_args; stop_args.ctxt_to_hw_map = hw_config->ctxt_to_hw_map; cam_custom_mgr_stop_hw(hw_mgr_priv, &stop_args); deinit_hw: @@ -1113,6 +1132,81 @@ static int cam_custom_mgr_prepare_hw_update(void *hw_mgr_priv, return 0; } +static int cam_custom_hw_mgr_reset_csid_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_csid_reset_cfg_args csid_reset_args; + struct cam_isp_resource_node *custom_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + custom_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!custom_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + csid_reset_args.reset_type = CAM_IFE_CSID_RESET_PATH; + csid_reset_args.node_res = custom_rsrc_node; + hw_intf = custom_rsrc_node->hw_intf; + if (hw_intf->hw_ops.reset) { + CAM_DBG(CAM_CUSTOM, "RESET HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.reset(hw_intf->hw_priv, + &csid_reset_args, + sizeof(struct cam_csid_reset_cfg_args)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_ERR(CAM_CUSTOM, + "RESET HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_hw_mgr_reset( + void *hw_mgr_priv, void *hw_reset_args) +{ + struct cam_hw_reset_args *reset_args = + hw_reset_args; + struct cam_custom_hw_mgr_ctx *ctx; + struct cam_custom_hw_mgr_res *hw_mgr_res; + int rc = 0; + + if (!hw_mgr_priv || !hw_reset_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_custom_hw_mgr_ctx *) + reset_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_CUSTOM, "Reset SBI CSID and SBI core"); + list_for_each_entry(hw_mgr_res, &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_reset_csid_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, + "Failed to reset CSID:%d rc: %d", + hw_mgr_res->res_id, rc); + goto end; + } + } + + /* Reset SBI HW */ + +end: + return rc; +} + static int cam_custom_mgr_config_hw(void *hw_mgr_priv, void *hw_config_args) { @@ -1279,6 +1373,7 @@ int cam_custom_hw_mgr_init(struct device_node *of_node, hw_mgr_intf->hw_release = cam_custom_mgr_release_hw; hw_mgr_intf->hw_prepare_update = cam_custom_mgr_prepare_hw_update; hw_mgr_intf->hw_config = cam_custom_mgr_config_hw; + hw_mgr_intf->hw_reset = cam_custom_hw_mgr_reset; if (iommu_hdl) *iommu_hdl = g_custom_hw_mgr.img_iommu_hdl; -- GitLab From 74c685de081b3bee09446ff7d44de1a77e685bfc Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 11 Dec 2019 13:12:58 -0800 Subject: [PATCH 148/295] msm: camera: ife: Stop hardware in error This change adds logic to stop IFE hardware in case of hardware errors. CRs-Fixed: 2590331 Change-Id: I86773cc44ce890cea47f19f0482761e686b0cd00 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 23 +++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) 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 e94664879573..ccdc046649eb 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 @@ -6149,6 +6149,9 @@ static int cam_ife_mgr_process_recovery_cb(void *priv, void *data) } } + if (!g_ife_hw_mgr.debug_cfg.enable_recovery) + break; + CAM_DBG(CAM_ISP, "RESET: CSID PATH"); for (i = 0; i < recovery_data->no_of_context; i++) { ctx = recovery_data->affected_ctx[i]; @@ -6377,22 +6380,12 @@ static int cam_ife_hw_mgr_handle_hw_err( rc = cam_ife_hw_mgr_find_affected_ctx(&error_event_data, core_idx, &recovery_data); - if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT) - return rc; - - if (g_ife_hw_mgr.debug_cfg.enable_recovery) { - CAM_DBG(CAM_ISP, "IFE Mgr recovery is enabled"); + if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) + recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; + else + recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; - /* Trigger for recovery */ - if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) - recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; - else - recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; - cam_ife_hw_mgr_do_error_recovery(&recovery_data); - } else { - CAM_DBG(CAM_ISP, "recovery is not enabled"); - rc = 0; - } + cam_ife_hw_mgr_do_error_recovery(&recovery_data); return rc; } -- GitLab From a1c2e500a359e755d81232f1e106f65a1883a3db Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 11 Oct 2019 15:39:42 -0700 Subject: [PATCH 149/295] msm: camera: reqmgr: Reduce delay by one frame during bubble recovery The EPOCH at which bubble is detected no setting is applied to any device. This change will trigger applying the bubbled setting to the device with highest pipeline delay. CRs-Fixed: 2564669 Change-Id: I180b4a1d2d29267f330546b8860a099baf1688e9 Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/cam_isp_context.c | 15 +++++++++++ drivers/cam_req_mgr/cam_req_mgr_core.c | 30 +++++++++++++++++++++ drivers/cam_req_mgr/cam_req_mgr_interface.h | 6 +++++ 3 files changed, 51 insertions(+) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index cd0a0f8ae95a..c0cd56a7c41a 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1317,6 +1317,11 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; + notify.trigger = 0; + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.frame_id = ctx_isp->frame_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; CAM_WARN(CAM_ISP, "Notify CRM about Bubble req %lld frame %lld, ctx %u", req->request_id, ctx_isp->frame_id, ctx->ctx_id); @@ -1495,6 +1500,11 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; + notify.trigger = 0; + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.frame_id = ctx_isp->frame_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; CAM_WARN(CAM_REQ, "Notify CRM about Bubble req_id %llu frame %lld, ctx %u", req->request_id, ctx_isp->frame_id, ctx->ctx_id); @@ -3003,6 +3013,11 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; + notify.trigger = 0; + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.frame_id = ctx_isp->frame_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; CAM_WARN(CAM_ISP, "Notify CRM about Bubble req %lld frame %lld ctx %u", req->request_id, diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index e1db980c78b9..1341d74974ed 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -2342,6 +2342,35 @@ int cam_req_mgr_process_add_req(void *priv, void *data) return rc; } +/** + * __cam_req_mgr_apply_on_bubble() + * + * @brief : This API tries to apply settings to the device + * with highest pd on the bubbled frame + * @link : link information. + * @err_info : contains information about frame_id, trigger etc. + * + */ +void __cam_req_mgr_apply_on_bubble( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_error_notify *err_info) +{ + int rc = 0; + struct cam_req_mgr_trigger_notify trigger_data; + + trigger_data.dev_hdl = err_info->dev_hdl; + trigger_data.frame_id = err_info->frame_id; + trigger_data.link_hdl = err_info->link_hdl; + trigger_data.sof_timestamp_val = + err_info->sof_timestamp_val; + trigger_data.trigger = err_info->trigger; + + rc = __cam_req_mgr_process_req(link, &trigger_data); + if (rc) + CAM_ERR(CAM_CRM, + "Failed to apply request on bubbled frame"); +} + /** * cam_req_mgr_process_error() * @@ -2432,6 +2461,7 @@ int cam_req_mgr_process_error(void *priv, void *data) link->state = CAM_CRM_LINK_STATE_ERR; spin_unlock_bh(&link->link_state_spin_lock); link->open_req_cnt++; + __cam_req_mgr_apply_on_bubble(link, err_info); } } mutex_unlock(&link->req.lock); diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index de3a4606be1d..7c184d675c6f 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -239,12 +239,18 @@ struct cam_req_mgr_timer_notify { * @link_hdl : link identifier * @dev_hdl : device handle which has sent this req id * @req_id : req id which hit error + * @frame_id : frame id for internal tracking + * @trigger : trigger point of this notification, CRM will send apply + * @sof_timestamp_val : Captured time stamp value at sof hw event * @error : what error device hit while processing this req */ struct cam_req_mgr_error_notify { int32_t link_hdl; int32_t dev_hdl; uint64_t req_id; + int64_t frame_id; + uint32_t trigger; + uint64_t sof_timestamp_val; enum cam_req_mgr_device_error error; }; -- GitLab From 82ebc5e7478819919f90af18e6c4d71e04301604 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Tue, 28 Jan 2020 15:08:08 +0530 Subject: [PATCH 150/295] msm: camera: ope: Add support for OPE Replay Add support for OPE Replay by dumping the required information to Debug buffer. CRs-Fixed: 2624540 Change-Id: I44a8e46f6dab3ddca960fbb5071ab53fa6e7d869 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 265 +++++++++++++++++++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 66 +++++ 2 files changed, 330 insertions(+), 1 deletion(-) 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 607e265cc1be..71c704e1bb75 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 @@ -302,6 +302,267 @@ static int32_t cam_ope_mgr_process_msg(void *priv, void *data) 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)) { + CAM_ERR(CAM_OPE, "OPE debug buf is invalid"); + 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 int32_t cam_ope_process_request_timer(void *priv, void *data) { struct ope_clk_work_data *clk_data = (struct ope_clk_work_data *)data; @@ -1242,6 +1503,7 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, handle, userdata, status, cookie, ope_req->request_id); CAM_ERR(CAM_OPE, "Rst of CDM and OPE for error reqid = %lld", ope_req->request_id); + cam_ope_dump_req_data(ope_req); rc = cam_ope_mgr_reset_hw(); flag = true; } @@ -2801,7 +3063,8 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, 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); return rc; 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 8e8ec020f575..e2f2b025bb21 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 @@ -385,6 +385,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; @@ -404,6 +405,7 @@ struct cam_ope_request { 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; }; /** @@ -524,4 +526,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 */ -- GitLab From f8681d76a9c821d3019e732aeedd0dde815b106b Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Thu, 31 Oct 2019 09:50:07 +0530 Subject: [PATCH 151/295] msm: camera: ife: calculate accurate boot timestamp at CSID SOF The boot timestamp is calculated in tasklet context. Due to system performance and scheduling delay, it may vary. It is somtimes causing failure for few time bound test cases To handle above problem, This change also considers qtime difference to calculate accurate boot time at CSID each SOF. CRs-Fixed: 2557758 Change-Id: I36b21a0f2c12cc1c83c209ab01ea90c0ac226995 Signed-off-by: Alok Pandey --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 63 ++++++++++--------- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 22 ++++++- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 4 ++ 3 files changed, 55 insertions(+), 34 deletions(-) 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 ccdc046649eb..d70094db859a 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 @@ -6066,41 +6066,42 @@ static int cam_ife_mgr_cmd_get_sof_timestamp( struct cam_hw_intf *hw_intf; struct cam_csid_get_time_stamp_args csid_get_time; - list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) { - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!hw_mgr_res->hw_res[i]) - continue; + hw_mgr_res = list_first_entry(&ife_ctx->res_list_ife_csid, + struct cam_isp_hw_mgr_res, list); + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + /* + * Get the SOF time stamp from left resource only. + * Left resource is master for dual vfe case and + * Rdi only context case left resource only hold + * the RDI resource + */ + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { /* - * Get the SOF time stamp from left resource only. - * Left resource is master for dual vfe case and - * Rdi only context case left resource only hold - * the RDI resource + * Single VFE case, Get the time stamp from + * available one csid hw in the context + * Dual VFE case, get the time stamp from + * master(left) would be sufficient */ - hw_intf = hw_mgr_res->hw_res[i]->hw_intf; - if (hw_intf->hw_ops.process_cmd) { - /* - * Single VFE case, Get the time stamp from - * available one csid hw in the context - * Dual VFE case, get the time stamp from - * master(left) would be sufficient - */ - - csid_get_time.node_res = - hw_mgr_res->hw_res[i]; - rc = hw_intf->hw_ops.process_cmd( - hw_intf->hw_priv, - CAM_IFE_CSID_CMD_GET_TIME_STAMP, - &csid_get_time, - sizeof( - struct cam_csid_get_time_stamp_args)); - if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { - *time_stamp = - csid_get_time.time_stamp_val; - *boot_time_stamp = - csid_get_time.boot_timestamp; - } + csid_get_time.node_res = + hw_mgr_res->hw_res[i]; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_CMD_GET_TIME_STAMP, + &csid_get_time, + sizeof( + struct cam_csid_get_time_stamp_args)); + if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { + *time_stamp = + csid_get_time.time_stamp_val; + *boot_time_stamp = + csid_get_time.boot_timestamp; } } } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index d2b5177d4e20..7e35772ca1f0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -517,6 +517,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d", csid_hw->hw_intf->hw_idx, val); csid_hw->error_irq_count = 0; + csid_hw->prev_boot_timestamp = 0; end: return rc; @@ -1322,6 +1323,7 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) spin_unlock_irqrestore(&csid_hw->lock_state, flags); csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; + csid_hw->prev_boot_timestamp = 0; return rc; } @@ -2921,6 +2923,7 @@ static int cam_ife_csid_get_time_stamp( const struct cam_ife_csid_udi_reg_offset *udi_reg; struct timespec64 ts; uint32_t time_32, id; + uint64_t time_delta; time_stamp = (struct cam_csid_get_time_stamp_args *)cmd_args; res = time_stamp->node_res; @@ -2992,9 +2995,22 @@ static int cam_ife_csid_get_time_stamp( CAM_IFE_CSID_QTIMER_MUL_FACTOR, CAM_IFE_CSID_QTIMER_DIV_FACTOR); - get_monotonic_boottime64(&ts); - time_stamp->boot_timestamp = (uint64_t)((ts.tv_sec * 1000000000) + - ts.tv_nsec); + if (!csid_hw->prev_boot_timestamp) { + get_monotonic_boottime64(&ts); + time_stamp->boot_timestamp = + (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + csid_hw->prev_qtimer_ts = 0; + CAM_DBG(CAM_ISP, "timestamp:%lld", + time_stamp->boot_timestamp); + } else { + time_delta = time_stamp->time_stamp_val - + csid_hw->prev_qtimer_ts; + time_stamp->boot_timestamp = + csid_hw->prev_boot_timestamp + time_delta; + } + csid_hw->prev_qtimer_ts = time_stamp->time_stamp_val; + csid_hw->prev_boot_timestamp = time_stamp->boot_timestamp; return 0; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 1b5c6d40cb21..6d7a9c3aa0c2 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -551,6 +551,8 @@ struct cam_ife_csid_path_cfg { * @binning_enable Flag is set if hardware supports QCFA binning * @binning_supported Flag is set if sensor supports QCFA binning * + * @prev_boot_timestamp first bootime stamp at the start + * @prev_qtimer_ts stores csid timestamp */ struct cam_ife_csid_hw { struct cam_hw_intf *hw_intf; @@ -582,6 +584,8 @@ struct cam_ife_csid_hw { spinlock_t lock_state; uint32_t binning_enable; uint32_t binning_supported; + uint64_t prev_boot_timestamp; + uint64_t prev_qtimer_ts; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, -- GitLab From f0dcf8e6a735deabd818a2a687328e55810d08c0 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Tue, 7 Jan 2020 16:06:46 +0530 Subject: [PATCH 152/295] msm: camera: fd: skip halt and reset for session start Halt and reset can be applied only at probe time and flush time to clean up the MSF interface. CRs-Fixed: 2593760 Change-Id: I8a19a5a5f4a3b25ef5fe9c18a1e754529418c53c Signed-off-by: Tejas Prajapati --- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 10 ++++++++++ drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c | 10 ++++++---- drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h | 4 +++- drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c | 3 ++- drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h | 2 ++ drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h | 3 ++- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index cfbb8840eb63..a293770542ec 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -1244,6 +1244,8 @@ static int cam_fd_mgr_hw_start(void *hw_mgr_priv, void *mgr_start_args) struct cam_fd_hw_mgr_ctx *hw_ctx; struct cam_fd_device *hw_device; struct cam_fd_hw_init_args hw_init_args; + struct cam_hw_info *fd_hw; + struct cam_fd_core *fd_core; if (!hw_mgr_priv || !hw_mgr_start_args) { CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", @@ -1266,9 +1268,17 @@ static int cam_fd_mgr_hw_start(void *hw_mgr_priv, void *mgr_start_args) return rc; } + fd_hw = (struct cam_hw_info *)hw_device->hw_intf->hw_priv; + fd_core = (struct cam_fd_core *)fd_hw->core_info; + if (hw_device->hw_intf->hw_ops.init) { hw_init_args.hw_ctx = hw_ctx; hw_init_args.ctx_hw_private = hw_ctx->ctx_hw_private; + if (fd_core->hw_static_info->enable_errata_wa.skip_reset) + hw_init_args.reset_required = false; + else + hw_init_args.reset_required = true; + rc = hw_device->hw_intf->hw_ops.init( hw_device->hw_intf->hw_priv, &hw_init_args, sizeof(hw_init_args)); diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index 16a66c2a41ce..80e30ad6c64e 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -747,10 +747,12 @@ int cam_fd_hw_init(void *hw_priv, void *init_hw_args, uint32_t arg_size) fd_core->core_state = CAM_FD_CORE_STATE_IDLE; spin_unlock_irqrestore(&fd_core->spin_lock, flags); - rc = cam_fd_hw_reset(hw_priv, NULL, 0); - if (rc) { - CAM_ERR(CAM_FD, "Reset Failed, rc=%d", rc); - goto disable_soc; + if (init_args->reset_required) { + rc = cam_fd_hw_reset(hw_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_FD, "Reset Failed, rc=%d", rc); + goto disable_soc; + } } cam_fd_hw_util_enable_power_on_settings(fd_hw); diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h index 1f8815e72f20..22bcdf6fc733 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FD_HW_CORE_H_ @@ -135,11 +135,13 @@ struct cam_fd_wrapper_regs { * @ro_mode_enable_always : Whether to enable ro mode always * @ro_mode_results_invalid : Whether results written directly into output * memory by HW are valid or not + * @skip_reset : Whether to skip reset during init */ struct cam_fd_hw_errata_wa { bool single_irq_only; bool ro_mode_enable_always; bool ro_mode_results_invalid; + bool skip_reset; }; /** diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c index 3498e6235279..7a42379512be 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -110,6 +110,7 @@ static int cam_fd_hw_dev_probe(struct platform_device *pdev) memset(&init_args, 0x0, sizeof(init_args)); memset(&deinit_args, 0x0, sizeof(deinit_args)); + init_args.reset_required = true; rc = cam_fd_hw_init(fd_hw, &init_args, sizeof(init_args)); if (rc) { CAM_ERR(CAM_FD, "Failed to hw init, rc=%d", rc); diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h index 11ef1b913f91..85ec6fa390ff 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h @@ -162,10 +162,12 @@ struct cam_fd_hw_release_args { * * @hw_ctx : HW context for which init is requested * @ctx_hw_private : HW layer's private information specific to this hw context + * @reset_required : Indicates if the reset is required during init or not */ struct cam_fd_hw_init_args { void *hw_ctx; void *ctx_hw_private; + bool reset_required; }; /** diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h index f3eedeb3b811..d8b78d6e4414 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FD_HW_V501_H_ @@ -50,6 +50,7 @@ static struct cam_fd_hw_static_info cam_fd_wrapper200_core501_info = { .single_irq_only = true, .ro_mode_enable_always = true, .ro_mode_results_invalid = true, + .skip_reset = true, }, .irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) | CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) | -- GitLab From 502e394ea6f734ad8155a1f066a959c3b67a8ecd Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Fri, 3 Jan 2020 18:37:51 +0530 Subject: [PATCH 153/295] msm: camera: cpas: Add support for camnoc based voting For some targets, it is needed to vote for camnoc clock as there is no CAMNOC AXI clock source in camera domain. Voting is done with the bus drivers and it calcultates the clock rate. This change adds support for camnoc based voting. CRs-Fixed: 2571273 Change-Id: I38a4fa8d40892b6dfe7e925b6368eb259132615d Signed-off-by: Gaurav Jindal --- drivers/cam_cpas/cam_cpas_hw.c | 164 +++++++++++++++++++++++++++----- drivers/cam_cpas/cam_cpas_hw.h | 8 +- drivers/cam_cpas/cam_cpas_soc.c | 54 ++++++++++- drivers/cam_cpas/cam_cpas_soc.h | 2 + 4 files changed, 203 insertions(+), 25 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index c3a0c27ca88b..e5ddbe179575 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -242,6 +242,12 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, return -EINVAL; } + if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", + cpas_core->num_camnoc_axi_ports); + return -EINVAL; + } + for (i = 0; i < cpas_core->num_axi_ports; i++) { cam_cpas_util_unregister_bus_client( &cpas_core->axi_port[i].bus_client); @@ -249,6 +255,13 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, cpas_core->axi_port[i].axi_port_node = NULL; } + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + cam_cpas_util_unregister_bus_client( + &cpas_core->camnoc_axi_port[i].bus_client); + of_node_put(cpas_core->camnoc_axi_port[i].axi_port_node); + cpas_core->camnoc_axi_port[i].axi_port_node = NULL; + } + return 0; } @@ -257,6 +270,7 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, { int i = 0, rc = 0; struct device_node *axi_port_mnoc_node = NULL; + struct device_node *axi_port_camnoc_node = NULL; if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d", @@ -271,6 +285,15 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, if (rc) goto bus_register_fail; } + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + axi_port_camnoc_node = + cpas_core->camnoc_axi_port[i].axi_port_node; + rc = cam_cpas_util_register_bus_client(soc_info, + axi_port_camnoc_node, + &cpas_core->camnoc_axi_port[i].bus_client); + if (rc) + goto bus_register_fail; + } return 0; bus_register_fail: @@ -608,6 +631,99 @@ static int cam_cpas_axi_consolidate_path_votes( return rc; } +static int cam_cpas_update_axi_vote_bw( + struct cam_hw_info *cpas_hw, + struct cam_cpas_tree_node *cpas_tree_node, + bool *mnoc_axi_port_updated, + bool *camnoc_axi_port_updated) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + + if (cpas_tree_node->axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d", + cpas_tree_node->axi_port_idx); + return -EINVAL; + } + + cpas_core->axi_port[cpas_tree_node->axi_port_idx].ab_bw = + cpas_tree_node->mnoc_ab_bw; + cpas_core->axi_port[cpas_tree_node->axi_port_idx].ib_bw = + cpas_tree_node->mnoc_ib_bw; + mnoc_axi_port_updated[cpas_tree_node->axi_port_idx] = true; + + if (soc_private->control_camnoc_axi_clk) + return 0; + + cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx].camnoc_bw = + cpas_tree_node->camnoc_bw; + camnoc_axi_port_updated[cpas_tree_node->camnoc_axi_port_idx] = true; + return 0; +} + +static int cam_cpas_camnoc_set_vote_axi_clk_rate( + struct cam_hw_info *cpas_hw, + bool *camnoc_axi_port_updated) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + int i; + int rc = 0; + struct cam_cpas_axi_port *camnoc_axi_port = NULL; + uint64_t camnoc_bw; + + if (soc_private->control_camnoc_axi_clk) { + rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); + if (rc) + CAM_ERR(CAM_CPAS, + "Failed in setting axi clk rate rc=%d", rc); + return rc; + } + + /* Below code is executed if we just vote and do not set the clk rate + * for camnoc + */ + + if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", + cpas_core->num_camnoc_axi_ports); + return -EINVAL; + } + + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + if (camnoc_axi_port_updated[i]) + camnoc_axi_port = &cpas_core->camnoc_axi_port[i]; + else + continue; + + CAM_DBG(CAM_PERF, "Port[%s] : camnoc_bw=%lld", + camnoc_axi_port->axi_port_name, + camnoc_axi_port->camnoc_bw); + + if (camnoc_axi_port->camnoc_bw) + camnoc_bw = camnoc_axi_port->camnoc_bw; + else + camnoc_bw = camnoc_axi_port->additional_bw; + + rc = cam_cpas_util_vote_bus_client_bw( + &camnoc_axi_port->bus_client, + 0, camnoc_bw, true); + + CAM_DBG(CAM_CPAS, + "camnoc vote camnoc_bw[%llu] rc=%d %s", + camnoc_bw, rc, camnoc_axi_port->axi_port_name); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in camnoc vote camnoc_bw[%llu] rc=%d", + camnoc_bw, rc); + break; + } + } + return rc; +} + static int cam_cpas_util_apply_client_axi_vote( struct cam_hw_info *cpas_hw, struct cam_cpas_client *cpas_client, @@ -615,12 +731,13 @@ static int cam_cpas_util_apply_client_axi_vote( { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_axi_vote *con_axi_vote = NULL; - struct cam_cpas_axi_port *axi_port = NULL; + struct cam_cpas_axi_port *mnoc_axi_port = NULL; struct cam_cpas_tree_node *curr_tree_node = NULL; struct cam_cpas_tree_node *par_tree_node = NULL; uint32_t transac_type; uint32_t path_data_type; - bool axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; + bool mnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; + bool camnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0, curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; @@ -643,7 +760,7 @@ static int cam_cpas_util_apply_client_axi_vote( cpas_core->axi_port[i].additional_bw -= CAM_CPAS_DEFAULT_AXI_BW; } - axi_port_updated[i] = true; + mnoc_axi_port_updated[i] = true; } goto vote_start_clients; } @@ -733,15 +850,15 @@ static int cam_cpas_util_apply_client_axi_vote( rc = -EINVAL; goto unlock_tree; } - - cpas_core->axi_port - [par_tree_node->axi_port_idx].ab_bw = - par_tree_node->mnoc_ab_bw; - cpas_core->axi_port - [par_tree_node->axi_port_idx].ib_bw = - par_tree_node->mnoc_ib_bw; - axi_port_updated[par_tree_node->axi_port_idx] = - true; + rc = cam_cpas_update_axi_vote_bw(cpas_hw, + par_tree_node, + mnoc_axi_port_updated, + camnoc_axi_port_updated); + if (rc) { + CAM_ERR(CAM_CPAS, + "Update Vote failed"); + goto unlock_tree; + } } curr_tree_node = par_tree_node; @@ -759,26 +876,27 @@ static int cam_cpas_util_apply_client_axi_vote( vote_start_clients: for (i = 0; i < cpas_core->num_axi_ports; i++) { - if (axi_port_updated[i]) - axi_port = &cpas_core->axi_port[i]; + if (mnoc_axi_port_updated[i]) + mnoc_axi_port = &cpas_core->axi_port[i]; else continue; CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld", - axi_port->axi_port_name, axi_port->ab_bw, - axi_port->ib_bw, axi_port->additional_bw); + mnoc_axi_port->axi_port_name, mnoc_axi_port->ab_bw, + mnoc_axi_port->ib_bw, mnoc_axi_port->additional_bw); - if (axi_port->ab_bw) - mnoc_ab_bw = axi_port->ab_bw; + if (mnoc_axi_port->ab_bw) + mnoc_ab_bw = mnoc_axi_port->ab_bw; else - mnoc_ab_bw = axi_port->additional_bw; + mnoc_ab_bw = mnoc_axi_port->additional_bw; if (cpas_core->axi_port[i].ib_bw_voting_needed) - mnoc_ib_bw = axi_port->ib_bw; + mnoc_ib_bw = mnoc_axi_port->ib_bw; else mnoc_ib_bw = 0; - rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, + rc = cam_cpas_util_vote_bus_client_bw( + &mnoc_axi_port->bus_client, mnoc_ab_bw, mnoc_ib_bw, false); if (rc) { CAM_ERR(CAM_CPAS, @@ -787,8 +905,8 @@ static int cam_cpas_util_apply_client_axi_vote( goto unlock_tree; } } - - rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); + rc = cam_cpas_camnoc_set_vote_axi_clk_rate( + cpas_hw, camnoc_axi_port_updated); if (rc) CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index b3c01b3ee737..cfa7dfbb69b2 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.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 _CAM_CPAS_HW_H_ @@ -153,6 +153,7 @@ struct cam_cpas_bus_client { * @axi_port_node: Node representing AXI Port info in device tree * @ab_bw: AB bw value for this port * @ib_bw: IB bw value for this port + * @camnoc_bw: CAMNOC bw value for this port * @additional_bw: Additional bandwidth to cover non-hw cpas clients */ struct cam_cpas_axi_port { @@ -162,6 +163,7 @@ struct cam_cpas_axi_port { struct device_node *axi_port_node; uint64_t ab_bw; uint64_t ib_bw; + uint64_t camnoc_bw; uint64_t additional_bw; }; @@ -174,11 +176,13 @@ struct cam_cpas_axi_port { * @tree_lock: Mutex lock for accessing CPAS node tree * @num_clients: Total number of clients that CPAS supports * @num_axi_ports: Total number of axi ports found in device tree + * @num_camnoc_axi_ports: Total number of camnoc axi ports found in device tree * @registered_clients: Number of Clients registered currently * @streamon_clients: Number of Clients that are in start state currently * @regbase_index: Register base indices for CPAS register base IDs * @ahb_bus_client: AHB Bus client info * @axi_port: AXI port info for a specific axi index + * @camnoc_axi_port: CAMNOC AXI port info for a specific camnoc axi index * @internal_ops: CPAS HW internal ops * @work_queue: Work queue handle * @irq_count: atomic irq count @@ -193,11 +197,13 @@ struct cam_cpas { struct mutex tree_lock; uint32_t num_clients; uint32_t num_axi_ports; + uint32_t num_camnoc_axi_ports; uint32_t registered_clients; uint32_t streamon_clients; int32_t regbase_index[CAM_CPAS_REG_MAX]; struct cam_cpas_bus_client ahb_bus_client; struct cam_cpas_axi_port axi_port[CAM_CPAS_MAX_AXI_PORTS]; + struct cam_cpas_axi_port camnoc_axi_port[CAM_CPAS_MAX_AXI_PORTS]; struct cam_cpas_internal_ops internal_ops; struct workqueue_struct *work_queue; atomic_t irq_count; diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index 16345d662af2..df4c1585c531 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/drivers/cam_cpas/cam_cpas_soc.c @@ -134,6 +134,47 @@ static int cam_cpas_util_path_type_to_idx(uint32_t *path_data_type) return 0; } +static int cam_cpas_update_camnoc_node(struct cam_cpas *cpas_core, + struct device_node *curr_node, + struct cam_cpas_tree_node *cpas_node_ptr, + int *camnoc_idx) + +{ + struct device_node *camnoc_node; + int rc; + + camnoc_node = of_find_node_by_name(curr_node, + "qcom,axi-port-camnoc"); + if (camnoc_node) { + + if (*camnoc_idx >= + CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "CAMNOC axi index overshoot %d", + *camnoc_idx); + return -EINVAL; + } + + cpas_core->camnoc_axi_port[*camnoc_idx] + .axi_port_node = camnoc_node; + rc = of_property_read_string( + curr_node, + "qcom,axi-port-name", + &cpas_core->camnoc_axi_port[*camnoc_idx] + .axi_port_name); + + if (rc) { + CAM_ERR(CAM_CPAS, + "fail to read camnoc-port-name rc=%d", + rc); + return rc; + } + cpas_node_ptr->camnoc_axi_port_idx = *camnoc_idx; + cpas_core->num_camnoc_axi_ports++; + (*camnoc_idx)++; + } + return 0; +} + static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, struct device_node *of_node, struct cam_cpas_private_soc *soc_private) { @@ -142,7 +183,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, struct device_node *curr_node; struct device_node *parent_node; struct device_node *mnoc_node; - int mnoc_idx = 0; + int mnoc_idx = 0, camnoc_idx = 0; uint32_t path_idx; bool camnoc_max_needed = false; struct cam_cpas_tree_node *curr_node_ptr = NULL; @@ -248,6 +289,17 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, cpas_core->num_axi_ports++; } + if (!soc_private->control_camnoc_axi_clk) { + rc = cam_cpas_update_camnoc_node( + cpas_core, curr_node, curr_node_ptr, + &camnoc_idx); + if (rc) { + CAM_ERR(CAM_CPAS, + "Parse Camnoc port fail"); + return rc; + } + } + rc = of_property_read_string(curr_node, "client-name", &client_name); if (!rc) { diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index 663a5e8c838d..3a2c889cfea0 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/drivers/cam_cpas/cam_cpas_soc.h @@ -31,6 +31,7 @@ struct cam_cpas_vdd_ahb_mapping { * @cell_idx: Index to identify node from device tree and its parent * @level_idx: Index to identify at what level the node is present * @axi_port_idx: Index to identify which axi port to vote the consolidated bw + * @camnoc_axi_port_idx: Index to find which axi port to vote consolidated bw * @path_data_type: Traffic type info from device tree (ife-vid, ife-disp etc) * @path_trans_type: Transaction type info from device tree (rd, wr) * @merge_type: Traffic merge type (calculation info) from device tree @@ -54,6 +55,7 @@ struct cam_cpas_tree_node { uint32_t cell_idx; uint32_t level_idx; int axi_port_idx; + int camnoc_axi_port_idx; const char *node_name; uint32_t path_data_type; uint32_t path_trans_type; -- GitLab From c5cfbfeb2bae535c4a98b339af9f858af884204c Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Fri, 21 Feb 2020 16:22:27 +0530 Subject: [PATCH 154/295] msm: camera: reqmgr: increase the rd idx if no lower pd device For link with maximum pipeline delay of 1 e.g., TPG use case or sensors with pipeline delay of 1, if the request is not submitted before 2 consecutive triggers we do not get chance to increment rd idx, in the mean time the slot which was last applied will be reset and we will not be able to apply request even if new requests are scheduled. This will cause the camera to not apply any request further, hence increasing the rd idx if no lower pd devices are pending will fix the issue. CRs-Fixed: 2622845 Change-Id: I012e242c7fca22abecc171ef4d7063d851bb5748 Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_req_mgr_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 5629218b4cb4..3b6b38403b83 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -2537,6 +2537,8 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) CAM_DBG(CAM_REQ, "No pending req to apply to lower pd devices"); rc = 0; + __cam_req_mgr_inc_idx(&in_q->rd_idx, + 1, in_q->num_slots); goto release_lock; } __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); -- GitLab From a140ad5f4b413be28e80f277bba568f321ebbcb6 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Wed, 26 Feb 2020 11:30:54 +0530 Subject: [PATCH 155/295] msm: camera: ope: Stop OPE in case of init failure Stop the OPE in case of init failure. This will help OPE to move to completely deinit state if init fails. CRs-Fixed: 2628585 Change-Id: I181349e1736f10208f5e5a7b2d3529316c0b09bc Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 4 ++++ 1 file changed, 4 insertions(+) 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 607e265cc1be..951d4132b679 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 @@ -2341,6 +2341,10 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) 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"); } } end: -- GitLab From d21994948124cc53cdff41c17f26d87796840a81 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Thu, 20 Feb 2020 02:45:08 +0530 Subject: [PATCH 156/295] msm: camera: ope: Synchronize process cmd and flush request There are chances that process cmd and flush request run in parallel. This can cause bl request to get free and CDM to be in reset state and finally lead to failure. Avoid running process cmd and flush simultaneously. CRs-Fixed: 2627548 Change-Id: I5fd28c2b517d91619c71f8f57ba91a621b585b22 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) 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 89874929da4f..6c23d8907839 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); @@ -98,10 +99,12 @@ static int cam_ope_mgr_process_cmd(void *priv, void *data) CAM_DBG(CAM_OPE, "cam_cdm_submit_bls: handle = %u", ctx_data->ope_cdm.cdm_handle); + 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; } @@ -115,6 +118,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; } @@ -3043,7 +3048,6 @@ static int cam_ope_mgr_flush_all(struct cam_ope_ctx *ctx_data, rc = cam_cdm_flush_hw(ctx_data->ope_cdm.cdm_handle); - mutex_lock(&hw_mgr->hw_mgr_mutex); mutex_lock(&ctx_data->ctx_mutex); for (i = 0; i < hw_mgr->num_ope; i++) { rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( @@ -3066,7 +3070,6 @@ static int cam_ope_mgr_flush_all(struct cam_ope_ctx *ctx_data, clear_bit(i, ctx_data->bitmap); } mutex_unlock(&ctx_data->ctx_mutex); - mutex_unlock(&hw_mgr->hw_mgr_mutex); return rc; } @@ -3075,6 +3078,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"); @@ -3094,14 +3098,17 @@ static int cam_ope_mgr_hw_flush(void *hw_priv, void *hw_flush_args) return -EINVAL; } - 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); - 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); -- GitLab From d5b7af72486ef0b1cb4ecad067890cfeb2f99458 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 24 Feb 2020 13:22:20 +0530 Subject: [PATCH 157/295] msm: camera: cdm: Fix CDM IRQ handling Issue: In CDM irq handling, workq to handle the irq was scheduled before clearing the status registers. Due to which reset complete can be done before clearing the status registers. This creates a possibility of issuing next reset before clearing the status registers. Fix: Clear the status registers before scheduiling workq to handle interrupt. Also moved the reset done logic from workq to interrupt handler for quick handling of reset irq. CRs-Fixed: 2626672 Change-Id: I89846cbf8a970802fd789352ad6bba62678bf1df Signed-off-by: Rishabh Jain --- drivers/cam_cdm/cam_cdm.h | 1 + drivers/cam_cdm/cam_cdm_hw_core.c | 123 ++++++++++++++++-------------- 2 files changed, 67 insertions(+), 57 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index 7f8c90f9285d..e1b8697fef77 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -468,6 +468,7 @@ struct cam_cdm_bl_fifo { struct mutex fifo_lock; uint8_t bl_tag; uint32_t bl_depth; + uint8_t last_bl_tag_done; }; /** diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 15a816a7bfa4..07111f5e2a41 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -986,7 +986,12 @@ 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) { @@ -1003,37 +1008,40 @@ 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] + .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); - } - list_del_init(&node->entry); - if (node->bl_tag == payload->irq_data) { + } 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; + } kfree(node); - break; } - kfree(node); } 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)) { @@ -1107,6 +1115,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) struct cam_hw_info *cdm_hw = data; struct cam_cdm *cdm_core = cdm_hw->core_info; struct cam_cdm_work_payload *payload[CAM_CDM_BL_FIFO_MAX] = {0}; + uint32_t rst_done_cnt = 0; uint32_t user_data = 0; uint32_t irq_status[CAM_CDM_BL_FIFO_MAX] = {0}; bool work_status; @@ -1120,40 +1129,43 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) &irq_status[i])) { CAM_ERR(CAM_CDM, "Failed to read CDM HW IRQ status"); } + if (cam_cdm_write_hw_reg(cdm_hw, + cdm_core->offsets->irq_reg[i]->irq_clear, + irq_status[i])) { + CAM_ERR(CAM_CDM, "Failed to write CDM HW IRQ clear"); + } } + 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 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"); for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo_irq; i++) { - if (!irq_status[i]) { - cam_cdm_write_hw_reg(cdm_hw, - cdm_core->offsets->irq_reg[i]->irq_clear, - irq_status[i]); + if (!irq_status[i]) + continue; + + if (irq_status[i] & CAM_CDM_IRQ_STATUS_RST_DONE_MASK) { + 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)) & 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"); } payload[i]->fifo_idx = i; @@ -1167,32 +1179,27 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) 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)) { - CAM_ERR(CAM_CDM, - "Failed to Write CDM HW IRQ Clear"); - kfree(payload[i]); - return IRQ_HANDLED; - } - 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 (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"); - + if (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 (rst_done_cnt && + rst_done_cnt != cdm_core->offsets->reg_data->num_bl_fifo_irq) + CAM_ERR(CAM_CDM, + "Reset IRQ received for %d fifos instead of %d", + rst_done_cnt, + cdm_core->offsets->reg_data->num_bl_fifo_irq); return IRQ_HANDLED; } @@ -1552,6 +1559,8 @@ 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 = 0; rc = cam_hw_cdm_reset_hw(cdm_hw, reset_hw_hdl); -- GitLab From 3a9861ae8f2315f9f2b70263c6ca5e39286662a5 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 10 Feb 2020 12:21:25 +0530 Subject: [PATCH 158/295] msm: camera: tfe: LDAR dump for TFE When user space detects an error or does not receive response for a request, Lets do a reset(LDAR) is triggered. Before LDAR, user space sends flush command to the kernel space. In order to debug the cause for this situation and to dump the information, user space sends a dump command to kernel space before sending flush. As a part of this command, it passes the culprit request id and the buffer into which the information can be dumped. Kernel space traverses across the drivers and find the culprit hw and dumps the relevant information in the buffer. This data is written to a file for offline processing. This commit dumps the TFE, CSID registers, LUT tables and context information, cmd buffers, timestamps information for submit, apply, RUP, epoch and buffdones of the last 20 requests. Change-Id: I9a5decdf88d94e5d05b8c5a14e9f301f42adaa20 CRs-Fixed: 2612116 Signed-off-by: Gaurav Jindal --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 173 ++++++++++++- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 2 + .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 103 ++++++++ .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.h | 6 + .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 232 ++++++++++++++++++ .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.h | 10 +- 6 files changed, 518 insertions(+), 8 deletions(-) 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 322d75fe0f30..5f31e23a2212 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 @@ -118,7 +118,9 @@ 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 = -EINVAL, i; @@ -142,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", @@ -153,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, @@ -1719,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); @@ -2979,6 +2982,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; @@ -4226,7 +4382,8 @@ 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 num_reg_dump:0x%x rc: %d", @@ -4242,7 +4399,8 @@ 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 num_reg_dump:0x%x rc: %d", @@ -5309,6 +5467,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/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 5fd1172a4033..e5610b98d528 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 @@ -267,6 +267,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; @@ -274,6 +275,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 be6980db4376..d68424ae0a91 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 @@ -2301,6 +2301,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) { @@ -2332,6 +2432,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); 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 c0c3532bcc82..e008fd518e9a 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) 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 b57b17265c2c..e8a2052d468a 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 @@ -1490,6 +1490,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) @@ -2570,6 +2798,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 3f7208a7babb..2418831d00c1 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 @@ -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. */ @@ -28,6 +28,14 @@ #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, -- GitLab From 29964e85367756eaf912d0bef4444f35dcc9fd0a Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Thu, 27 Feb 2020 20:10:11 +0530 Subject: [PATCH 159/295] msm: camera: ope: Fix the length check for debug buffer Debug buffer passed by UMD is smaller than the required size to collect the replay dump. Corrected the debug buffer length check and don't dump replay data incase of flush. CRs-Fixed: 2629735 Change-Id: I07bc3c9585ab8ad00cd858ecd807e473075795aa Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 19 ++++++++++++++----- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) 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 71c704e1bb75..c56f1226006d 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 @@ -551,8 +551,14 @@ static void cam_ope_dump_req_data(struct cam_ope_request *ope_req) (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)) { - CAM_ERR(CAM_OPE, "OPE debug buf is invalid"); + 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; @@ -1503,7 +1509,8 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, handle, userdata, status, cookie, ope_req->request_id); CAM_ERR(CAM_OPE, "Rst of CDM and OPE for error reqid = %lld", ope_req->request_id); - cam_ope_dump_req_data(ope_req); + if (status != CAM_CDM_CB_STATUS_HW_FLUSH) + cam_ope_dump_req_data(ope_req); rc = cam_ope_mgr_reset_hw(); flag = true; } @@ -1996,9 +2003,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; 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 e2f2b025bb21..962138b242a8 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 @@ -225,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; }; /** -- GitLab From b45ff00c19891abf934e23a0f3c7f54166bf1122 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Wed, 4 Mar 2020 13:53:45 +0530 Subject: [PATCH 160/295] msm: camera: cdm: Fix dangling pointer issue Explicitly set pointer to NULL after freeing the memory. This avoid causing memory corruption incase the memory is already freed. CRs-Fixed: 2631601 Change-Id: I2f4db99ccfefb2516e98ea5150a2bd5a342819e5 Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 07111f5e2a41..e4ac053d6301 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -674,6 +674,7 @@ int cam_hw_cdm_submit_gen_irq( core->bl_fifo[fifo_idx].bl_tag); list_del_init(&node->entry); kfree(node); + node = NULL; rc = -EIO; goto end; } @@ -684,6 +685,7 @@ int cam_hw_cdm_submit_gen_irq( core->bl_fifo[fifo_idx].bl_tag); list_del_init(&node->entry); kfree(node); + node = NULL; rc = -EIO; } @@ -970,6 +972,7 @@ static void cam_hw_cdm_reset_cleanup( } list_del_init(&node->entry); kfree(node); + node = NULL; } core->bl_fifo[i].bl_tag = 0; } @@ -990,6 +993,7 @@ static void cam_hw_cdm_work(struct work_struct *work) CAM_ERR(CAM_CDM, "Invalid fifo idx %d", payload->fifo_idx); kfree(payload); + payload = NULL; return; } CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); @@ -1003,6 +1007,7 @@ static void cam_hw_cdm_work(struct work_struct *work) if (payload->irq_data == 0xff) { CAM_INFO(CAM_CDM, "Debug genirq received"); kfree(payload); + payload = NULL; return; } @@ -1033,9 +1038,11 @@ static void cam_hw_cdm_work(struct work_struct *work) list_del_init(&node->entry); if (node->bl_tag == payload->irq_data) { kfree(node); + node = NULL; break; } kfree(node); + node = NULL; } } mutex_unlock(&core->bl_fifo[payload->fifo_idx] @@ -1071,6 +1078,7 @@ static void cam_hw_cdm_work(struct work_struct *work) &core->cdm_status); } kfree(payload); + payload = NULL; } else { CAM_ERR(CAM_CDM, "NULL payload"); } @@ -1188,6 +1196,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) "Failed to queue work for FIFO: %d irq=0x%x", i, payload[i]->irq_status); kfree(payload[i]); + payload[i] = NULL; } } if (rst_done_cnt == cdm_core->offsets->reg_data->num_bl_fifo_irq) { @@ -1424,6 +1433,7 @@ int cam_hw_cdm_handle_error_info( } list_del_init(&node->entry); kfree(node); + node = NULL; } cam_hw_cdm_reset_cleanup(cdm_hw, reset_hw_hdl); @@ -1608,6 +1618,7 @@ int cam_hw_cdm_deinit(void *hw_priv, &cdm_core->bl_fifo[i].bl_request_list, entry) { list_del_init(&node->entry); kfree(node); + node = NULL; } } @@ -1670,13 +1681,16 @@ int cam_hw_cdm_probe(struct platform_device *pdev) cdm_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); if (!cdm_hw) { kfree(cdm_hw_intf); + cdm_hw_intf = NULL; return -ENOMEM; } cdm_hw->core_info = kzalloc(sizeof(struct cam_cdm), GFP_KERNEL); if (!cdm_hw->core_info) { kfree(cdm_hw); + cdm_hw = NULL; kfree(cdm_hw_intf); + cdm_hw_intf = NULL; return -ENOMEM; } @@ -1905,11 +1919,15 @@ int cam_hw_cdm_probe(struct platform_device *pdev) mutex_unlock(&cdm_hw->hw_mutex); release_private_mem: kfree(cdm_hw->soc_info.soc_private); + cdm_hw->soc_info.soc_private = NULL; release_mem: mutex_destroy(&cdm_hw->hw_mutex); kfree(cdm_hw_intf); + cdm_hw_intf = NULL; kfree(cdm_hw->core_info); + cdm_hw->core_info = NULL; kfree(cdm_hw); + cdm_hw = NULL; return rc; } @@ -1976,9 +1994,13 @@ int cam_hw_cdm_remove(struct platform_device *pdev) mutex_destroy(&cdm_hw->hw_mutex); kfree(cdm_hw->soc_info.soc_private); + cdm_hw->soc_info.soc_private = NULL; kfree(cdm_hw_intf); + cdm_hw_intf = NULL; kfree(cdm_hw->core_info); + cdm_hw->core_info = NULL; kfree(cdm_hw); + cdm_hw = NULL; return 0; } -- GitLab From 5f5f18d7ba048606e484d8c5ad8051c5f73318d5 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Tue, 3 Mar 2020 16:03:25 +0530 Subject: [PATCH 161/295] msm: camera: cdm: Fix CDM reset logic As per HW team, CDM HW should be in pause state before reset the HW. Add a delay as well before reset to make sure CDM is in idle state. CRs-Fixed: 2632672 Change-Id: Id0805964bae418b8b13e73112d3eac041aaf996e Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 07111f5e2a41..19e0149ddb1c 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -303,8 +303,7 @@ void cam_hw_cdm_dump_core_debug_registers( 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); - /* First pause CDM, If it fails still proceed to dump debug info */ - cam_hw_cdm_pause_core(cdm_hw, true); + usleep_range(1000, 1010); cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->debug_status, @@ -373,8 +372,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); - /* Resume CDM back */ - cam_hw_cdm_pause_core(cdm_hw, false); } enum cam_cdm_arbitration cam_cdm_get_arbitration_type( @@ -1060,7 +1057,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); @@ -1092,8 +1096,16 @@ 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); - if (cdm_hw->hw_state == CAM_HW_STATE_POWER_UP) + 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++) @@ -1277,6 +1289,10 @@ int cam_hw_cdm_reset_hw(struct cam_hw_info *cdm_hw, uint32_t handle) set_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); 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)); @@ -1614,6 +1630,10 @@ int cam_hw_cdm_deinit(void *hw_priv, set_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); 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)); -- GitLab From dcaee01c883261c94e52801ad8deaa4306b7571e Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Tue, 25 Feb 2020 17:31:39 +0530 Subject: [PATCH 162/295] msm: camera: ope: Dump debug registers in case of HW hang Add support for dumping debug registers in case of HW hang. This will help to identify the culprit module in case of HW hang. CRs-Fixed: 2628745 Change-Id: Ie978df9eee684de4718dfce2aa47cd941704ae0d Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 4 +++ drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 22 ++++++++++++ .../cam_ope/ope_hw_mgr/ope_hw/ope_dev_intf.h | 3 +- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h | 12 ++++++- .../cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h | 36 ++++++++++++++++++- .../cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c | 22 ++++++++++++ 6 files changed, 96 insertions(+), 3 deletions(-) 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 13c711f77356..362b993fdf7b 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 @@ -349,6 +349,10 @@ 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"); + 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"); 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 824e04427425..9bfede8cdd8e 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 @@ -285,6 +285,16 @@ int cam_ope_deinit_hw(void *device_priv, 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; +} + static int cam_ope_dev_process_reset(struct ope_hw *ope_hw, void *cmd_args) { int rc = 0; @@ -1529,6 +1539,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) { @@ -1670,6 +1689,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 41e317168faa..aeeca5e7bbd9 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 @@ -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_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 55e2ab21b039..2890f1579e67 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 @@ -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_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 34548e7cac1d..95ae384161af 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 @@ -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_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 d3f4e648b36f..2ecfa4e1e417 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 @@ -70,11 +70,29 @@ static int cam_ope_top_reset(struct ope_hw *ope_hw_info, /* 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); mutex_unlock(&ope_top_info.ope_hw_mutex); return rc; } +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; + struct cam_ope_top_reg_val *top_reg_val; + + top_reg = ope_hw_info->top_reg; + top_reg_val = ope_hw_info->top_reg_val; + 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_release(struct ope_hw *ope_hw_info, int32_t ctx_id, void *data) { @@ -141,6 +159,8 @@ static int cam_ope_top_init(struct ope_hw *ope_hw_info, /* 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); @@ -249,6 +269,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; } -- GitLab From 2788edf51ced8fe4d71e3fdeb403ee008bcb9361 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 2 Mar 2020 12:09:35 +0530 Subject: [PATCH 163/295] msm: camera: tfe: Support the RDI bus port for line based mode Add support to enable the RDI port bus on line based mode. In one ITS testcase rdi buffer need to be stride aligned. Currently RDI works in frame based mode, so stride is not applicable in frame based mode. Added support to enable the RDI bus mode based on the acquire time user space send mode. CRs-Fixed: 2621505 Change-Id: Iea17b4f12594d5bac03b299d782bdb13a70f9dd3 Signed-off-by: Ravikishore Pampana --- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 190 ++++++++++++++---- include/uapi/media/cam_tfe.h | 7 +- 2 files changed, 152 insertions(+), 45 deletions(-) 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 9eaec1d1d17f..01ffb90d7461 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 @@ -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. */ #include @@ -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; @@ -453,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, @@ -467,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) { @@ -495,6 +627,7 @@ 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 @@ -510,44 +643,10 @@ static int cam_tfe_bus_acquire_wm( 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) { @@ -594,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; } @@ -643,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)); @@ -1783,7 +1884,8 @@ static int cam_tfe_bus_update_wm(void *priv, void *cmd_args, 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/include/uapi/media/cam_tfe.h b/include/uapi/media/cam_tfe.h index 9055f7fbe55c..7da5493466b0 100644 --- a/include/uapi/media/cam_tfe.h +++ b/include/uapi/media/cam_tfe.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_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 -- GitLab From 44801afc0f42f7988fc422f542bd06a4b42e9a87 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Fri, 6 Mar 2020 16:40:10 +0530 Subject: [PATCH 164/295] msm: camera: cdm: Handle out of order reset done events There is possibility that BL fifo's reset done events comes as part of separate IRQs. This will lead to resent wait failure due to number of reset done doesn't match with number of bl fifo irqs. Handle the scenario if reset done irqs comes out of order by maintaining the reset done events for all fifo. CRs-Fixed: 2636535 Change-Id: I3f31c967c915198cd40dcf31295cd115684f7972 Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm.h | 2 ++ drivers/cam_cdm/cam_cdm_hw_core.c | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index e1b8697fef77..458ecca48dbd 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -496,6 +496,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; @@ -518,6 +519,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_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 9f952a42eff8..28207a14376c 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1135,7 +1135,6 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) struct cam_hw_info *cdm_hw = data; struct cam_cdm *cdm_core = cdm_hw->core_info; struct cam_cdm_work_payload *payload[CAM_CDM_BL_FIFO_MAX] = {0}; - uint32_t rst_done_cnt = 0; uint32_t user_data = 0; uint32_t irq_status[CAM_CDM_BL_FIFO_MAX] = {0}; bool work_status; @@ -1169,7 +1168,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) continue; if (irq_status[i] & CAM_CDM_IRQ_STATUS_RST_DONE_MASK) { - rst_done_cnt++; + cdm_core->rst_done_cnt++; continue; } @@ -1211,15 +1210,17 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) payload[i] = NULL; } } - if (rst_done_cnt == cdm_core->offsets->reg_data->num_bl_fifo_irq) { + 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 (rst_done_cnt && - rst_done_cnt != cdm_core->offsets->reg_data->num_bl_fifo_irq) - CAM_ERR(CAM_CDM, + 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", - rst_done_cnt, + cdm_core->rst_done_cnt, cdm_core->offsets->reg_data->num_bl_fifo_irq); return IRQ_HANDLED; } @@ -1296,6 +1297,7 @@ int cam_hw_cdm_reset_hw(struct cam_hw_info *cdm_hw, uint32_t handle) 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 */ @@ -1366,6 +1368,7 @@ int cam_hw_cdm_handle_error_info( 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); @@ -1639,6 +1642,7 @@ int cam_hw_cdm_deinit(void *hw_priv, } 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 */ @@ -1748,6 +1752,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) 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; -- GitLab From ffbfb16374ec5d113b09f0037e8a9d9edf894f5e Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Wed, 4 Mar 2020 16:05:00 +0530 Subject: [PATCH 165/295] msm: camera: ope: Consider other contexts during timeout Issue: Sometimes, ope context is not getting the callback from CDM till timeout due to other contexts processing. This results into hang detection on the waiting context. Fix: Maintaining the timestamp for last cdm callback. And checking in case of timeout if timeout happens due to processing of other contexts. CRs-Fixed: 2626430 Change-Id: Ib74c31f281ef902c663bbff08033da867f2e9ee6 Signed-off-by: Rishabh Jain Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 47 +++++++++++++++------ drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 1 + 2 files changed, 36 insertions(+), 12 deletions(-) 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 362b993fdf7b..8c06e0408fe4 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 @@ -96,8 +96,10 @@ 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) { @@ -338,17 +340,34 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) return 0; } - get_monotonic_boottime64(&ts); - ts_ns = (uint64_t)((ts.tv_sec * 1000000000) + - ts.tv_nsec); - if (ts_ns - ctx_data->last_req_time < - ((OPE_REQUEST_TIMEOUT - OPE_REQUEST_TIMEOUT / 10) * 1000000)) { - mutex_unlock(&ctx_data->ctx_mutex); - return 0; - } - if (cam_ope_is_pending_request(ctx_data)) { - CAM_DBG(CAM_OPE, "pending requests means, issue is with HW"); + + get_monotonic_boottime64(&ts); + ts_ns = (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + + if (ts_ns - ctx_data->last_req_time < + ((OPE_REQUEST_TIMEOUT - + OPE_REQUEST_TIMEOUT / 10) * 1000000)) { + cam_ope_req_timer_reset(ctx_data); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + if (ts_ns - ope_hw_mgr->last_callback_time < + ((OPE_REQUEST_TIMEOUT - + OPE_REQUEST_TIMEOUT / 10) * 1000000)) { + CAM_WARN(CAM_OPE, + "ope ctx: %d stuck due to other contexts", + ctx_data->ctx_id); + cam_ope_req_timer_reset(ctx_data); + 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); hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( hw_mgr->ope_dev_intf[i]->hw_priv, OPE_HW_DUMP_DEBUG, @@ -1200,6 +1219,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) { @@ -1228,6 +1248,9 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, handle, userdata, status, cookie); CAM_DBG(CAM_REQ, "req_id= %llu ctx_id= %d", ope_req->request_id, ctx->ctx_id); + get_monotonic_boottime64(&ts); + ope_hw_mgr->last_callback_time = (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); if (ctx->ctx_state != OPE_CTX_STATE_ACQUIRED) { CAM_ERR(CAM_OPE, "ctx %u is in %d state", 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 8e8ec020f575..0850c2c5eee2 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 @@ -512,6 +512,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; -- GitLab From 259fc2c95011df154a75dc337c750589f7a15e8e Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Thu, 5 Mar 2020 10:48:11 +0530 Subject: [PATCH 166/295] msm: camera: ope: Put GenIRQ in last stripe BL As per HW team recommendation, adding the GenIRQ command in last stripe BL for arbitration based cdm clients. CRs-Fixed: 2626430 Change-Id: I4f57ca1374cbcb3f67a0fccc62c268a669c6859a Signed-off-by: Rishabh Jain Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_core_common.c | 70 +++++--- drivers/cam_cdm/cam_cdm_hw_core.c | 158 +++++++++++++++---- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 2 + drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 2 + drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 10 +- 5 files changed, 187 insertions(+), 55 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index 095fc4d9f8ba..381c6ea3f8a1 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.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 @@ -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) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 07111f5e2a41..dfc328cf6378 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -739,6 +739,78 @@ int cam_hw_cdm_submit_debug_gen_irq( 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 = 1; + 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) @@ -868,18 +940,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, @@ -894,20 +976,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) { @@ -924,11 +1017,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; } } } @@ -972,6 +1075,7 @@ 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; } } @@ -1560,7 +1664,7 @@ int cam_hw_cdm_init(void *hw_priv, 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 = 0; + cdm_core->bl_fifo[i].last_bl_tag_done = -1; rc = cam_hw_cdm_reset_hw(cdm_hw, reset_hw_hdl); 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 8c06e0408fe4..1aa904f4e5e3 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 @@ -1759,6 +1759,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; 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 0850c2c5eee2..75e76518ebf1 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 @@ -240,6 +240,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 */ @@ -248,6 +249,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; }; 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 9bfede8cdd8e..fbf83e4b98a0 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 @@ -380,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; @@ -405,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) -- GitLab From ced0ab90154a04f84a526fc8d4842f049c8f5efb Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 16 Mar 2020 09:14:26 +0530 Subject: [PATCH 167/295] msm: camera: tfe: Process the rdi interrupts for rdi only resource If RDI only context has two rdi resources, only for one resources rdi only variable will set to true. So from tfe core need to process the rdi interrupts for only one resources. This change will avoid the rdi interrupt processing for rdi and pix use case. CRs-Fixed: 2642323 Change-Id: I2dfb1c57cb5ef7c3a8677ddae44f433d5fa71567 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 e8a2052d468a..a82add875df0 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 @@ -671,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; -- GitLab From 3659544d0d49e09c50aa8640b186ed223ddb05de Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Tue, 4 Feb 2020 11:33:11 +0530 Subject: [PATCH 168/295] msm: camera: core: Fix context release timing issue When sync object is invalid and num_in_map > 1, it will lead to context ref leak. Check sync object first, then register sync call back. CRs-Fixed: 2594185 Change-Id: I2d39ce3ea43bbe7bc05420b86b37fdfba4aa795a Signed-off-by: Ayush Kumar --- drivers/cam_core/cam_context_utils.c | 19 +++++++++++---- drivers/cam_sync/cam_sync.c | 35 +++++++++++++++++++++++++++- drivers/cam_sync/cam_sync_api.h | 11 ++++++++- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 87abebabaf00..09f164561d69 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.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 @@ -451,6 +451,17 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, "[%s][%d] : Moving req[%llu] from free_list to pending_list", ctx->dev_name, ctx->ctx_id, req->request_id); + for (j = 0; j < req->num_in_map_entries; j++) { + rc = cam_sync_check_valid( + req->in_map_entries[j].sync_id); + if (rc) { + CAM_ERR(CAM_CTXT, + "invalid in map sync object %d", + req->in_map_entries[j].sync_id); + goto put_ref; + } + } + for (j = 0; j < req->num_in_map_entries; j++) { cam_context_getref(ctx); rc = cam_sync_register_callback( @@ -472,7 +483,8 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, ctx->dev_name, ctx->ctx_id, req->request_id); - goto put_ctx_ref; + cam_context_putref(ctx); + goto put_ref; } CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d", req->in_map_entries[j].sync_id, rc); @@ -480,9 +492,6 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, } return rc; -put_ctx_ref: - for (; j >= 0; j--) - cam_context_putref(ctx); put_ref: for (--i; i >= 0; i--) { if (cam_sync_put_obj_ref(req->out_map_entries[i].sync_id)) diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index 5f205361d1e9..dfb8ac10ee22 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.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 @@ -286,6 +286,7 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) int rc; long idx = 0; bool bit; + int i = 0; if (!sync_obj || !merged_obj) { CAM_ERR(CAM_SYNC, "Invalid pointer(s)"); @@ -303,6 +304,14 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) return -EINVAL; } + for (i = 0; i < num_objs; i++) { + rc = cam_sync_check_valid(sync_obj[i]); + if (rc) { + CAM_ERR(CAM_SYNC, "Sync_obj[%d] %d valid check fail", + i, sync_obj[i]); + return rc; + } + } do { idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); if (idx >= CAM_SYNC_MAX_OBJS) @@ -374,6 +383,30 @@ int cam_sync_destroy(int32_t sync_obj) return cam_sync_deinit_object(sync_dev->sync_table, sync_obj); } +int cam_sync_check_valid(int32_t sync_obj) +{ + struct sync_table_row *row = NULL; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + row = sync_dev->sync_table + sync_obj; + + if (!test_bit(sync_obj, sync_dev->bitmap)) { + CAM_ERR(CAM_SYNC, "Error: Released sync obj received %d", + sync_obj); + return -EINVAL; + } + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + return -EINVAL; + } + return 0; +} + int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms) { unsigned long timeleft; diff --git a/drivers/cam_sync/cam_sync_api.h b/drivers/cam_sync/cam_sync_api.h index 3d99bc15eb18..3304acb50bba 100644 --- a/drivers/cam_sync/cam_sync_api.h +++ b/drivers/cam_sync/cam_sync_api.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef __CAM_SYNC_API_H__ @@ -140,5 +140,14 @@ int cam_sync_destroy(int32_t sync_obj); */ int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms); +/** + * @brief: Check if sync object is valid + * + * @param sync_obj: int referencing the sync object to be checked + * + * @return 0 upon success, -EINVAL if sync object is in bad state or arguments + * are invalid + */ +int cam_sync_check_valid(int32_t sync_obj); #endif /* __CAM_SYNC_API_H__ */ -- GitLab From 7d71c4632c91797b17dcc5a8fcc881e0b3e92c15 Mon Sep 17 00:00:00 2001 From: Sravan Muppidi Date: Tue, 24 Dec 2019 15:54:42 +0530 Subject: [PATCH 169/295] msm: camera: jpeg: Check the HW state before accessing register Check the hardware state before accessing registers to prevent unclocked access. CRs-Fixed: 2598203 Change-Id: I136b00d157d846c6582d80b8bf2be6b1238af50f Signed-off-by: Sravan Muppidi --- .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) 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 b9329a8173e5..c0cfbe7a76e4 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; + 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"); + 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); -- GitLab From 156642d0fc75b59a46d7f9e1b789bcfea29a04f5 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Mon, 27 Jan 2020 12:48:43 +0530 Subject: [PATCH 170/295] msm: camera: csiphy: Update csiphy power-up sequence for lito v2 Update the power-up sequence for lito v2, as per HPG revision M. CRs-Fixed: 2614237 Change-Id: I72caafdff0cfa7eb3be1d95c708c2225f45b52b1 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/cam_csiphy_soc.c | 6 ++--- .../include/cam_csiphy_1_2_2_hwreg.h | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) 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 3c1c01337bda..c96baff8c662 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.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 "cam_csiphy_soc.h" @@ -321,11 +321,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 dd88ba7cca38..119b6b575b60 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] = { { -- GitLab From 4731c26fe9f492d3cad22adba543758365249751 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Mon, 10 Feb 2020 20:09:37 +0530 Subject: [PATCH 171/295] msm: camera: cpas: Setting the vote level on max supported clock lvl basis In Some targets number of use cases are 7 and it was an issue during setting TURBO clock level. Changed the validation from number of client usecase to MAX supported clock level. CRs-Fixed: 2571273 Change-Id: I05cd06ff11c2c43eb4b70d69314e04055894c5fc Signed-off-by: Chandan Kumar Jha --- drivers/cam_cpas/cam_cpas_hw.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index e5ddbe179575..6b6cef4969a5 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -62,9 +62,11 @@ static int cam_cpas_util_vote_bus_client_level( return -EINVAL; } - if (level >= bus_client->num_usecases) { - CAM_ERR(CAM_CPAS, "Invalid vote level=%d, usecases=%d", level, - bus_client->num_usecases); + if (level >= CAM_MAX_VOTE) { + CAM_ERR(CAM_CPAS, + "Invalid votelevel=%d,usecases=%d,Bus client=[%d][%s]", + level, bus_client->num_usecases, + bus_client->client_id, bus_client->name); return -EINVAL; } -- GitLab From 8f8d50ed3150ee8aa148017363ddd2377d3983dd Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Thu, 19 Mar 2020 10:06:02 +0530 Subject: [PATCH 172/295] msm: camera: cdm: Secure freeing of request lists using locks If release is called while processing of request, there is a possibility of freeing the lists simultaneously in two contexts due to interrupt and release ioctl call. This can result into double free. Securing the release of request lists in interrupt handler and deinit using locks. CRs-Fixed: 2641842 Change-Id: I248fa80a32836c3a89494072c55af852c3d518eb Signed-off-by: Rishabh Jain --- drivers/cam_cdm/cam_cdm_hw_core.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 28207a14376c..6f08f1545511 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1141,7 +1141,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, @@ -1162,6 +1167,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) 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]) @@ -1565,6 +1571,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; @@ -1578,6 +1585,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"); @@ -1598,7 +1608,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, @@ -1609,6 +1618,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; @@ -1624,6 +1636,7 @@ int cam_hw_cdm_deinit(void *hw_priv, int rc = 0, i; uint32_t reset_val = 1; long time_left; + unsigned long flags; if (!hw_priv) return -EINVAL; @@ -1631,6 +1644,9 @@ int cam_hw_cdm_deinit(void *hw_priv, soc_info = &cdm_hw->soc_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, @@ -1674,13 +1690,17 @@ int cam_hw_cdm_deinit(void *hw_priv, } 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; -- GitLab From 9905a5d49ce23b78641a94b3109df73737b6bc0d Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Tue, 17 Mar 2020 17:02:01 +0530 Subject: [PATCH 173/295] msm: camera: csiphy: Clear secure phy flags on release Issue: Phy flags are set on CONFIG_DEV and are cleared on STOP_DEV. If release is called without stop dev, next session will be opened with incorrect phy configuration based on the previous stale secure mode flags. Fix: Clear the phy secure mode flags on RELEASE_DEV. CRs-Fixed: 2635529 Change-Id: Ib22bbdaa99ca29419200f0d9eb20792f34aaec0c Signed-off-by: Tony Lijo Jose --- .../cam_csiphy/cam_csiphy_core.c | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) 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 9d5976d86f26..65e571f036f3 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.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 @@ -45,6 +45,11 @@ static int cam_csiphy_notify_secure_mode(struct csiphy_device *csiphy_dev, CAM_ERR(CAM_CSIPHY, "scm call to hypervisor failed"); return -EINVAL; } + CAM_INFO(CAM_CSIPHY, "PHY : %d offset: %d SEC: %d Mask: %d", + csiphy_dev->soc_info.index, + offset, + protect, + csiphy_dev->csiphy_cpas_cp_reg_mask[offset]); return 0; } @@ -819,6 +824,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) { @@ -834,6 +840,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"); -- GitLab From 266e415db9441131e2522c3c8b52d9bd0a9fa0d8 Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Sun, 22 Mar 2020 17:14:37 +0530 Subject: [PATCH 174/295] msm: camera: cpas: Add support for Scuba camnoc Scuba has different version of camnoc and CPAS version which requires separate register space and camnoc interface changes and CPAS version change. This change adds the same. CRs-Fixed: 2643455 Change-Id: Iddea6900e9d466d8843a5b0f679425b6b959484c Signed-off-by: Suresh Vankadara --- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 10 +- drivers/cam_cpas/cpas_top/cpastop_v520_100.h | 240 +++++++++++++++++++ drivers/cam_cpas/include/cam_cpas_api.h | 3 +- 3 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v520_100.h diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 0c4cd7d1e51c..d62c06f59544 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.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 @@ -23,6 +23,7 @@ #include "cpastop_v175_130.h" #include "cpastop_v480_100.h" #include "cpastop_v540_100.h" +#include "cpastop_v520_100.h" struct cam_camnoc_info *camnoc_info; @@ -127,6 +128,10 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, (hw_caps->camera_version.minor == 4) && (hw_caps->camera_version.incr == 0)) { soc_info->hw_version = CAM_CPAS_TITAN_540_V100; + } else if ((hw_caps->camera_version.major == 5) && + (hw_caps->camera_version.minor == 2) && + (hw_caps->camera_version.incr == 0)) { + soc_info->hw_version = CAM_CPAS_TITAN_520_V100; } CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); @@ -634,6 +639,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 000000000000..ec99574ebf10 --- /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 ab8634f7119e..6b3c6c75f412 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.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 _CAM_CPAS_API_H_ @@ -47,6 +47,7 @@ enum cam_cpas_hw_version { CAM_CPAS_TITAN_175_V130 = 0x175130, CAM_CPAS_TITAN_480_V100 = 0x480100, CAM_CPAS_TITAN_540_V100 = 0x540100, + CAM_CPAS_TITAN_520_V100 = 0x520100, CAM_CPAS_TITAN_MAX }; -- GitLab From 1414835d6d915eed148b36e1d6046a8a22d8e984 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 9 Jan 2020 12:18:17 -0800 Subject: [PATCH 175/295] msm: camera: isp: Change data type for error handling Use unsigned long to capture the return value of wait_for_completion APIs as part of CSID path reset. CRs-Fixed: 2600604 Change-Id: Ic21ddf283180a177b2c2d9e9a33fec4ec68bdd98 Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) 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 d70094db859a..e353cb0e64b0 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 @@ -285,7 +285,7 @@ static int cam_ife_hw_mgr_reset_csid_res( rc = hw_intf->hw_ops.reset(hw_intf->hw_priv, &csid_reset_args, sizeof(struct cam_csid_reset_cfg_args)); - if (rc <= 0) + if (rc) goto err; } } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 7e35772ca1f0..2b499ecf2223 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -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. */ #include @@ -527,6 +527,7 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, struct cam_csid_reset_cfg_args *reset) { int rc = 0; + unsigned long rem_jiffies; struct cam_hw_soc_info *soc_info; struct cam_isp_resource_node *res; const struct cam_ife_csid_reg_offset *csid_reg; @@ -646,14 +647,13 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, cam_io_w_mb(reset_strb_val, soc_info->reg_map[0].mem_base + reset_strb_addr); - rc = wait_for_completion_timeout(complete, + rem_jiffies = wait_for_completion_timeout(complete, msecs_to_jiffies(IFE_CSID_TIMEOUT)); - if (rc <= 0) { + if (!rem_jiffies) { + rc = -ETIMEDOUT; CAM_ERR(CAM_ISP, "CSID:%d Res id %d fail rc = %d", csid_hw->hw_intf->hw_idx, res->res_id, rc); - if (rc == 0) - rc = -ETIMEDOUT; } end: -- GitLab From d2591569bb80557c863bafa3fb1112fff98ade88 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 23 Mar 2020 16:09:32 +0530 Subject: [PATCH 176/295] msm: camera: tfe: validate the tfe bw num paths If tfe bandwidth number of paths configuration is zero then do not proceed. Number of bandwidth paths should be minimum one and should not be greater than max value. CRs-Fixed: 2647558 Change-Id: I56b05302ab7e1a33f61012f7678d47d56b33a99d Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 5f31e23a2212..8611e9f0063e 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 @@ -3611,7 +3611,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; -- GitLab From 64aa7f79a84a9177c32b750d253aeb6be25b92ae Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Tue, 24 Mar 2020 11:33:55 +0530 Subject: [PATCH 177/295] msm: camera: ope: Reorder the reset order in ope acquire Initialize CDM prior to the OPE. This will help to reset CDM before OPE. CRs-Fixed: 2646377 Change-Id: I7136cbb04f687e7d5756431731af618718c5a2a7 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 94 ++++++++++----------- 1 file changed, 47 insertions(+), 47 deletions(-) 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 982ecad55524..bceb76d6d571 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 @@ -2470,6 +2470,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++) { @@ -2479,7 +2515,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; } } @@ -2525,43 +2561,6 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) } } - cdm_acquire = kzalloc(sizeof(struct cam_cdm_acquire_data), GFP_KERNEL); - if (!cdm_acquire) { - CAM_ERR(CAM_ISP, "Out of memory"); - goto ope_dev_acquire_failed; - } - 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; - } - 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( @@ -2619,11 +2618,6 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) kzfree(bw_update); bw_update = NULL; ope_clk_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++) { if (hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( @@ -2631,10 +2625,6 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) &ope_dev_release, sizeof(ope_dev_release))) CAM_ERR(CAM_OPE, "OPE Dev release failed"); } - -free_cdm_acquire: - kzfree(cdm_acquire); - cdm_acquire = NULL; ope_dev_acquire_failed: if (!hw_mgr->ope_ctx_cnt) { irq_cb.ope_hw_mgr_cb = NULL; @@ -2661,6 +2651,16 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) 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); -- GitLab From 78a0740078f2927eb64214c08fb57a631490e940 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Tue, 24 Mar 2020 13:54:34 +0530 Subject: [PATCH 178/295] msm: camera: ope: Dump debug registers in case of reset failure Dump debug registers and irq status register in case of reset failure. CRs-Fixed: 2646377 Change-Id: I1acea4761b884d0ffeba9d44e2f0e70d53f1813b Signed-off-by: Rishabh Jain --- .../cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c | 65 +++++++++++-------- 1 file changed, 39 insertions(+), 26 deletions(-) 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 2ecfa4e1e417..becfa63540ed 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"); @@ -59,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,29 +94,11 @@ static int cam_ope_top_reset(struct ope_hw *ope_hw_info, /* 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); mutex_unlock(&ope_top_info.ope_hw_mutex); return rc; } -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; - struct cam_ope_top_reg_val *top_reg_val; - - top_reg = ope_hw_info->top_reg; - top_reg_val = ope_hw_info->top_reg_val; - 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_release(struct ope_hw *ope_hw_info, int32_t ctx_id, void *data) { @@ -130,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"); @@ -148,7 +155,6 @@ static int cam_ope_top_init(struct ope_hw *ope_hw_info, /* 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); @@ -156,20 +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; } -- GitLab From a3770ced1a88165e2a4c306df2eeab718f190c57 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Sun, 22 Mar 2020 20:16:30 +0530 Subject: [PATCH 179/295] msm: camera: ope: Add logic to detect hang in CDM It is possible that cdm clients get callback from CDM in sometime due to delay in scheduling CDM workqueue. Add a logic to detect this delay so that client don't detect false hang. CRs-Fixed: 2640897 Change-Id: I1a9fdc1ac5d6bcc1869802793632bf6bf8b4c2ca Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm.h | 2 + drivers/cam_cdm/cam_cdm_core_common.c | 35 +++++++++++ drivers/cam_cdm/cam_cdm_core_common.h | 3 +- drivers/cam_cdm/cam_cdm_hw_core.c | 57 +++++++++++++++-- drivers/cam_cdm/cam_cdm_intf.c | 29 ++++++++- drivers/cam_cdm/cam_cdm_intf_api.h | 11 +++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 70 ++++++++++++++++----- 7 files changed, 183 insertions(+), 24 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index 458ecca48dbd..cc808fe2c508 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -373,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, }; @@ -469,6 +470,7 @@ struct cam_cdm_bl_fifo { uint8_t bl_tag; uint32_t bl_depth; uint8_t last_bl_tag_done; + uint32_t work_record; }; /** diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index 381c6ea3f8a1..e93e54f0335e 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -785,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 5cde7c504fa2..5545f15903e0 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.h +++ b/drivers/cam_cdm/cam_cdm_core_common.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 _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 38c3627c24c6..67199b94e94c 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -301,7 +301,11 @@ 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); + + 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); @@ -1076,6 +1080,7 @@ static void cam_hw_cdm_reset_cleanup( } core->bl_fifo[i].bl_tag = 0; core->bl_fifo[i].last_bl_tag_done = -1; + core->bl_fifo[i].work_record = 0; } } @@ -1102,8 +1107,10 @@ static void cam_hw_cdm_work(struct work_struct *work) 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"); @@ -1114,6 +1121,10 @@ static void cam_hw_cdm_work(struct work_struct *work) mutex_lock(&core->bl_fifo[payload->fifo_idx] .fifo_lock); + + 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) { @@ -1145,6 +1156,10 @@ static void cam_hw_cdm_work(struct work_struct *work) kfree(node); node = NULL; } + } 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); @@ -1291,6 +1306,10 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) CAM_CDM_IRQ_STATUS_USR_DATA_MASK; } + 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; @@ -1302,6 +1321,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) payload[i]->irq_status, cdm_hw->soc_info.index); + cdm_core->bl_fifo[i].work_record++; work_status = queue_work( cdm_core->bl_fifo[i].work_queue, &payload[i]->work); @@ -1597,6 +1617,33 @@ int cam_hw_cdm_handle_error( 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; @@ -1692,8 +1739,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++) + 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); diff --git a/drivers/cam_cdm/cam_cdm_intf.c b/drivers/cam_cdm/cam_cdm_intf.c index 7796eb7f9a40..3d50beb4cf43 100644 --- a/drivers/cam_cdm/cam_cdm_intf.c +++ b/drivers/cam_cdm/cam_cdm_intf.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 @@ -479,6 +479,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 756f7f4bea4e..0a3155824f8d 100644 --- a/drivers/cam_cdm/cam_cdm_intf_api.h +++ b/drivers/cam_cdm/cam_cdm_intf_api.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 _CAM_CDM_API_H_ @@ -250,4 +250,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_ope/ope_hw_mgr/cam_ope_hw_mgr.c b/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c index 982ecad55524..fb0cb10ce482 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 @@ -576,6 +576,28 @@ static void cam_ope_dump_req_data(struct cam_ope_request *ope_req) 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 *clk_data = (struct ope_clk_work_data *)data; @@ -588,8 +610,6 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) int i = 0; int device_share_ratio = 1; int path_index; - struct timespec64 ts; - uint64_t ts_ns; struct crm_workq_task *task; struct ope_msg_work_data *task_data; @@ -609,25 +629,33 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) if (cam_ope_is_pending_request(ctx_data)) { - get_monotonic_boottime64(&ts); - ts_ns = (uint64_t)((ts.tv_sec * 1000000000) + - ts.tv_nsec); + 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 (ts_ns - ctx_data->last_req_time < - ((OPE_REQUEST_TIMEOUT - - OPE_REQUEST_TIMEOUT / 10) * 1000000)) { + 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; } - if (ts_ns - ope_hw_mgr->last_callback_time < - ((OPE_REQUEST_TIMEOUT - - OPE_REQUEST_TIMEOUT / 10) * 1000000)) { + /* 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); - cam_ope_req_timer_reset(ctx_data); mutex_unlock(&ctx_data->ctx_mutex); return 0; } @@ -635,6 +663,9 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) 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, @@ -1510,15 +1541,17 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, ope_req = ctx->req_list[cookie]; - 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", - ope_req->request_id, ctx->ctx_id); 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_ERR(CAM_OPE, "ctx %u is in %d state", ctx->ctx_id, ctx->ctx_state); @@ -3067,6 +3100,9 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, 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); ctx_data->req_list[request_idx] = -- GitLab From 97c8cb415e654673f348d529206e2baf0f81f38f Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 30 Mar 2020 10:12:05 +0530 Subject: [PATCH 180/295] msm: camera: isp: Increase max count of cfg to support more init packets Increase maximum count of command buffers in a request to support more number of init packets. CRs-Fixed: 2652124 Change-Id: I6c85cf5720076c09350b952bc09ed30fbcf27497 Signed-off-by: Rishabh Jain --- drivers/cam_isp/cam_isp_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 78e2db92f0b1..2bffd0c85323 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -26,7 +26,7 @@ * Maximum configuration entry size - This is based on the * worst case DUAL IFE use case plus some margin. */ -#define CAM_ISP_CTX_CFG_MAX 22 +#define CAM_ISP_CTX_CFG_MAX 25 /* * Maximum entries in state monitoring array for error logging -- GitLab From 2c31a669021309ca688935a2c423d4c4a8d84db3 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 13 Jan 2020 17:14:33 +0530 Subject: [PATCH 181/295] msm: camera: core: Fix cpas axi clk rate overflow Change the clk variable type from int32_t to int64_t to avoid integer overflow. CRs-Fixed: 2609090 Change-Id: I9f785ce2c1e45b1e9a238c42e86da1161bf70f75 Signed-off-by: Ravikishore Pampana --- drivers/cam_cpas/cam_cpas_hw.c | 6 +++--- drivers/cam_utils/cam_soc_util.c | 18 +++++++++--------- drivers/cam_utils/cam_soc_util.h | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 6b6cef4969a5..2a829f817a1d 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -450,7 +450,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]; @@ -479,7 +479,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); /* @@ -492,7 +492,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); } } diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index ce80569ab0f9..57c8efaf75fb 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 aeaf1c6563ea..bb4aff5e71ce 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, -- GitLab From bd6f0641687a2560f65f1984501f3f3f6d7dd30e Mon Sep 17 00:00:00 2001 From: Anil Kumar Kanakanti Date: Tue, 18 Feb 2020 11:49:52 +0530 Subject: [PATCH 182/295] msm: camera: csiphy: Secure cam usecase not working Secure CP control register always assume that it contains 7 bit mask for each PHY. But this register format is different based on target. Update secure CP control bitmask generation logic for each PHY index based on phy_version. So we have below 3 combinations to handle at SW. 1.Old Titan Targets : 7 bits for each PHY. 2.PHY 1_2_1 : for 4 pHYS 7 bits and for remaining 2 PHYs 8 bits are reserved. 3.Mimas (PHY 2_0_1): 8 bits for each PHY. CRs-Fixed: 2624698 Change-Id: Iac4c3c718fc96a51592e07b45458fb045c52366d Signed-off-by: Anil Kumar Kanakanti --- .../cam_csiphy/cam_csiphy_core.c | 60 ++++++++++++++++--- .../cam_csiphy/cam_csiphy_soc.c | 19 +++++- .../cam_csiphy/cam_csiphy_soc.h | 3 +- 3 files changed, 73 insertions(+), 9 deletions(-) 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 9d5976d86f26..6a0da8302b13 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.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 @@ -23,6 +23,9 @@ #define LANE_MASK_2PH 0x1F #define LANE_MASK_3PH 0x7 +#define SEC_LANE_CP_REG_LEN 32 +#define MAX_PHY_MSK_PER_REG 4 + static int csiphy_dump; module_param(csiphy_dump, int, 0644); @@ -107,7 +110,7 @@ int32_t cam_csiphy_update_secure_info( struct cam_csiphy_info *cam_cmd_csiphy_info, struct cam_config_dev_cmd *cfg_dev) { - uint32_t clock_lane, adj_lane_mask, temp; + uint32_t clock_lane, adj_lane_mask, temp, phy_mask_len; int32_t offset; if (csiphy_dev->acquire_count >= @@ -141,12 +144,37 @@ int32_t cam_csiphy_update_secure_info( csiphy_dev->csiphy_info.secure_mode[offset] = 1; - csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = - adj_lane_mask << (csiphy_dev->soc_info.index * - (CAM_CSIPHY_MAX_DPHY_LANES + CAM_CSIPHY_MAX_CPHY_LANES) + - (!cam_cmd_csiphy_info->csiphy_3phase) * - (CAM_CSIPHY_MAX_CPHY_LANES)); + if (csiphy_dev->hw_version == CSIPHY_VERSION_V201) { + phy_mask_len = CAM_CSIPHY_MAX_DPHY_LANES + + CAM_CSIPHY_MAX_CPHY_LANES + 1; + } else if (csiphy_dev->hw_version == CSIPHY_VERSION_V121) { + phy_mask_len = + (csiphy_dev->soc_info.index < MAX_PHY_MSK_PER_REG) ? + CAM_CSIPHY_MAX_DPHY_LANES + CAM_CSIPHY_MAX_CPHY_LANES : + CAM_CSIPHY_MAX_DPHY_LANES + + CAM_CSIPHY_MAX_CPHY_LANES + 1; + } else { + phy_mask_len = CAM_CSIPHY_MAX_DPHY_LANES + + CAM_CSIPHY_MAX_CPHY_LANES; + } + if (csiphy_dev->soc_info.index < MAX_PHY_MSK_PER_REG) { + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = + ((uint64_t)adj_lane_mask) << + (csiphy_dev->soc_info.index * phy_mask_len + + (!cam_cmd_csiphy_info->csiphy_3phase) * + (CAM_CSIPHY_MAX_CPHY_LANES)); + } else { + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = + ((uint64_t)adj_lane_mask) << + ((csiphy_dev->soc_info.index - MAX_PHY_MSK_PER_REG) * + phy_mask_len + SEC_LANE_CP_REG_LEN + + (!cam_cmd_csiphy_info->csiphy_3phase) * + (CAM_CSIPHY_MAX_CPHY_LANES)); + } + CAM_DBG(CAM_CSIPHY, "csi phy idx:%d, cp_reg_mask:0x%lx", + csiphy_dev->soc_info.index, + csiphy_dev->csiphy_cpas_cp_reg_mask[offset]); return 0; } @@ -243,6 +271,24 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, cam_csiphy_update_secure_info(csiphy_dev, cam_cmd_csiphy_info, cfg_dev); + CAM_DBG(CAM_CSIPHY, + "phy version_%d, lane count:%d, mask:0x%x", + csiphy_dev->hw_version, + csiphy_dev->csiphy_info.lane_cnt, + csiphy_dev->csiphy_info.lane_mask + ); + CAM_DBG(CAM_CSIPHY, + "3phase:%d, combo mode:%d, secure mode:%d", + csiphy_dev->csiphy_info.csiphy_3phase, + csiphy_dev->csiphy_info.combo_mode, + cam_cmd_csiphy_info->secure_mode + ); + CAM_DBG(CAM_CSIPHY, + "phy idx:%d, settle time:%d, datarate:%d", + csiphy_dev->soc_info.index, + csiphy_dev->csiphy_info.settle_time, + csiphy_dev->csiphy_info.data_rate); + return rc; } 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 3c1c01337bda..6740df37d40e 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.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 "cam_csiphy_soc.h" @@ -349,6 +349,23 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->is_divisor_32_comp = false; csiphy_dev->clk_lane = 0; csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v2.0.1")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v2_0_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; + csiphy_dev->hw_version = CSIPHY_VERSION_V201; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else { CAM_ERR(CAM_CSIPHY, "invalid hw version : 0x%x", csiphy_dev->hw_version); diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h index c02b9556add4..8b40319a60f5 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.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 _CAM_CSIPHY_SOC_H_ @@ -31,6 +31,7 @@ #define CSIPHY_VERSION_V12 0x12 #define CSIPHY_VERSION_V121 0x121 #define CSIPHY_VERSION_V20 0x20 +#define CSIPHY_VERSION_V201 0x201 /** * @csiphy_dev: CSIPhy device structure -- GitLab From a6acefc70084c845f504abe27d455daf29e884f3 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Wed, 1 Apr 2020 14:26:18 +0530 Subject: [PATCH 183/295] msm: camera: ope: Fix OPE hang dump OPE is using memhandle to fill bl information. So, updating the hang dump logic to use memhandle instead of iova address to fill bl related information. IOVA address will be fetched from memhandle inside dump logic. CRs-Fixed: 2655671 Change-Id: I536aef71050964c985db359662732f26f026c3d8 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) 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 62a1cddec7ed..666f76f7550e 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 @@ -536,13 +536,21 @@ 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; + size_t size; + int i, rc; + dma_addr_t iova_addr; cdm_cmd = ope_req->cdm_cmd; for (i = 0; i < cdm_cmd->cmd_arrary_count; i++) { + rc = cam_mem_get_io_buf(cdm_cmd->cmd[i].bl_addr.mem_handle, + ope_hw_mgr->iommu_hdl, &iova_addr, &size); + if (rc) { + CAM_ERR(CAM_OPE, "get io buf fail 0x%x", + cdm_cmd->cmd[i].bl_addr.mem_handle); + return rc; + } dump->bl_entries[dump->num_bls].base = - (uint32_t)cdm_cmd->cmd[i].bl_addr.hw_iova + - cdm_cmd->cmd[i].offset; + (uint32_t)iova_addr + 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; -- GitLab From dcc74ba3c184e4fd39150be4a097daea65382f41 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Thu, 2 Apr 2020 20:11:02 +0530 Subject: [PATCH 184/295] msm: camera: cdm: Add a check for fifo list in cdm workqueue CDM workqueue stores the last fifo bl tag done entry for which it's got scheduled. There is possibility that flush can execute before workqueue and remove all the fifo entries. This can skip the work for new requests if new bl tag matches with last bl tag done entry and cdm don't send notification to clients. Add a check to validate fifo list for empty entry in cdm workqueue function. CRs-Fixed: 2653649 Change-Id: I788f6d1e4c1c011a2a9ed690ddeff2b1bde0e569 Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index e473a33acaed..be73a79054e0 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1063,6 +1063,9 @@ static void cam_hw_cdm_reset_cleanup( &core->bl_fifo[i].bl_request_list, entry) { if (node->request_type == CAM_HW_CDM_BL_CB_CLIENT) { + CAM_DBG(CAM_CDM, + "Notifying client %d for tag %d", + node->client_hdl, node->bl_tag); if (flush_hw) cam_cdm_notify_clients(cdm_hw, (node->client_hdl == handle) ? @@ -1125,6 +1128,17 @@ static void cam_hw_cdm_work(struct work_struct *work) if (core->bl_fifo[payload->fifo_idx].work_record) core->bl_fifo[payload->fifo_idx].work_record--; + if (list_empty(&core->bl_fifo[payload->fifo_idx] + .bl_request_list)) { + CAM_INFO(CAM_CDM, + "Fifo list empty, idx %d tag %d arb %d", + payload->fifo_idx, payload->irq_data, + core->arbitration); + mutex_unlock(&core->bl_fifo[payload->fifo_idx] + .fifo_lock); + return; + } + if (core->bl_fifo[payload->fifo_idx] .last_bl_tag_done != payload->irq_data) { @@ -1157,7 +1171,7 @@ static void cam_hw_cdm_work(struct work_struct *work) node = NULL; } } else { - CAM_DBG(CAM_CDM, + CAM_INFO(CAM_CDM, "Skip GenIRQ, tag 0x%x fifo %d", payload->irq_data, payload->fifo_idx); } -- GitLab From 82fc667b436e47a97eee21fbcf7c9312ec306469 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 19 Mar 2020 11:03:04 +0530 Subject: [PATCH 185/295] msm: camera: isp: variable should be accessed only if match is found There is a possibility that the priority variable would be accessed even for the HEAD node which would result in out of bound errors, so access the elements of the structure only if the handler is found. CRs-Fixed: 2646173 Change-Id: I0540658b9c9487f6e3a4601a488a1add1e790dda Signed-off-by: Tejas Prajapati --- .../isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c index cc1fe18e05fd..5763939fd310 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.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 @@ -515,8 +515,8 @@ int cam_irq_controller_unsubscribe_irq(void *irq_controller, } } - priority = evt_handler->priority; if (found) { + priority = evt_handler->priority; for (i = 0; i < controller->num_registers; i++) { irq_register = &controller->irq_register_arr[i]; irq_register->top_half_enable_mask[priority] &= -- GitLab From 28a7d67a1d8e02df57b076d1e6f018ba671c5236 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Sat, 21 Mar 2020 13:52:02 +0530 Subject: [PATCH 186/295] msm: camera: ope: Add a check to validate dmi cmd address Add a check to validate DMI command address before writing DMI in command buffer. This can avoid cdm doing null pointer de-reference. CRs-Fixed: 2664479 Change-Id: If99da6fd23f73c1c666cdcec60b0f68eb300425e Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 26 +++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) 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 fbf83e4b98a0..9f1068adc473 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 @@ -581,6 +581,11 @@ static uint32_t *ope_create_frame_cmd_batch(struct cam_ope_hw_mgr *hw_mgr, memcpy(temp, (const void *)print_ptr, sizeof(struct cdm_dmi_cmd)); dmi_cmd = (struct cdm_dmi_cmd *)temp; + if (!dmi_cmd->addr) { + CAM_ERR(CAM_OPE, "Null dmi cmd addr"); + return NULL; + } + kmd_buf = cdm_ops->cdm_write_dmi( kmd_buf, 0, dmi_cmd->DMIAddr, @@ -731,6 +736,12 @@ static uint32_t *ope_create_frame_cmd(struct cam_ope_hw_mgr *hw_mgr, memcpy(temp, (const void *)print_ptr, sizeof(struct cdm_dmi_cmd)); dmi_cmd = (struct cdm_dmi_cmd *)temp; + if (!dmi_cmd->addr) { + CAM_ERR(CAM_OPE, + "Null dmi cmd addr"); + return NULL; + } + kmd_buf = cdm_ops->cdm_write_dmi( kmd_buf, 0, dmi_cmd->DMIAddr, @@ -837,6 +848,11 @@ static uint32_t *ope_create_stripe_cmd(struct cam_ope_hw_mgr *hw_mgr, memcpy(temp, (const void *)print_ptr, sizeof(struct cdm_dmi_cmd)); dmi_cmd = (struct cdm_dmi_cmd *)temp; + if (!dmi_cmd->addr) { + CAM_ERR(CAM_OPE, "Null dmi cmd addr"); + return NULL; + } + kmd_buf = cdm_ops->cdm_write_dmi(kmd_buf, 0, dmi_cmd->DMIAddr, dmi_cmd->DMISel, dmi_cmd->addr, dmi_cmd->length); @@ -1511,10 +1527,12 @@ static int cam_ope_dev_process_prepare(struct ope_hw *ope_hw, void *cmd_args) if (rc) goto end; - cam_ope_dev_create_kmd_buf(ope_dev_prepare_req->hw_mgr, - ope_dev_prepare_req->prepare_args, - ope_dev_prepare_req->ctx_data, ope_dev_prepare_req->req_idx, - ope_dev_prepare_req->kmd_buf_offset, ope_dev_prepare_req); + rc = cam_ope_dev_create_kmd_buf(ope_dev_prepare_req->hw_mgr, + ope_dev_prepare_req->prepare_args, + ope_dev_prepare_req->ctx_data, + ope_dev_prepare_req->req_idx, + ope_dev_prepare_req->kmd_buf_offset, + ope_dev_prepare_req); end: return rc; -- GitLab From 0a0ebfa0ad84f1c25b14be1c8e37a6ced631f8e6 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Sat, 21 Mar 2020 14:24:17 +0530 Subject: [PATCH 187/295] msm: camera: ope: Add check for number of stripe There is possibility that ope driver gets invalid number of stripes. Add a check to validate it and return failure to user-space. CRs-Fixed: 2664479 Change-Id: Ic80d3376b853e500b793b0b5d051288f2a2640ba Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 6 ++++++ 1 file changed, 6 insertions(+) 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 666f76f7550e..67594b9d2e0d 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 @@ -1831,6 +1831,12 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, CAM_DBG(CAM_OPE, "m_hdl: %d len: %d", in_io_buf->mem_handle[k], in_io_buf->length[k]); + + if (!in_io_buf->num_stripes[k]) { + CAM_ERR(CAM_OPE, "Null num_stripes"); + return -EINVAL; + } + for (l = 0; l < in_io_buf->num_stripes[k]; l++) { in_stripe_info = -- GitLab From 3bd49ac00040baaf6b35a102a3086d7170bddd36 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Tue, 7 Apr 2020 20:10:04 +0530 Subject: [PATCH 188/295] msm: camera: tfe: Support tfe pdaf port Added Pdaf support to tfe driver. TFE camif module register will configure by user space as per the use case. So removing the camif module register configuration from tfe driver. Tfe pdaf port bus shares same write master as rdi2, but pdaf should be configured as line based and proper packer format. CRs-Fixed: 2664724 Change-Id: Idcf481eefda24e37ffebb58ed1c8d9e9d3ca6241 Signed-off-by: Ravikishore Pampana --- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 20 ++++++++++++++----- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 17 ---------------- 2 files changed, 15 insertions(+), 22 deletions(-) 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 01ffb90d7461..5e954c14997c 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 @@ -77,6 +77,7 @@ struct cam_tfe_bus_common_data { struct cam_tfe_bus_wm_resource_data { uint32_t index; + uint32_t out_id; struct cam_tfe_bus_common_data *common_data; struct cam_tfe_bus_reg_offset_bus_client *hw_regs; @@ -628,6 +629,7 @@ static int cam_tfe_bus_acquire_wm( rsrc_data->height = out_port_info->height; rsrc_data->stride = out_port_info->stride; rsrc_data->mode = out_port_info->wm_mode; + rsrc_data->out_id = tfe_out_res_id; /* * Store the acquire width, height separately. For frame based ports @@ -641,14 +643,16 @@ static int cam_tfe_bus_acquire_wm( /* Set WM offset value to default */ rsrc_data->offset = 0; - if (rsrc_data->index > 6) { + if ((rsrc_data->index > 6) && + (tfe_out_res_id != CAM_TFE_BUS_TFE_OUT_PDAF)) { /* WM 7-9 refers to RDI 0/ RDI 1/RDI 2 */ 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 */ + } else if (rsrc_data->index == 0 || rsrc_data->index == 1 || + (tfe_out_res_id == CAM_TFE_BUS_TFE_OUT_PDAF)) { + /* WM 0 FULL_OUT WM 1 IDEAL RAW WM9 for pdaf */ switch (rsrc_data->format) { case CAM_FORMAT_MIPI_RAW_8: rsrc_data->pack_fmt = 0x1; @@ -744,9 +748,14 @@ static int cam_tfe_bus_start_wm(struct cam_isp_resource_node *wm_res) /* Configure stride for RDIs on full TFE and TFE lite */ if ((rsrc_data->index > 6) && - (rsrc_data->mode != CAM_ISP_TFE_WM_LINE_BASED_MODE)) + ((rsrc_data->mode != CAM_ISP_TFE_WM_LINE_BASED_MODE) && + (rsrc_data->out_id != CAM_TFE_BUS_TFE_OUT_PDAF))) { cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + rsrc_data->hw_regs->image_cfg_2)); + CAM_DBG(CAM_ISP, "WM:%d configure stride reg :0x%x", + rsrc_data->index, + rsrc_data->stride); + } /* Enable WM */ cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + @@ -1885,7 +1894,8 @@ static int cam_tfe_bus_update_wm(void *priv, void *cmd_args, wm_data->index, reg_val_pair[j-1]); if ((wm_data->index < 7) || ((wm_data->index >= 7) && - (wm_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE))) { + (wm_data->mode == CAM_ISP_TFE_WM_LINE_BASED_MODE)) || + (wm_data->out_id == CAM_TFE_BUS_TFE_OUT_PDAF)) { 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_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c index a82add875df0..e0cd354e80da 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 @@ -1922,23 +1922,6 @@ static int cam_tfe_camif_resource_start( return -ENODEV; } - /* Camif module config */ - val = cam_io_r(rsrc_data->mem_base + - rsrc_data->camif_reg->module_cfg); - val &= ~(rsrc_data->reg_data->pixel_pattern_mask); - val |= (rsrc_data->pix_pattern << - rsrc_data->reg_data->pixel_pattern_shift); - val |= (1 << rsrc_data->reg_data->module_enable_shift); - val |= (1 << rsrc_data->reg_data->pix_out_enable_shift); - if (rsrc_data->camif_pd_enable) - val |= (1 << rsrc_data->reg_data->pdaf_output_enable_shift); - - cam_io_w_mb(val, rsrc_data->mem_base + - rsrc_data->camif_reg->module_cfg); - - CAM_DBG(CAM_ISP, "TFE:%d camif module config val:%d", - core_info->core_index, val); - /* Config tfe core*/ val = 0; if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) -- GitLab From b46d4b015654c3617f09ebf063eda6fb81fd10dc Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Fri, 3 Apr 2020 15:32:14 +0530 Subject: [PATCH 189/295] msm: camera: tfe: check cdm hang in the tfe config timeout TFE driver submit the config packet to cdm and wait for call back. If call back has not received with in 60ms, then tfe return failure which cause tfe stream on failure. Some time cdm call back is not coming due to cdm worker thread execution delay. So add mechanism to check if cdm worker thread delay happened then wait for some more time and check it again. CRs-Fixed: 2664317 Change-Id: I2eb975a2c70b5889238e9cf706c703022f1bf2f5 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 124 ++++++++++++-------- 1 file changed, 75 insertions(+), 49 deletions(-) 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 8611e9f0063e..d869d96540fe 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 @@ -26,6 +26,7 @@ #define CAM_TFE_HW_ENTRIES_MAX 20 #define CAM_TFE_HW_CONFIG_TIMEOUT 60 +#define CAM_TFE_HW_CONFIG_WAIT_MAX_TRY 3 #define TZ_SVC_SMMU_PROGRAM 0x15 #define TZ_SAFE_SYSCALL_ID 0x3 @@ -2387,65 +2388,90 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, "Enter ctx id:%d num_hw_upd_entries %d request id: %llu", ctx->ctx_index, cfg->num_hw_update_entries, cfg->request_id); - if (cfg->num_hw_update_entries > 0) { - cdm_cmd = ctx->cdm_cmd; - cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries; - cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; - cdm_cmd->flag = true; - cdm_cmd->userdata = hw_update_data; - cdm_cmd->cookie = cfg->request_id; - cdm_cmd->gen_irq_arb = false; - - for (i = 0 ; i < cfg->num_hw_update_entries; i++) { - cmd = (cfg->hw_update_entries + i); - if (cfg->reapply && cmd->flags == CAM_ISP_IQ_BL) { - skip++; - continue; - } + if (cfg->num_hw_update_entries <= 0) { + CAM_ERR(CAM_ISP, + "Enter ctx id:%d no valid hw entries:%d request id: %llu", + ctx->ctx_index, cfg->num_hw_update_entries, + cfg->request_id); + goto end; + } - if (cmd->flags == CAM_ISP_UNUSED_BL || - cmd->flags >= CAM_ISP_BL_MAX) - CAM_ERR(CAM_ISP, "Unexpected BL type %d", - cmd->flags); + cdm_cmd = ctx->cdm_cmd; + cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = true; + cdm_cmd->userdata = hw_update_data; + cdm_cmd->cookie = cfg->request_id; + cdm_cmd->gen_irq_arb = false; - cdm_cmd->cmd[i - skip].bl_addr.mem_handle = cmd->handle; - cdm_cmd->cmd[i - skip].offset = cmd->offset; - cdm_cmd->cmd[i - skip].len = cmd->len; - cdm_cmd->cmd[i - skip].arbitrate = false; + for (i = 0 ; i < cfg->num_hw_update_entries; i++) { + cmd = (cfg->hw_update_entries + i); + if (cfg->reapply && cmd->flags == CAM_ISP_IQ_BL) { + skip++; + continue; } - cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries - skip; - reinit_completion(&ctx->config_done_complete); - ctx->applied_req_id = cfg->request_id; + if (cmd->flags == CAM_ISP_UNUSED_BL || + cmd->flags >= CAM_ISP_BL_MAX) + CAM_ERR(CAM_ISP, "Unexpected BL type %d", + cmd->flags); - CAM_DBG(CAM_ISP, "Submit to CDM"); - atomic_set(&ctx->cdm_done, 0); - rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); - if (rc) { - CAM_ERR(CAM_ISP, "Failed to apply the configs"); - return rc; - } + cdm_cmd->cmd[i - skip].bl_addr.mem_handle = cmd->handle; + cdm_cmd->cmd[i - skip].offset = cmd->offset; + cdm_cmd->cmd[i - skip].len = cmd->len; + cdm_cmd->cmd[i - skip].arbitrate = false; + } + cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries - skip; + + reinit_completion(&ctx->config_done_complete); + ctx->applied_req_id = cfg->request_id; + + CAM_DBG(CAM_ISP, "Submit to CDM"); + atomic_set(&ctx->cdm_done, 0); + rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to apply the configs"); + return rc; + } - if (cfg->init_packet) { - rc = wait_for_completion_timeout( - &ctx->config_done_complete, - msecs_to_jiffies(CAM_TFE_HW_CONFIG_TIMEOUT)); - if (rc <= 0) { + if (!cfg->init_packet) + goto end; + + for (i = 0; i < CAM_TFE_HW_CONFIG_WAIT_MAX_TRY; i++) { + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies( + CAM_TFE_HW_CONFIG_TIMEOUT)); + if (rc <= 0) { + if (!cam_cdm_detect_hang_error(ctx->cdm_handle)) { CAM_ERR(CAM_ISP, - "config done completion timeout for req_id=%llu rc=%d ctx_index %d", - cfg->request_id, rc, ctx->ctx_index); - if (rc == 0) - rc = -ETIMEDOUT; - } else { - rc = 0; - CAM_DBG(CAM_ISP, - "config done Success for req_id=%llu ctx_index %d", - cfg->request_id, ctx->ctx_index); + "CDM workqueue delay detected, wait for some more time req_id=%llu rc=%d ctx_index %d", + cfg->request_id, rc, + ctx->ctx_index); + continue; } + + CAM_ERR(CAM_ISP, + "config done completion timeout for req_id=%llu rc=%d ctx_index %d", + cfg->request_id, rc, + ctx->ctx_index); + if (rc == 0) + rc = -ETIMEDOUT; + + goto end; + } else { + rc = 0; + CAM_DBG(CAM_ISP, + "config done Success for req_id=%llu ctx_index %d", + cfg->request_id, ctx->ctx_index); + break; } - } else { - CAM_ERR(CAM_ISP, "No commands to config"); } + + if ((i == CAM_TFE_HW_CONFIG_WAIT_MAX_TRY) && (rc == 0)) + rc = -ETIMEDOUT; + +end: CAM_DBG(CAM_ISP, "Exit: Config Done: %llu", cfg->request_id); return rc; -- GitLab From 6128405ac6693a3599b931460b07f03de63964e6 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Tue, 3 Dec 2019 20:18:07 +0800 Subject: [PATCH 190/295] msm: camera: sensor: Turn off the flash while flushing Turn off the flash while flushing if the flushed request turns off the flash. CRs-Fixed: 2576732 Change-Id: I546fc6b6ee79f492af905d163515eb19eed78f41 Signed-off-by: Depeng Shao --- .../cam_flash/cam_flash_core.c | 61 ++++++++++++++++--- 1 file changed, 51 insertions(+), 10 deletions(-) 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 0e1440d13b46..6d45ef26eed8 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -287,6 +287,8 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, int rc = 0; int i = 0, j = 0; int frame_offset = 0; + bool is_off_needed = false; + struct cam_flash_frame_setting *flash_data = NULL; if (!fctrl) { CAM_ERR(CAM_FLASH, "Device data is NULL"); @@ -296,23 +298,47 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, if (type == FLUSH_ALL) { /* flush all requests*/ for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { - fctrl->per_frame[i].cmn_attr.request_id = 0; - fctrl->per_frame[i].cmn_attr.is_settings_valid = false; - fctrl->per_frame[i].cmn_attr.count = 0; + flash_data = + &fctrl->per_frame[i]; + if ((flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_OFF) && + (flash_data->cmn_attr.request_id > 0) && + (flash_data->cmn_attr.request_id <= req_id) && + flash_data->cmn_attr.is_settings_valid) { + is_off_needed = true; + CAM_DBG(CAM_FLASH, + "FLASH_ALL: Turn off the flash for req %llu", + flash_data->cmn_attr.request_id); + } + + flash_data->cmn_attr.request_id = 0; + flash_data->cmn_attr.is_settings_valid = false; + flash_data->cmn_attr.count = 0; for (j = 0; j < CAM_FLASH_MAX_LED_TRIGGERS; j++) - fctrl->per_frame[i].led_current_ma[j] = 0; + flash_data->led_current_ma[j] = 0; } cam_flash_pmic_flush_nrt(fctrl); } else if ((type == FLUSH_REQ) && (req_id != 0)) { /* flush request with req_id*/ frame_offset = req_id % MAX_PER_FRAME_ARRAY; - fctrl->per_frame[frame_offset].cmn_attr.request_id = 0; - fctrl->per_frame[frame_offset].cmn_attr.is_settings_valid = + flash_data = + &fctrl->per_frame[frame_offset]; + + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_OFF) { + is_off_needed = true; + CAM_DBG(CAM_FLASH, + "FLASH_REQ: Turn off the flash for req %llu", + flash_data->cmn_attr.request_id); + } + + flash_data->cmn_attr.request_id = 0; + flash_data->cmn_attr.is_settings_valid = false; - fctrl->per_frame[frame_offset].cmn_attr.count = 0; + flash_data->cmn_attr.count = 0; for (i = 0; i < CAM_FLASH_MAX_LED_TRIGGERS; i++) - fctrl->per_frame[frame_offset].led_current_ma[i] = 0; + flash_data->led_current_ma[i] = 0; } else if ((type == FLUSH_REQ) && (req_id == 0)) { /* Handels NonRealTime usecase */ cam_flash_pmic_flush_nrt(fctrl); @@ -321,6 +347,9 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, return -EINVAL; } + if (is_off_needed) + cam_flash_off(fctrl); + return rc; } @@ -567,7 +596,9 @@ static int cam_flash_i2c_delete_req(struct cam_flash_ctrl *fctrl, CAM_DBG(CAM_FLASH, "top: %llu, del_req_id:%llu", top, del_req_id); } - fctrl->func_tbl.flush_req(fctrl, FLUSH_REQ, del_req_id); + + cam_flash_i2c_flush_nrt(fctrl); + return 0; } @@ -577,6 +608,7 @@ static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, int i = 0; struct cam_flash_frame_setting *flash_data = NULL; uint64_t top = 0, del_req_id = 0; + int frame_offset = 0; if (req_id != 0) { for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { @@ -612,7 +644,16 @@ static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, top, del_req_id); } - fctrl->func_tbl.flush_req(fctrl, FLUSH_REQ, del_req_id); + /* delete the request */ + frame_offset = del_req_id % MAX_PER_FRAME_ARRAY; + flash_data = &fctrl->per_frame[frame_offset]; + flash_data->cmn_attr.request_id = 0; + flash_data->cmn_attr.is_settings_valid = false; + flash_data->cmn_attr.count = 0; + + for (i = 0; i < CAM_FLASH_MAX_LED_TRIGGERS; i++) + flash_data->led_current_ma[i] = 0; + return 0; } -- GitLab From db1e8beb7f38e01a1484912091a03ba63d12b6e8 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Thu, 16 Apr 2020 21:23:38 +0530 Subject: [PATCH 191/295] msm: camera: ope: Handle reset IRQ delay If reset irq is not received within allocated time, check for irq status to confirm if irq is delayed or reset failed. In case of irq delay, clear the irq status and mark it as success. CRs-Fixed: 2663505 Change-Id: I1b3658e2ada973f531ddba8bc2378b0440c9088a Signed-off-by: Rishabh Jain --- .../cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c | 79 ++++++++++++++----- .../cam_ope/ope_hw_mgr/ope_hw/top/ope_top.h | 2 + 2 files changed, 60 insertions(+), 21 deletions(-) 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 becfa63540ed..44acc41dbf22 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 @@ -50,6 +50,7 @@ static int cam_ope_top_reset(struct ope_hw *ope_hw_info, struct cam_ope_top_reg *top_reg; struct cam_ope_top_reg_val *top_reg_val; uint32_t irq_mask, irq_status; + unsigned long flags; if (!ope_hw_info) { CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); @@ -72,21 +73,37 @@ static int cam_ope_top_reset(struct ope_hw *ope_hw_info, rc = wait_for_completion_timeout( &ope_top_info.reset_complete, - msecs_to_jiffies(30)); + msecs_to_jiffies(60)); 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); - 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; + spin_lock_irqsave(&ope_top_info.hw_lock, flags); + if (!completion_done(&ope_top_info.reset_complete)) { + CAM_DBG(CAM_OPE, + "IRQ delayed, checking the status registers"); + 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); + if (irq_status & top_reg_val->rst_done) { + CAM_DBG(CAM_OPE, "ope reset done"); + cam_io_w_mb(irq_status, + top_reg->base + top_reg->irq_clear); + cam_io_w_mb(top_reg_val->irq_set_clear, + top_reg->base + top_reg->irq_cmd); + } else { + 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; + } + spin_unlock_irqrestore(&ope_top_info.hw_lock, flags); } else { rc = 0; } @@ -137,6 +154,7 @@ static int cam_ope_top_init(struct ope_hw *ope_hw_info, struct cam_ope_top_reg_val *top_reg_val; struct cam_ope_dev_init *dev_init = data; uint32_t irq_mask, irq_status; + unsigned long flags; if (!ope_hw_info) { CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); @@ -160,25 +178,41 @@ static int cam_ope_top_init(struct ope_hw *ope_hw_info, rc = wait_for_completion_timeout( &ope_top_info.reset_complete, - msecs_to_jiffies(30)); + msecs_to_jiffies(60)); 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); - 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; + spin_lock_irqsave(&ope_top_info.hw_lock, flags); + if (!completion_done(&ope_top_info.reset_complete)) { + CAM_DBG(CAM_OPE, + "IRQ delayed, checking the status registers"); + 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); + if (irq_status & top_reg_val->rst_done) { + CAM_DBG(CAM_OPE, "ope reset done"); + cam_io_w_mb(irq_status, + top_reg->base + top_reg->irq_clear); + cam_io_w_mb(top_reg_val->irq_set_clear, + top_reg->base + top_reg->irq_cmd); + } else { + 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 { + CAM_DBG(CAM_OPE, "reset done"); + rc = 0; + } + spin_unlock_irqrestore(&ope_top_info.hw_lock, flags); } 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); @@ -197,6 +231,7 @@ static int cam_ope_top_probe(struct ope_hw *ope_hw_info, } ope_top_info.ope_hw_info = ope_hw_info; + spin_lock_init(&ope_top_info.hw_lock); return rc; } @@ -219,6 +254,7 @@ static int cam_ope_top_isr(struct ope_hw *ope_hw_info, top_reg = ope_hw_info->top_reg; top_reg_val = ope_hw_info->top_reg_val; + spin_lock(&ope_top_info.hw_lock); /* Read and Clear Top Interrupt status */ irq_status = cam_io_r_mb(top_reg->base + top_reg->irq_status); cam_io_w_mb(irq_status, @@ -238,6 +274,7 @@ static int cam_ope_top_isr(struct ope_hw *ope_hw_info, irq_data->error = 1; CAM_ERR(CAM_OPE, "ope violation: %x", violation_status); } + spin_unlock(&ope_top_info.hw_lock); return rc; } 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 428d66f7e9b8..57d90712bdeb 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 @@ -33,11 +33,13 @@ struct ope_top_ctx { * @top_ctx: OPE top context * @reset_complete: Reset complete flag * @ope_mutex: OPE hardware mutex + * @hw_lock: OPE hardware spinlock */ 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; + spinlock_t hw_lock; }; #endif /* OPE_TOP_H */ -- GitLab From 70d9d84976a6977c99f8dbacd113eac7067d490f Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Thu, 9 Apr 2020 21:17:00 +0530 Subject: [PATCH 192/295] msm: camera: ope: enable pp modules hw status dump Enable pp module hw status register during violation. CRs-Fixed: 2663871 Change-Id: I7f1988c7aeaae7b32f0df1316163f4b99f0194a3 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c | 3 +- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h | 15 +++ .../cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h | 96 +++++++++++++++++++ .../cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c | 18 ++++ 4 files changed, 131 insertions(+), 1 deletion(-) diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c index ac06a9d4aeb7..c17629c9b1f0 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c @@ -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. */ #include @@ -78,6 +78,7 @@ static int cam_ope_init_hw_version(struct cam_hw_soc_info *soc_info, ope_hw_100.top_reg->base = core_info->ope_hw_info->ope_top_base; ope_hw_100.bus_rd_reg->base = core_info->ope_hw_info->ope_bus_rd_base; ope_hw_100.bus_wr_reg->base = core_info->ope_hw_info->ope_bus_wr_base; + ope_hw_100.pp_reg->base = core_info->ope_hw_info->ope_pp_base; return rc; } 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 2890f1579e67..bb5a2bbff27f 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 @@ -13,6 +13,7 @@ #define MAX_RD_CLIENTS 2 #define MAX_WR_CLIENTS 8 +#define MAX_PP_CLIENTS 29 #define OPE_CDM_BASE 0x0 #define OPE_TOP_BASE 0x1 @@ -385,6 +386,18 @@ struct cam_ope_debug_register { uint32_t offset; }; +struct cam_ope_bus_pp_client_reg { + uint32_t hw_status; +}; + +struct cam_ope_pp_reg { + void *base; + uint32_t offset; + + uint32_t num_clients; + struct cam_ope_bus_pp_client_reg pp_clients[MAX_PP_CLIENTS]; +}; + struct ope_hw { struct cam_ope_top_reg *top_reg; struct cam_ope_top_reg_val *top_reg_val; @@ -399,6 +412,8 @@ struct ope_hw { struct cam_ope_qos_reg_val *qos_reg_val; struct cam_ope_common *common; + + struct cam_ope_pp_reg *pp_reg; }; struct hw_version_reg { 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 95ae384161af..727b43c68512 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 @@ -554,6 +554,101 @@ static struct cam_ope_bus_wr_reg_val ope_bus_wr_reg_val = { }, }, }; + +static struct cam_ope_pp_reg ope_pp_reg = { + .offset = 0x800, + .num_clients = MAX_PP_CLIENTS, + .pp_clients = { + { + .hw_status = 0x4, + }, + { + .hw_status = 0x204, + }, + { + .hw_status = 0x404, + }, + { + .hw_status = 0x604, + }, + { + .hw_status = 0x804, + }, + { + .hw_status = 0xA04, + }, + { + .hw_status = 0xC04, + }, + { + .hw_status = 0xE04, + }, + { + .hw_status = 0x1004, + }, + { + .hw_status = 0x1204, + }, + { + .hw_status = 0x1404, + }, + { + .hw_status = 0x1604, + }, + { + .hw_status = 0x1804, + }, + { + .hw_status = 0x1A04, + }, + { + .hw_status = 0x1C04, + }, + { + .hw_status = 0x1E04, + }, + { + .hw_status = 0x2204, + }, + { + .hw_status = 0x2604, + }, + { + .hw_status = 0x2804, + }, + { + .hw_status = 0x2A04, + }, + { + .hw_status = 0x2C04, + }, + { + .hw_status = 0x2E04, + }, + { + .hw_status = 0x3004, + }, + { + .hw_status = 0x3204, + }, + { + .hw_status = 0x3404, + }, + { + .hw_status = 0x3604, + }, + { + .hw_status = 0x3804, + }, + { + .hw_status = 0x3A04, + }, + { + .hw_status = 0x3C04, + }, + }, +}; + static struct ope_hw ope_hw_100 = { .top_reg = &ope_top_reg, .top_reg_val = &ope_top_reg_val, @@ -561,6 +656,7 @@ static struct ope_hw ope_hw_100 = { .bus_rd_reg_val = &ope_bus_rd_reg_val, .bus_wr_reg = &ope_bus_wr_reg, .bus_wr_reg_val = &ope_bus_wr_reg_val, + .pp_reg = &ope_pp_reg, }; #endif /* CAM_OPE_HW_100_H */ 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 becfa63540ed..e53bc43f63b4 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 @@ -207,9 +207,12 @@ static int cam_ope_top_isr(struct ope_hw *ope_hw_info, int rc = 0; uint32_t irq_status; uint32_t violation_status; + uint32_t pp_hw_status = 0; struct cam_ope_top_reg *top_reg; struct cam_ope_top_reg_val *top_reg_val; + struct cam_ope_pp_reg *pp_reg; struct cam_ope_irq_data *irq_data = data; + int i; if (!ope_hw_info) { CAM_ERR(CAM_OPE, "Invalid ope_hw_info"); @@ -218,6 +221,7 @@ static int cam_ope_top_isr(struct ope_hw *ope_hw_info, top_reg = ope_hw_info->top_reg; top_reg_val = ope_hw_info->top_reg_val; + pp_reg = ope_hw_info->pp_reg; /* Read and Clear Top Interrupt status */ irq_status = cam_io_r_mb(top_reg->base + top_reg->irq_status); @@ -237,6 +241,20 @@ static int cam_ope_top_isr(struct ope_hw *ope_hw_info, top_reg->violation_status); irq_data->error = 1; CAM_ERR(CAM_OPE, "ope violation: %x", violation_status); + + for (i = 0; i < pp_reg->num_clients ; i++) { + pp_hw_status = 0; + pp_hw_status = + cam_io_r_mb(pp_reg->base + + pp_reg->pp_clients[i] + .hw_status); + + if (pp_hw_status) + CAM_ERR(CAM_OPE, + "ope pp hw_status offset 0x%x val 0x%x", + pp_reg->pp_clients[i].hw_status, + pp_hw_status); + } } return rc; -- GitLab From 2dfb765b4a4c79fd26d59ff768d33156eb8e446f Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Fri, 17 Apr 2020 20:04:26 +0530 Subject: [PATCH 193/295] msm: camera: ope: Fix OPE clock issue Due to non-availability of all clock levels, while downgrading or upgrading the clock rate, ope is voting for zero clock rate. Fix issue by voting for nearest non-zero clockrate while upgrading or downgrading the clock rate. CRs-Fixed: 2649906 Change-Id: I2f3488084e0aa32ecfa84bcbebad887a1ef8409d Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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 67594b9d2e0d..5cf4e6c1952b 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 @@ -1020,8 +1020,11 @@ static int cam_ope_get_lower_clk_rate(struct cam_ope_hw_mgr *hw_mgr, i = cam_ope_get_actual_clk_rate_idx(ctx_data, base_clk); - if (i > 0) - return ctx_data->clk_info.clk_rate[i - 1]; + while (i > 0) { + if (ctx_data->clk_info.clk_rate[i - 1]) + return ctx_data->clk_info.clk_rate[i - 1]; + i--; + } CAM_DBG(CAM_OPE, "Already clk at lower level"); @@ -1035,8 +1038,11 @@ static int cam_ope_get_next_clk_rate(struct cam_ope_hw_mgr *hw_mgr, i = cam_ope_get_actual_clk_rate_idx(ctx_data, base_clk); - if (i < CAM_MAX_VOTE - 1) - return ctx_data->clk_info.clk_rate[i + 1]; + while (i < CAM_MAX_VOTE - 1) { + if (ctx_data->clk_info.clk_rate[i + 1]) + return ctx_data->clk_info.clk_rate[i + 1]; + i++; + } CAM_DBG(CAM_OPE, "Already clk at higher level"); -- GitLab From 1c4493f0cb0cbd0506396ec881f8c05c40fd1361 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Sun, 29 Mar 2020 02:13:00 +0530 Subject: [PATCH 194/295] msm: camera: ope: Add LDAR dump support When user space detects an error or does not receive response for a request, Lets do a reset(LDAR) is triggered. Before LDAR, user space sends flush command to the kernel space. In order to debug the cause for this situation and to dump the information, user space sends a dump command to the kernel space before sending flush. As a part of this command, it passes the culprit request id and the buffer into which the information can be dumped. Kernel space traverses across the drivers and find the culprit hw and log about culprit information for OPE. CRs-Fixed: 2669222 Change-Id: Ida5cbee7a36917f7276a0f9accf2c35f24bf69c9 Signed-off-by: Alok Chauhan --- drivers/cam_ope/cam_ope_context.c | 16 ++++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 72 +++++++++++++++++++++ drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 4 +- 3 files changed, 89 insertions(+), 3 deletions(-) diff --git a/drivers/cam_ope/cam_ope_context.c b/drivers/cam_ope/cam_ope_context.c index 487881a21f69..4e34fb607a16 100644 --- a/drivers/cam_ope/cam_ope_context.c +++ b/drivers/cam_ope/cam_ope_context.c @@ -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. */ #include @@ -122,6 +122,18 @@ static int __cam_ope_flush_dev_in_ready(struct cam_context *ctx, return rc; } +static int __cam_ope_dump_dev_in_ready(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_OPE, "Failed to dump device"); + + return rc; +} + static int __cam_ope_config_dev_in_ready(struct cam_context *ctx, struct cam_config_dev_cmd *cmd) { @@ -205,6 +217,7 @@ static struct cam_ctx_ops .start_dev = __cam_ope_start_dev_in_acquired, .config_dev = __cam_ope_config_dev_in_ready, .flush_dev = __cam_ope_flush_dev_in_ready, + .dump_dev = __cam_ope_dump_dev_in_ready, }, .crm_ops = {}, .irq_ops = __cam_ope_handle_buf_done_in_ready, @@ -217,6 +230,7 @@ static struct cam_ctx_ops .release_dev = __cam_ope_release_dev_in_ready, .config_dev = __cam_ope_config_dev_in_ready, .flush_dev = __cam_ope_flush_dev_in_ready, + .dump_dev = __cam_ope_dump_dev_in_ready, }, .crm_ops = {}, .irq_ops = __cam_ope_handle_buf_done_in_ready, 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 67594b9d2e0d..b7e54ab08ddb 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 @@ -3302,6 +3302,7 @@ static int cam_ope_mgr_config_hw(void *hw_priv, void *hw_config_args) cdm_cmd->cookie = ope_req->req_idx; cam_ope_mgr_ope_clk_update(hw_mgr, ctx_data, ope_req->req_idx); + ctx_data->req_list[ope_req->req_idx]->submit_timestamp = ktime_get(); if (ope_req->request_id <= ctx_data->last_flush_req) CAM_WARN(CAM_OPE, @@ -3429,6 +3430,76 @@ static int cam_ope_mgr_flush_all(struct cam_ope_ctx *ctx_data, return rc; } +static int cam_ope_mgr_hw_dump(void *hw_priv, void *hw_dump_args) +{ + struct cam_ope_ctx *ctx_data; + struct cam_ope_hw_mgr *hw_mgr = hw_priv; + struct cam_hw_dump_args *dump_args; + int idx; + ktime_t cur_time; + struct timespec64 cur_ts, req_ts; + uint64_t diff; + + if ((!hw_priv) || (!hw_dump_args)) { + CAM_ERR(CAM_OPE, "Invalid params %pK %pK", + hw_priv, hw_dump_args); + return -EINVAL; + } + + dump_args = (struct cam_hw_dump_args *)hw_dump_args; + ctx_data = dump_args->ctxt_to_hw_map; + + if (!ctx_data) { + CAM_ERR(CAM_OPE, "Invalid context"); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + CAM_INFO(CAM_OPE, "Req %lld", dump_args->request_id); + for (idx = 0; idx < CAM_CTX_REQ_MAX; idx++) { + if (!ctx_data->req_list[idx]) + continue; + + if (ctx_data->req_list[idx]->request_id == + dump_args->request_id) + break; + } + + /* no matching request found */ + if (idx == CAM_CTX_REQ_MAX) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return 0; + } + + cur_time = ktime_get(); + diff = ktime_us_delta(ctx_data->req_list[idx]->submit_timestamp, + cur_time); + cur_ts = ktime_to_timespec64(cur_time); + req_ts = ktime_to_timespec64(ctx_data->req_list[idx]->submit_timestamp); + + if (diff < (OPE_REQUEST_TIMEOUT * 1000)) { + CAM_INFO(CAM_OPE, "No Error req %llu %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return 0; + } + + CAM_ERR(CAM_OPE, "Error req %llu %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return 0; +} + static int cam_ope_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; @@ -3703,6 +3774,7 @@ int cam_ope_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, hw_mgr_intf->hw_open = cam_ope_mgr_hw_open_u; hw_mgr_intf->hw_close = cam_ope_mgr_hw_close_u; hw_mgr_intf->hw_flush = cam_ope_mgr_hw_flush; + hw_mgr_intf->hw_dump = cam_ope_mgr_hw_dump; ope_hw_mgr->secure_mode = false; mutex_init(&ope_hw_mgr->hw_mgr_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 07ef8203bbef..01d37fe22ecb 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 @@ -62,8 +62,6 @@ #define OPE_DEVICE_IDLE_TIMEOUT 400 #define OPE_REQUEST_TIMEOUT 200 - - /** * struct cam_ope_clk_bw_request_v2 * @budget_ns: Time required to process frame @@ -390,6 +388,7 @@ struct ope_io_buf { * @clk_info: Clock Info V1 * @clk_info_v2: Clock Info V2 * @hang_data: Debug data for HW error + * @submit_timestamp: Submit timestamp to hw */ struct cam_ope_request { uint64_t request_id; @@ -410,6 +409,7 @@ struct cam_ope_request { 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; + ktime_t submit_timestamp; }; /** -- GitLab From 5a7da6d114a2616ce09052152483d4bef44266d1 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Wed, 15 Apr 2020 13:01:52 +0530 Subject: [PATCH 195/295] msm: camera: flash: Add qti flash property for scuba Add qti flash property with updated max current DT property CRs-Fixed: 2655601 Change-Id: Ic52a0bdae81347f5dc9f1bbe6560ae67f6e13de0 Signed-off-by: shiwgupt --- drivers/cam_sensor_module/cam_flash/cam_flash_soc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c index 762977f4b968..4c544b1170f3 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, 2020, The Linux Foundation. All rights reserved. */ #include @@ -94,6 +94,9 @@ static int32_t cam_get_source_node_info( rc = of_property_read_u32(flash_src_node, "qcom,max-current", &soc_private->flash_max_current[i]); + rc &= of_property_read_u32(flash_src_node, + "qcom,max-current-ma", + &soc_private->flash_max_current[i]); if (rc < 0) { CAM_WARN(CAM_FLASH, "LED FLASH max-current read fail: %d", @@ -180,6 +183,9 @@ static int32_t cam_get_source_node_info( rc = of_property_read_u32(torch_src_node, "qcom,max-current", &soc_private->torch_max_current[i]); + rc &= of_property_read_u32(torch_src_node, + "qcom,max-current-ma", + &soc_private->torch_max_current[i]); if (rc < 0) { CAM_WARN(CAM_FLASH, "LED-TORCH max-current read failed: %d", -- GitLab From db9d8b9b891702b79bdefa1427524a4131d17f83 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Thu, 23 Apr 2020 15:04:12 +0530 Subject: [PATCH 196/295] msm: camera: ope: Add context state check in process cmd There is chance that release hw run before process cmd workq which got scheduled as part of config hw. This causes workq to continue the context though it got released as part of release hw. Added a context state check in process cmd workq handler to avoid submitting request to cdm hardware. CRs-Fixed: 2670524 Change-Id: I7009d4b60bd97b9f6d46df51790c127a2cf18205 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) 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 67594b9d2e0d..211ecfe37535 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 @@ -96,12 +96,19 @@ 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 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); + if (!cdm_cmd) { + CAM_ERR(CAM_OPE, "Invalid params%pK", cdm_cmd); + return -EINVAL; + } mutex_lock(&hw_mgr->hw_mgr_mutex); + if (ctx_data->ctx_state != OPE_CTX_STATE_ACQUIRED) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_OPE, "ctx id :%u is not in use", + ctx_data->ctx_id); + return -EINVAL; + } + if (task_data->req_id <= ctx_data->last_flush_req) { CAM_WARN(CAM_OPE, "request %lld has been flushed, reject packet", @@ -110,6 +117,11 @@ static int cam_ope_mgr_process_cmd(void *priv, void *data) return -EINVAL; } + 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); + if (task_data->req_id > ctx_data->last_flush_req) ctx_data->last_flush_req = 0; -- GitLab From 8237ce6cc910db9dd22cef0d87dc709ea532e4cf Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 6 Apr 2020 21:10:31 +0530 Subject: [PATCH 197/295] msm: camera: smmu: Protect create handle with mutex mutex lock is missing while creating smmu handle. This gives warning on mutext_unlock. Added mutext lock for create smmu handle. CRs-Fixed: 2671612 Change-Id: Ia1880c335ed9cacc4d6d34e9184599a4467efdcd Signed-off-by: Alok Chauhan --- drivers/cam_smmu/cam_smmu_api.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 752a208a133d..034de6ee564b 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -868,6 +868,7 @@ static int cam_smmu_create_add_handle_in_table(char *name, if (iommu_cb_set.cb_info[i].handle == HANDLE_INIT && valid) { + mutex_lock(&iommu_cb_set.cb_info[i].lock); /* make sure handle is unique */ do { handle = -- GitLab From 2a3f5094e886c87e24ac42d3f4c8dbff11bdb218 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 30 Mar 2020 13:07:37 +0530 Subject: [PATCH 198/295] msm: camera: tfe: Do tfe-csid and tfe probe based on fuse feature Some ISP hardware id instances are disabled on some target skus. Cpas driver has fuse information based on the dtsi entries. ISP hw driver queries the cpas driver whether hw instance is supported or not. If ISP hardware is supported on the target then continue the isp hardware probe. CRs-Fixed: 2670876 Change-Id: I6b2316d87aeabccbdf74e151e0e25ff77ed6634f Signed-off-by: Ravikishore Pampana --- drivers/cam_cpas/cam_cpas_intf.c | 23 +++-- drivers/cam_cpas/cam_cpas_soc.c | 80 ++++++++++++++--- drivers/cam_cpas/cam_cpas_soc.h | 23 ++++- drivers/cam_cpas/include/cam_cpas_api.h | 11 ++- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 3 +- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 85 +++++++------------ .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 12 +++ .../cam_csiphy/cam_csiphy_core.c | 3 +- 8 files changed, 155 insertions(+), 85 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index 5308eaf0ac26..9a26d4ff1b2c 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.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 @@ -118,28 +118,37 @@ const char *cam_cpas_axi_util_trans_type_to_string( } EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string); -int cam_cpas_is_feature_supported(uint32_t flag) +bool cam_cpas_is_feature_supported(uint32_t flag, + uint32_t hw_id) { struct cam_hw_info *cpas_hw = NULL; struct cam_cpas_private_soc *soc_private = NULL; - uint32_t feature_mask; + uint32_t i; + bool supported = true; if (!CAM_CPAS_INTF_INITIALIZED()) { CAM_ERR(CAM_CPAS, "cpas intf not initialized"); - return -ENODEV; + return false; } cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv; soc_private = (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private; - feature_mask = soc_private->feature_mask; if (flag >= CAM_CPAS_FUSE_FEATURE_MAX) { CAM_ERR(CAM_CPAS, "Unknown feature flag %x", flag); - return -EINVAL; + return false; + } + + for (i = 0; i < soc_private->num_feature_entries; i++) { + if ((soc_private->feature_info[i].feature == flag) && + (soc_private->feature_info[i].hw_id == hw_id)) { + supported = soc_private->feature_info[i].enable; + break; + } } - return feature_mask & flag ? 1 : 0; + return supported; } EXPORT_SYMBOL(cam_cpas_is_feature_supported); diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index df4c1585c531..f6906025f368 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/drivers/cam_cpas/cam_cpas_soc.c @@ -401,42 +401,95 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, return 0; } - int cam_cpas_get_hw_features(struct platform_device *pdev, struct cam_cpas_private_soc *soc_private) { struct device_node *of_node; void *fuse; uint32_t fuse_addr, fuse_bit; - uint32_t fuse_val = 0, feature_bit_pos; - int count = 0, i = 0; + uint32_t fuse_val = 0, feature; + uint32_t enable_type = 0, hw_id = 0; + int count = 0, i = 0, num_feature = 0; of_node = pdev->dev.of_node; count = of_property_count_u32_elems(of_node, "cam_hw_fuse"); - for (i = 0; (i + 3) <= count; i = i + 3) { + CAM_DBG(CAM_CPAS, "fuse info elements count %d", count); + + if (count <= 0) + goto end; + + for (i = 0; (i + 5) <= count; i = i + 5) { of_property_read_u32_index(of_node, "cam_hw_fuse", i, - &feature_bit_pos); + &feature); of_property_read_u32_index(of_node, "cam_hw_fuse", i + 1, &fuse_addr); of_property_read_u32_index(of_node, "cam_hw_fuse", i + 2, &fuse_bit); - CAM_INFO(CAM_CPAS, "feature_bit 0x%x addr 0x%x, bit %d", - feature_bit_pos, fuse_addr, fuse_bit); + of_property_read_u32_index(of_node, "cam_hw_fuse", i + 3, + &enable_type); + of_property_read_u32_index(of_node, "cam_hw_fuse", i + 4, + &hw_id); + CAM_INFO(CAM_CPAS, + "feature 0x%x addr 0x%x, bit %d enable type:%d hw_id=%d", + feature, fuse_addr, fuse_bit, + enable_type, hw_id); fuse = ioremap(fuse_addr, 4); if (fuse) { fuse_val = cam_io_r(fuse); - if (fuse_val & BIT(fuse_bit)) - soc_private->feature_mask |= feature_bit_pos; + } else { + /* if fuse ioremap is failed, disable the feature */ + CAM_ERR(CAM_CPAS, + "fuse register io remap failed fuse_addr:0x%x feature0x%x ", + fuse_addr, feature); + + if (enable_type) + fuse_val = ~BIT(fuse_bit); else - soc_private->feature_mask &= ~feature_bit_pos; + fuse_val = BIT(fuse_bit); } - CAM_INFO(CAM_CPAS, "fuse %pK, fuse_val %x, feature_mask %x", - fuse, fuse_val, soc_private->feature_mask); + soc_private->feature_info[num_feature].feature = + feature; + soc_private->feature_info[num_feature].hw_id = hw_id; + + if (enable_type) { + /* + * fuse is for enable feature + * if fust bit is set means feature is enabled or + * HW is enabled + */ + if (fuse_val & BIT(fuse_bit)) + soc_private->feature_info[num_feature].enable = + true; + else + soc_private->feature_info[num_feature].enable = + false; + } else { + /* + * fuse is for disable feature + * if fust bit is set means feature is disabled or + * HW is disabled + */ + if (fuse_val & BIT(fuse_bit)) + soc_private->feature_info[num_feature].enable = + false; + else + soc_private->feature_info[num_feature].enable = + true; + } + CAM_INFO(CAM_CPAS, + "num entries:%d feature 0x%x enable=%d hw id=%d", + num_feature, + soc_private->feature_info[num_feature].feature, + soc_private->feature_info[num_feature].enable, + soc_private->feature_info[num_feature].hw_id); + num_feature++; } +end: + soc_private->num_feature_entries = num_feature; return 0; } @@ -454,8 +507,7 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, } of_node = pdev->dev.of_node; - soc_private->feature_mask = 0xFFFFFFFF; - + soc_private->num_feature_entries = 0; rc = of_property_read_string(of_node, "arch-compat", &soc_private->arch_compat); if (rc) { diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index 3a2c889cfea0..46c748fbb12f 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/drivers/cam_cpas/cam_cpas_soc.h @@ -12,7 +12,7 @@ #define CAM_REGULATOR_LEVEL_MAX 16 #define CAM_CPAS_MAX_TREE_NODES 50 - +#define CAM_CPAS_MAX_FUSE_FEATURE 10 /** * struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping * @@ -72,6 +72,21 @@ struct cam_cpas_tree_node { struct cam_cpas_tree_node *parent_node; }; +/** + * struct cam_cpas_feature_info : Fuse feature information + * + * @feature : feature + * @enable : feature is enabled or disabled + * @hw_id : hw id for this feature, it will be zero + * if not applicable + * + */ +struct cam_cpas_feature_info { + uint32_t feature; + uint32_t enable; + uint32_t hw_id; +}; + /** * struct cam_cpas_private_soc : CPAS private DT info * @@ -90,7 +105,8 @@ struct cam_cpas_tree_node { * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating * camnoc axi clock * @camnoc_axi_min_ib_bw: Min camnoc BW which varies based on target - * @feature_mask: feature mask value for hw supported features + * @num_feature_entries: number of feature entries + * @feature_info: fuse based feature info for hw supported features * @cx_ipeak_gpu_limit: Flag for Cx Ipeak GPU mitigation * @gpu_pwr_limit: Handle for Cx Ipeak GPU Mitigation * @@ -109,7 +125,8 @@ struct cam_cpas_private_soc { uint32_t camnoc_bus_width; uint32_t camnoc_axi_clk_bw_margin; uint64_t camnoc_axi_min_ib_bw; - uint32_t feature_mask; + uint32_t num_feature_entries; + struct cam_cpas_feature_info feature_info[CAM_CPAS_MAX_FUSE_FEATURE]; uint32_t cx_ipeak_gpu_limit; struct kgsl_pwr_limit *gpu_pwr_limit; }; diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 6b3c6c75f412..cd844d13f161 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -525,7 +525,7 @@ int cam_cpas_get_hw_info( * */ int cam_cpas_get_cpas_hw_version( - uint32_t *hw_version); + uint32_t *hw_version); /** * cam_cpas_is_feature_supported() @@ -534,11 +534,14 @@ int cam_cpas_get_cpas_hw_version( * * @flag : Camera hw features to check * - * @return 1 if feature is supported + * @hw_id : HW id index, if hw id is not valid feature, send zero + * + * @return true if feature is supported + * false if feature is not supported * */ -int cam_cpas_is_feature_supported( - uint32_t flag); +bool cam_cpas_is_feature_supported(uint32_t flag, + uint32_t hw_id); /** * cam_cpas_axi_util_path_type_to_string() diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 2b499ecf2223..45a61b6cc475 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -4384,7 +4384,8 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, goto err; } - if (cam_cpas_is_feature_supported(CAM_CPAS_QCFA_BINNING_ENABLE) == 1) + if (cam_cpas_is_feature_supported(CAM_CPAS_QCFA_BINNING_ENABLE, + csid_idx) == true) ife_csid_hw->binning_enable = 1; ife_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_ife_csid_get_hw_caps; 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 d68424ae0a91..f7d4237b0067 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 @@ -15,6 +15,7 @@ #include "cam_debug_util.h" #include "cam_cpas_api.h" #include "cam_isp_hw_mgr_intf.h" +#include /* Timeout value in msec */ #define TFE_CSID_TIMEOUT 1000 @@ -2817,11 +2818,12 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, uint32_t csid_idx) { int rc = -EINVAL; - uint32_t i, val, clk_lvl; + uint32_t i; struct cam_tfe_csid_path_cfg *path_data; struct cam_hw_info *csid_hw_info; struct cam_tfe_csid_hw *tfe_csid_hw = NULL; const struct cam_tfe_csid_reg_offset *csid_reg; + int pixel_pipe_supported = true; if (csid_idx >= CAM_TFE_CSID_HW_NUM_MAX) { CAM_ERR(CAM_ISP, "Invalid csid index:%d", csid_idx); @@ -2835,11 +2837,34 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, tfe_csid_hw->hw_info = csid_hw_info; csid_reg = tfe_csid_hw->csid_info->csid_reg; - CAM_DBG(CAM_ISP, "type %d index %d", - tfe_csid_hw->hw_intf->hw_type, csid_idx); - tfe_csid_hw->device_enabled = 0; tfe_csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + + if (!cam_cpas_is_feature_supported(CAM_CPAS_ISP_FUSE_ID, + csid_idx)) { + CAM_INFO(CAM_ISP, "TFE:%d is not supported", + csid_idx); + rc = -EINVAL; + goto err; + } + + CAM_DBG(CAM_ISP, "type %d index %d supported", + tfe_csid_hw->hw_intf->hw_type, csid_idx); + + if (!cam_cpas_is_feature_supported(CAM_CPAS_ISP_PIX_FUSE_ID, + csid_idx)) { + pixel_pipe_supported = false; + CAM_INFO(CAM_ISP, "TFE:%d PIX path is not supported", + csid_idx); + } + + rc = cam_tfe_csid_init_soc_resources(&tfe_csid_hw->hw_info->soc_info, + cam_tfe_csid_irq, tfe_csid_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d Failed to init_soc", csid_idx); + goto err; + } + mutex_init(&tfe_csid_hw->hw_info->hw_mutex); spin_lock_init(&tfe_csid_hw->hw_info->hw_lock); spin_lock_init(&tfe_csid_hw->spin_lock); @@ -2851,25 +2876,6 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, for (i = 0; i < CAM_TFE_CSID_RDI_MAX; i++) init_completion(&tfe_csid_hw->csid_rdin_complete[i]); - rc = cam_tfe_csid_init_soc_resources(&tfe_csid_hw->hw_info->soc_info, - cam_tfe_csid_irq, tfe_csid_hw); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d Failed to init_soc", csid_idx); - goto err; - } - rc = cam_soc_util_get_clk_level(&tfe_csid_hw->hw_info->soc_info, - tfe_csid_hw->clk_rate, - tfe_csid_hw->hw_info->soc_info.src_clk_idx, &clk_lvl); - CAM_DBG(CAM_ISP, "CSID clock lvl %u", clk_lvl); - - rc = cam_tfe_csid_enable_soc_resources(&tfe_csid_hw->hw_info->soc_info, - clk_lvl); - if (rc) { - CAM_ERR(CAM_ISP, "CSID:%d Enable SOC failed", - tfe_csid_hw->hw_intf->hw_idx); - goto err; - } - tfe_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_tfe_csid_get_hw_caps; tfe_csid_hw->hw_intf->hw_ops.init = cam_tfe_csid_init_hw; tfe_csid_hw->hw_intf->hw_ops.deinit = cam_tfe_csid_deinit_hw; @@ -2889,31 +2895,8 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, tfe_csid_hw->cid_res[i].cnt = 0; } - if (tfe_csid_hw->hw_intf->hw_idx == 2) { - val = cam_io_r_mb( - tfe_csid_hw->hw_info->soc_info.reg_map[1].mem_base + - csid_reg->cmn_reg->top_tfe2_fuse_reg); - if (val) { - CAM_INFO(CAM_ISP, "TFE 2 is not supported by hardware"); - - 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; - } - } - - val = cam_io_r_mb( - tfe_csid_hw->hw_info->soc_info.reg_map[1].mem_base + - csid_reg->cmn_reg->top_tfe2_pix_pipe_fuse_reg); - /* Initialize the IPP resources */ - if (!(val && (tfe_csid_hw->hw_intf->hw_idx == 2))) { + if (pixel_pipe_supported) { CAM_DBG(CAM_ISP, "initializing the pix path"); tfe_csid_hw->ipp_res.res_type = CAM_ISP_RESOURCE_PIX_PATH; @@ -2954,14 +2937,6 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, tfe_csid_hw->csid_debug = 0; tfe_csid_hw->error_irq_count = 0; - 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); - goto err; - } - return 0; err: if (rc) { 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 e0cd354e80da..4ce7511a0c97 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 @@ -17,6 +17,7 @@ #include "cam_tfe_bus.h" #include "cam_debug_util.h" #include "cam_cpas_api.h" +#include static const char drv_name[] = "tfe"; @@ -2812,6 +2813,17 @@ int cam_tfe_core_init(struct cam_tfe_hw_core_info *core_info, int rc = -EINVAL; int i; + if (!cam_cpas_is_feature_supported(CAM_CPAS_ISP_FUSE_ID, + hw_intf->hw_idx)) { + CAM_INFO(CAM_ISP, "TFE:%d is not supported", + hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "TFE:%d is supported", + hw_intf->hw_idx); + rc = cam_tfe_top_init(soc_info, hw_intf, tfe_hw_info->top_hw_info, core_info); if (rc) { 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 83a5c7c08734..8ea1c8dac0c2 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -991,7 +991,8 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, if (csiphy_dev->csiphy_info.secure_mode[offset] == 1) { if (cam_cpas_is_feature_supported( - CAM_CPAS_SECURE_CAMERA_ENABLE) != 1) { + CAM_CPAS_SECURE_CAMERA_ENABLE, + 0) != true) { CAM_ERR(CAM_CSIPHY, "sec_cam: camera fuse bit not set"); cam_cpas_stop(csiphy_dev->cpas_handle); -- GitLab From a873fb67b3e55d179dcce94c572c202647c14444 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 26 Mar 2020 13:24:42 +0530 Subject: [PATCH 199/295] msm: camera: isp: validate in_port before accessing in_port information we are getting from the UMD and accessing it directly without validation which might lead to corruption and device failure. CRs-Fixed: 2629969 Change-Id: I0a1c57db9b94f9657427872ae6797635c6aed668 Signed-off-by: Tejas Prajapati --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 50 ++++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) 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 e353cb0e64b0..7dea594f1573 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 @@ -2119,18 +2119,36 @@ static int cam_ife_hw_mgr_acquire_res_root( static int cam_ife_mgr_check_and_update_fe_v0( struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_isp_acquire_hw_info *acquire_hw_info) + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t acquire_info_size) { int i; struct cam_isp_in_port_info *in_port = NULL; uint32_t in_port_length = 0; uint32_t total_in_port_length = 0; + if (acquire_hw_info->input_info_offset >= + acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, + "Invalid size offset 0x%x is greater then size 0x%x", + acquire_hw_info->input_info_offset, + acquire_hw_info->input_info_size); + return -EINVAL; + } + in_port = (struct cam_isp_in_port_info *) ((uint8_t *)&acquire_hw_info->data + acquire_hw_info->input_info_offset); for (i = 0; i < acquire_hw_info->num_inputs; i++) { + if (((uint8_t *)in_port + + sizeof(struct cam_isp_in_port_info)) > + ((uint8_t *)acquire_hw_info + + acquire_info_size)) { + CAM_ERR(CAM_ISP, "Invalid size"); + return -EINVAL; + } + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || (in_port->num_out_res <= 0)) { CAM_ERR(CAM_ISP, "Invalid num output res %u", @@ -2164,18 +2182,36 @@ static int cam_ife_mgr_check_and_update_fe_v0( static int cam_ife_mgr_check_and_update_fe_v2( struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_isp_acquire_hw_info *acquire_hw_info) + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t acquire_info_size) { int i; struct cam_isp_in_port_info_v2 *in_port = NULL; uint32_t in_port_length = 0; uint32_t total_in_port_length = 0; + if (acquire_hw_info->input_info_offset >= + acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, + "Invalid size offset 0x%x is greater then size 0x%x", + acquire_hw_info->input_info_offset, + acquire_hw_info->input_info_size); + return -EINVAL; + } + in_port = (struct cam_isp_in_port_info_v2 *) ((uint8_t *)&acquire_hw_info->data + acquire_hw_info->input_info_offset); for (i = 0; i < acquire_hw_info->num_inputs; i++) { + if (((uint8_t *)in_port + + sizeof(struct cam_isp_in_port_info)) > + ((uint8_t *)acquire_hw_info + + acquire_info_size)) { + CAM_ERR(CAM_ISP, "Invalid size"); + return -EINVAL; + } + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || (in_port->num_out_res <= 0)) { CAM_ERR(CAM_ISP, "Invalid num output res %u", @@ -2209,7 +2245,8 @@ static int cam_ife_mgr_check_and_update_fe_v2( static int cam_ife_mgr_check_and_update_fe( struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_isp_acquire_hw_info *acquire_hw_info) + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t acquire_info_size) { uint32_t major_ver = 0, minor_ver = 0; @@ -2222,10 +2259,10 @@ static int cam_ife_mgr_check_and_update_fe( switch (major_ver) { case 1: return cam_ife_mgr_check_and_update_fe_v0( - ife_ctx, acquire_hw_info); + ife_ctx, acquire_hw_info, acquire_info_size); case 2: return cam_ife_mgr_check_and_update_fe_v2( - ife_ctx, acquire_hw_info); + ife_ctx, acquire_hw_info, acquire_info_size); break; default: CAM_ERR(CAM_ISP, "Invalid ver of common info from user"); @@ -2728,7 +2765,8 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) acquire_hw_info = (struct cam_isp_acquire_hw_info *)acquire_args->acquire_info; - rc = cam_ife_mgr_check_and_update_fe(ife_ctx, acquire_hw_info); + rc = cam_ife_mgr_check_and_update_fe(ife_ctx, acquire_hw_info, + acquire_args->acquire_info_size); if (rc) { CAM_ERR(CAM_ISP, "buffer size is not enough"); goto free_cdm; -- GitLab From cbc03dba7f931ad86e8257ffc805654938967945 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Fri, 1 May 2020 11:20:55 +0530 Subject: [PATCH 200/295] msm: camera: ope: Change parameters to find time difference Change the earlier and later parameters to calculate the time differene. CRs-Fixed: 2675079 Change-Id: I113e084da870470b2186c05f64c414a69e741946 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 ca9c45ea03fc..ad989d0ae184 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 @@ -3491,8 +3491,8 @@ static int cam_ope_mgr_hw_dump(void *hw_priv, void *hw_dump_args) } cur_time = ktime_get(); - diff = ktime_us_delta(ctx_data->req_list[idx]->submit_timestamp, - cur_time); + diff = ktime_us_delta(cur_time, + ctx_data->req_list[idx]->submit_timestamp); cur_ts = ktime_to_timespec64(cur_time); req_ts = ktime_to_timespec64(ctx_data->req_list[idx]->submit_timestamp); -- GitLab From e20615fe08bb6119741b697fe1a34bda6f0baa34 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 27 Apr 2020 21:13:08 +0530 Subject: [PATCH 201/295] msm: camera: cpas: Correct error handling in cpas start cpas driver goes into error handling during any error and reset the error return code as well. This makes cpas start to return success though it is failed. Correct error handling be returning failure to cpas clients. CRs-Fixed: 2684122 Change-Id: I4cf90de550095bc1884e59ae200c9c89e11d214d Signed-off-by: Alok Chauhan --- drivers/cam_cpas/cam_cpas_hw.c | 24 ++++++++++++--------- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c | 4 ++++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 2a829f817a1d..92b4c10c9e2e 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1224,7 +1224,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, struct cam_ahb_vote remove_ahb; struct cam_axi_vote axi_vote = {0}; enum cam_vote_level applied_level = CAM_SVS_VOTE; - int rc, i = 0; + int rc, rc_eh, i = 0; struct cam_cpas_private_soc *soc_private = NULL; bool invalid_start = true; @@ -1346,6 +1346,9 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, kgsl_pwr_limits_del( soc_private->gpu_pwr_limit); soc_private->gpu_pwr_limit = NULL; + CAM_ERR(CAM_CPAS, + "set cx_ipeak_gpu_limit failed, rc %d", + rc); goto remove_axi_vote; } } @@ -1395,25 +1398,26 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, remove_axi_vote: memset(&axi_vote, 0x0, sizeof(struct cam_axi_vote)); - rc = cam_cpas_util_create_vote_all_paths(cpas_client, &axi_vote); - if (rc) - CAM_ERR(CAM_CPAS, "Unable to create per path votes rc: %d", rc); + rc_eh = cam_cpas_util_create_vote_all_paths(cpas_client, &axi_vote); + if (rc_eh) + CAM_ERR(CAM_CPAS, + "Unable to create per path votes rc_eh: %d", rc_eh); cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start fail Vote", &axi_vote); - rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + rc_eh = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); - if (rc) - CAM_ERR(CAM_CPAS, "Unable remove votes rc: %d", rc); + if (rc_eh) + CAM_ERR(CAM_CPAS, "Unable remove votes rc_eh: %d", rc_eh); remove_ahb_vote: remove_ahb.type = CAM_VOTE_ABSOLUTE; remove_ahb.vote.level = CAM_SUSPEND_VOTE; - rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, + rc_eh = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, &remove_ahb, NULL); - if (rc) - CAM_ERR(CAM_CPAS, "Removing AHB vote failed, rc=%d", rc); + if (rc_eh) + CAM_ERR(CAM_CPAS, "Removing AHB vote failed, rc_eh=%d", rc_eh); error: mutex_unlock(&cpas_core->client_mutex[client_indx]); diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c index c17629c9b1f0..e7d1528a63d1 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c @@ -210,6 +210,10 @@ int cam_ope_probe(struct platform_device *pdev) rc = cam_cpas_start(core_info->cpas_handle, &cpas_vote.ahb_vote, &cpas_vote.axi_vote); + if (rc) { + CAM_ERR(CAM_OPE, "cam_cpas_start failed, rc=%d", rc); + goto init_hw_failure; + } rc = cam_ope_init_hw_version(&ope_dev->soc_info, ope_dev->core_info); if (rc) -- GitLab From 780b20112e261575fd280bf6112980a27742d824 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Thu, 2 Apr 2020 20:51:00 +0530 Subject: [PATCH 202/295] msm: camera: req_mgr: Delay detection mechanism Created debugfs variable to track the count of bubble occurrence. Also trace events were added in case of bubble occurrence, timeouts and dual tfe irq mismatch. These traces when enabled will help to gather relative information on which device bubble occurred or timeout happened or if any irq mismatch happened in case of dual tfe. CRs-Fixed: 2666621 Change-Id: I4b46009caa6778aa97d3564eec267299a2370dc4 Signed-off-by: Shravya Samala --- drivers/cam_isp/cam_isp_context.c | 14 ++++++++ drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 23 ++++++++++++- drivers/cam_req_mgr/cam_req_mgr_core.c | 10 ++++++ drivers/cam_req_mgr/cam_req_mgr_debug.c | 12 ++++++- drivers/cam_req_mgr/cam_req_mgr_debug.h | 6 +++- drivers/cam_utils/cam_trace.h | 37 ++++++++++++++++++++- 6 files changed, 98 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 890adee71a04..33a06e463abf 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -19,6 +19,7 @@ #include "cam_cdm_util.h" #include "cam_isp_context.h" #include "cam_common_util.h" +#include "cam_req_mgr_debug.h" static const char isp_dev_name[] = "cam-isp"; @@ -1373,6 +1374,12 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, CAM_DBG(CAM_ISP, "next Substate[%s]", __cam_isp_ctx_substate_val_to_type( ctx_isp->substate_activated)); + + cam_req_mgr_debug_delay_detect(); + trace_cam_delay_detect("ISP", + "bubble epoch_in_applied", req->request_id, + ctx->ctx_id, ctx->link_hdl, ctx->session_hdl, + CAM_DEFAULT_VALUE); end: if (request_id == 0) { req = list_last_entry(&ctx->active_req_list, @@ -1567,6 +1574,13 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( CAM_DBG(CAM_ISP, "next Substate[%s]", __cam_isp_ctx_substate_val_to_type( ctx_isp->substate_activated)); + + cam_req_mgr_debug_delay_detect(); + trace_cam_delay_detect("ISP", + "bubble epoch_in_bubble_applied", + req->request_id, ctx->ctx_id, + ctx->link_hdl, ctx->session_hdl, + CAM_DEFAULT_VALUE); end: req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request, list); 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 d869d96540fe..434a462f9218 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 @@ -23,6 +23,8 @@ #include "cam_cpas_api.h" #include "cam_mem_mgr_api.h" #include "cam_common_util.h" +#include "cam_req_mgr_debug.h" +#include "cam_trace.h" #define CAM_TFE_HW_ENTRIES_MAX 20 #define CAM_TFE_HW_CONFIG_TIMEOUT 60 @@ -2448,6 +2450,12 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, "CDM workqueue delay detected, wait for some more time req_id=%llu rc=%d ctx_index %d", cfg->request_id, rc, ctx->ctx_index); + cam_req_mgr_debug_delay_detect(); + trace_cam_delay_detect("CDM", + "CDM workqueue delay detected", + cfg->request_id, ctx->ctx_index, + CAM_DEFAULT_VALUE, + CAM_DEFAULT_VALUE, rc); continue; } @@ -2455,6 +2463,14 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, "config done completion timeout for req_id=%llu rc=%d ctx_index %d", cfg->request_id, rc, ctx->ctx_index); + + cam_req_mgr_debug_delay_detect(); + trace_cam_delay_detect("ISP", + "config done completion timeout", + cfg->request_id, ctx->ctx_index, + CAM_DEFAULT_VALUE, CAM_DEFAULT_VALUE, + rc); + if (rc == 0) rc = -ETIMEDOUT; @@ -4956,8 +4972,13 @@ static int cam_tfe_hw_mgr_check_irq_for_dual_tfe( tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt++; } - if (tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt == 1) + if (tfe_hw_mgr_ctx->dual_tfe_irq_mismatch_cnt == 1) { cam_tfe_mgr_ctx_irq_dump(tfe_hw_mgr_ctx); + trace_cam_delay_detect("ISP", "dual tfe irq mismatch", + CAM_DEFAULT_VALUE, tfe_hw_mgr_ctx->ctx_index, + CAM_DEFAULT_VALUE, CAM_DEFAULT_VALUE, + rc); + } rc = 0; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 22c30a452e3b..4535fc745174 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -15,6 +15,7 @@ #include "cam_trace.h" #include "cam_debug_util.h" #include "cam_req_mgr_dev.h" +#include "cam_req_mgr_debug.h" static struct cam_req_mgr_core_device *g_crm_core_dev; static struct cam_req_mgr_core_link g_links[MAXIMUM_LINKS_PER_SESSION]; @@ -1471,6 +1472,15 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, "Max retry attempts reached on link[0x%x] for req [%lld]", link->link_hdl, in_q->slot[in_q->rd_idx].req_id); + + cam_req_mgr_debug_delay_detect(); + trace_cam_delay_detect("CRM", + "Max retry attempts reached", + in_q->slot[in_q->rd_idx].req_id, + CAM_DEFAULT_VALUE, + link->link_hdl, + CAM_DEFAULT_VALUE, rc); + __cam_req_mgr_notify_error_on_link(link, dev); link->retry_cnt = 0; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_debug.c b/drivers/cam_req_mgr/cam_req_mgr_debug.c index 6b428c41c1b0..5de86c66b360 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_debug.c +++ b/drivers/cam_req_mgr/cam_req_mgr_debug.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include "cam_req_mgr_debug.h" @@ -8,6 +8,7 @@ #define MAX_SESS_INFO_LINE_BUFF_LEN 256 static char sess_info_buffer[MAX_SESS_INFO_LINE_BUFF_LEN]; +static int cam_debug_mgr_delay_detect; static int cam_req_mgr_debug_set_bubble_recovery(void *data, u64 val) { @@ -128,5 +129,14 @@ int cam_req_mgr_debug_register(struct cam_req_mgr_core_device *core_dev) debugfs_root, core_dev, &bubble_recovery)) return -ENOMEM; + if (!debugfs_create_u32("delay_detect_count", 0644, + debugfs_root, &cam_debug_mgr_delay_detect)) + return -ENOMEM; + return 0; } + +void cam_req_mgr_debug_delay_detect(void) +{ + cam_debug_mgr_delay_detect += 1; +} diff --git a/drivers/cam_req_mgr/cam_req_mgr_debug.h b/drivers/cam_req_mgr/cam_req_mgr_debug.h index dc72c522d140..ff169baed74c 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_debug.h +++ b/drivers/cam_req_mgr/cam_req_mgr_debug.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_DEBUG_H_ @@ -11,4 +11,8 @@ int cam_req_mgr_debug_register(struct cam_req_mgr_core_device *core_dev); +/* cam_req_mgr_debug_delay_detect() + * @brief : increment debug_fs varaible by 1 whenever delay occurred. + */ +void cam_req_mgr_debug_delay_detect(void); #endif diff --git a/drivers/cam_utils/cam_trace.h b/drivers/cam_utils/cam_trace.h index c564b1582a3a..94e26405cbae 100644 --- a/drivers/cam_utils/cam_trace.h +++ b/drivers/cam_utils/cam_trace.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. */ #if !defined(_CAM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) @@ -19,6 +19,8 @@ #include "cam_req_mgr_interface.h" #include "cam_context.h" +#define CAM_DEFAULT_VALUE 0xFF + TRACE_EVENT(cam_context_state, TP_PROTO(const char *name, struct cam_context *ctx), TP_ARGS(name, ctx), @@ -250,6 +252,39 @@ TRACE_EVENT(cam_req_mgr_add_req, ) ); +TRACE_EVENT(cam_delay_detect, + TP_PROTO(const char *entity, + const char *text, uint64_t req_id, + uint32_t ctx_id, int32_t link_hdl, + int32_t session_hdl, int rc), + TP_ARGS(entity, text, req_id, ctx_id, + link_hdl, session_hdl, rc), + TP_STRUCT__entry( + __string(entity, entity) + __string(text, text) + __field(uint64_t, req_id) + __field(uint64_t, ctx_id) + __field(int32_t, link_hdl) + __field(int32_t, session_hdl) + __field(int32_t, rc) + ), + TP_fast_assign( + __assign_str(entity, entity); + __assign_str(text, text); + __entry->req_id = req_id; + __entry->ctx_id = ctx_id; + __entry->link_hdl = link_hdl; + __entry->session_hdl = session_hdl; + __entry->rc = rc; + ), + TP_printk( + "%s: %s request=%lld ctx_id=%d link_hdl=0x%x session_hdl=0x%x rc=%d", + __get_str(entity), __get_str(text), __entry->req_id, + __entry->ctx_id, __entry->link_hdl, + __entry->session_hdl, __entry->rc + ) +); + TRACE_EVENT(cam_submit_to_hw, TP_PROTO(const char *entity, uint64_t req_id), TP_ARGS(entity, req_id), -- GitLab From 07de3bdde1fd81d37ad507255b8e36ad53d76795 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Wed, 6 May 2020 23:39:17 +0530 Subject: [PATCH 203/295] msm: camera: req_mgr: Thread switch delay detection mechanisms Added timestamp logic incase of thread switch. Difference between thread scheduled and thread triggered is compared with a threshold value. If this difference is more than threshold value then, thread switch delay is detected. CRs-Fixed: 2686338 Change-Id: Icbfbd0db4600cef2e5d74d39faabff1744f88b69 Signed-off-by: Shravya Samala --- drivers/cam_cdm/cam_cdm.h | 1 + drivers/cam_cdm/cam_cdm_hw_core.c | 6 +++ drivers/cam_cdm/cam_cdm_virtual_core.c | 11 +++- drivers/cam_cpas/cpas_top/Makefile | 1 + drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 5 ++ drivers/cam_cpas/cpas_top/cam_cpastop_hw.h | 4 +- drivers/cam_req_mgr/cam_req_mgr_core.c | 4 ++ drivers/cam_req_mgr/cam_req_mgr_workq.c | 26 ++++++++- drivers/cam_req_mgr/cam_req_mgr_workq.h | 53 ++++++++++++------- .../cam_sensor_module/cam_cci/cam_cci_core.c | 6 ++- .../cam_sensor_module/cam_cci/cam_cci_dev.h | 4 +- drivers/cam_sync/Makefile | 1 + drivers/cam_sync/cam_sync.c | 2 + drivers/cam_sync/cam_sync_private.h | 16 +++--- drivers/cam_sync/cam_sync_util.c | 6 ++- 15 files changed, 114 insertions(+), 32 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index cc808fe2c508..71d9b1071cc0 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -434,6 +434,7 @@ struct cam_cdm_work_payload { uint32_t irq_status; uint32_t irq_data; int fifo_idx; + ktime_t workq_scheduled_ts; struct work_struct work; }; diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index be73a79054e0..e7cdde454845 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -23,6 +23,7 @@ #include "cam_cdm_hw_reg_1_2.h" #include "cam_cdm_hw_reg_2_0.h" #include "cam_trace.h" +#include "cam_req_mgr_workq.h" #define CAM_CDM_BL_FIFO_WAIT_TIMEOUT 2000 #define CAM_CDM_DBG_GEN_IRQ_USR_DATA 0xff @@ -1105,6 +1106,9 @@ static void cam_hw_cdm_work(struct work_struct *work) payload = NULL; return; } + cam_req_mgr_thread_switch_delay_detect( + payload->workq_scheduled_ts); + CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); if (payload->irq_status & CAM_CDM_IRQ_STATUS_INLINE_IRQ_MASK) { @@ -1342,6 +1346,8 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) cdm_hw->soc_info.index); cdm_core->bl_fifo[i].work_record++; + payload[i]->workq_scheduled_ts = ktime_get(); + work_status = queue_work( cdm_core->bl_fifo[i].work_queue, &payload[i]->work); diff --git a/drivers/cam_cdm/cam_cdm_virtual_core.c b/drivers/cam_cdm/cam_cdm_virtual_core.c index 5abca3939338..481d37616c48 100644 --- a/drivers/cam_cdm/cam_cdm_virtual_core.c +++ b/drivers/cam_cdm/cam_cdm_virtual_core.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 @@ -19,6 +19,7 @@ #include "cam_cdm_core_common.h" #include "cam_cdm_soc.h" #include "cam_io_util.h" +#include "cam_req_mgr_workq.h" #define CAM_CDM_VIRTUAL_NAME "qcom,cam_virtual_cdm" @@ -32,6 +33,10 @@ static void cam_virtual_cdm_work(struct work_struct *work) if (payload) { cdm_hw = payload->hw; core = (struct cam_cdm *)cdm_hw->core_info; + + cam_req_mgr_thread_switch_delay_detect( + payload->workq_scheduled_ts); + if (payload->irq_status & 0x2) { struct cam_cdm_bl_cb_request_entry *node; @@ -183,9 +188,11 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, INIT_WORK((struct work_struct *) &payload->work, cam_virtual_cdm_work); + payload->workq_scheduled_ts = + ktime_get(); queue_work(core->work_queue, &payload->work); - } + } } core->bl_tag++; CAM_DBG(CAM_CDM, diff --git a/drivers/cam_cpas/cpas_top/Makefile b/drivers/cam_cpas/cpas_top/Makefile index 0306b14ef14a..6cce35859776 100644 --- a/drivers/cam_cpas/cpas_top/Makefile +++ b/drivers/cam_cpas/cpas_top/Makefile @@ -5,5 +5,6 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpastop_hw.o diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index d62c06f59544..f6af26fc579d 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_v540_100.h" #include "cpastop_v520_100.h" +#include "cam_req_mgr_workq.h" struct cam_camnoc_info *camnoc_info; @@ -415,6 +416,9 @@ static void cam_cpastop_work(struct work_struct *work) return; } + cam_req_mgr_thread_switch_delay_detect( + payload->workq_scheduled_ts); + cpas_hw = payload->hw; cpas_core = (struct cam_cpas *) cpas_hw->core_info; soc_info = &cpas_hw->soc_info; @@ -514,6 +518,7 @@ static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data) cam_cpastop_reset_irq(cpas_hw); + payload->workq_scheduled_ts = ktime_get(); queue_work(cpas_core->work_queue, &payload->work); done: atomic_dec(&cpas_core->irq_count); diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h index 1804d93354ed..597f988f7de9 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.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 _CAM_CPASTOP_HW_H_ @@ -276,6 +276,7 @@ struct cam_camnoc_info { * @hw: Pointer to HW info * @irq_status: IRQ status value * @irq_data: IRQ data + * @workq_scheduled_ts: workqueue scheduled timestamp * @work: Work handle * */ @@ -283,6 +284,7 @@ struct cam_cpas_work_payload { struct cam_hw_info *hw; uint32_t irq_status; uint32_t irq_data; + ktime_t workq_scheduled_ts; struct work_struct work; }; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 22c30a452e3b..71fbbede3f8e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -2097,6 +2097,7 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) rc = -EINVAL; goto end; } + link = (struct cam_req_mgr_core_link *)priv; task_data = (struct crm_task_payload *)data; flush_info = (struct cam_req_mgr_flush_info *)&task_data->u; @@ -2396,6 +2397,7 @@ int cam_req_mgr_process_error(void *priv, void *data) rc = -EINVAL; goto end; } + link = (struct cam_req_mgr_core_link *)priv; task_data = (struct crm_task_payload *)data; err_info = (struct cam_req_mgr_error_notify *)&task_data->u; @@ -2489,6 +2491,7 @@ int cam_req_mgr_process_stop(void *priv, void *data) rc = -EINVAL; goto end; } + link = (struct cam_req_mgr_core_link *)priv; __cam_req_mgr_flush_req_slot(link); end: @@ -2519,6 +2522,7 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) rc = -EINVAL; goto end; } + link = (struct cam_req_mgr_core_link *)priv; task_data = (struct crm_task_payload *)data; trigger_data = (struct cam_req_mgr_trigger_notify *)&task_data->u; diff --git a/drivers/cam_req_mgr/cam_req_mgr_workq.c b/drivers/cam_req_mgr/cam_req_mgr_workq.c index 29d98503f305..79fc47f40d62 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_workq.c +++ b/drivers/cam_req_mgr/cam_req_mgr_workq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include "cam_req_mgr_workq.h" @@ -102,6 +102,7 @@ static void cam_req_mgr_process_workq(struct work_struct *w) workq = (struct cam_req_mgr_core_workq *) container_of(w, struct cam_req_mgr_core_workq, work); + cam_req_mgr_thread_switch_delay_detect(workq->workq_scheduled_ts); while (i < CRM_TASK_PRIORITY_MAX) { WORKQ_ACQUIRE_LOCK(workq, flags); while (!list_empty(&workq->task.process_head[i])) { @@ -164,6 +165,7 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, CAM_DBG(CAM_CRM, "enq task %pK pending_cnt %d", task, atomic_read(&workq->task.pending_cnt)); + workq->workq_scheduled_ts = ktime_get(); queue_work(workq->job, &workq->work); WORKQ_RELEASE_LOCK(workq, flags); end: @@ -265,3 +267,25 @@ void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq) *crm_workq = NULL; } } + +void cam_req_mgr_thread_switch_delay_detect(ktime_t workq_scheduled) +{ + uint64_t diff; + ktime_t cur_time; + struct timespec64 cur_ts; + struct timespec64 workq_scheduled_ts; + + cur_time = ktime_get(); + diff = ktime_ms_delta(cur_time, workq_scheduled); + workq_scheduled_ts = ktime_to_timespec64(workq_scheduled); + cur_ts = ktime_to_timespec64(cur_time); + + if (diff > CAM_WORKQ_RESPONSE_TIME_THRESHOLD) { + CAM_ERR(CAM_CRM, + "Workq delay detected %ld:%06ld %ld:%06ld %ld:", + workq_scheduled_ts.tv_sec, + workq_scheduled_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, cur_ts.tv_nsec/NSEC_PER_USEC, + diff); + } +} diff --git a/drivers/cam_req_mgr/cam_req_mgr_workq.h b/drivers/cam_req_mgr/cam_req_mgr_workq.h index f938710b69ae..5956b1a233c4 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_workq.h +++ b/drivers/cam_req_mgr/cam_req_mgr_workq.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_WORKQ_H_ @@ -26,6 +26,13 @@ */ #define CAM_WORKQ_FLAG_SERIAL (1 << 1) +/* + * Response time threshold in ms beyond which it is considered + * as workq scheduling/processing delay. + */ +#define CAM_WORKQ_RESPONSE_TIME_THRESHOLD 5 + + /* Task priorities, lower the number higher the priority*/ enum crm_task_priority { CRM_TASK_PRIORITY_0, @@ -54,27 +61,28 @@ enum crm_workq_context { * @ret : return value in future to use for blocking calls */ struct crm_workq_task { - int32_t priority; - void *payload; - int32_t (*process_cb)(void *priv, void *data); - void *parent; - struct list_head entry; - uint8_t cancel; - void *priv; - int32_t ret; + int32_t priority; + void *payload; + int32_t (*process_cb)(void *priv, void *data); + void *parent; + struct list_head entry; + uint8_t cancel; + void *priv; + int32_t ret; }; /** struct cam_req_mgr_core_workq - * @work : work token used by workqueue - * @job : workqueue internal job struct + * @work : work token used by workqueue + * @job : workqueue internal job struct + * @workq_scheduled_ts: workqueue scheduled timestamp * task - - * @lock_bh : lock for task structs - * @in_irq : set true if workque can be used in irq context - * @free_cnt : num of free/available tasks - * @empty_head : list head of available taska which can be used - * or acquired in order to enqueue a task to workq - * @pool : pool of tasks used for handling events in workq context - * @num_task : size of tasks pool + * @lock_bh : lock for task structs + * @in_irq : set true if workque can be used in irq context + * @free_cnt : num of free/available tasks + * @empty_head : list head of available taska which can be used + * or acquired in order to enqueue a task to workq + * @pool : pool of tasks used for handling events in workq context + * @num_task : size of tasks pool * - */ struct cam_req_mgr_core_workq { @@ -82,6 +90,7 @@ struct cam_req_mgr_core_workq { struct workqueue_struct *job; spinlock_t lock_bh; uint32_t in_irq; + ktime_t workq_scheduled_ts; /* tasks */ struct { @@ -133,6 +142,14 @@ void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **workq); int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, void *priv, int32_t prio); +/** + * cam_req_mgr_thread_switch_delay_detect() + * @brief: Detects if workq delay has occurred or not + * @timestamp: workq scheduled timestamp + */ +void cam_req_mgr_thread_switch_delay_detect( + ktime_t timestamp); + /** * cam_req_mgr_workq_get_task() * @brief: Returns empty task pointer for use 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 74b324678f15..edcf81e3f418 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1,11 +1,12 @@ // 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 #include "cam_cci_core.h" #include "cam_cci_dev.h" +#include "cam_req_mgr_workq.h" static int32_t cam_cci_convert_type_to_num_bytes( enum camera_sensor_i2c_type type) @@ -1427,6 +1428,8 @@ static void cam_cci_write_async_helper(struct work_struct *work) enum cci_i2c_master_t master; struct cam_cci_master_info *cci_master_info; + cam_req_mgr_thread_switch_delay_detect( + write_async->workq_scheduled_ts); cci_dev = write_async->cci_dev; i2c_msg = &write_async->c_ctrl.cfg.cci_i2c_write_cfg; master = write_async->c_ctrl.cci_info->cci_i2c_master; @@ -1493,6 +1496,7 @@ static int32_t cam_cci_i2c_write_async(struct v4l2_subdev *sd, cci_i2c_write_cfg_w->size = cci_i2c_write_cfg->size; cci_i2c_write_cfg_w->delay = cci_i2c_write_cfg->delay; + write_async->workq_scheduled_ts = ktime_get(); queue_work(cci_dev->write_wq[write_async->queue], &write_async->work); return rc; 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 8b78cde86738..2d7e8390acca 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.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 _CAM_CCI_DEV_H_ @@ -30,6 +30,7 @@ #include "cam_cci_hwreg.h" #include "cam_soc_util.h" #include "cam_debug_util.h" +#include "cam_req_mgr_workq.h" #define V4L2_IDENT_CCI 50005 #define CCI_I2C_QUEUE_0_SIZE 128 @@ -294,6 +295,7 @@ struct cci_write_async { struct cam_cci_ctrl c_ctrl; enum cci_i2c_queue_t queue; struct work_struct work; + ktime_t workq_scheduled_ts; enum cci_i2c_sync sync_en; }; diff --git a/drivers/cam_sync/Makefile b/drivers/cam_sync/Makefile index 40efdf4dd794..3008761f59e0 100644 --- a/drivers/cam_sync/Makefile +++ b/drivers/cam_sync/Makefile @@ -2,6 +2,7 @@ ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-$(CONFIG_MSM_GLOBAL_SYNX) += -I$(srctree)/drivers/media/platform/msm/synx ccflags-y += -I$(src) diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index dfb8ac10ee22..6daadc3120e4 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -12,6 +12,7 @@ #include "cam_sync_util.h" #include "cam_debug_util.h" #include "cam_common_util.h" +#include "cam_req_mgr_workq.h" #ifdef CONFIG_MSM_GLOBAL_SYNX #include @@ -127,6 +128,7 @@ int cam_sync_register_callback(sync_callback cb_func, sync_cb->status = row->state; CAM_DBG(CAM_SYNC, "Enqueue callback for sync object:%d", sync_cb->sync_obj); + sync_cb->workq_scheduled_ts = ktime_get(); queue_work(sync_dev->work_queue, &sync_cb->cb_dispatch_work); spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); diff --git a/drivers/cam_sync/cam_sync_private.h b/drivers/cam_sync/cam_sync_private.h index a8612fdcd7c5..a77dc5f7f126 100644 --- a/drivers/cam_sync/cam_sync_private.h +++ b/drivers/cam_sync/cam_sync_private.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 __CAM_SYNC_PRIVATE_H__ @@ -89,18 +89,20 @@ struct sync_child_info { * struct sync_callback_info - Single node of information about a kernel * callback registered on a sync object * - * @callback_func : Callback function, registered by client driver - * @cb_data : Callback data, registered by client driver - * @status........ : Status with which callback will be invoked in client - * @sync_obj : Sync id of the object for which callback is registered - * @cb_dispatch_work : Work representing the call dispatch - * @list : List member used to append this node to a linked list + * @callback_func : Callback function, registered by client driver + * @cb_data : Callback data, registered by client driver + * @status : Status with which callback will be invoked in client + * @sync_obj : Sync id of the object for which callback is registered + * @workq_scheduled_ts : workqueue scheduled timestamp + * @cb_dispatch_work : Work representing the call dispatch + * @list : List member used to append this node to a linked list */ struct sync_callback_info { sync_callback callback_func; void *cb_data; int status; int32_t sync_obj; + ktime_t workq_scheduled_ts; struct work_struct cb_dispatch_work; struct list_head list; }; diff --git a/drivers/cam_sync/cam_sync_util.c b/drivers/cam_sync/cam_sync_util.c index d7e0f4125290..f632212ac796 100644 --- a/drivers/cam_sync/cam_sync_util.c +++ b/drivers/cam_sync/cam_sync_util.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_sync_util.h" +#include "cam_req_mgr_workq.h" int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, long *idx) @@ -290,6 +291,9 @@ void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work) struct sync_callback_info, cb_dispatch_work); + cam_req_mgr_thread_switch_delay_detect( + cb_info->workq_scheduled_ts); + cb_info->callback_func(cb_info->sync_obj, cb_info->status, cb_info->cb_data); -- GitLab From e2afd6fd24d4af6a0926edae48022b7421b87fd9 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 20 Apr 2020 23:25:03 +0530 Subject: [PATCH 204/295] msm: camera: ope: Add debug fs for dumping frame setting logs Adding debug_fs to enable/disable dumping frame settings. Also refactoring debug logs to decrease logging and avoid log dropping. CRs-Fixed: 2678217 Change-Id: I28646116ac9a05fb84a24dcd176a443182bc1de0 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 73 +++++++++++-------- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 2 + .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 51 +++++-------- .../ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.c | 41 ++++------- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 55 +++++++------- 5 files changed, 108 insertions(+), 114 deletions(-) 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 ad989d0ae184..c7bb138669ca 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 @@ -1791,15 +1791,14 @@ static void cam_ope_mgr_print_stripe_info(uint32_t batch, { CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d: E", batch, io_buf, plane, stripe); - CAM_DBG(CAM_OPE, "width: %d s_w: %u s_h: %u s_s: %u", - stripe_info->width, stripe_info->width, - stripe_info->height, stripe_info->stride); + CAM_DBG(CAM_OPE, "width: %d s_h: %u s_s: %u", + stripe_info->width, stripe_info->height, + stripe_info->stride); CAM_DBG(CAM_OPE, "s_xinit = %u iova = %x s_loc = %u", - stripe_info->s_location, stripe_info->x_init, - iova_addr); - CAM_DBG(CAM_OPE, "s_off = %u s_format = %u s_len = %u", + stripe_info->x_init, iova_addr, stripe_info->s_location); + CAM_DBG(CAM_OPE, "s_off = %u s_format = %u s_len = %u d_bus %d", stripe_info->offset, stripe_info->format, - stripe_info->len); + stripe_info->len, stripe_info->disable_bus); CAM_DBG(CAM_OPE, "s_align = %u s_pack = %u s_unpack = %u", stripe_info->alignment, stripe_info->pack_format, stripe_info->unpack_format); @@ -1839,35 +1838,15 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, in_frame_set = &in_frame_process->frame_set[i]; for (j = 0; j < in_frame_set->num_io_bufs; j++) { in_io_buf = &in_frame_set->io_buf[j]; - CAM_DBG(CAM_OPE, "i:%d j:%d dir: %x rsc: %u plane: %d", - i, j, in_io_buf->direction, - in_io_buf->resource_type, - in_io_buf->num_planes); for (k = 0; k < in_io_buf->num_planes; k++) { - CAM_DBG(CAM_OPE, "i:%d j:%d k:%d numstripe: %d", - i, j, k, in_io_buf->num_stripes[k]); - CAM_DBG(CAM_OPE, "m_hdl: %d len: %d", - in_io_buf->mem_handle[k], - in_io_buf->length[k]); - if (!in_io_buf->num_stripes[k]) { CAM_ERR(CAM_OPE, "Null num_stripes"); return -EINVAL; } - for (l = 0; l < in_io_buf->num_stripes[k]; l++) { in_stripe_info = &in_io_buf->stripe_info[k][l]; - CAM_DBG(CAM_OPE, "i:%d j:%d k:%d l:%d", - i, j, k, l); - CAM_DBG(CAM_OPE, "%d s_loc:%d w:%d", - in_stripe_info->x_init, - in_stripe_info->stripe_location, - in_stripe_info->width); - CAM_DBG(CAM_OPE, "s_off: %d d_bus: %d", - in_stripe_info->offset, - in_stripe_info->disable_bus); } } } @@ -1925,9 +1904,6 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, unpack_format = 0; } - CAM_DBG(CAM_OPE, "i:%d j:%d dir:%d rsc type:%d fmt:%d", - i, j, io_buf->direction, io_buf->resource_type, - io_buf->format); for (k = 0; k < in_io_buf->num_planes; k++) { io_buf->num_stripes[k] = in_io_buf->num_stripes[k]; @@ -1954,6 +1930,11 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, return -EINVAL; } iova_addr += in_io_buf->plane_offset[k]; + CAM_DBG(CAM_OPE, + "E rsc %d stripes %d dir %d plane %d", + in_io_buf->resource_type, + in_io_buf->direction, + in_io_buf->num_stripes[k], k); for (l = 0; l < in_io_buf->num_stripes[k]; l++) { in_stripe_info = @@ -1984,6 +1965,11 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, cam_ope_mgr_print_stripe_info(i, j, k, l, stripe_info, iova_addr); } + CAM_DBG(CAM_OPE, + "X rsc %d stripes %d dir %d plane %d", + in_io_buf->resource_type, + in_io_buf->direction, + in_io_buf->num_stripes[k], k); } } } @@ -3755,6 +3741,31 @@ static int cam_ope_mgr_create_wq(void) return rc; } +static int cam_ope_create_debug_fs(void) +{ + ope_hw_mgr->dentry = debugfs_create_dir("camera_ope", + NULL); + + if (!ope_hw_mgr->dentry) { + CAM_ERR(CAM_OPE, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_bool("frame_dump_enable", + 0644, + ope_hw_mgr->dentry, + &ope_hw_mgr->frame_dump_enable)) { + CAM_ERR(CAM_OPE, + "failed to create dump_enable_debug"); + goto err; + } + + return 0; +err: + debugfs_remove_recursive(ope_hw_mgr->dentry); + return -ENOMEM; +} + int cam_ope_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, int *iommu_hdl) @@ -3860,6 +3871,8 @@ int cam_ope_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, if (rc) goto ope_wq_create_failed; + cam_ope_create_debug_fs(); + if (iommu_hdl) *iommu_hdl = ope_hw_mgr->iommu_hdl; 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 01d37fe22ecb..be0821c11f0b 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 @@ -529,6 +529,8 @@ struct cam_ope_hw_mgr { struct cam_hw_intf *ope_dev_intf[OPE_DEV_MAX]; struct cam_soc_reg_map *cdm_reg_map[OPE_DEV_MAX][OPE_BASE_MAX]; struct cam_ope_clk_info clk_info; + struct dentry *dentry; + bool frame_dump_enable; }; /** 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 d58d4dd5e94a..1f650490f6f5 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 @@ -190,16 +190,18 @@ static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, cdm_ops = ctx_data->ope_cdm.cdm_ops; ope_request = ctx_data->req_list[req_idx]; - CAM_DBG(CAM_OPE, "req_idx = %d req_id = %lld KMDbuf %x offset %d", - req_idx, ope_request->request_id, - kmd_buf, prepare->kmd_buf_offset); + bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; io_port_info = &bus_rd_ctx->io_port_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]; + CAM_DBG(CAM_OPE, + "req_idx = %d req_id = %lld KMDbuf 0x%x offset %d rsc %d", + req_idx, ope_request->request_id, + kmd_buf, prepare->kmd_buf_offset, + io_buf->resource_type); CAM_DBG(CAM_OPE, "batch:%d iobuf:%d direction:%d", batch_idx, io_idx, io_buf->direction); io_port_cdm = @@ -307,20 +309,15 @@ static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, sizeof(temp)); CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", batch_idx, io_idx, k, l); - for (m = 0; m < count; m++) - CAM_DBG(CAM_OPE, "%d:temp:%x", - m, temp_reg[m]); + for (m = 0; m < count; m += 2) + CAM_DBG(CAM_OPE, "%d: off: 0x%x val: 0x%x", + m, temp_reg[m], temp_reg[m+1]); CAM_DBG(CAM_OPE, "kmd_buf:%x offset:%d", - kmd_buf, prepare->kmd_buf_offset); - CAM_DBG(CAM_OPE, "%x count: %d size:%d", - temp_reg, count, header_size); - CAM_DBG(CAM_OPE, "RD cmdbufs:%d off:%d", - io_port_cdm->num_s_cmd_bufs[l], - io_port_cdm->s_cdm_info[l][idx].offset); - CAM_DBG(CAM_OPE, "len:%d", - io_port_cdm->s_cdm_info[l][idx].len); - CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", - batch_idx, io_idx, k, l); + kmd_buf, prepare->kmd_buf_offset); + CAM_DBG(CAM_OPE, "RD cmdbufs:%d off:%d len %d", + io_port_cdm->num_s_cmd_bufs[l], + io_port_cdm->s_cdm_info[l][idx].offset, + io_port_cdm->s_cdm_info[l][idx].len); count = 0; } } @@ -372,8 +369,9 @@ static uint32_t *cam_ope_bus_rm_disable(struct ope_hw *ope_hw_info, io_port_cdm_batch = &bus_rd_ctx->io_port_cdm_batch; rd_reg = ope_hw_info->bus_rd_reg; - CAM_DBG(CAM_OPE, "kmd_buf = %x req_idx = %d offset = %d", - kmd_buf, req_idx, prepare->kmd_buf_offset); + CAM_DBG(CAM_OPE, + "kmd_buf = 0x%x req_idx = %d offset = %d rd_idx %d b %d", + kmd_buf, req_idx, prepare->kmd_buf_offset, rm_idx, batch_idx); io_port_cdm = &bus_rd_ctx->io_port_cdm_batch.io_port_cdm[batch_idx]; @@ -402,20 +400,11 @@ static uint32_t *cam_ope_bus_rm_disable(struct ope_hw *ope_hw_info, prepare->kmd_buf_offset += ((count + header_size) * sizeof(temp)); - CAM_DBG(CAM_OPE, "b:%d s:%d", - batch_idx, l); - CAM_DBG(CAM_OPE, "kmdbuf:%x, offset:%d", - kmd_buf, prepare->kmd_buf_offset); - CAM_DBG(CAM_OPE, "count:%d temp_reg:%x", - count, temp_reg, header_size); - CAM_DBG(CAM_OPE, "header_size:%d", header_size); - CAM_DBG(CAM_OPE, "RD cmd bufs = %d", + CAM_DBG(CAM_OPE, "RD cmd bufs = %d", io_port_cdm->num_s_cmd_bufs[l]); - CAM_DBG(CAM_OPE, "off:%d len:%d", - io_port_cdm->s_cdm_info[l][idx].offset, + CAM_DBG(CAM_OPE, "stripe %d off:%d len:%d", + l, io_port_cdm->s_cdm_info[l][idx].offset, io_port_cdm->s_cdm_info[l][idx].len); - CAM_DBG(CAM_OPE, "b:%d s:%d", - batch_idx, l); count = 0; } 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 bade41972a26..df5cb89b1eea 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 @@ -169,7 +169,7 @@ static uint32_t *cam_ope_bus_wr_update(struct ope_hw *ope_hw_info, int batch_idx, int io_idx, uint32_t *kmd_buf, uint32_t *num_stripes) { - int k, l, out_port_idx; + int k, l, m, out_port_idx; uint32_t idx; uint32_t num_wm_ports; uint32_t comb_idx; @@ -226,8 +226,8 @@ static uint32_t *cam_ope_bus_wr_update(struct ope_hw *ope_hw_info, prepare->kmd_buf_offset); 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); + CAM_DBG(CAM_OPE, "batch = %d io buf num = %d dir = %d rsc %d", + batch_idx, io_idx, io_buf->direction, io_buf->resource_type); io_port_cdm = &bus_wr_ctx->io_port_cdm_batch.io_port_cdm[batch_idx]; @@ -335,19 +335,15 @@ static uint32_t *cam_ope_bus_wr_update(struct ope_hw *ope_hw_info, CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", batch_idx, io_idx, k, l); + for (m = 0; m < count; m += 2) + CAM_DBG(CAM_OPE, "%d: off: 0x%x val: 0x%x", + m, temp_reg[m], temp_reg[m+1]); CAM_DBG(CAM_OPE, "kmdbuf:%x, offset:%d", kmd_buf, prepare->kmd_buf_offset); - CAM_DBG(CAM_OPE, "count:%d temp_reg:%x", - count, temp_reg, header_size); - CAM_DBG(CAM_OPE, "header_size:%d", header_size); - - CAM_DBG(CAM_OPE, "WR cmd bufs = %d", - io_port_cdm->num_s_cmd_bufs[l]); - CAM_DBG(CAM_OPE, "off:%d len:%d", + CAM_DBG(CAM_OPE, "WR cmd bufs = %d off:%d len:%d", + io_port_cdm->num_s_cmd_bufs[l], io_port_cdm->s_cdm_info[l][idx].offset, io_port_cdm->s_cdm_info[l][idx].len); - CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", - batch_idx, io_idx, k, l); count = 0; } } @@ -398,8 +394,9 @@ static uint32_t *cam_ope_bus_wm_disable(struct ope_hw *ope_hw_info, io_port_cdm_batch = &bus_wr_ctx->io_port_cdm_batch; wr_reg = ope_hw_info->bus_wr_reg; - CAM_DBG(CAM_OPE, "kmd_buf = %x req_idx = %d offset = %d", - kmd_buf, req_idx, prepare->kmd_buf_offset); + CAM_DBG(CAM_OPE, + "kmd_buf = %x req_idx = %d offset = %d out_idx %d b %d", + kmd_buf, req_idx, prepare->kmd_buf_offset, io_idx, batch_idx); io_port_cdm = &bus_wr_ctx->io_port_cdm_batch.io_port_cdm[batch_idx]; @@ -409,8 +406,6 @@ static uint32_t *cam_ope_bus_wm_disable(struct ope_hw *ope_hw_info, for (k = 0; k < num_wm_ports; k++) { for (l = 0; l < num_stripes; l++) { - CAM_DBG(CAM_OPE, "comb_idx = %d p_idx = %d s_idx = %d", - comb_idx, k, l); /* frame level info */ /* stripe level info */ wm_port_id = out_port_to_wm->wm_port_id[comb_idx][k]; @@ -436,21 +431,11 @@ static uint32_t *cam_ope_bus_wm_disable(struct ope_hw *ope_hw_info, prepare->kmd_buf_offset += ((count + header_size) * sizeof(temp)); - CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", - batch_idx, io_idx, k, l); - CAM_DBG(CAM_OPE, "kmdbuf:%x, offset:%d", - kmd_buf, prepare->kmd_buf_offset); - CAM_DBG(CAM_OPE, "count:%d temp_reg:%x", - count, temp_reg, header_size); - CAM_DBG(CAM_OPE, "header_size:%d", header_size); - CAM_DBG(CAM_OPE, "WR cmd bufs = %d", io_port_cdm->num_s_cmd_bufs[l]); - CAM_DBG(CAM_OPE, "off:%d len:%d", - io_port_cdm->s_cdm_info[l][idx].offset, + CAM_DBG(CAM_OPE, "s:%d off:%d len:%d", + l, io_port_cdm->s_cdm_info[l][idx].offset, io_port_cdm->s_cdm_info[l][idx].len); - CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d", - batch_idx, io_idx, k, l); count = 0; } } 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 9f1068adc473..12f5d1750cc2 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 @@ -427,7 +427,7 @@ static int dump_dmi_cmd(uint32_t print_idx, return 0; } -static int dump_frame_direct(uint32_t print_idx, +static int dump_direct_cmd(uint32_t print_idx, uint32_t *print_ptr, struct ope_frame_process *frm_proc, int batch_idx, int cmd_buf_idx) @@ -569,7 +569,7 @@ static uint32_t *ope_create_frame_cmd_batch(struct cam_ope_hw_mgr *hw_mgr, iova_addr, frm_proc->cmd_buf[i][j].length); print_ptr = (uint32_t *)cpu_addr; - dump_frame_direct(print_idx, print_ptr, + dump_direct_cmd(print_idx, print_ptr, frm_proc, i, j); } else { num_dmi = frm_proc->cmd_buf[i][j].length / @@ -591,16 +591,18 @@ static uint32_t *ope_create_frame_cmd_batch(struct cam_ope_hw_mgr *hw_mgr, 0, dmi_cmd->DMIAddr, dmi_cmd->DMISel, dmi_cmd->addr, dmi_cmd->length); - dump_dmi_cmd(print_idx, - print_ptr, dmi_cmd, temp); + if (hw_mgr->frame_dump_enable) + 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); + if (hw_mgr->frame_dump_enable) + dump_frame_cmd(frm_proc, i, j, + iova_addr, kmd_buf, buf_len); } return kmd_buf; @@ -724,8 +726,9 @@ static uint32_t *ope_create_frame_cmd(struct cam_ope_hw_mgr *hw_mgr, 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); + if (hw_mgr->frame_dump_enable) + dump_direct_cmd(print_idx, print_ptr, + frm_proc, i, j); } else { num_dmi = frm_proc->cmd_buf[i][j].length / sizeof(struct cdm_dmi_cmd); @@ -747,16 +750,19 @@ static uint32_t *ope_create_frame_cmd(struct cam_ope_hw_mgr *hw_mgr, 0, dmi_cmd->DMIAddr, dmi_cmd->DMISel, dmi_cmd->addr, dmi_cmd->length); - dump_dmi_cmd(print_idx, - print_ptr, dmi_cmd, temp); + if (hw_mgr->frame_dump_enable) + 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); + if (hw_mgr->frame_dump_enable) + dump_frame_cmd(frm_proc, i, j, + iova_addr, kmd_buf, buf_len); } } return kmd_buf; @@ -828,15 +834,12 @@ static uint32_t *ope_create_stripe_cmd(struct cam_ope_hw_mgr *hw_mgr, kmd_buf, iova_addr, frm_proc->cmd_buf[i][k].length); - print_ptr = (uint32_t *)cpu_addr; - CAM_DBG(CAM_OPE, "Stripe:%d direct:E", - stripe_idx); - for (print_idx = 0; print_idx < - frm_proc->cmd_buf[i][k].length / 4; - print_idx++) { - CAM_DBG(CAM_OPE, "%d: %x", print_idx, - print_ptr[print_idx]); - } + print_ptr = (uint32_t *)cpu_addr; + CAM_DBG(CAM_OPE, "Stripe:%d direct:E", + stripe_idx); + if (hw_mgr->frame_dump_enable) + dump_direct_cmd(print_idx, print_ptr, + frm_proc, i, k); CAM_DBG(CAM_OPE, "Stripe:%d direct:X", stripe_idx); } else if (frm_proc->cmd_buf[i][k].type == OPE_CMD_BUF_TYPE_INDIRECT) { @@ -856,15 +859,17 @@ static uint32_t *ope_create_stripe_cmd(struct cam_ope_hw_mgr *hw_mgr, 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); + if (hw_mgr->frame_dump_enable) + dump_dmi_cmd(print_idx, + print_ptr, dmi_cmd, temp); print_ptr += sizeof(struct cdm_dmi_cmd) / sizeof(uint32_t); } CAM_DBG(CAM_OPE, "Stripe:%d Indirect:X", stripe_idx); } - dump_stripe_cmd(frm_proc, stripe_idx, i, k, - iova_addr, kmd_buf, buf_len); + if (hw_mgr->frame_dump_enable) + dump_stripe_cmd(frm_proc, stripe_idx, i, k, + iova_addr, kmd_buf, buf_len); } return kmd_buf; } -- GitLab From b5fa90cec895d1a69ec7737bee7683189c94d617 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Wed, 6 May 2020 19:50:23 +0530 Subject: [PATCH 205/295] msm: camera: ope: Add debugfs support to dump ope hang dump Add debugfs support to dump ope hang dump info for each frame to aid in debugging. CRs-Fixed: 2684109 Change-Id: Ib09d2deefabbe516472663a772b40762717eed53 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 18 +++++++++++++++++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 4 ++++ 2 files changed, 21 insertions(+), 1 deletion(-) 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 c7bb138669ca..c10b337dc499 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 @@ -588,6 +588,7 @@ static void cam_ope_dump_req_data(struct cam_ope_request *ope_req) 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; @@ -1545,6 +1546,7 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, struct cam_hw_done_event_data buf_data; struct timespec64 ts; bool flag = false; + bool dump_flag = true; if (!userdata) { CAM_ERR(CAM_OPE, "Invalid ctx from CDM callback"); @@ -1604,12 +1606,17 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, 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) + if (status != CAM_CDM_CB_STATUS_HW_FLUSH) { cam_ope_dump_req_data(ope_req); + dump_flag = false; + } rc = cam_ope_mgr_reset_hw(); flag = true; } + if (ope_hw_mgr->dump_req_data_enable && dump_flag) + cam_ope_dump_req_data(ope_req); + ctx->req_cnt--; buf_data.request_id = ope_req->request_id; @@ -3760,6 +3767,15 @@ static int cam_ope_create_debug_fs(void) goto err; } + if (!debugfs_create_bool("dump_req_data_enable", + 0644, + ope_hw_mgr->dentry, + &ope_hw_mgr->dump_req_data_enable)) { + CAM_ERR(CAM_OPE, + "failed to create dump_enable_debug"); + goto err; + } + return 0; err: debugfs_remove_recursive(ope_hw_mgr->dentry); 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 be0821c11f0b..98d3587ac929 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 @@ -499,6 +499,9 @@ struct cam_ope_ctx { * @ope_dev_intf: OPE device interface * @cdm_reg_map: OPE CDM register map * @clk_info: OPE clock Info for HW manager + * @dentry: Pointer to OPE debugfs directory + * @frame_dump_enable: OPE frame setting dump enablement + * @dump_req_data_enable: OPE hang dump enablement */ struct cam_ope_hw_mgr { int32_t open_cnt; @@ -531,6 +534,7 @@ struct cam_ope_hw_mgr { struct cam_ope_clk_info clk_info; struct dentry *dentry; bool frame_dump_enable; + bool dump_req_data_enable; }; /** -- GitLab From d98dba68028bd1ca26259c3e548c123d5548d5ac Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 11 May 2020 12:47:02 +0530 Subject: [PATCH 206/295] msm: camera: cpas: Updated new api to limit gpu fmax Existing gfx api returns failure when requested frequency is larger than fmax supported. Updated new gfx api to limit gpu fmax. CRs-Fixed: 2684122 Change-Id: Idfb9232b7a2885adbed83851c41ed316a6b23590 Signed-off-by: Alok Chauhan --- drivers/cam_cpas/cam_cpas_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 92b4c10c9e2e..f4503bb71bcc 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1339,7 +1339,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, soc_private->gpu_pwr_limit = kgsl_pwr_limits_add(KGSL_DEVICE_3D0); if (soc_private->gpu_pwr_limit) { - rc = kgsl_pwr_limits_set_freq( + rc = kgsl_pwr_limits_set_gpu_fmax( soc_private->gpu_pwr_limit, soc_private->cx_ipeak_gpu_limit); if (rc) { -- GitLab From f485b82d4c0efd908a76e6cb074f5cb8f20263e8 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Tue, 5 May 2020 17:09:09 +0530 Subject: [PATCH 207/295] msm: camera: tfe: Handle unsupported outport format If requested format is not supported by any write master port, tfe driver need to return the error and also need to release the acquired write masters for that port. This change handles proper release of write master port, if no acquire happen, it will not call the write master port release functions. CRs-Fixed: 2692793 Change-Id: Ibec809ddfe76564ec25ffcf723f50c7857fc96b6 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_bus.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 5e954c14997c..91ce4e542e3b 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 @@ -1189,9 +1189,9 @@ static int cam_tfe_bus_acquire_tfe_out(void *priv, void *acquire_args, struct cam_tfe_bus_tfe_out_data *rsrc_data = NULL; enum cam_tfe_bus_tfe_out_id tfe_out_res_id; enum cam_tfe_bus_comp_grp_id comp_grp_id; - int rc = -ENODEV; + int i, rc = -ENODEV; uint32_t secure_caps = 0, mode; - uint32_t i, format, num_wm, client_done_mask = 0; + uint32_t format, num_wm, client_done_mask = 0; if (!bus_priv || !acquire_args) { CAM_ERR(CAM_ISP, "Invalid Param"); @@ -1315,10 +1315,10 @@ static int cam_tfe_bus_acquire_tfe_out(void *priv, void *acquire_args, release_wm: for (i--; i >= 0; i--) - cam_tfe_bus_release_wm(bus_priv, - rsrc_data->wm_res[i]); + cam_tfe_bus_release_wm(bus_priv, rsrc_data->wm_res[i]); - cam_tfe_bus_release_comp_grp(bus_priv, rsrc_data->comp_grp); + if (rsrc_data->comp_grp) + cam_tfe_bus_release_comp_grp(bus_priv, rsrc_data->comp_grp); return rc; } -- GitLab From 14bfba450692b9f2995a07b42271f09fc919524b Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 7 May 2020 17:00:07 +0530 Subject: [PATCH 208/295] msm: camera: sensor: Read using addr and data type Read using address and data type provided in xml CRs-Fixed: 2675042 Change-Id: Ice85f2ce4a6fa38a7de4b1bf4233449c52cd39e2 Signed-off-by: Vishal Verma --- drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 696bbd3b90cb..a0405784ca90 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -131,7 +131,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, csl_packet = (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); - if (cam_packet_util_validate_packet(csl_packet, + if ((csl_packet == NULL) || cam_packet_util_validate_packet(csl_packet, remain_len)) { CAM_ERR(CAM_SENSOR, "Invalid packet params"); rc = -EINVAL; @@ -627,8 +627,9 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) rc = camera_io_dev_read( &(s_ctrl->io_master_info), slave_info->sensor_id_reg_addr, - &chipid, CAMERA_SENSOR_I2C_TYPE_WORD, - CAMERA_SENSOR_I2C_TYPE_WORD); + &chipid, + s_ctrl->sensor_probe_addr_type, + s_ctrl->sensor_probe_data_type); CAM_DBG(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", chipid, slave_info->sensor_id); -- GitLab From 3c1ca9724c00b89f17d34b3e116256b0e9df99b0 Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Tue, 19 May 2020 11:12:15 +0530 Subject: [PATCH 209/295] msm: camera: csiphy: Update cdr delay mask based on data rate Update the cdr delay mask register based on the sensor input data rate. CRs-Fixed: 2696070 Change-Id: I122acc1f5a874c55e4cce45b5f24db47bbbab0bb Signed-off-by: Tony Lijo Jose --- .../cam_csiphy/cam_csiphy_soc.c | 3 ++- .../cam_csiphy/include/cam_csiphy_2_0_hwreg.h | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) 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 4408a402113a..0f1e9435acdc 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -365,7 +365,8 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->is_divisor_32_comp = false; csiphy_dev->clk_lane = 0; - csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_2_0; } else { CAM_ERR(CAM_CSIPHY, "invalid hw version : 0x%x", csiphy_dev->hw_version); diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h index 9549919e2ea7..0be5643d1e34 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -290,4 +290,30 @@ struct csiphy_reg_t csiphy_3ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { }, }; +struct data_rate_settings_t data_rate_delta_table_2_0 = { + .num_data_rate_settings = 2, + .data_rate_settings = { + { + /* (2 * 10**9 * 2.28) rounded value*/ + .bandwidth = 4560000000, + .data_rate_reg_array_size = 3, + .csiphy_data_rate_regs = { + {0x164, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + } + }, + { + /* (2.5 * 10**9 * 2.28) rounded value*/ + .bandwidth = 5700000000, + .data_rate_reg_array_size = 3, + .csiphy_data_rate_regs = { + {0x164, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + } + }, + } +}; + #endif /* _CAM_CSIPHY_2_0_HWREG_H_ */ -- GitLab From 637bbd68ef6629b387fa9bda785c0a5683b5ba0a Mon Sep 17 00:00:00 2001 From: Shankar Ravi Date: Mon, 10 Feb 2020 14:50:18 +0530 Subject: [PATCH 210/295] msm: camera: eeprom: Correct EEPROM Read return EEPROM Read using QUP I2C returns the number of bytes read from the EEPROM, While CCI/SPI returns zero value. Return Error only when if the value is less than zero. CRs-Fixed: 2617882 External Impact: No Change-Id: I9a9674366c10de4efce779f75dd36b293838c47b Signed-off-by: Shankar Ravi --- drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index c50230309c57..caf5132b3df2 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.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 @@ -108,7 +108,7 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, emap[j].mem.addr_type, emap[j].mem.data_type, emap[j].mem.valid_size); - if (rc) { + if (rc < 0) { CAM_ERR(CAM_EEPROM, "read failed rc %d", rc); return rc; -- GitLab From 2df8855857cb9485bc48b5e17322cb93f47ecf57 Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Fri, 22 May 2020 00:16:34 +0530 Subject: [PATCH 211/295] msm: camera: cci: Avoid reading from i2c fifo if empty Avoid reading from cci i2c read buffer while register dump, This may lead to read underflow status bits getting set. CRs-Fixed: 2662669 Change-Id: I6035af21277ab291e536c91ba08a1f054a59f923 Signed-off-by: Tony Lijo Jose --- drivers/cam_sensor_module/cam_cci/cam_cci_core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 edcf81e3f418..5085527d1c06 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -184,6 +184,8 @@ static void cam_cci_dump_registers(struct cci_device *cci_dev, uint32_t read_val = 0; uint32_t i = 0; uint32_t reg_offset = 0; + uint32_t read_buf_level = 0; + uint32_t read_data_reg_offset = 0x0; void __iomem *base = cci_dev->soc_info.reg_map[0].mem_base; /* CCI Top Registers */ @@ -198,8 +200,19 @@ static void cam_cci_dump_registers(struct cci_device *cci_dev, /* CCI Master registers */ CAM_INFO(CAM_CCI, "****CCI MASTER %d Registers ****", master); + read_buf_level = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + read_data_reg_offset = CCI_I2C_M0_READ_DATA_ADDR + master * 0x100; for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) { reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4; + /* + * Don't read from READ_DATA_ADDR if + * i2c read fifo is empty, this may lead to + * read underflow status bits getting set + */ + if ((read_buf_level == 0) && + (reg_offset == read_data_reg_offset)) + continue; read_val = cam_io_r_mb(base + reg_offset); CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", reg_offset, read_val); -- GitLab From 662fb4b72f4e902937c8c357f0fe25fcf9381ceb Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Tue, 26 May 2020 20:57:23 +0530 Subject: [PATCH 212/295] msm: camera: ope: add page fault handlers in ope driver Add page fault handler functions to ope driver. Add logic to find closest buffer and related port to page fault address. CRs-Fixed: 2693184 Change-Id: Iaea12795b4553eaca1642cd64acd7879342d94d8 Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 2 +- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 108 +++++++++++++++++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index e7cdde454845..c6cc91f5386f 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1256,7 +1256,7 @@ static void cam_hw_cdm_iommu_fault_handler(struct iommu_domain *domain, 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); - CAM_ERR_RATE_LIMIT(CAM_CDM, "Page fault iova addr %pK\n", + CAM_ERR_RATE_LIMIT(CAM_CDM, "Page fault iova addr %pK", (void *)iova); cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_PAGEFAULT, (void *)iova); 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 c10b337dc499..431d7d21fc92 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 @@ -3339,6 +3339,112 @@ static int cam_ope_mgr_config_hw(void *hw_priv, void *hw_config_args) return rc; } +static void cam_ope_mgr_print_io_bufs(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, + bool *mem_found) +{ + dma_addr_t iova_addr; + size_t src_buf_size; + int i; + int j; + int rc = 0; + int32_t mmu_hdl; + + struct cam_buf_io_cfg *io_cfg = NULL; + + if (mem_found) + *mem_found = false; + + io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + + for (i = 0; i < packet->num_io_configs; i++) { + for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { + if (!io_cfg[i].mem_handle[j]) + break; + + if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + GET_FD_FROM_HANDLE(pf_buf_info)) { + CAM_INFO(CAM_OPE, + "Found PF at port: %d mem %x fd: %x", + io_cfg[i].resource_type, + io_cfg[i].mem_handle[j], + pf_buf_info); + if (mem_found) + *mem_found = true; + } + + CAM_INFO(CAM_OPE, "port: %d f: %u format: %d dir %d", + io_cfg[i].resource_type, + io_cfg[i].fence, + io_cfg[i].format, + io_cfg[i].direction); + + mmu_hdl = cam_mem_is_secure_buf( + io_cfg[i].mem_handle[j]) ? sec_mmu_hdl : + iommu_hdl; + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j], + mmu_hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, + "get src buf address fail rc %d mem %x", + rc, io_cfg[i].mem_handle[j]); + continue; + } + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { + CAM_ERR(CAM_OPE, "Invalid mapped address"); + rc = -EINVAL; + continue; + } + + CAM_INFO(CAM_OPE, + "pln %d dir %d w %d h %d s %u sh %u sz %d addr 0x%x off 0x%x memh %x", + j, io_cfg[i].direction, + io_cfg[i].planes[j].width, + io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + io_cfg[i].planes[j].slice_height, + (int32_t)src_buf_size, + (unsigned int)iova_addr, + io_cfg[i].offsets[j], + io_cfg[i].mem_handle[j]); + + iova_addr += io_cfg[i].offsets[j]; + + } + } + cam_packet_dump_patch_info(packet, ope_hw_mgr->iommu_hdl, + ope_hw_mgr->iommu_sec_hdl); +} + +static int cam_ope_mgr_cmd(void *hw_mgr_priv, void *cmd_args) +{ + int rc = 0; + struct cam_hw_cmd_args *hw_cmd_args = cmd_args; + struct cam_ope_hw_mgr *hw_mgr = hw_mgr_priv; + + if (!hw_mgr_priv || !cmd_args) { + CAM_ERR(CAM_OPE, "Invalid arguments"); + return -EINVAL; + } + + switch (hw_cmd_args->cmd_type) { + case CAM_HW_MGR_CMD_DUMP_PF_INFO: + cam_ope_mgr_print_io_bufs( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr->iommu_hdl, + hw_mgr->iommu_sec_hdl, + hw_cmd_args->u.pf_args.buf_info, + hw_cmd_args->u.pf_args.mem_found); + + break; + default: + CAM_ERR(CAM_OPE, "Invalid cmd"); + } + + return rc; +} + static int cam_ope_mgr_hw_open_u(void *hw_priv, void *fw_download_args) { struct cam_ope_hw_mgr *hw_mgr; @@ -3815,7 +3921,7 @@ int cam_ope_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, hw_mgr_intf->hw_config = cam_ope_mgr_config_hw; hw_mgr_intf->hw_read = NULL; hw_mgr_intf->hw_write = NULL; - hw_mgr_intf->hw_cmd = NULL; + hw_mgr_intf->hw_cmd = cam_ope_mgr_cmd; hw_mgr_intf->hw_open = cam_ope_mgr_hw_open_u; hw_mgr_intf->hw_close = cam_ope_mgr_hw_close_u; hw_mgr_intf->hw_flush = cam_ope_mgr_hw_flush; -- GitLab From 050249040f7b5793db571ca0fee6252517778693 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Wed, 20 May 2020 20:23:40 +0530 Subject: [PATCH 213/295] msm: camera: tfe: Handle sof monotonic boot time stamp Modify the sof monotonic boot timestamp logic. Boot time stamp difference between two frames should not change, it should be same as qtime csid time stamp difference. So modified logic to give proper boot time stamp with no difference in the successive frames, the difference of sof time stamp taken from qtime stamp value. Delayed IRQ handling can lead to torn read of timestamp register (LSB from nth frame and MSB from n+1th frame). This change tries to detect torn read cases and corrects timestamp close to the actual value. CRs-Fixed: 2688271 Change-Id: I1dc75629887cfcf971d51a7dae6ea28624d272f1 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 64 ++++++------- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 89 +++++++++++++++---- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.h | 4 + 3 files changed, 107 insertions(+), 50 deletions(-) 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 434a462f9218..89c0df47c936 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 @@ -4469,41 +4469,43 @@ static int cam_tfe_mgr_cmd_get_sof_timestamp( struct cam_hw_intf *hw_intf; struct cam_tfe_csid_get_time_stamp_args csid_get_time; - 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_mgr_res = list_first_entry(&tfe_ctx->res_list_tfe_csid, + struct cam_isp_hw_mgr_res, list); + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + /* + * Get the SOF time stamp from left resource only. + * Left resource is master for dual tfe case and + * Rdi only context case left resource only hold + * the RDI resource + */ + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { /* - * Get the SOF time stamp from left resource only. - * Left resource is master for dual tfe case and - * Rdi only context case left resource only hold - * the RDI resource + * Single TFE case, Get the time stamp from + * available one csid hw in the context + * Dual TFE case, get the time stamp from + * master(left) would be sufficient */ - hw_intf = hw_mgr_res->hw_res[i]->hw_intf; - if (hw_intf->hw_ops.process_cmd) { - /* - * Single TFE case, Get the time stamp from - * available one csid hw in the context - * Dual TFE case, get the time stamp from - * master(left) would be sufficient - */ - - csid_get_time.node_res = - hw_mgr_res->hw_res[i]; - rc = hw_intf->hw_ops.process_cmd( - hw_intf->hw_priv, - CAM_TFE_CSID_CMD_GET_TIME_STAMP, - &csid_get_time, - sizeof(struct - cam_tfe_csid_get_time_stamp_args)); - if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { - *time_stamp = - csid_get_time.time_stamp_val; - *boot_time_stamp = - csid_get_time.boot_timestamp; - } + csid_get_time.node_res = + hw_mgr_res->hw_res[i]; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_TFE_CSID_CMD_GET_TIME_STAMP, + &csid_get_time, + sizeof(struct + cam_tfe_csid_get_time_stamp_args)); + if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { + *time_stamp = + csid_get_time.time_stamp_val; + *boot_time_stamp = + csid_get_time.boot_timestamp; + break; } } } 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 f7d4237b0067..682c80a07014 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 @@ -343,6 +343,7 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d", csid_hw->hw_intf->hw_idx, val); csid_hw->error_irq_count = 0; + csid_hw->prev_boot_timestamp = 0; return rc; } @@ -966,6 +967,7 @@ static int cam_tfe_csid_disable_hw(struct cam_tfe_csid_hw *csid_hw) spin_unlock_irqrestore(&csid_hw->spin_lock, flags); csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; + csid_hw->prev_boot_timestamp = 0; return rc; } @@ -1580,16 +1582,36 @@ static int cam_tfe_csid_poll_stop_status( return rc; } +static int __cam_tfe_csid_read_timestamp(void __iomem *base, + uint32_t msb_offset, uint32_t lsb_offset, uint64_t *timestamp) +{ + uint32_t lsb, msb, tmp, torn = 0; + + msb = cam_io_r_mb(base + msb_offset); + do { + tmp = msb; + torn++; + lsb = cam_io_r_mb(base + lsb_offset); + msb = cam_io_r_mb(base + msb_offset); + } while (tmp != msb); + + *timestamp = msb; + *timestamp = (*timestamp << 32) | lsb; + + return (torn > 1); +} + static int cam_tfe_csid_get_time_stamp( struct cam_tfe_csid_hw *csid_hw, void *cmd_args) { - struct cam_tfe_csid_get_time_stamp_args *time_stamp; + struct cam_tfe_csid_get_time_stamp_args *time_stamp; struct cam_isp_resource_node *res; const struct cam_tfe_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; const struct cam_tfe_csid_rdi_reg_offset *rdi_reg; struct timespec64 ts; - uint32_t time_32, id; + uint32_t id, torn; + uint64_t time_delta; time_stamp = (struct cam_tfe_csid_get_time_stamp_args *)cmd_args; res = time_stamp->node_res; @@ -1612,33 +1634,61 @@ static int cam_tfe_csid_get_time_stamp( } if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) { - time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_pxl_timestamp_curr1_sof_addr); - time_stamp->time_stamp_val = (uint64_t) time_32; - time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; - time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_pxl_timestamp_curr0_sof_addr); + torn = __cam_tfe_csid_read_timestamp( + soc_info->reg_map[0].mem_base, + csid_reg->ipp_reg->csid_pxl_timestamp_curr1_sof_addr, + csid_reg->ipp_reg->csid_pxl_timestamp_curr0_sof_addr, + &time_stamp->time_stamp_val); } else { id = res->res_id; rdi_reg = csid_reg->rdi_reg[id]; - time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + - rdi_reg->csid_rdi_timestamp_curr1_sof_addr); - time_stamp->time_stamp_val = (uint64_t) time_32; - time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; - - time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + - rdi_reg->csid_rdi_timestamp_curr0_sof_addr); + torn = __cam_tfe_csid_read_timestamp( + soc_info->reg_map[0].mem_base, + rdi_reg->csid_rdi_timestamp_curr1_sof_addr, + rdi_reg->csid_rdi_timestamp_curr0_sof_addr, + &time_stamp->time_stamp_val); } - time_stamp->time_stamp_val |= (uint64_t) time_32; time_stamp->time_stamp_val = mul_u64_u32_div( time_stamp->time_stamp_val, CAM_TFE_CSID_QTIMER_MUL_FACTOR, CAM_TFE_CSID_QTIMER_DIV_FACTOR); - get_monotonic_boottime64(&ts); - time_stamp->boot_timestamp = (uint64_t)((ts.tv_sec * 1000000000) + - ts.tv_nsec); + if (!csid_hw->prev_boot_timestamp) { + get_monotonic_boottime64(&ts); + time_stamp->boot_timestamp = + (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + csid_hw->prev_qtimer_ts = 0; + CAM_DBG(CAM_ISP, "timestamp:%lld", + time_stamp->boot_timestamp); + } else { + time_delta = time_stamp->time_stamp_val - + csid_hw->prev_qtimer_ts; + + if (csid_hw->prev_boot_timestamp > + U64_MAX - time_delta) { + CAM_WARN(CAM_ISP, "boottimestamp overflowed"); + CAM_INFO(CAM_ISP, + "currQTimer %lx prevQTimer %lx prevBootTimer %lx torn %d", + time_stamp->time_stamp_val, + csid_hw->prev_qtimer_ts, + csid_hw->prev_boot_timestamp, torn); + return -EINVAL; + } + + time_stamp->boot_timestamp = + csid_hw->prev_boot_timestamp + time_delta; + } + + CAM_DBG(CAM_ISP, + "currQTimer %lx prevQTimer %lx currBootTimer %lx prevBootTimer %lx torn %d", + time_stamp->time_stamp_val, + csid_hw->prev_qtimer_ts, time_stamp->boot_timestamp, + csid_hw->prev_boot_timestamp, torn); + + csid_hw->prev_qtimer_ts = time_stamp->time_stamp_val; + csid_hw->prev_boot_timestamp = time_stamp->boot_timestamp; return 0; } @@ -2936,6 +2986,7 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, tfe_csid_hw->csid_debug = 0; tfe_csid_hw->error_irq_count = 0; + tfe_csid_hw->prev_boot_timestamp = 0; return 0; 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 e008fd518e9a..481fbe9b611f 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 @@ -383,6 +383,8 @@ struct cam_tfe_csid_path_cfg { * @lock_state csid spin lock * @event_cb: Callback function to hw mgr in case of hw events * @event_cb_priv: Context data + * @prev_boot_timestamp previous frame bootime stamp + * @prev_qtimer_ts previous frame qtimer csid timestamp * */ struct cam_tfe_csid_hw { @@ -409,6 +411,8 @@ struct cam_tfe_csid_hw { spinlock_t spin_lock; cam_hw_mgr_event_cb_func event_cb; void *event_cb_priv; + uint64_t prev_boot_timestamp; + uint64_t prev_qtimer_ts; }; int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, -- GitLab From 4eb0112a26c7c10b5573f03cecd9be8c1dc43cca Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 2 Apr 2020 20:43:26 +0530 Subject: [PATCH 214/295] msm: camera: sensor: Dump phy registers on error Dump csiphy registers on following fatal errors: 1. lane overflow error 2. unbounded frame error 3. SOT ans EOT reception error 4. stream underflow error These errors irqs are set at csid end, Currently there is no interface to send message from one subdevice to other if the subdev is not a real time device. This change adds an interface to notify the no real time subdev. CRs-Fixed: 2696744 Change-Id: I522167d1639ac298bc739a8a5a380a01356f0776 Signed-off-by: Vishal Verma --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 6 ++- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 8 ++++ drivers/cam_req_mgr/cam_req_mgr_dev.c | 22 ++++++++- drivers/cam_req_mgr/cam_subdev.h | 24 +++++++++- .../cam_csiphy/cam_csiphy_dev.c | 23 ++++++++- .../cam_csiphy/cam_csiphy_dev.h | 3 +- .../cam_csiphy/cam_csiphy_soc.c | 48 +++++++++++++++++++ .../cam_csiphy/cam_csiphy_soc.h | 6 +++ .../cam_csiphy/include/cam_csiphy_1_0_hwreg.h | 3 +- .../cam_csiphy/include/cam_csiphy_1_1_hwreg.h | 3 +- .../include/cam_csiphy_1_2_1_hwreg.h | 3 +- .../include/cam_csiphy_1_2_2_hwreg.h | 1 + .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 3 +- .../cam_csiphy/include/cam_csiphy_2_0_hwreg.h | 1 + 14 files changed, 144 insertions(+), 10 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 45a61b6cc475..fc9d3316b457 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -7,7 +7,7 @@ #include #include #include - +#include #include #include "cam_ife_csid_core.h" @@ -16,6 +16,7 @@ #include "cam_io_util.h" #include "cam_debug_util.h" #include "cam_cpas_api.h" +#include "cam_subdev.h" /* Timeout value in msec */ #define IFE_CSID_TIMEOUT 1000 @@ -1654,6 +1655,9 @@ static void cam_ife_csid_halt_csi2( csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, + CAM_SUBDEV_MESSAGE_IRQ_ERR, + csid_hw->csi2_rx_cfg.phy_sel); } static int cam_ife_csid_init_config_pxl_path( 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 f7d4237b0067..86517082a075 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 @@ -7,6 +7,7 @@ #include #include #include +#include #include "cam_tfe_csid_core.h" #include "cam_isp_hw.h" @@ -16,6 +17,7 @@ #include "cam_cpas_api.h" #include "cam_isp_hw_mgr_intf.h" #include +#include "cam_subdev.h" /* Timeout value in msec */ #define TFE_CSID_TIMEOUT 1000 @@ -2587,6 +2589,12 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + /* phy_sel starts from 1 and should never be zero*/ + if (csid_hw->csi2_rx_cfg.phy_sel > 0) { + cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, + CAM_SUBDEV_MESSAGE_IRQ_ERR, + (csid_hw->csi2_rx_cfg.phy_sel - 1)); + } } if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOT_IRQ) { diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 9f9ae3e4e327..a0688466a060 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -635,6 +635,24 @@ void cam_register_subdev_fops(struct v4l2_file_operations *fops) } EXPORT_SYMBOL(cam_register_subdev_fops); +void cam_subdev_notify_message(u32 subdev_type, + enum cam_subdev_message_type_t message_type, + uint32_t data) +{ + struct v4l2_subdev *sd = NULL; + struct cam_subdev *csd = NULL; + + list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { + sd->entity.name = video_device_node_name(sd->devnode); + if (sd->entity.function == subdev_type) { + csd = container_of(sd, struct cam_subdev, sd); + if (csd->msg_cb != NULL) + csd->msg_cb(sd, message_type, data); + } + } +} +EXPORT_SYMBOL(cam_subdev_notify_message); + int cam_register_subdev(struct cam_subdev *csd) { struct v4l2_subdev *sd; @@ -663,7 +681,7 @@ int cam_register_subdev(struct cam_subdev *csd) sd = &csd->sd; v4l2_subdev_init(sd, csd->ops); sd->internal_ops = csd->internal_ops; - snprintf(sd->name, ARRAY_SIZE(sd->name), csd->name); + snprintf(sd->name, V4L2_SUBDEV_NAME_SIZE, "%s", csd->name); v4l2_set_subdevdata(sd, csd->token); sd->flags = csd->sd_flags; diff --git a/drivers/cam_req_mgr/cam_subdev.h b/drivers/cam_req_mgr/cam_subdev.h index 385643d5e532..6f8eff420f6c 100644 --- a/drivers/cam_req_mgr/cam_subdev.h +++ b/drivers/cam_req_mgr/cam_subdev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SUBDEV_H_ @@ -16,6 +16,10 @@ #define CAM_SUBDEVICE_EVENT_MAX 30 +enum cam_subdev_message_type_t { + CAM_SUBDEV_MESSAGE_IRQ_ERR = 0x1 +}; + /** * struct cam_subdev - describes a camera sub-device * @@ -49,8 +53,26 @@ struct cam_subdev { u32 sd_flags; void *token; u32 ent_function; + void (*msg_cb)( + struct v4l2_subdev *sd, + enum cam_subdev_message_type_t msg_type, + uint32_t data); }; +/** + * cam_subdev_notify_message() + * + * @brief: Notify message to a subdevs of specific type + * + * @subdev_type: Subdev type + * @message_type: message type + * @data: data to be delivered. + * + */ +void cam_subdev_notify_message(u32 subdev_type, + enum cam_subdev_message_type_t message_type, + uint32_t data); + /** * cam_subdev_probe() * diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index ba98d9adcc2d..0719f42d654d 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_csiphy_dev.h" @@ -9,6 +9,25 @@ #include "cam_csiphy_core.h" #include +static void cam_csiphy_subdev_handle_message( + struct v4l2_subdev *sd, + enum cam_subdev_message_type_t message_type, + uint32_t data) +{ + struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); + + switch (message_type) { + case CAM_SUBDEV_MESSAGE_IRQ_ERR: + CAM_INFO(CAM_CSIPHY, "subdev index : %d CSIPHY index: %d", + csiphy_dev->soc_info.index, data); + if (data == csiphy_dev->soc_info.index) + cam_csiphy_status_dmp(csiphy_dev); + break; + default: + break; + } +} + static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -148,6 +167,8 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); new_csiphy_dev->v4l2_dev_str.ent_function = CAM_CSIPHY_DEVICE_TYPE; + new_csiphy_dev->v4l2_dev_str.msg_cb = + cam_csiphy_subdev_handle_message; new_csiphy_dev->v4l2_dev_str.token = new_csiphy_dev; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 78c7a848cd81..a2b07380385f 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.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 _CAM_CSIPHY_DEV_H_ @@ -107,6 +107,7 @@ struct csiphy_reg_parms_t { uint32_t mipi_csiphy_interrupt_mask_addr; uint32_t mipi_csiphy_interrupt_clear0_addr; uint32_t csiphy_version; + uint32_t csiphy_interrupt_status_size; uint32_t csiphy_common_array_size; uint32_t csiphy_reset_array_size; uint32_t csiphy_2ph_config_array_size; 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 4408a402113a..01167d0a1582 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -77,6 +77,54 @@ int32_t cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info) return rc; } +int32_t cam_csiphy_status_dmp(struct csiphy_device *csiphy_dev) +{ + struct csiphy_reg_parms_t *csiphy_reg = NULL; + int32_t rc = 0; + resource_size_t size = 0; + void __iomem *phy_base = NULL; + int reg_id = 0; + uint32_t irq, status_reg, clear_reg; + + if (!csiphy_dev) { + rc = -EINVAL; + CAM_ERR(CAM_CSIPHY, "invalid input %d", rc); + return rc; + } + + csiphy_reg = &csiphy_dev->ctrl_reg->csiphy_reg; + phy_base = csiphy_dev->soc_info.reg_map[0].mem_base; + status_reg = csiphy_reg->mipi_csiphy_interrupt_status0_addr; + clear_reg = csiphy_reg->mipi_csiphy_interrupt_clear0_addr; + size = csiphy_reg->csiphy_interrupt_status_size; + + CAM_INFO(CAM_CSIPHY, "PHY base addr=%pK offset=0x%x size=%d", + phy_base, status_reg, size); + + if (phy_base != NULL) { + for (reg_id = 0; reg_id < size; reg_id++) { + uint32_t offset; + + offset = status_reg + (0x4 * reg_id); + irq = cam_io_r(phy_base + offset); + offset = clear_reg + (0x4 * reg_id); + cam_io_w_mb(irq, phy_base + offset); + cam_io_w_mb(0, phy_base + offset); + + CAM_INFO(CAM_CSIPHY, + "CSIPHY%d_IRQ_STATUS_ADDR%d = 0x%x", + csiphy_dev->soc_info.index, reg_id, irq); + } + } else { + rc = -EINVAL; + CAM_ERR(CAM_CSIPHY, "phy base is NULL %d", rc); + return rc; + } + return rc; +} + + + enum cam_vote_level get_clk_vote_default(struct csiphy_device *csiphy_dev) { CAM_DBG(CAM_CSIPHY, "voting for SVS"); diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h index 8b40319a60f5..3a909e6eb6b9 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -71,4 +71,10 @@ int cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev); */ int cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info); +/** + * @csiphy_dev: CSIPhy device structure + * + * This API dumps memory for the entire status region + */ +int32_t cam_csiphy_status_dmp(struct csiphy_device *csiphy_dev); #endif /* _CAM_CSIPHY_SOC_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h index e910162858b3..eaedc7b672a8 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_0_HWREG_H_ @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_0 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 5, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 14, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h index 30b61067a792..e1db638da5f0 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_1_HWREG_H_ @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_1 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 5, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 14, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index 32fbf47eabd9..b2b813df8e90 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_2_1_HWREG_H_ @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_1 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 20, 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 119b6b575b60..00e6bb30392b 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 @@ -12,6 +12,7 @@ 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_interrupt_status_size = 11, .csiphy_common_array_size = 8, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 18, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 179ccebddc54..446c8197df8a 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.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_CSIPHY_1_2_HWREG_H_ @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 7, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 18, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h index 9549919e2ea7..f7be2b60a4b5 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v2_0 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 8, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 15, -- GitLab From 360ac8bcaa40bea624d4ca360f2543f4572f0168 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Thu, 21 May 2020 15:29:35 +0530 Subject: [PATCH 215/295] msm: camera: cdm: change work record to atomic variable In some corner case, Flush and request timer function can run in parallel. In timer function we check for hang detect by acquiring cdm hw mutex lock, same lock is being used as part of flush operation as well which can cause deadlock scenario. Change hang detect logic by making work record as atomic variable. CRs-Fixed: 2701653 Change-Id: I8c44778cfa2ad35dbc4f72acb93be8e0323a5f6b Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm.h | 2 +- drivers/cam_cdm/cam_cdm_core_common.c | 4 --- drivers/cam_cdm/cam_cdm_hw_core.c | 52 +++++++++++++-------------- 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index 71d9b1071cc0..1814bcddda97 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -471,7 +471,7 @@ struct cam_cdm_bl_fifo { uint8_t bl_tag; uint32_t bl_depth; uint8_t last_bl_tag_done; - uint32_t work_record; + atomic_t work_record; }; /** diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index e93e54f0335e..29aef156cd9a 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -798,13 +798,11 @@ int cam_cdm_process_cmd(void *hw_priv, } 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; } @@ -812,12 +810,10 @@ int cam_cdm_process_cmd(void *hw_priv, 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: diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index c6cc91f5386f..06c42ee6c4ea 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1084,7 +1084,7 @@ static void cam_hw_cdm_reset_cleanup( } core->bl_fifo[i].bl_tag = 0; core->bl_fifo[i].last_bl_tag_done = -1; - core->bl_fifo[i].work_record = 0; + atomic_set(&core->bl_fifo[i].work_record, 0); } } @@ -1093,15 +1093,16 @@ static void cam_hw_cdm_work(struct work_struct *work) struct cam_cdm_work_payload *payload; struct cam_hw_info *cdm_hw; struct cam_cdm *core; - int i; + int i, fifo_idx; payload = container_of(work, struct cam_cdm_work_payload, 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) { + fifo_idx = payload->fifo_idx; + if (fifo_idx >= core->offsets->reg_data->num_bl_fifo) { CAM_ERR(CAM_CDM, "Invalid fifo idx %d", - payload->fifo_idx); + fifo_idx); kfree(payload); payload = NULL; return; @@ -1116,7 +1117,7 @@ static void cam_hw_cdm_work(struct work_struct *work) CAM_DBG(CAM_CDM, "inline IRQ data=0x%x last tag: 0x%x", payload->irq_data, - core->bl_fifo[payload->fifo_idx] + core->bl_fifo[fifo_idx] .last_bl_tag_done); if (payload->irq_data == 0xff) { @@ -1126,31 +1127,32 @@ static void cam_hw_cdm_work(struct work_struct *work) return; } - mutex_lock(&core->bl_fifo[payload->fifo_idx] + mutex_lock(&core->bl_fifo[fifo_idx] .fifo_lock); - if (core->bl_fifo[payload->fifo_idx].work_record) - core->bl_fifo[payload->fifo_idx].work_record--; + if (atomic_read(&core->bl_fifo[fifo_idx].work_record)) + atomic_dec( + &core->bl_fifo[fifo_idx].work_record); - if (list_empty(&core->bl_fifo[payload->fifo_idx] + if (list_empty(&core->bl_fifo[fifo_idx] .bl_request_list)) { CAM_INFO(CAM_CDM, "Fifo list empty, idx %d tag %d arb %d", - payload->fifo_idx, payload->irq_data, + fifo_idx, payload->irq_data, core->arbitration); - mutex_unlock(&core->bl_fifo[payload->fifo_idx] + mutex_unlock(&core->bl_fifo[fifo_idx] .fifo_lock); return; } - if (core->bl_fifo[payload->fifo_idx] + if (core->bl_fifo[fifo_idx] .last_bl_tag_done != payload->irq_data) { - core->bl_fifo[payload->fifo_idx] + core->bl_fifo[fifo_idx] .last_bl_tag_done = payload->irq_data; list_for_each_entry_safe(node, tnode, - &core->bl_fifo[payload->fifo_idx] + &core->bl_fifo[fifo_idx] .bl_request_list, entry) { if (node->request_type == @@ -1177,17 +1179,17 @@ static void cam_hw_cdm_work(struct work_struct *work) } else { CAM_INFO(CAM_CDM, "Skip GenIRQ, tag 0x%x fifo %d", - payload->irq_data, payload->fifo_idx); + payload->irq_data, fifo_idx); } - mutex_unlock(&core->bl_fifo[payload->fifo_idx] + mutex_unlock(&core->bl_fifo[fifo_idx] .fifo_lock); } if (payload->irq_status & CAM_CDM_IRQ_STATUS_BL_DONE_MASK) { - if (test_bit(payload->fifo_idx, &core->cdm_status)) { + if (test_bit(fifo_idx, &core->cdm_status)) { CAM_DBG(CAM_CDM, "CDM HW BL done IRQ"); - complete(&core->bl_fifo[payload->fifo_idx] + complete(&core->bl_fifo[fifo_idx] .bl_complete); } } @@ -1345,7 +1347,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) payload[i]->irq_status, cdm_hw->soc_info.index); - cdm_core->bl_fifo[i].work_record++; + atomic_inc(&cdm_core->bl_fifo[i].work_record); payload[i]->workq_scheduled_ts = ktime_get(); work_status = queue_work( @@ -1653,20 +1655,14 @@ int cam_hw_cdm_hang_detect( 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) { + if (atomic_read(&cdm_core->bl_fifo[i].work_record)) { CAM_WARN(CAM_CDM, "workqueue got delayed, work_record :%u", - cdm_core->bl_fifo[i].work_record); + atomic_read(&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; } @@ -1771,7 +1767,7 @@ int cam_hw_cdm_init(void *hw_priv, } 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; + atomic_set(&cdm_core->bl_fifo[i].work_record, 0); } rc = cam_hw_cdm_reset_hw(cdm_hw, reset_hw_hdl); -- GitLab From 4e759b9ef0e2f9c59008820b348adc35a4853c4d Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Wed, 29 Apr 2020 13:40:18 +0530 Subject: [PATCH 216/295] msm: camera: utils: add spacing between register values when using the cam_io_dump function to dump the register values we are getting 4 register values without spacing which makes is difficult to read, so adding space between two specific register values. CRs-Fixed: 2675959 Change-Id: I7e5db59398e406c30aa9729eb38331aa85736175 Signed-off-by: Tejas Prajapati --- drivers/cam_utils/cam_io_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_utils/cam_io_util.c b/drivers/cam_utils/cam_io_util.c index d35320e7e487..fcbc4b5e00f5 100644 --- a/drivers/cam_utils/cam_io_util.c +++ b/drivers/cam_utils/cam_io_util.c @@ -265,8 +265,8 @@ int cam_io_dump(void __iomem *base_addr, uint32_t start_offset, int size) p_str += 11; } data = readl_relaxed(base_addr + REG_OFFSET(start_offset, i)); - snprintf(p_str, 9, "%08x ", data); - p_str += 8; + snprintf(p_str, 10, "%08x ", data); + p_str += 9; if ((i + 1) % NUM_REGISTER_PER_LINE == 0) { CAM_ERR(CAM_UTIL, "%s", line_str); line_str[0] = '\0'; -- GitLab From 2f76876e41e17b3b35e47b104755c46a18083857 Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Sat, 23 May 2020 11:15:14 +0530 Subject: [PATCH 217/295] msm: camera: ope: Reduce OPE BUS memory Update OPE BUS driver to reduce memory allocation at boot time. It reduces the consumption of memory when camera is not active. CRs-Fixed: 2700579 Change-Id: Ic9a13ee53f6bb140de8e943a017cf996eda5df65 Signed-off-by: Suresh Vankadara --- .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 40 +++++++++---------- .../ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.h | 4 +- 2 files changed, 21 insertions(+), 23 deletions(-) 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 1f650490f6f5..0042675f1821 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 @@ -190,8 +190,10 @@ static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, cdm_ops = ctx_data->ope_cdm.cdm_ops; ope_request = ctx_data->req_list[req_idx]; - - bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; + CAM_DBG(CAM_OPE, "req_idx = %d req_id = %lld KMDbuf %x offset %d", + req_idx, ope_request->request_id, + kmd_buf, prepare->kmd_buf_offset); + bus_rd_ctx = bus_rd->bus_rd_ctx[ctx_id]; io_port_info = &bus_rd_ctx->io_port_info; rd_reg = ope_hw_info->bus_rd_reg; rd_reg_val = ope_hw_info->bus_rd_reg_val; @@ -365,7 +367,7 @@ static uint32_t *cam_ope_bus_rm_disable(struct ope_hw *ope_hw_info, req_idx = prepare->req_idx; cdm_ops = ctx_data->ope_cdm.cdm_ops; - bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; + bus_rd_ctx = bus_rd->bus_rd_ctx[ctx_id]; io_port_cdm_batch = &bus_rd_ctx->io_port_cdm_batch; rd_reg = ope_hw_info->bus_rd_reg; @@ -453,7 +455,7 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, req_idx, ope_request->request_id); CAM_DBG(CAM_OPE, "KMD buf and offset = %x %d", kmd_buf, prepare->kmd_buf_offset); - bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; + bus_rd_ctx = bus_rd->bus_rd_ctx[ctx_id]; io_port_cdm_batch = &bus_rd_ctx->io_port_cdm_batch; memset(io_port_cdm_batch, 0, @@ -551,25 +553,15 @@ static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info, static int cam_ope_bus_rd_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_rd_ctx *bus_rd_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 = bus_rd->bus_rd_ctx[ctx_id].ope_acquire; - bus_rd->bus_rd_ctx[ctx_id].ope_acquire = NULL; - bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; - bus_rd_ctx->num_in_ports = 0; - - for (i = 0; i < bus_rd_ctx->num_in_ports; i++) { - bus_rd_ctx->io_port_info.input_port_id[i] = 0; - bus_rd_ctx->io_port_info.input_format_type[i - 1] = 0; - bus_rd_ctx->io_port_info.pixel_pattern[i - 1] = 0; - } + vfree(bus_rd->bus_rd_ctx[ctx_id]); + bus_rd->bus_rd_ctx[ctx_id] = NULL; return rc; } @@ -586,15 +578,21 @@ static int cam_ope_bus_rd_acquire(struct ope_hw *ope_hw_info, int in_port_idx; - if (ctx_id < 0 || !data || !ope_hw_info) { + if (ctx_id < 0 || !data || !ope_hw_info || ctx_id >= OPE_CTX_MAX) { CAM_ERR(CAM_OPE, "Invalid data: %d %x %x", ctx_id, data, ope_hw_info); return -EINVAL; } - bus_rd->bus_rd_ctx[ctx_id].ope_acquire = data; + bus_rd->bus_rd_ctx[ctx_id] = vzalloc(sizeof(struct ope_bus_rd_ctx)); + if (!bus_rd->bus_rd_ctx[ctx_id]) { + CAM_ERR(CAM_OPE, "Out of memory"); + return -ENOMEM; + } + + bus_rd->bus_rd_ctx[ctx_id]->ope_acquire = data; in_acquire = data; - bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id]; + bus_rd_ctx = bus_rd->bus_rd_ctx[ctx_id]; bus_rd_ctx->num_in_ports = in_acquire->num_in_res; bus_rd_ctx->security_flag = in_acquire->secure_mode; bus_rd_reg_val = ope_hw_info->bus_rd_reg_val; diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.h b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.h index da91d75fcbd5..b461374c2a63 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.h +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.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 OPE_BUS_RD_H @@ -132,7 +132,7 @@ struct ope_bus_rd_ctx { struct ope_bus_rd { struct ope_hw *ope_hw_info; struct ope_bus_in_port_to_rm in_port_to_rm[OPE_IN_RES_MAX]; - struct ope_bus_rd_ctx bus_rd_ctx[OPE_CTX_MAX]; + struct ope_bus_rd_ctx *bus_rd_ctx[OPE_CTX_MAX]; struct completion reset_complete; }; #endif /* OPE_BUS_RD_H */ -- GitLab From 412a91a483abe2a17b19dbd8e66638db57604eb5 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Sun, 31 May 2020 19:50:21 +0530 Subject: [PATCH 218/295] msm: camera: ope: Change turbo clock limit change turbo clock limit as per suggested by hw team. CRs-Fixed: 2702653 Change-Id: I103e3f7ed3ddb628e3780f21f543247937b0affc Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) 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 431d7d21fc92..75310e527acc 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 @@ -2504,6 +2504,9 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) struct cam_ope_dev_clk_update clk_update; struct cam_ope_dev_bw_update *bw_update; struct cam_ope_set_irq_cb irq_cb; + struct cam_hw_info *dev = NULL; + struct cam_hw_soc_info *soc_info = NULL; + int32_t idx; if ((!hw_priv) || (!hw_acquire_args)) { CAM_ERR(CAM_OPE, "Invalid args: %x %x", @@ -2592,8 +2595,14 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) } } - hw_mgr->clk_info.base_clk = 600000000; - hw_mgr->clk_info.curr_clk = 600000000; + dev = (struct cam_hw_info *)hw_mgr->ope_dev_intf[0]->hw_priv; + soc_info = &dev->soc_info; + idx = soc_info->src_clk_idx; + + hw_mgr->clk_info.base_clk = + soc_info->clk_rate[CAM_TURBO_VOTE][idx]; + hw_mgr->clk_info.curr_clk = + soc_info->clk_rate[CAM_TURBO_VOTE][idx]; hw_mgr->clk_info.threshold = 5; hw_mgr->clk_info.over_clked = 0; @@ -2620,7 +2629,11 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) } for (i = 0; i < ope_hw_mgr->num_ope; i++) { - clk_update.clk_rate = 600000000; + dev = (struct cam_hw_info *)hw_mgr->ope_dev_intf[i]->hw_priv; + soc_info = &dev->soc_info; + idx = soc_info->src_clk_idx; + clk_update.clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][idx]; + rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( hw_mgr->ope_dev_intf[i]->hw_priv, OPE_HW_CLK_UPDATE, &clk_update, sizeof(clk_update)); -- GitLab From 73f0430a22ccc33f9ac4d2bb9eb514213c8b3163 Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Thu, 7 May 2020 10:10:51 +0530 Subject: [PATCH 219/295] msm: camera: cci: Return failure if cpas start fails We are reading from cci hw version register even if the cci cpas start fails, this will lead to a NOC error; To avoid this we need to return with failure if the cpas start fails. CRs-Fixed: 2683494 Change-Id: Id8c214ed480dc3286414edffc59515606c4133cd Signed-off-by: Tony Lijo Jose --- drivers/cam_sensor_module/cam_cci/cam_cci_soc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 eebfec135e79..05f9e1240bad 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.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 "cam_cci_dev.h" @@ -89,8 +89,11 @@ int cam_cci_init(struct v4l2_subdev *sd, rc = cam_cpas_start(cci_dev->cpas_handle, &ahb_vote, &axi_vote); - if (rc != 0) + if (rc) { CAM_ERR(CAM_CCI, "CPAS start failed"); + cci_dev->ref_count--; + return rc; + } cam_cci_get_clk_rates(cci_dev, c_ctrl); -- GitLab From 9448209c9d787b7e87cd74c2495f6658e03b688c Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Wed, 10 Jun 2020 16:55:45 +0530 Subject: [PATCH 220/295] msm: camera: isp: Correct the bitmask for packet header Bitmask for printing the CSI short packet and CPHY packet is configured wrong. Change the bitmask to print the correct values. Change-Id: I372dff148677701511451ef182e8abdbb587b357 CRs-Fixed: 2672724 Signed-off-by: Gaurav Jindal --- .../cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 4 ++-- .../cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 45a61b6cc475..1a138b9e71be 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -4140,7 +4140,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d short pkt VC :%d DT:%d LC:%d", csid_hw->hw_intf->hw_idx, - (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csi2_reg->csid_csi2_rx_captured_short_pkt_1_addr); CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d short packet ECC :%d", @@ -4156,7 +4156,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d cphy packet VC :%d DT:%d WC:%d", csid_hw->hw_intf->hw_idx, - (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); } /*read the IPP errors */ 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 682c80a07014..3b112ecffa59 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 @@ -2724,7 +2724,7 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d short pkt VC :%d DT:%d LC:%d", csid_hw->hw_intf->hw_idx, - (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csi2_reg->csid_csi2_rx_captured_short_pkt_1_addr); CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d short packet ECC :%d", @@ -2741,7 +2741,7 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d cphy packet VC :%d DT:%d WC:%d", csid_hw->hw_intf->hw_idx, - (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); } if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_RST_IRQ_LOG) { -- GitLab From b2a50ca5352d006fcf1948bb0b53ee228e889414 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 25 May 2020 19:25:02 +0530 Subject: [PATCH 221/295] msm: camera: common: Define debugflag to allocate usecase info Define debug flag to allocate usecase info for debug purpose. This flag can be used to get usecase buffer index. CRs-Fixed: 2707314 Change-Id: Iffacdb48f77ec6907b8070d4c19eb1c56be30f14 Signed-off-by: Alok Chauhan --- drivers/cam_req_mgr/cam_mem_mgr.c | 6 +++++- drivers/cam_req_mgr/cam_mem_mgr.h | 4 +++- include/uapi/media/cam_req_mgr.h | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index ae0f167e189f..877618e6d631 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -703,6 +703,9 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) } } + if (cmd->flags & CAM_MEM_FLAG_KMD_DEBUG_FLAG) + tbl.dbg_buf_idx = idx; + tbl.bufq[idx].kmdvaddr = kvaddr; tbl.bufq[idx].vaddr = hw_vaddr; tbl.bufq[idx].dma_buf = dmabuf; @@ -959,6 +962,7 @@ void cam_mem_mgr_deinit(void) bitmap_zero(tbl.bitmap, tbl.bits); kfree(tbl.bitmap); tbl.bitmap = NULL; + tbl.dbg_buf_idx = -1; mutex_unlock(&tbl.m_lock); mutex_destroy(&tbl.m_lock); } diff --git a/drivers/cam_req_mgr/cam_mem_mgr.h b/drivers/cam_req_mgr/cam_mem_mgr.h index 415639a67172..2c692a076dfd 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.h +++ b/drivers/cam_req_mgr/cam_mem_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_MEM_MGR_H_ @@ -67,6 +67,7 @@ struct cam_mem_buf_queue { * @bufq: array of buffers * @dentry: Debugfs entry * @alloc_profile_enable: Whether to enable alloc profiling + * @dbg_buf_idx: debug buffer index to get usecases info */ struct cam_mem_table { struct mutex m_lock; @@ -75,6 +76,7 @@ struct cam_mem_table { struct cam_mem_buf_queue bufq[CAM_MEM_BUFQ_MAX]; struct dentry *dentry; bool alloc_profile_enable; + size_t dbg_buf_idx; }; /** diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index d876f21575bb..4b11c6a3a9ed 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -280,6 +280,8 @@ struct cam_req_mgr_link_control { #define CAM_MEM_FLAG_HW_SHARED_ACCESS (1<<11) #define CAM_MEM_FLAG_CDSP_OUTPUT (1<<12) #define CAM_MEM_FLAG_DISABLE_DELAYED_UNMAP (1<<13) +#define CAM_MEM_FLAG_KMD_DEBUG_FLAG (1<<14) + #define CAM_MEM_MMU_MAX_HANDLE 16 -- GitLab From de18f79585a2f354d97806a34f46747331b9cc25 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Wed, 13 May 2020 15:54:15 +0530 Subject: [PATCH 222/295] msm: camera: utils: Adding device type to track device handles Adding device type for each driver to track how many device handles are created and freed. CRs-Fixed: 2695692 Change-Id: I3d86b3a0a6c247c5458a22451fe8f8784cde4e04 Signed-off-by: Alok Chauhan --- drivers/cam_core/cam_context_utils.c | 2 +- drivers/cam_core/cam_node.c | 6 ++-- drivers/cam_isp/cam_isp_context.c | 2 +- drivers/cam_req_mgr/cam_req_mgr_core.c | 6 ++-- drivers/cam_req_mgr/cam_req_mgr_dev.c | 3 +- drivers/cam_req_mgr/cam_req_mgr_util.c | 29 ++++++++++++++++--- drivers/cam_req_mgr/cam_req_mgr_util.h | 6 +++- .../cam_actuator/cam_actuator_core.c | 1 + .../cam_csiphy/cam_csiphy_core.c | 1 + .../cam_eeprom/cam_eeprom_core.c | 1 + .../cam_flash/cam_flash_dev.c | 3 +- .../cam_sensor_module/cam_ois/cam_ois_core.c | 1 + .../cam_sensor/cam_sensor_core.c | 1 + 13 files changed, 48 insertions(+), 14 deletions(-) diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 09f164561d69..d3ea1041591b 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -571,7 +571,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, req_hdl_param.media_entity_flag = 0; req_hdl_param.priv = ctx; req_hdl_param.ops = ctx->crm_ctx_intf; - + req_hdl_param.dev_id = ctx->dev_id; ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); if (ctx->dev_hdl <= 0) { rc = -EFAULT; diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index 672ae35b6226..347ca09f9db1 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.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 @@ -796,14 +796,14 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) rc = __cam_node_handle_acquire_hw_v1(node, acquire_ptr); if (rc) { CAM_ERR(CAM_CORE, - "acquire device failed(rc = %d)", rc); + "acquire hw failed(rc = %d)", rc); goto acquire_kfree; } } else if (api_version == 2) { rc = __cam_node_handle_acquire_hw_v2(node, acquire_ptr); if (rc) { CAM_ERR(CAM_CORE, - "acquire device failed(rc = %d)", rc); + "acquire hw failed(rc = %d)", rc); goto acquire_kfree; } } diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 33a06e463abf..ac942446c9e6 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -3835,7 +3835,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, req_hdl_param.media_entity_flag = 0; req_hdl_param.ops = ctx->crm_ctx_intf; req_hdl_param.priv = ctx; - + req_hdl_param.dev_id = CAM_ISP; CAM_DBG(CAM_ISP, "get device handle form bridge"); ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); if (ctx->dev_hdl <= 0) { diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index c81f4bcf3264..cff711500abc 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3168,7 +3168,8 @@ int cam_req_mgr_create_session( ses_info->session_hdl = session_hdl; mutex_init(&cam_session->lock); - CAM_DBG(CAM_CRM, "LOCK_DBG session lock %pK", &cam_session->lock); + CAM_DBG(CAM_CRM, "LOCK_DBG session lock %pK hdl 0x%x", + &cam_session->lock, session_hdl); mutex_lock(&cam_session->lock); cam_session->session_hdl = session_hdl; @@ -3328,7 +3329,7 @@ int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); root_dev.session_hdl = link_info->u.link_info_v1.session_hdl; root_dev.priv = (void *)link; - + root_dev.dev_id = CAM_CRM; mutex_lock(&link->lock); /* Create unique dev handle for link */ link->link_hdl = cam_create_device_hdl(&root_dev); @@ -3437,6 +3438,7 @@ int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); root_dev.session_hdl = link_info->u.link_info_v2.session_hdl; root_dev.priv = (void *)link; + root_dev.dev_id = CAM_CRM; mutex_lock(&link->lock); /* Create unique dev handle for link */ diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index a0688466a060..9c4fdb1e06b5 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -156,7 +156,8 @@ static int cam_req_mgr_close(struct file *filep) struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); CAM_WARN(CAM_CRM, - "release invoked associated userspace process has died"); + "release invoked associated userspace process has died, open_cnt: %d", + g_dev.open_cnt); mutex_lock(&g_dev.cam_lock); if (g_dev.open_cnt <= 0) { diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c index 88b6bf079e9c..df180a615104 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/cam_req_mgr/cam_req_mgr_util.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. */ #define pr_fmt(fmt) "CAM-REQ-MGR_UTIL %s:%d " fmt, __func__, __LINE__ @@ -113,14 +113,30 @@ static int32_t cam_get_free_handle_index(void) idx = find_first_zero_bit(hdl_tbl->bitmap, hdl_tbl->bits); - if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2 || idx < 0) + if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2 || idx < 0) { + CAM_DBG(CAM_CRM, "idx: %d", idx); return -ENOSR; + } set_bit(idx, hdl_tbl->bitmap); return idx; } +void cam_dump_tbl_info(void) +{ + int i; + + for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES_V2; i++) + CAM_INFO(CAM_CRM, + "i: %d session_hdl=0x%x hdl_value=0x%x type=%d state=%d dev_id=0x%llx", + i, hdl_tbl->hdl[i].session_hdl, + hdl_tbl->hdl[i].hdl_value, + hdl_tbl->hdl[i].type, + hdl_tbl->hdl[i].state, + hdl_tbl->hdl[i].dev_id); +} + int32_t cam_create_session_hdl(void *priv) { int idx; @@ -137,6 +153,7 @@ int32_t cam_create_session_hdl(void *priv) idx = cam_get_free_handle_index(); if (idx < 0) { CAM_ERR(CAM_CRM, "Unable to create session handle"); + cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } @@ -149,6 +166,7 @@ int32_t cam_create_session_hdl(void *priv) hdl_tbl->hdl[idx].state = HDL_ACTIVE; hdl_tbl->hdl[idx].priv = priv; hdl_tbl->hdl[idx].ops = NULL; + hdl_tbl->hdl[idx].dev_id = CAM_CRM; spin_unlock_bh(&hdl_tbl_lock); return handle; @@ -169,7 +187,9 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) idx = cam_get_free_handle_index(); if (idx < 0) { - CAM_ERR(CAM_CRM, "Unable to create device handle"); + CAM_ERR(CAM_CRM, + "Unable to create device handle(idx= %d)", idx); + cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } @@ -182,9 +202,10 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) hdl_tbl->hdl[idx].state = HDL_ACTIVE; hdl_tbl->hdl[idx].priv = hdl_data->priv; hdl_tbl->hdl[idx].ops = hdl_data->ops; + hdl_tbl->hdl[idx].dev_id = hdl_data->dev_id; spin_unlock_bh(&hdl_tbl_lock); - pr_debug("%s: handle = %x", __func__, handle); + pr_debug("%s: handle = 0x%x idx = %d\n", __func__, handle, idx); return handle; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.h b/drivers/cam_req_mgr/cam_req_mgr_util.h index c0e339eedd9b..9cf733871569 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.h +++ b/drivers/cam_req_mgr/cam_req_mgr_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_UTIL_API_H_ @@ -35,6 +35,7 @@ enum hdl_type { * @hdl_value: Allocated handle * @type: session/device handle * @state: free/used + * @dev_id: device id for handle * @ops: ops structure * @priv: private data of a handle */ @@ -43,6 +44,7 @@ struct handle { uint32_t hdl_value; enum hdl_type type; enum hdl_state state; + uint64_t dev_id; void *ops; void *priv; }; @@ -65,6 +67,7 @@ struct cam_req_mgr_util_hdl_tbl { * @v4l2_sub_dev_flag: flag to create v4l2 sub device * @media_entity_flag: flag for media entity * @reserved: reserved field + * @dev_id: device id for handle * @ops: ops pointer for a device handle * @priv: private data for a device handle */ @@ -73,6 +76,7 @@ struct cam_create_dev_hdl { int32_t v4l2_sub_dev_flag; int32_t media_entity_flag; int32_t reserved; + uint64_t dev_id; void *ops; void *priv; }; diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c index 0b6e25572e90..d82eea628532 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -822,6 +822,7 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = a_ctrl; + bridge_params.dev_id = CAM_ACTUATOR; actuator_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); 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 8ea1c8dac0c2..dbd2141cc5c6 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -766,6 +766,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = csiphy_dev; + bridge_params.dev_id = CAM_CSIPHY; if (csiphy_acq_params.combo_mode >= 2) { CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d", diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index caf5132b3df2..8b9bd2adcb63 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -351,6 +351,7 @@ static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = e_ctrl; + bridge_params.dev_id = CAM_EEPROM; eeprom_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index 5eccfd8aa11b..4d07bd8186a9 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.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 @@ -63,6 +63,7 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = fctrl; + bridge_params.dev_id = CAM_FLASH; flash_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 6a1ccbd4aa11..ebfc8ec0557c 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -82,6 +82,7 @@ static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = o_ctrl; + bridge_params.dev_id = CAM_OIS; ois_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index a0405784ca90..61d33c5cbaad 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -774,6 +774,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = s_ctrl; + bridge_params.dev_id = CAM_SENSOR; sensor_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); -- GitLab From 04e78317a3395b7a48f2c2f495a33bf6868470c8 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Mon, 6 Apr 2020 12:23:11 +0530 Subject: [PATCH 223/295] msm: camera: cdm: Debug info in case of cdm page fault When tfe cdm callback is called with cdm page fault or invalid irq status,then dump last submitted BLs hw_addr, length, type of BL and also dump patch info for the request that hit CDM page fault/invalid irq. CRs-Fixed: 2663740 Change-Id: I19763598876faa8e9497870338c611369730933e Signed-off-by: Shravya Samala --- drivers/cam_cdm/cam_cdm_core_common.c | 1 + drivers/cam_cdm/cam_cdm_hw_core.c | 257 ++++++++++-------- drivers/cam_cdm/cam_cdm_intf_api.h | 37 +++ drivers/cam_cdm/cam_cdm_util.c | 78 +++++- drivers/cam_isp/cam_isp_context.c | 1 + drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 109 +++++++- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h | 5 + .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 2 + drivers/cam_utils/cam_packet_util.c | 3 + 9 files changed, 366 insertions(+), 127 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index 29aef156cd9a..8859fa833546 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -204,6 +204,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, } else if (status == CAM_CDM_CB_STATUS_HW_RESET_DONE || status == CAM_CDM_CB_STATUS_HW_FLUSH || status == CAM_CDM_CB_STATUS_HW_RESUBMIT || + status == CAM_CDM_CB_STATUS_INVALID_BL_CMD || status == CAM_CDM_CB_STATUS_HW_ERROR) { int client_idx; struct cam_cdm_bl_cb_request_entry *node = diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 06c42ee6c4ea..4491c5234c4a 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1056,7 +1056,8 @@ static void cam_hw_cdm_reset_cleanup( struct cam_cdm_bl_cb_request_entry *node, *tnode; bool flush_hw = false; - if (test_bit(CAM_CDM_FLUSH_HW_STATUS, &core->cdm_status)) + if (test_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status) || + test_bit(CAM_CDM_FLUSH_HW_STATUS, &core->cdm_status)) flush_hw = true; for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) { @@ -1094,137 +1095,169 @@ static void cam_hw_cdm_work(struct work_struct *work) struct cam_hw_info *cdm_hw; struct cam_cdm *core; int i, fifo_idx; + struct cam_cdm_bl_cb_request_entry *tnode = NULL; + struct cam_cdm_bl_cb_request_entry *node = NULL; payload = container_of(work, struct cam_cdm_work_payload, work); - if (payload) { - cdm_hw = payload->hw; - core = (struct cam_cdm *)cdm_hw->core_info; - fifo_idx = payload->fifo_idx; - if (fifo_idx >= core->offsets->reg_data->num_bl_fifo) { - CAM_ERR(CAM_CDM, "Invalid fifo idx %d", - fifo_idx); + if (!payload) { + CAM_ERR(CAM_CDM, "NULL payload"); + return; + } + + cdm_hw = payload->hw; + core = (struct cam_cdm *)cdm_hw->core_info; + fifo_idx = payload->fifo_idx; + if (fifo_idx >= core->offsets->reg_data->num_bl_fifo) { + CAM_ERR(CAM_CDM, "Invalid fifo idx %d", + fifo_idx); + kfree(payload); + payload = NULL; + return; + } + + cam_req_mgr_thread_switch_delay_detect( + payload->workq_scheduled_ts); + + CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INLINE_IRQ_MASK) { + 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"); kfree(payload); payload = NULL; return; } - cam_req_mgr_thread_switch_delay_detect( - payload->workq_scheduled_ts); - 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 last tag: 0x%x", - payload->irq_data, - core->bl_fifo[fifo_idx] - .last_bl_tag_done); - - if (payload->irq_data == 0xff) { - CAM_INFO(CAM_CDM, "Debug genirq received"); - kfree(payload); - payload = NULL; - return; - } + mutex_lock(&core->bl_fifo[fifo_idx] + .fifo_lock); - mutex_lock(&core->bl_fifo[fifo_idx] - .fifo_lock); - - if (atomic_read(&core->bl_fifo[fifo_idx].work_record)) - atomic_dec( - &core->bl_fifo[fifo_idx].work_record); - - if (list_empty(&core->bl_fifo[fifo_idx] - .bl_request_list)) { - CAM_INFO(CAM_CDM, - "Fifo list empty, idx %d tag %d arb %d", - fifo_idx, payload->irq_data, - core->arbitration); - mutex_unlock(&core->bl_fifo[fifo_idx] - .fifo_lock); - return; - } + if (atomic_read(&core->bl_fifo[fifo_idx].work_record)) + atomic_dec( + &core->bl_fifo[fifo_idx].work_record); - if (core->bl_fifo[fifo_idx] - .last_bl_tag_done != - payload->irq_data) { - core->bl_fifo[fifo_idx] - .last_bl_tag_done = - payload->irq_data; - list_for_each_entry_safe(node, tnode, - &core->bl_fifo[fifo_idx] - .bl_request_list, - entry) { - 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); - } - list_del_init(&node->entry); - if (node->bl_tag == payload->irq_data) { - kfree(node); - node = NULL; - break; - } + if (list_empty(&core->bl_fifo[fifo_idx] + .bl_request_list)) { + CAM_INFO(CAM_CDM, + "Fifo list empty, idx %d tag %d arb %d", + fifo_idx, payload->irq_data, + core->arbitration); + mutex_unlock(&core->bl_fifo[fifo_idx] + .fifo_lock); + return; + } + + if (core->bl_fifo[fifo_idx] + .last_bl_tag_done != + payload->irq_data) { + core->bl_fifo[fifo_idx] + .last_bl_tag_done = + payload->irq_data; + list_for_each_entry_safe(node, tnode, + &core->bl_fifo[fifo_idx] + .bl_request_list, + entry) { + 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); + } + list_del_init(&node->entry); + if (node->bl_tag == payload->irq_data) { kfree(node); node = NULL; + break; } - } else { - CAM_INFO(CAM_CDM, - "Skip GenIRQ, tag 0x%x fifo %d", - payload->irq_data, fifo_idx); + kfree(node); + node = NULL; } - mutex_unlock(&core->bl_fifo[fifo_idx] - .fifo_lock); + } else { + CAM_INFO(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_BL_DONE_MASK) { + if (test_bit(payload->fifo_idx, &core->cdm_status)) { + CAM_DBG(CAM_CDM, "CDM HW BL done IRQ"); + complete(&core->bl_fifo[payload->fifo_idx] + .bl_complete); + } + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_ERRORS) { + int reset_hw_hdl = 0x0; + + CAM_ERR_RATE_LIMIT(CAM_CDM, + "CDM Error IRQ status %d\n", + payload->irq_status); + set_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status); + 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); + /* + * 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); if (payload->irq_status & - CAM_CDM_IRQ_STATUS_BL_DONE_MASK) { - if (test_bit(fifo_idx, &core->cdm_status)) { - CAM_DBG(CAM_CDM, "CDM HW BL done IRQ"); - complete(&core->bl_fifo[fifo_idx] - .bl_complete); + CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK) { + node = list_first_entry_or_null( + &core->bl_fifo[payload->fifo_idx].bl_request_list, + struct cam_cdm_bl_cb_request_entry, entry); + + if (node != NULL) { + if (node->request_type == + CAM_HW_CDM_BL_CB_CLIENT) { + cam_cdm_notify_clients(cdm_hw, + CAM_CDM_CB_STATUS_INVALID_BL_CMD, + (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); + } + list_del_init(&node->entry); + kfree(node); } } + /* 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); + if (payload->irq_status & - CAM_CDM_IRQ_STATUS_ERRORS) { - CAM_ERR_RATE_LIMIT(CAM_CDM, - "CDM Error IRQ status %d\n", - payload->irq_status); - set_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status); - 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); - /* - * 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); - mutex_unlock(&cdm_hw->hw_mutex); - if (!(payload->irq_status & - CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK)) - clear_bit(CAM_CDM_ERROR_HW_STATUS, - &core->cdm_status); - } - kfree(payload); - payload = NULL; - } else { - CAM_ERR(CAM_CDM, "NULL payload"); + CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK) + cam_hw_cdm_reset_hw(cdm_hw, reset_hw_hdl); + + mutex_unlock(&cdm_hw->hw_mutex); + if (!(payload->irq_status & + CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK)) + clear_bit(CAM_CDM_ERROR_HW_STATUS, + &core->cdm_status); } + kfree(payload); + payload = NULL; } diff --git a/drivers/cam_cdm/cam_cdm_intf_api.h b/drivers/cam_cdm/cam_cdm_intf_api.h index 0a3155824f8d..25d0a5db88ed 100644 --- a/drivers/cam_cdm/cam_cdm_intf_api.h +++ b/drivers/cam_cdm/cam_cdm_intf_api.h @@ -10,6 +10,8 @@ #include "cam_cdm_util.h" #include "cam_soc_util.h" +#define CAM_CDM_BL_CMD_MAX 25 + /* enum cam_cdm_id - Enum for possible CAM CDM hardwares */ enum cam_cdm_id { CAM_CDM_VIRTUAL, @@ -150,6 +152,41 @@ struct cam_cdm_bl_request { struct cam_cdm_bl_cmd cmd[1]; }; +/** + * struct cam_cdm_bl_data - last submiited CDM BL data + * + * @mem_handle : Input mem handle of bl cmd + * @hw_addr : Hw address of submitted Bl command + * @offset : Input offset of the actual bl cmd in the memory pointed + * by mem_handle + * @len : length of submitted Bl command to CDM. + * @input_len : Input length of the BL command, Cannot be more than 1MB and + * this is will be validated with offset+size of the memory pointed + * by mem_handle + * @type : CDM bl cmd addr types. + */ +struct cam_cdm_bl_data { + int32_t mem_handle; + dma_addr_t hw_addr; + uint32_t offset; + size_t len; + uint32_t input_len; + enum cam_cdm_bl_cmd_addr_type type; +}; + +/** + * struct cam_cdm_bl_info + * + * @bl_count : No. of Bl commands submiited to CDM. + * @cmd : payload holding the BL cmd's arrary + * that is sumbitted. + * + */ +struct cam_cdm_bl_info { + int32_t bl_count; + struct cam_cdm_bl_data cmd[CAM_CDM_BL_CMD_MAX]; +}; + /** * @brief : API to get the CDM capabilities for a camera device type * diff --git a/drivers/cam_cdm/cam_cdm_util.c b/drivers/cam_cdm/cam_cdm_util.c index 117680a5f8a0..d56ab6db3555 100644 --- a/drivers/cam_cdm/cam_cdm_util.c +++ b/drivers/cam_cdm/cam_cdm_util.c @@ -689,25 +689,53 @@ int cam_cdm_util_cmd_buf_write(void __iomem **current_device_base, return ret; } -static long cam_cdm_util_dump_dmi_cmd(uint32_t *cmd_buf_addr) +static long cam_cdm_util_dump_dmi_cmd(uint32_t *cmd_buf_addr, + uint32_t *cmd_buf_addr_end) { long ret = 0; + struct cdm_dmi_cmd *p_dmi_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + p_dmi_cmd = (struct cdm_dmi_cmd *)cmd_buf_addr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI]; ret += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI]; - CAM_INFO(CAM_CDM, "DMI"); + + if (temp_ptr > cmd_buf_addr_end) + CAM_ERR(CAM_CDM, + "Invalid cmd start addr:%pK end addr:%pK", + temp_ptr, cmd_buf_addr_end); + + CAM_INFO(CAM_CDM, + "DMI: LEN: %u DMIAddr: 0x%X DMISel: 0x%X LUT_addr: 0x%X", + p_dmi_cmd->length, p_dmi_cmd->DMIAddr, + p_dmi_cmd->DMISel, p_dmi_cmd->addr); return ret; } -static long cam_cdm_util_dump_buff_indirect(uint32_t *cmd_buf_addr) +static long cam_cdm_util_dump_buff_indirect(uint32_t *cmd_buf_addr, + uint32_t *cmd_buf_addr_end) { long ret = 0; + struct cdm_indirect_cmd *p_indirect_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + p_indirect_cmd = (struct cdm_indirect_cmd *)cmd_buf_addr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT]; ret += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT]; - CAM_INFO(CAM_CDM, "Buff Indirect"); + + if (temp_ptr > cmd_buf_addr_end) + CAM_ERR(CAM_CDM, + "Invalid cmd start addr:%pK end addr:%pK", + temp_ptr, cmd_buf_addr_end); + + CAM_INFO(CAM_CDM, + "Buff Indirect: LEN: %u addr: 0x%X", + p_indirect_cmd->length, p_indirect_cmd->addr); return ret; } -static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr) +static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr, + uint32_t *cmd_buf_addr_end) { long ret = 0; struct cdm_regcontinuous_cmd *p_regcont_cmd; @@ -722,6 +750,12 @@ static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr) p_regcont_cmd->count, p_regcont_cmd->offset); for (i = 0; i < p_regcont_cmd->count; i++) { + if (temp_ptr > cmd_buf_addr_end) { + CAM_ERR(CAM_CDM, + "Invalid cmd(%d) start addr:%pK end addr:%pK", + i, temp_ptr, cmd_buf_addr_end); + break; + } CAM_INFO(CAM_CDM, "DATA_%d: 0x%X", i, *temp_ptr); temp_ptr++; @@ -731,7 +765,8 @@ static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr) return ret; } -static long cam_cdm_util_dump_reg_random_cmd(uint32_t *cmd_buf_addr) +static long cam_cdm_util_dump_reg_random_cmd(uint32_t *cmd_buf_addr, + uint32_t *cmd_buf_addr_end) { struct cdm_regrandom_cmd *p_regrand_cmd; uint32_t *temp_ptr = cmd_buf_addr; @@ -746,6 +781,12 @@ static long cam_cdm_util_dump_reg_random_cmd(uint32_t *cmd_buf_addr) p_regrand_cmd->count); for (i = 0; i < p_regrand_cmd->count; i++) { + if (temp_ptr > cmd_buf_addr_end) { + CAM_ERR(CAM_CDM, + "Invalid cmd(%d) start addr:%pK end addr:%pK", + i, temp_ptr, cmd_buf_addr_end); + break; + } CAM_INFO(CAM_CDM, "OFFSET_%d: 0x%X DATA_%d: 0x%X", i, *temp_ptr & CAM_CDM_REG_OFFSET_MASK, i, *(temp_ptr + 1)); @@ -778,15 +819,22 @@ static long cam_cdm_util_dump_wait_event_cmd(uint32_t *cmd_buf_addr) return ret; } -static long cam_cdm_util_dump_change_base_cmd(uint32_t *cmd_buf_addr) +static long cam_cdm_util_dump_change_base_cmd(uint32_t *cmd_buf_addr, + uint32_t *cmd_buf_addr_end) { long ret = 0; struct cdm_changebase_cmd *p_cbase_cmd; uint32_t *temp_ptr = cmd_buf_addr; p_cbase_cmd = (struct cdm_changebase_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE]; ret += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE]; + if (temp_ptr > cmd_buf_addr_end) + CAM_ERR(CAM_CDM, + "Invalid cmd start addr:%pK end addr:%pK", + temp_ptr, cmd_buf_addr_end); + CAM_INFO(CAM_CDM, "CHANGE_BASE: 0x%X", p_cbase_cmd->base); @@ -808,6 +856,7 @@ void cam_cdm_util_dump_cmd_buf( uint32_t *cmd_buf_start, uint32_t *cmd_buf_end) { uint32_t *buf_now = cmd_buf_start; + uint32_t *buf_end = cmd_buf_end; uint32_t cmd = 0; if (!cmd_buf_start || !cmd_buf_end) { @@ -823,16 +872,20 @@ void cam_cdm_util_dump_cmd_buf( case CAM_CDM_CMD_DMI: case CAM_CDM_CMD_DMI_32: case CAM_CDM_CMD_DMI_64: - buf_now += cam_cdm_util_dump_dmi_cmd(buf_now); + buf_now += cam_cdm_util_dump_dmi_cmd(buf_now, + buf_end); break; case CAM_CDM_CMD_REG_CONT: - buf_now += cam_cdm_util_dump_reg_cont_cmd(buf_now); + buf_now += cam_cdm_util_dump_reg_cont_cmd(buf_now, + buf_end); break; case CAM_CDM_CMD_REG_RANDOM: - buf_now += cam_cdm_util_dump_reg_random_cmd(buf_now); + buf_now += cam_cdm_util_dump_reg_random_cmd(buf_now, + buf_end); break; case CAM_CDM_CMD_BUFF_INDIRECT: - buf_now += cam_cdm_util_dump_buff_indirect(buf_now); + buf_now += cam_cdm_util_dump_buff_indirect(buf_now, + buf_end); break; case CAM_CDM_CMD_GEN_IRQ: buf_now += cam_cdm_util_dump_gen_irq_cmd(buf_now); @@ -841,7 +894,8 @@ void cam_cdm_util_dump_cmd_buf( buf_now += cam_cdm_util_dump_wait_event_cmd(buf_now); break; case CAM_CDM_CMD_CHANGE_BASE: - buf_now += cam_cdm_util_dump_change_base_cmd(buf_now); + buf_now += cam_cdm_util_dump_change_base_cmd(buf_now, + buf_end); break; case CAM_CDM_CMD_PERF_CTRL: buf_now += cam_cdm_util_dump_perf_ctrl_cmd(buf_now); diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 33a06e463abf..2b611a4a38f5 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -3626,6 +3626,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( req_isp->num_fence_map_in = cfg.num_in_map_entries; req_isp->num_acked = 0; req_isp->bubble_detected = false; + req_isp->hw_update_data.packet = packet; for (i = 0; i < req_isp->num_fence_map_out; i++) { rc = cam_sync_get_obj_ref(req_isp->fence_map_out[i].sync_id); 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 89c0df47c936..9502725968de 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 @@ -1708,16 +1708,21 @@ void cam_tfe_cam_cdm_callback(uint32_t handle, void *userdata, { struct cam_isp_prepare_hw_update_data *hw_update_data = NULL; struct cam_tfe_hw_mgr_ctx *ctx = NULL; + uint32_t *buf_start, *buf_end; + int i, rc = 0; + size_t len = 0; + uint32_t *buf_addr; if (!userdata) { CAM_ERR(CAM_ISP, "Invalid args"); return; } - hw_update_data = (struct cam_isp_prepare_hw_update_data *)userdata; - ctx = (struct cam_tfe_hw_mgr_ctx *)hw_update_data->isp_mgr_ctx; - if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { + hw_update_data = + (struct cam_isp_prepare_hw_update_data *)userdata; + ctx = + (struct cam_tfe_hw_mgr_ctx *)hw_update_data->isp_mgr_ctx; complete_all(&ctx->config_done_complete); atomic_set(&ctx->cdm_done, 1); if (g_tfe_hw_mgr.debug_cfg.per_req_reg_dump) @@ -1729,6 +1734,40 @@ void cam_tfe_cam_cdm_callback(uint32_t handle, void *userdata, 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); + } else if (status == CAM_CDM_CB_STATUS_PAGEFAULT || + status == CAM_CDM_CB_STATUS_INVALID_BL_CMD || + status == CAM_CDM_CB_STATUS_HW_ERROR) { + ctx = userdata; + CAM_INFO(CAM_ISP, + "req_id =%d ctx_id =%d Bl_cmd_count =%d status=%d", + ctx->applied_req_id, ctx->ctx_index, + ctx->last_submit_bl_cmd.bl_count, status); + + for (i = 0; i < ctx->last_submit_bl_cmd.bl_count; i++) { + CAM_INFO(CAM_ISP, + "BL(%d) hdl=0x%x addr=0x%x len=%d input_len =%d offset=0x%x type=%d", + i, ctx->last_submit_bl_cmd.cmd[i].mem_handle, + ctx->last_submit_bl_cmd.cmd[i].hw_addr, + ctx->last_submit_bl_cmd.cmd[i].len, + ctx->last_submit_bl_cmd.cmd[i].input_len, + ctx->last_submit_bl_cmd.cmd[i].offset, + ctx->last_submit_bl_cmd.cmd[i].type); + + rc = cam_packet_util_get_cmd_mem_addr( + ctx->last_submit_bl_cmd.cmd[i].mem_handle, + &buf_addr, &len); + + buf_start = (uint32_t *)((uint8_t *) buf_addr + + ctx->last_submit_bl_cmd.cmd[i].offset); + buf_end = (uint32_t *)((uint8_t *) buf_start + + ctx->last_submit_bl_cmd.cmd[i].input_len - 1); + + cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + } + if (ctx->packet != NULL) + cam_packet_dump_patch_info(ctx->packet, + g_tfe_hw_mgr.mgr_common.img_iommu_hdl, + g_tfe_hw_mgr.mgr_common.img_iommu_hdl_secure); } else { CAM_WARN(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", @@ -2436,6 +2475,47 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, return rc; } + ctx->packet = (struct cam_packet *)hw_update_data->packet; + ctx->last_submit_bl_cmd.bl_count = cdm_cmd->cmd_arrary_count; + + for (i = 0; i < cdm_cmd->cmd_arrary_count; i++) { + if (cdm_cmd->type == CAM_CDM_BL_CMD_TYPE_MEM_HANDLE) { + ctx->last_submit_bl_cmd.cmd[i].mem_handle = + cdm_cmd->cmd[i].bl_addr.mem_handle; + + rc = cam_mem_get_io_buf( + cdm_cmd->cmd[i].bl_addr.mem_handle, + g_tfe_hw_mgr.mgr_common.cmd_iommu_hdl, + &ctx->last_submit_bl_cmd.cmd[i].hw_addr, + &ctx->last_submit_bl_cmd.cmd[i].len); + } else if (cdm_cmd->type == + CAM_CDM_BL_CMD_TYPE_HW_IOVA) { + if (!cdm_cmd->cmd[i].bl_addr.hw_iova) { + CAM_ERR(CAM_CDM, + "Submitted Hw bl hw_iova is invalid %d:%d", + i, cdm_cmd->cmd_arrary_count); + rc = -EINVAL; + break; + } + rc = 0; + ctx->last_submit_bl_cmd.cmd[i].hw_addr = + (uint64_t)cdm_cmd->cmd[i].bl_addr.hw_iova; + ctx->last_submit_bl_cmd.cmd[i].len = + cdm_cmd->cmd[i].len + cdm_cmd->cmd[i].offset; + ctx->last_submit_bl_cmd.cmd[i].mem_handle = 0; + } else + CAM_INFO(CAM_ISP, + "submitted invalid bl cmd addr type :%d for Bl(%d)", + cdm_cmd->type, i); + + ctx->last_submit_bl_cmd.cmd[i].offset = + cdm_cmd->cmd[i].offset; + ctx->last_submit_bl_cmd.cmd[i].type = + cdm_cmd->type; + ctx->last_submit_bl_cmd.cmd[i].input_len = + cdm_cmd->cmd[i].len; + } + if (!cfg->init_packet) goto end; @@ -2714,6 +2794,17 @@ static int cam_tfe_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) atomic_dec_return(&g_tfe_hw_mgr.active_ctx_cnt); mutex_unlock(&g_tfe_hw_mgr.ctx_mutex); + for (i = 0; i < ctx->last_submit_bl_cmd.bl_count; i++) { + ctx->last_submit_bl_cmd.cmd[i].mem_handle = 0; + ctx->last_submit_bl_cmd.cmd[i].hw_addr = 0; + ctx->last_submit_bl_cmd.cmd[i].len = 0; + ctx->last_submit_bl_cmd.cmd[i].offset = 0; + ctx->last_submit_bl_cmd.cmd[i].type = 0; + ctx->last_submit_bl_cmd.cmd[i].input_len = 0; + } + ctx->last_submit_bl_cmd.bl_count = 0; + ctx->packet = NULL; + end: return rc; } @@ -3268,6 +3359,18 @@ static int cam_tfe_mgr_release_hw(void *hw_mgr_priv, 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 < ctx->last_submit_bl_cmd.bl_count; i++) { + ctx->last_submit_bl_cmd.cmd[i].mem_handle = 0; + ctx->last_submit_bl_cmd.cmd[i].hw_addr = 0; + ctx->last_submit_bl_cmd.cmd[i].len = 0; + ctx->last_submit_bl_cmd.cmd[i].offset = 0; + ctx->last_submit_bl_cmd.cmd[i].type = 0; + ctx->last_submit_bl_cmd.cmd[i].input_len = 0; + } + ctx->last_submit_bl_cmd.bl_count = 0; + ctx->packet = NULL; + for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) { ctx->sof_cnt[i] = 0; ctx->eof_cnt[i] = 0; 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 66eabc3fb442..b41b38e6d3e3 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 @@ -13,6 +13,7 @@ #include "cam_tfe_csid_hw_intf.h" #include "cam_top_tpg_hw_intf.h" #include "cam_tasklet_util.h" +#include "cam_cdm_intf_api.h" @@ -61,6 +62,7 @@ struct cam_tfe_hw_mgr_debug { * @cdm_ops cdm util operation pointer for building * cdm commands * @cdm_cmd cdm base and length request pointer + * @last_submit_bl_cmd last submiited CDM BL command data * @config_done_complete indicator for configuration complete * @sof_cnt sof count value per core, used for dual TFE * @epoch_cnt epoch count value per core, used for dual TFE @@ -82,6 +84,7 @@ struct cam_tfe_hw_mgr_debug { * @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 + * packet CSL packet from user mode driver */ struct cam_tfe_hw_mgr_ctx { struct list_head list; @@ -105,6 +108,7 @@ struct cam_tfe_hw_mgr_ctx { uint32_t cdm_handle; struct cam_cdm_utils_ops *cdm_ops; struct cam_cdm_bl_request *cdm_cmd; + struct cam_cdm_bl_info last_submit_bl_cmd; struct completion config_done_complete; uint32_t sof_cnt[CAM_TFE_HW_NUM_MAX]; @@ -125,6 +129,7 @@ struct cam_tfe_hw_mgr_ctx { uint32_t master_hw_idx; uint32_t slave_hw_idx; uint32_t dual_tfe_irq_mismatch_cnt; + struct cam_packet *packet; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 86b47da0b313..5eab896e613e 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -128,6 +128,7 @@ struct cam_isp_bw_config_internal { * is valid or not * @reg_dump_buf_desc: cmd buffer descriptors for reg dump * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc + * @packet CSL packet from user mode driver * */ struct cam_isp_prepare_hw_update_data { @@ -140,6 +141,7 @@ struct cam_isp_prepare_hw_update_data { struct cam_cmd_buf_desc reg_dump_buf_desc[ CAM_REG_DUMP_MAX_BUF_ENTRIES]; uint32_t num_reg_dump_buf; + struct cam_packet *packet; }; diff --git a/drivers/cam_utils/cam_packet_util.c b/drivers/cam_utils/cam_packet_util.c index 1569d5dbafa6..69d823f12b92 100644 --- a/drivers/cam_utils/cam_packet_util.c +++ b/drivers/cam_utils/cam_packet_util.c @@ -171,6 +171,9 @@ void cam_packet_dump_patch_info(struct cam_packet *packet, ((uint32_t *) &packet->payload + packet->patch_offset/4); + CAM_INFO(CAM_UTIL, "Total num of patches : %d", + packet->num_patches); + for (i = 0; i < packet->num_patches; i++) { hdl = cam_mem_is_secure_buf(patch_desc[i].src_buf_hdl) ? sec_mmu_hdl : iommu_hdl; -- GitLab From b82aa49c0aedb7c61dee853c0151b8a36c4868a7 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Fri, 5 Jun 2020 22:42:27 +0530 Subject: [PATCH 224/295] msm: camera: ope: Updated logic to calculate num bw path Ope driver was incorrectly calculating the number of bw path. This is causing bw to be skip for some of the ports. Updated logic to correctly calculate number of path based on valid path type. CRs-Fixed: 2715586 Change-Id: I95b6dcfae454713a7b5db6d629310244bb304b19 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 43 ++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) 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 75310e527acc..a25d951ef5ec 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 @@ -1319,6 +1319,46 @@ static int cam_ope_mgr_update_clk_rate(struct cam_ope_hw_mgr *hw_mgr, return 0; } +static int cam_ope_mgr_calculate_num_path( + struct cam_ope_clk_bw_req_internal_v2 *clk_info, + struct cam_ope_ctx *ctx_data) +{ + int i, path_index = 0; + + for (i = 0; i < CAM_OPE_MAX_PER_PATH_VOTES; i++) { + if ((clk_info->axi_path[i].path_data_type < + CAM_AXI_PATH_DATA_OPE_START_OFFSET) || + (clk_info->axi_path[i].path_data_type > + CAM_AXI_PATH_DATA_OPE_MAX_OFFSET) || + ((clk_info->axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_OPE_START_OFFSET) >= + 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; + } + + path_index = clk_info->axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_OPE_START_OFFSET; + + CAM_DBG(CAM_OPE, + "clk_info: i[%d]: [%s %s] bw [%lld %lld] num_path: %d", + i, + cam_cpas_axi_util_trans_type_to_string( + clk_info->axi_path[i].transac_type), + cam_cpas_axi_util_path_type_to_string( + clk_info->axi_path[i].path_data_type), + clk_info->axi_path[i].camnoc_bw, + clk_info->axi_path[i].mnoc_ab_bw, + clk_info->num_paths); + } + + return (path_index+1); +} + static bool cam_ope_update_bw_v2(struct cam_ope_hw_mgr *hw_mgr, struct cam_ope_ctx *ctx_data, struct cam_ope_clk_info *hw_mgr_clk_info, @@ -1401,7 +1441,8 @@ static bool cam_ope_update_bw_v2(struct cam_ope_hw_mgr *hw_mgr, ctx_data->clk_info.axi_path[i].ddr_ib_bw; } - ctx_data->clk_info.num_paths = clk_info->num_paths; + ctx_data->clk_info.num_paths = + cam_ope_mgr_calculate_num_path(clk_info, ctx_data); memcpy(&ctx_data->clk_info.axi_path[0], &clk_info->axi_path[0], -- GitLab From 37224a0fb113602efbbc75e686921495e81255d5 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 16 Jun 2020 22:23:48 +0530 Subject: [PATCH 225/295] msm: camera: isp: Update last reported request ID correctly The last reported request ID indicates the request ID for which the shutter was sent last. Only update this field for requests that have not bubbled in a given ISP ctx. CRs-Fixed: 2712404 Change-Id: I7aa1e8154fecd0b8ca8dca230173fbbe6ecd78bd Signed-off-by: Trishansh Bhardwaj --- drivers/cam_isp/cam_isp_context.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index f123fb1e8719..b4fb8ff84045 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1137,7 +1137,9 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( } list_for_each_entry(req, &ctx->active_req_list, list) { - if (req->request_id > ctx_isp->reported_req_id) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if ((!req_isp->bubble_detected) && + (req->request_id > ctx_isp->reported_req_id)) { request_id = req->request_id; ctx_isp->reported_req_id = request_id; __cam_isp_ctx_update_event_record(ctx_isp, @@ -1362,10 +1364,12 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); - if (req->request_id > ctx_isp->reported_req_id) { + if ((req->request_id > ctx_isp->reported_req_id) + && !req_isp->bubble_report) { request_id = req->request_id; ctx_isp->reported_req_id = request_id; } + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); __cam_isp_ctx_update_event_record(ctx_isp, -- GitLab From ffcd3c71da5eb6ebe0b96553cb626fe5907ddb79 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Fri, 29 May 2020 15:14:21 +0530 Subject: [PATCH 226/295] msm: camera: tfe: Reduce stack footprint during bw vote Reduce the stack footprint during bw vote from tfe driver to avoid corruption on device with lesser stack size. CRs-Fixed: 2691692 Change-Id: I58033323735ade16adb0d471f211ff8224583cc1 Signed-off-by: Alok Chauhan --- drivers/cam_cpas/cam_cpas_hw.c | 28 ++++++++++++++------- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 23 +++++++++++------ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index f4503bb71bcc..0258f5488e1c 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -961,7 +961,7 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_cpas_client *cpas_client = NULL; - struct cam_axi_vote axi_vote = {0}; + struct cam_axi_vote *axi_vote = NULL; uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); int rc = 0; @@ -971,16 +971,24 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, return -EINVAL; } - memcpy(&axi_vote, client_axi_vote, sizeof(struct cam_axi_vote)); - if (!CAM_CPAS_CLIENT_VALID(client_indx)) return -EINVAL; - cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx], - "Incoming Vote", &axi_vote); - mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); + + axi_vote = kmemdup(client_axi_vote, sizeof(struct cam_axi_vote), + GFP_KERNEL); + if (!axi_vote) { + CAM_ERR(CAM_CPAS, "Out of memory"); + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return -ENOMEM; + } + + cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx], + "Incoming Vote", axi_vote); + cpas_client = cpas_core->cpas_client[client_indx]; if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { @@ -991,7 +999,7 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, goto unlock_client; } - rc = cam_cpas_util_translate_client_paths(&axi_vote); + rc = cam_cpas_util_translate_client_paths(axi_vote); if (rc) { CAM_ERR(CAM_CPAS, "Unable to translate per path votes rc: %d", rc); @@ -999,12 +1007,14 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, } cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx], - "Translated Vote", &axi_vote); + "Translated Vote", axi_vote); rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, - cpas_core->cpas_client[client_indx], &axi_vote); + cpas_core->cpas_client[client_indx], axi_vote); unlock_client: + kzfree(axi_vote); + axi_vote = NULL; mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return rc; 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 9502725968de..e7f0cb782b43 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 @@ -2309,7 +2309,7 @@ static int cam_isp_tfe_blob_bw_update( { struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_hw_intf *hw_intf; - struct cam_tfe_bw_update_args bw_upd_args; + struct cam_tfe_bw_update_args *bw_upd_args = NULL; int rc = -EINVAL; uint32_t i, split_idx; bool camif_l_bw_updated = false; @@ -2330,32 +2330,38 @@ static int cam_isp_tfe_blob_bw_update( bw_config->axi_path[i].mnoc_ib_bw); } + bw_upd_args = kzalloc(sizeof(struct cam_tfe_bw_update_args), + GFP_KERNEL); + if (!bw_upd_args) { + CAM_ERR(CAM_ISP, "Out of memory"); + return -ENOMEM; + } list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { for (split_idx = 0; split_idx < CAM_ISP_HW_SPLIT_MAX; split_idx++) { if (!hw_mgr_res->hw_res[split_idx]) continue; - memset(&bw_upd_args.isp_vote, 0, + memset(&bw_upd_args->isp_vote, 0, sizeof(struct cam_axi_vote)); rc = cam_tfe_classify_vote_info(hw_mgr_res, bw_config, - &bw_upd_args.isp_vote, split_idx, + &bw_upd_args->isp_vote, split_idx, &camif_l_bw_updated, &camif_r_bw_updated); if (rc) - return rc; + goto end; - if (!bw_upd_args.isp_vote.num_paths) + if (!bw_upd_args->isp_vote.num_paths) continue; hw_intf = hw_mgr_res->hw_res[split_idx]->hw_intf; if (hw_intf && hw_intf->hw_ops.process_cmd) { - bw_upd_args.node_res = + bw_upd_args->node_res = hw_mgr_res->hw_res[split_idx]; rc = hw_intf->hw_ops.process_cmd( hw_intf->hw_priv, CAM_ISP_HW_CMD_BW_UPDATE_V2, - &bw_upd_args, + bw_upd_args, sizeof( struct cam_tfe_bw_update_args)); if (rc) @@ -2367,6 +2373,9 @@ static int cam_isp_tfe_blob_bw_update( } } +end: + kzfree(bw_upd_args); + bw_upd_args = NULL; return rc; } -- GitLab From ab15ec2d5e883b45f3d8cf676194e33155e45310 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Fri, 12 Jun 2020 10:46:09 +0530 Subject: [PATCH 227/295] msm: camera: isp: Max requests per context reduction in isp driver Reduced maximum no of requests per context from 20 to 8 in isp driver. CRs-Fixed: 2720238 Change-Id: If557b190fe94af72cc6fb28f36c3e1f6189218a5 Signed-off-by: Shravya Samala --- drivers/cam_isp/cam_isp_context.c | 4 ++-- drivers/cam_isp/cam_isp_context.h | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index b4fb8ff84045..034e80e99169 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -4986,14 +4986,14 @@ int cam_isp_context_init(struct cam_isp_context *ctx, ctx->init_timestamp = jiffies_to_msecs(jiffies); ctx->isp_device_type = isp_device_type; - for (i = 0; i < CAM_CTX_REQ_MAX; i++) { + for (i = 0; i < CAM_ISP_CTX_REQ_MAX; i++) { ctx->req_base[i].req_priv = &ctx->req_isp[i]; ctx->req_isp[i].base = &ctx->req_base[i]; } /* camera context setup */ rc = cam_context_init(ctx_base, isp_dev_name, CAM_ISP, ctx_id, - crm_node_intf, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + crm_node_intf, hw_intf, ctx->req_base, CAM_ISP_CTX_REQ_MAX); if (rc) { CAM_ERR(CAM_ISP, "Camera Context Base init failed"); goto err; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 2bffd0c85323..a98f1d874d5a 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -22,6 +22,8 @@ */ #define CAM_ISP_CTX_RES_MAX 24 +/* max requests per ctx for isp */ +#define CAM_ISP_CTX_REQ_MAX 8 /* * Maximum configuration entry size - This is based on the * worst case DUAL IFE use case plus some margin. @@ -261,8 +263,8 @@ struct cam_isp_context { struct cam_ctx_ops *substate_machine; struct cam_isp_ctx_irq_ops *substate_machine_irq; - struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; - struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX]; + struct cam_ctx_request req_base[CAM_ISP_CTX_REQ_MAX]; + struct cam_isp_ctx_req req_isp[CAM_ISP_CTX_REQ_MAX]; void *hw_ctx; uint64_t sof_timestamp_val; -- GitLab From dd0db4d665fb8b5b060161ce7b9c60d904ab7390 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Fri, 12 Jun 2020 12:59:17 +0530 Subject: [PATCH 228/295] msm: camera: isp: Disable compilation of IFE, incase of TFE Added checks to not compile ife files for tfe based and vice-versa. CRs-Fixed: 2721073 Change-Id: I2a3b0ae2c1cce283429034a0edd238e654a806db Signed-off-by: Shravya Samala --- config/bengalcamera.conf | 2 +- config/bengalcameraconf.h | 4 ++-- config/konacamera.conf | 2 +- config/konacameraconf.h | 4 ++-- config/litocamera.conf | 2 +- config/litocameraconf.h | 4 ++-- drivers/Makefile | 2 +- drivers/cam_isp/isp_hw_mgr/Makefile | 10 +++++++++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 8 +++++++- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h | 6 ++++++ drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile | 11 +++++++++-- 11 files changed, 41 insertions(+), 14 deletions(-) diff --git a/config/bengalcamera.conf b/config/bengalcamera.conf index 0db46fd848a4..167e76fba136 100644 --- a/config/bengalcamera.conf +++ b/config/bengalcamera.conf @@ -2,5 +2,5 @@ # Copyright (c) 2019, The Linux Foundation. All rights reserved. export CONFIG_SPECTRA_CAMERA=y -export CONFIG_SPECTRA_CAMERA_ISP=y export CONFIG_SPECTRA_CAMERA_OPE=y +export CONFIG_SPECTRA_CAMERA_TFE=y diff --git a/config/bengalcameraconf.h b/config/bengalcameraconf.h index 126187d99ed3..b4478b5980dd 100644 --- a/config/bengalcameraconf.h +++ b/config/bengalcameraconf.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #define CONFIG_SPECTRA_CAMERA 1 -#define CONFIG_SPECTRA_CAMERA_ISP 1 #define CONFIG_SPECTRA_CAMERA_OPE 1 +#define CONFIG_SPECTRA_CAMERA_TFE 1 diff --git a/config/konacamera.conf b/config/konacamera.conf index 3123906bf37f..a50077b2eb62 100644 --- a/config/konacamera.conf +++ b/config/konacamera.conf @@ -6,5 +6,5 @@ export CONFIG_SPECTRA_CAMERA_CUST=y export CONFIG_SPECTRA_CAMERA_FD=y export CONFIG_SPECTRA_CAMERA_ICP=y export CONFIG_SPECTRA_CAMERA_JPEG=y -export CONFIG_SPECTRA_CAMERA_ISP=y +export CONFIG_SPECTRA_CAMERA_IFE=y export CONFIG_SPECTRA_CAMERA_LRME=y diff --git a/config/konacameraconf.h b/config/konacameraconf.h index 2a753fb9934a..412dfa5d8380 100644 --- a/config/konacameraconf.h +++ b/config/konacameraconf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #define CONFIG_SPECTRA_CAMERA 1 @@ -8,5 +8,5 @@ #define CONFIG_SPECTRA_CAMERA_FD 1 #define CONFIG_SPECTRA_CAMERA_ICP 1 #define CONFIG_SPECTRA_CAMERA_JPEG 1 -#define CONFIG_SPECTRA_CAMERA_ISP 1 +#define CONFIG_SPECTRA_CAMERA_IFE 1 #define CONFIG_SPECTRA_CAMERA_LRME 1 diff --git a/config/litocamera.conf b/config/litocamera.conf index 977636e7897c..dc68ff8bba86 100644 --- a/config/litocamera.conf +++ b/config/litocamera.conf @@ -5,5 +5,5 @@ export CONFIG_SPECTRA_CAMERA=y export CONFIG_SPECTRA_CAMERA_FD=y export CONFIG_SPECTRA_CAMERA_ICP=y export CONFIG_SPECTRA_CAMERA_JPEG=y -export CONFIG_SPECTRA_CAMERA_ISP=y +export CONFIG_SPECTRA_CAMERA_IFE=y export CONFIG_SPECTRA_CAMERA_LRME=y diff --git a/config/litocameraconf.h b/config/litocameraconf.h index 90cacf1b899a..412ff016195c 100644 --- a/config/litocameraconf.h +++ b/config/litocameraconf.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #define CONFIG_SPECTRA_CAMERA 1 #define CONFIG_SPECTRA_CAMERA_FD 1 #define CONFIG_SPECTRA_CAMERA_ICP 1 #define CONFIG_SPECTRA_CAMERA_JPEG 1 -#define CONFIG_SPECTRA_CAMERA_ISP 1 +#define CONFIG_SPECTRA_CAMERA_IFE 1 #define CONFIG_SPECTRA_CAMERA_LRME 1 diff --git a/drivers/Makefile b/drivers/Makefile index cf1e956f5c7b..0004fce1ef9e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpas/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm/ -obj-$(CONFIG_SPECTRA_CAMERA_ISP) += cam_isp/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_module/ obj-$(CONFIG_SPECTRA_CAMERA_ICP) += cam_icp/ obj-$(CONFIG_SPECTRA_CAMERA_JPEG) += cam_jpeg/ diff --git a/drivers/cam_isp/isp_hw_mgr/Makefile b/drivers/cam_isp/isp_hw_mgr/Makefile index b13c4fc1a8fd..52ec0dbe2c35 100644 --- a/drivers/cam_isp/isp_hw_mgr/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/Makefile @@ -14,4 +14,12 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(src) obj-$(CONFIG_SPECTRA_CAMERA) += hw_utils/ isp_hw/ -obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_hw_mgr.o cam_ife_hw_mgr.o cam_tfe_hw_mgr.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_hw_mgr.o + +ifdef CONFIG_SPECTRA_CAMERA_TFE +obj-$(CONFIG_SPECTRA_CAMERA) += cam_tfe_hw_mgr.o +endif + +ifdef CONFIG_SPECTRA_CAMERA_IFE +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ife_hw_mgr.o +endif diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index d508a21f8a0f..10a313748725 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.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 _CAM_IFE_HW_MGR_H_ @@ -196,4 +196,10 @@ struct cam_ife_hw_event_recovery_data { */ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl); +#ifndef CONFIG_SPECTRA_CAMERA_IFE +int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) +{ + return 0; +} +#endif #endif /* _CAM_IFE_HW_MGR_H_ */ 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 b41b38e6d3e3..1904fbb8f3b4 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 @@ -200,4 +200,10 @@ struct cam_tfe_hw_event_recovery_data { */ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl); +#ifndef CONFIG_SPECTRA_CAMERA_TFE +int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) +{ + return 0; +} +#endif #endif /* _CAM_TFE_HW_MGR_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile index 20d61bede674..67cf169a3569 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile @@ -1,4 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_SPECTRA_CAMERA) += ife_csid_hw/ tfe_csid_hw/ top_tpg/ -obj-$(CONFIG_SPECTRA_CAMERA) += vfe_hw/ tfe_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += top_tpg/ + +ifdef CONFIG_SPECTRA_CAMERA_TFE +obj-$(CONFIG_SPECTRA_CAMERA) += tfe_csid_hw/ tfe_hw/ +endif + +ifdef CONFIG_SPECTRA_CAMERA_IFE +obj-$(CONFIG_SPECTRA_CAMERA) += ife_csid_hw/ vfe_hw/ +endif -- GitLab From 9033341cbb318c33675045731a3ce8eea84348dc Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Fri, 12 Jun 2020 11:43:15 +0530 Subject: [PATCH 229/295] msm: camera: isp: Max context reduction for TFE in isp driver Reduced total number of contexts for TFE from 8 to 4. CRs-Fixed: 2720374 Change-Id: I03eed741e5cf72c431d7cc5b7f9a418537d1c6f7 Signed-off-by: Shravya Samala --- drivers/cam_core/cam_node.c | 5 +- drivers/cam_isp/cam_isp_dev.c | 60 ++++++++++++++----- drivers/cam_isp/cam_isp_dev.h | 10 +++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 6 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 4 +- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 6 +- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h | 4 +- .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 6 ++ 8 files changed, 72 insertions(+), 29 deletions(-) diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index 347ca09f9db1..4ad93c7f5537 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -96,8 +96,9 @@ static int __cam_node_handle_acquire_dev(struct cam_node *node, ctx = cam_node_get_ctxt_from_free_list(node); if (!ctx) { - CAM_ERR(CAM_CORE, "No free ctx in free list node %s", - node->name); + CAM_ERR(CAM_CORE, + "No free ctx in free list node %s with size:%d", + node->name, node->ctx_size); cam_node_print_ctx_state(node); rc = -ENOMEM; diff --git a/drivers/cam_isp/cam_isp_dev.c b/drivers/cam_isp/cam_isp_dev.c index 81ae824164ba..99959b8a8329 100644 --- a/drivers/cam_isp/cam_isp_dev.c +++ b/drivers/cam_isp/cam_isp_dev.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 @@ -95,13 +95,17 @@ static int cam_isp_dev_remove(struct platform_device *pdev) int rc = 0; int i; - /* clean up resources */ - for (i = 0; i < CAM_CTX_MAX; i++) { + /* clean up ife/tfe resources */ + for (i = 0; i < g_isp_dev.max_context; i++) { rc = cam_isp_context_deinit(&g_isp_dev.ctx_isp[i]); if (rc) CAM_ERR(CAM_ISP, "ISP context %d deinit failed", - i); + i); } + kfree(g_isp_dev.ctx); + g_isp_dev.ctx = NULL; + kfree(g_isp_dev.ctx_isp); + g_isp_dev.ctx_isp = NULL; rc = cam_subdev_remove(&g_isp_dev.sd); if (rc) @@ -118,7 +122,6 @@ static int cam_isp_dev_probe(struct platform_device *pdev) struct cam_hw_mgr_intf hw_mgr_intf; struct cam_node *node; const char *compat_str = NULL; - uint32_t isp_device_type; int iommu_hdl = -1; @@ -130,11 +133,13 @@ static int cam_isp_dev_probe(struct platform_device *pdev) if (strnstr(compat_str, "ife", strlen(compat_str))) { rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, CAM_IFE_DEVICE_TYPE); - isp_device_type = CAM_IFE_DEVICE_TYPE; + g_isp_dev.isp_device_type = CAM_IFE_DEVICE_TYPE; + g_isp_dev.max_context = CAM_IFE_CTX_MAX; } else if (strnstr(compat_str, "tfe", strlen(compat_str))) { rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, CAM_TFE_DEVICE_TYPE); - isp_device_type = CAM_TFE_DEVICE_TYPE; + g_isp_dev.isp_device_type = CAM_TFE_DEVICE_TYPE; + g_isp_dev.max_context = CAM_TFE_CTX_MAX; } else { CAM_ERR(CAM_ISP, "Invalid ISP hw type %s", compat_str); rc = -EINVAL; @@ -148,30 +153,50 @@ static int cam_isp_dev_probe(struct platform_device *pdev) node = (struct cam_node *) g_isp_dev.sd.token; memset(&hw_mgr_intf, 0, sizeof(hw_mgr_intf)); + g_isp_dev.ctx = kcalloc(g_isp_dev.max_context, + sizeof(struct cam_context), + GFP_KERNEL); + if (!g_isp_dev.ctx) { + CAM_ERR(CAM_ISP, + "Mem Allocation failed for ISP base context"); + goto unregister; + } + + g_isp_dev.ctx_isp = kcalloc(g_isp_dev.max_context, + sizeof(struct cam_isp_context), + GFP_KERNEL); + if (!g_isp_dev.ctx_isp) { + CAM_ERR(CAM_ISP, + "Mem Allocation failed for Isp private context"); + kfree(g_isp_dev.ctx); + g_isp_dev.ctx = NULL; + goto unregister; + } + rc = cam_isp_hw_mgr_init(compat_str, &hw_mgr_intf, &iommu_hdl); if (rc != 0) { CAM_ERR(CAM_ISP, "Can not initialized ISP HW manager!"); - goto unregister; + goto kfree; } - for (i = 0; i < CAM_CTX_MAX; i++) { + for (i = 0; i < g_isp_dev.max_context; i++) { rc = cam_isp_context_init(&g_isp_dev.ctx_isp[i], &g_isp_dev.ctx[i], &node->crm_node_intf, &node->hw_mgr_intf, i, - isp_device_type); + g_isp_dev.isp_device_type); if (rc) { CAM_ERR(CAM_ISP, "ISP context init failed!"); - goto unregister; + goto kfree; } } + rc = cam_node_init(node, &hw_mgr_intf, g_isp_dev.ctx, + g_isp_dev.max_context, CAM_ISP_DEV_NAME); - rc = cam_node_init(node, &hw_mgr_intf, g_isp_dev.ctx, CAM_CTX_MAX, - CAM_ISP_DEV_NAME); if (rc) { CAM_ERR(CAM_ISP, "ISP node init failed!"); - goto unregister; + goto kfree; } cam_smmu_set_client_page_fault_handler(iommu_hdl, @@ -182,6 +207,13 @@ static int cam_isp_dev_probe(struct platform_device *pdev) CAM_INFO(CAM_ISP, "Camera ISP probe complete"); return 0; + +kfree: + kfree(g_isp_dev.ctx); + g_isp_dev.ctx = NULL; + kfree(g_isp_dev.ctx_isp); + g_isp_dev.ctx_isp = NULL; + unregister: rc = cam_subdev_remove(&g_isp_dev.sd); err: diff --git a/drivers/cam_isp/cam_isp_dev.h b/drivers/cam_isp/cam_isp_dev.h index cf9140eb8c88..5ba338f77e6f 100644 --- a/drivers/cam_isp/cam_isp_dev.h +++ b/drivers/cam_isp/cam_isp_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_DEV_H_ @@ -19,13 +19,17 @@ * @ctx_isp: Isp private context storage * @isp_mutex: ISP dev mutex * @open_cnt: Open device count + * @isp_device_type ISP device type + * @max_context maximum contexts for TFE is 4 and for IFE is 8 */ struct cam_isp_dev { struct cam_subdev sd; - struct cam_context ctx[CAM_CTX_MAX]; - struct cam_isp_context ctx_isp[CAM_CTX_MAX]; + struct cam_context *ctx; + struct cam_isp_context *ctx_isp; struct mutex isp_mutex; int32_t open_cnt; + uint32_t isp_device_type; + int32_t max_context; }; #endif /* __CAM_ISP_DEV_H__ */ 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 7dea594f1573..6b0ac2797417 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 @@ -6369,7 +6369,7 @@ static int cam_ife_hw_mgr_find_affected_ctx( /* Add affected_context in list of recovery data */ CAM_DBG(CAM_ISP, "Add affected ctx %d to list", ife_hwr_mgr_ctx->ctx_index); - if (recovery_data->no_of_context < CAM_CTX_MAX) + if (recovery_data->no_of_context < CAM_IFE_CTX_MAX) recovery_data->affected_ctx[ recovery_data->no_of_context++] = ife_hwr_mgr_ctx; @@ -7004,7 +7004,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) } atomic_set(&g_ife_hw_mgr.active_ctx_cnt, 0); - for (i = 0; i < CAM_CTX_MAX; i++) { + for (i = 0; i < CAM_IFE_CTX_MAX; i++) { memset(&g_ife_hw_mgr.ctx_pool[i], 0, sizeof(g_ife_hw_mgr.ctx_pool[i])); INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].list); @@ -7086,7 +7086,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) return 0; end: if (rc) { - for (i = 0; i < CAM_CTX_MAX; i++) { + for (i = 0; i < CAM_IFE_CTX_MAX; i++) { cam_tasklet_deinit( &g_ife_hw_mgr.mgr_common.tasklet_pool[i]); kfree(g_ife_hw_mgr.ctx_pool[i].cdm_cmd); diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 10a313748725..18183cb76bb1 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -159,7 +159,7 @@ struct cam_ife_hw_mgr { atomic_t active_ctx_cnt; struct list_head free_ctx_list; struct list_head used_ctx_list; - struct cam_ife_hw_mgr_ctx ctx_pool[CAM_CTX_MAX]; + struct cam_ife_hw_mgr_ctx ctx_pool[CAM_IFE_CTX_MAX]; struct cam_ife_csid_hw_caps ife_csid_dev_caps[ CAM_IFE_CSID_HW_NUM_MAX]; @@ -180,7 +180,7 @@ struct cam_ife_hw_mgr { struct cam_ife_hw_event_recovery_data { uint32_t error_type; uint32_t affected_core[CAM_ISP_HW_NUM_MAX]; - struct cam_ife_hw_mgr_ctx *affected_ctx[CAM_CTX_MAX]; + struct cam_ife_hw_mgr_ctx *affected_ctx[CAM_IFE_CTX_MAX]; uint32_t no_of_context; }; 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 e7f0cb782b43..dcdfeff17458 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 @@ -4910,7 +4910,7 @@ static int cam_tfe_hw_mgr_find_affected_ctx( /* Add affected_context in list of recovery data */ CAM_DBG(CAM_ISP, "Add affected ctx %d to list", tfe_hwr_mgr_ctx->ctx_index); - if (recovery_data->no_of_context < CAM_CTX_MAX) + if (recovery_data->no_of_context < CAM_TFE_CTX_MAX) recovery_data->affected_ctx[ recovery_data->no_of_context++] = tfe_hwr_mgr_ctx; @@ -5562,7 +5562,7 @@ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) } atomic_set(&g_tfe_hw_mgr.active_ctx_cnt, 0); - for (i = 0; i < CAM_CTX_MAX; i++) { + for (i = 0; i < CAM_TFE_CTX_MAX; i++) { memset(&g_tfe_hw_mgr.ctx_pool[i], 0, sizeof(g_tfe_hw_mgr.ctx_pool[i])); INIT_LIST_HEAD(&g_tfe_hw_mgr.ctx_pool[i].list); @@ -5640,7 +5640,7 @@ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) return 0; end: if (rc) { - for (i = 0; i < CAM_CTX_MAX; i++) { + for (i = 0; i < CAM_TFE_CTX_MAX; i++) { cam_tasklet_deinit( &g_tfe_hw_mgr.mgr_common.tasklet_pool[i]); kfree(g_tfe_hw_mgr.ctx_pool[i].cdm_cmd); 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 1904fbb8f3b4..d8205cd9097a 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 @@ -163,7 +163,7 @@ struct cam_tfe_hw_mgr { atomic_t active_ctx_cnt; struct list_head free_ctx_list; struct list_head used_ctx_list; - struct cam_tfe_hw_mgr_ctx ctx_pool[CAM_CTX_MAX]; + struct cam_tfe_hw_mgr_ctx ctx_pool[CAM_TFE_CTX_MAX]; struct cam_tfe_csid_hw_caps tfe_csid_dev_caps[ CAM_TFE_CSID_HW_NUM_MAX]; @@ -184,7 +184,7 @@ struct cam_tfe_hw_mgr { struct cam_tfe_hw_event_recovery_data { uint32_t error_type; uint32_t affected_core[CAM_TFE_HW_NUM_MAX]; - struct cam_tfe_hw_mgr_ctx *affected_ctx[CAM_CTX_MAX]; + struct cam_tfe_hw_mgr_ctx *affected_ctx[CAM_TFE_CTX_MAX]; uint32_t no_of_context; }; diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 5eab896e613e..4ad63a7a0a8c 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -20,6 +20,12 @@ #define CAM_TFE_HW_NUM_MAX 3 #define CAM_TFE_RDI_NUM_MAX 3 +/* maximum context numbers for TFE */ +#define CAM_TFE_CTX_MAX 4 + +/* maximum context numbers for IFE */ +#define CAM_IFE_CTX_MAX 8 + /* Appliacble vote paths for dual ife, based on no. of UAPI definitions */ #define CAM_ISP_MAX_PER_PATH_VOTES 30 /** -- GitLab From bcea7d87c3d5776a6530cebc996f6c118d9c999b Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Thu, 9 Jul 2020 15:43:14 +0530 Subject: [PATCH 230/295] msm: camera: cpas: Add api to log cpas bw, camnoc clock, ahb vote Debug changes for bus overflow issues. In many error cases it is required to know the bandwidth applied on axi ports and camnoc axi clock rate values. Added cpas api to print the current axi bus votes, camnoc axi clock and ahb vote level. This api can be called for isp errors such as bus overflow, pxl overflow cases. CRs-Fixed: 2731550 Change-Id: I75454c131cce7204b50614703f9914482f3ca7ab Signed-off-by: Shravya Samala --- drivers/cam_cpas/cam_cpas_hw.c | 77 +++++++++++++++++-- drivers/cam_cpas/cam_cpas_hw.h | 6 ++ drivers/cam_cpas/cam_cpas_hw_intf.h | 3 +- drivers/cam_cpas/cam_cpas_intf.c | 24 ++++++ drivers/cam_cpas/include/cam_cpas_api.h | 10 +++ .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 5 +- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 2 +- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 3 +- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 1 + 9 files changed, 120 insertions(+), 11 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 0258f5488e1c..c2c7f07f0734 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -83,7 +83,7 @@ static int cam_cpas_util_vote_bus_client_level( static int cam_cpas_util_vote_bus_client_bw( struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib, - bool camnoc_bw) + bool camnoc_bw, uint64_t *applied_ab, uint64_t *applied_ib) { struct msm_bus_paths *path; struct msm_bus_scale_pdata *pdata; @@ -146,6 +146,10 @@ static int cam_cpas_util_vote_bus_client_bw( CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]", bus_client->client_id, bus_client->name, ab, ib, idx); msm_bus_scale_client_update_request(bus_client->client_id, idx); + if (applied_ab) + *applied_ab = ab; + if (applied_ib) + *applied_ib = ib; return 0; } @@ -221,7 +225,8 @@ static int cam_cpas_util_unregister_bus_client( return -EINVAL; if (bus_client->dyn_vote) - cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false); + cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false, + NULL, NULL); else cam_cpas_util_vote_bus_client_level(bus_client, 0); @@ -309,6 +314,7 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, int rc, i = 0; struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info; uint64_t ab_bw, ib_bw; + uint64_t applied_ab_bw = 0, applied_ib_bw = 0; rc = cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client, (enable == true) ? CAM_SVS_VOTE : CAM_SUSPEND_VOTE); @@ -329,13 +335,15 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, for (i = 0; i < cpas_core->num_axi_ports; i++) { rc = cam_cpas_util_vote_bus_client_bw( &cpas_core->axi_port[i].bus_client, - ab_bw, ib_bw, false); + ab_bw, ib_bw, false, &applied_ab_bw, &applied_ib_bw); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote, enable=%d, rc=%d", enable, rc); goto remove_ahb_vote; } + cpas_core->axi_port[i].applied_ab_bw = applied_ab_bw; + cpas_core->axi_port[i].applied_ib_bw = applied_ib_bw; } return 0; @@ -494,6 +502,8 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %lld %d", required_camnoc_bw, clk_rate, rc); + + cpas_core->applied_camnoc_axi_rate = clk_rate; } } @@ -675,6 +685,7 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( int rc = 0; struct cam_cpas_axi_port *camnoc_axi_port = NULL; uint64_t camnoc_bw; + uint64_t applied_ab = 0, applied_ib = 0; if (soc_private->control_camnoc_axi_clk) { rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); @@ -711,7 +722,7 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( rc = cam_cpas_util_vote_bus_client_bw( &camnoc_axi_port->bus_client, - 0, camnoc_bw, true); + 0, camnoc_bw, true, &applied_ab, &applied_ib); CAM_DBG(CAM_CPAS, "camnoc vote camnoc_bw[%llu] rc=%d %s", @@ -722,6 +733,8 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( camnoc_bw, rc); break; } + camnoc_axi_port->applied_ab_bw = applied_ab; + camnoc_axi_port->applied_ib_bw = applied_ib; } return rc; } @@ -744,6 +757,7 @@ static int cam_cpas_util_apply_client_axi_vote( curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; int rc = 0, i = 0; + uint64_t applied_ab = 0, applied_ib = 0; mutex_lock(&cpas_core->tree_lock); if (!cpas_client->tree_node_valid) { @@ -899,13 +913,16 @@ static int cam_cpas_util_apply_client_axi_vote( rc = cam_cpas_util_vote_bus_client_bw( &mnoc_axi_port->bus_client, - mnoc_ab_bw, mnoc_ib_bw, false); + mnoc_ab_bw, mnoc_ib_bw, false, &applied_ab, + &applied_ib); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", mnoc_ab_bw, mnoc_ib_bw, rc); goto unlock_tree; } + mnoc_axi_port->applied_ab_bw = applied_ab; + mnoc_axi_port->applied_ib_bw = applied_ib; } rc = cam_cpas_camnoc_set_vote_axi_clk_rate( cpas_hw, camnoc_axi_port_updated); @@ -923,6 +940,7 @@ static int cam_cpas_util_apply_default_axi_vote( struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_cpas_axi_port *axi_port = NULL; uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0; + uint64_t applied_ab_bw = 0, applied_ib_bw = 0; int rc = 0, i = 0; mutex_lock(&cpas_core->tree_lock); @@ -942,13 +960,16 @@ static int cam_cpas_util_apply_default_axi_vote( axi_port->axi_port_name, mnoc_ab_bw, mnoc_ib_bw); rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, - mnoc_ab_bw, mnoc_ib_bw, false); + mnoc_ab_bw, mnoc_ib_bw, false, &applied_ab_bw, + &applied_ib_bw); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", mnoc_ab_bw, mnoc_ib_bw, rc); goto unlock_tree; } + cpas_core->axi_port[i].applied_ab_bw = applied_ab_bw; + cpas_core->axi_port[i].applied_ib_bw = applied_ib_bw; } unlock_tree: @@ -1739,6 +1760,46 @@ static int cam_cpas_hw_get_hw_info(void *hw_priv, return 0; } +static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + int rc = 0; + uint32_t i; + + for (i = 0; i < cpas_core->num_axi_ports; i++) { + CAM_INFO(CAM_CPAS, + "[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]", + cpas_core->axi_port[i].axi_port_name, + cpas_core->axi_port[i].ab_bw, + cpas_core->axi_port[i].ib_bw, + cpas_core->axi_port[i].additional_bw, + cpas_core->axi_port[i].applied_ab_bw, + cpas_core->axi_port[i].applied_ib_bw); + } + + if (soc_private->control_camnoc_axi_clk) { + CAM_INFO(CAM_CPAS, "applied camnoc axi clk[%lld]", + cpas_core->applied_camnoc_axi_rate); + } else { + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + CAM_INFO(CAM_CPAS, + "[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]", + cpas_core->camnoc_axi_port[i].axi_port_name, + cpas_core->camnoc_axi_port[i].ab_bw, + cpas_core->camnoc_axi_port[i].ib_bw, + cpas_core->camnoc_axi_port[i].additional_bw, + cpas_core->camnoc_axi_port[i].applied_ab_bw, + cpas_core->camnoc_axi_port[i].applied_ib_bw); + } + } + + CAM_INFO(CAM_CPAS, "ahb client curr vote level[%d]", + cpas_core->ahb_bus_client.curr_vote_level); + + return rc; +} static int cam_cpas_hw_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -1842,6 +1903,10 @@ static int cam_cpas_hw_process_cmd(void *hw_priv, cmd_axi_vote->client_handle, cmd_axi_vote->axi_vote); break; } + case CAM_CPAS_HW_CMD_LOG_VOTE: { + rc = cam_cpas_log_vote(hw_priv); + break; + } default: CAM_ERR(CAM_CPAS, "CPAS HW command not valid =%d", cmd_type); break; diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index cfa7dfbb69b2..acad4ba44b17 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -155,6 +155,8 @@ struct cam_cpas_bus_client { * @ib_bw: IB bw value for this port * @camnoc_bw: CAMNOC bw value for this port * @additional_bw: Additional bandwidth to cover non-hw cpas clients + * @applied_ab_bw: applied ab bw for this port + * @applied_ib_bw: applied ib bw for this port */ struct cam_cpas_axi_port { const char *axi_port_name; @@ -165,6 +167,8 @@ struct cam_cpas_axi_port { uint64_t ib_bw; uint64_t camnoc_bw; uint64_t additional_bw; + uint64_t applied_ab_bw; + uint64_t applied_ib_bw; }; /** @@ -189,6 +193,7 @@ struct cam_cpas_axi_port { * @irq_count_wq: wait variable to ensure all irq's are handled * @dentry: debugfs file entry * @ahb_bus_scaling_disable: ahb scaling based on src clk corner for bus + * @applied_camnoc_axi_rate: applied camnoc axi clock rate */ struct cam_cpas { struct cam_cpas_hw_caps hw_caps; @@ -210,6 +215,7 @@ struct cam_cpas { wait_queue_head_t irq_count_wq; struct dentry *dentry; bool ahb_bus_scaling_disable; + uint64_t applied_camnoc_axi_rate; }; int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); diff --git a/drivers/cam_cpas/cam_cpas_hw_intf.h b/drivers/cam_cpas/cam_cpas_hw_intf.h index 0926e6e3d8d1..3f644363062c 100644 --- a/drivers/cam_cpas/cam_cpas_hw_intf.h +++ b/drivers/cam_cpas/cam_cpas_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_HW_INTF_H_ @@ -38,6 +38,7 @@ enum cam_cpas_hw_cmd_process { CAM_CPAS_HW_CMD_REG_READ, CAM_CPAS_HW_CMD_AHB_VOTE, CAM_CPAS_HW_CMD_AXI_VOTE, + CAM_CPAS_HW_CMD_LOG_VOTE, CAM_CPAS_HW_CMD_INVALID, }; diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index 9a26d4ff1b2c..ce649c06b329 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -413,6 +413,30 @@ int cam_cpas_start(uint32_t client_handle, } EXPORT_SYMBOL(cam_cpas_start); +void cam_cpas_log_votes(void) +{ + uint32_t dummy_args; + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_LOG_VOTE, &dummy_args, + sizeof(dummy_args)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + } + +} +EXPORT_SYMBOL(cam_cpas_log_votes); + int cam_cpas_unregister_client(uint32_t client_handle) { int rc; diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index cd844d13f161..9dd3be1ff0d6 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -569,5 +569,15 @@ const char *cam_cpas_axi_util_path_type_to_string( const char *cam_cpas_axi_util_trans_type_to_string( uint32_t path_data_type); +/** + * cam_cpas_log_votes() + * + * @brief: API to print the all bw votes of axi client. It also print the + * applied camnoc axi clock vote value and ahb vote value + * + * @return 0 on success. + * + */ +void cam_cpas_log_votes(void); #endif /* _CAM_CPAS_API_H_ */ 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 7de58cdf5c80..97282ede31c3 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 @@ -2854,14 +2854,15 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) 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 %d irq status TOP: 0x%x RX: 0x%x IPP: 0x%x RDI0: 0x%x RDI1: 0x%x RDI2: 0x%x CSID clk:%d", 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]); + irq_status[TFE_CSID_IRQ_REG_RDI2], + csid_hw->clk_rate); 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); 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 4ce7511a0c97..2eb42ce2673d 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 @@ -438,7 +438,7 @@ static void cam_tfe_log_error_irq_status( "TFE clock rate:%d TFE total bw applied:%lld", top_priv->hw_clk_rate, top_priv->total_bw_applied); - + cam_cpas_log_votes(); } static int cam_tfe_error_irq_bottom_half( diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index bfb17d2145f8..e0032b7b5b53 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -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. */ #include @@ -888,6 +888,7 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", val0, val1, val2); + cam_cpas_log_votes(); } if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index e4187935b2b0..12cc394d51b3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -916,6 +916,7 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", val0, val1, val2); + cam_cpas_log_votes(); return; } -- GitLab From 5db11533388afbb521bbd485f8d26156191f54ee Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Tue, 28 Apr 2020 17:48:25 +0530 Subject: [PATCH 231/295] msm: camera: isp: Added CSID recovery mechanism CSID is not able to recover from the fatal errors like lane overflows, continuous unbound frames and ESD errors. To recover from such errors, it is necessary to restart the sensor as just starting the ISP hw do not make any change as the sensor can still be in bad state. This commit implements tasklet based CSID recovery mechanism. On detecting an error in CSID interrupt, tasklet is scheduled which in turn will call the ISP hw manager to notify the ISP context, from here a notification is sent to CRM to send a message to trigger full recovery. This full recovery includes the sensor release and start. This feature is debugfs based. Based on need this can be turned on. CRs-Fixed: 2674109 Change-Id: I7e4612e9bd24a20691146ae0b9dc6f77ccbc0714 Signed-off-by: Shravya Samala --- drivers/cam_isp/cam_isp_context.c | 10 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 67 ++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 4 + drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 67 ++- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h | 4 + .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 1 + .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 448 ++++++++++++++---- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 50 +- .../isp_hw/include/cam_ife_csid_hw_intf.h | 6 +- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 210 ++++++++ .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.h | 26 + include/uapi/media/cam_req_mgr.h | 2 + 12 files changed, 801 insertions(+), 94 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 034e80e99169..1e772dedc24f 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1818,8 +1818,14 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, if (notify.error == CRM_KMD_ERR_FATAL) { req_msg.session_hdl = ctx_isp->base->session_hdl; req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl; - req_msg.u.err_msg.error_type = - CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + + if (error_type == CAM_ISP_HW_ERROR_CSID_FATAL) + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY; + else + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + req_msg.u.err_msg.link_hdl = ctx_isp->base->link_hdl; req_msg.u.err_msg.request_id = error_request_id; req_msg.u.err_msg.resource_size = 0x0; 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 6b0ac2797417..c822b22a7918 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 @@ -1918,6 +1918,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( csid_acquire.in_port = in_port; csid_acquire.out_port = in_port->data; csid_acquire.node_res = NULL; + csid_acquire.event_cb = cam_ife_hw_mgr_event_handler; + csid_acquire.priv = ife_ctx; csid_acquire.crop_enable = crop_enable; csid_acquire.drop_enable = false; @@ -2046,6 +2048,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( csid_acquire.in_port = in_port; csid_acquire.out_port = out_port; csid_acquire.node_res = NULL; + csid_acquire.event_cb = cam_ife_hw_mgr_event_handler; + csid_acquire.priv = ife_ctx; /* * Enable RDI pixel drop by default. CSID will enable only for @@ -6363,6 +6367,12 @@ static int cam_ife_hw_mgr_find_affected_ctx( affected_core, CAM_IFE_HW_NUM_MAX)) continue; + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) { + CAM_INFO(CAM_ISP, "CTX:%d already error reported", + ife_hwr_mgr_ctx->ctx_index); + continue; + } + atomic_set(&ife_hwr_mgr_ctx->overflow_pending, 1); notify_err_cb = ife_hwr_mgr_ctx->common.event_cb[event_type]; @@ -6378,8 +6388,13 @@ static int cam_ife_hw_mgr_find_affected_ctx( * In the call back function corresponding ISP context * will update CRM about fatal Error */ - notify_err_cb(ife_hwr_mgr_ctx->common.cb_priv, - CAM_ISP_HW_EVENT_ERROR, error_event_data); + if (notify_err_cb) { + notify_err_cb(ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_ERROR, error_event_data); + } else { + CAM_WARN(CAM_ISP, "Error call back is not set"); + goto end; + } } /* fill the affected_core in recovery data */ @@ -6388,7 +6403,34 @@ static int cam_ife_hw_mgr_find_affected_ctx( CAM_DBG(CAM_ISP, "Vfe core %d is affected (%d)", i, recovery_data->affected_core[i]); } +end: + return 0; +} + +static int cam_ife_hw_mgr_handle_csid_event( + struct cam_isp_hw_event_info *event_info) +{ + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_ife_hw_event_recovery_data recovery_data = {0}; + + /* this can be extended based on the types of error + * received from CSID + */ + switch (event_info->err_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: { + + if (!g_ife_hw_mgr.debug_cfg.enable_csid_recovery) + break; + error_event_data.error_type = event_info->err_type; + cam_ife_hw_mgr_find_affected_ctx(&error_event_data, + event_info->hw_idx, + &recovery_data); + break; + } + default: + break; + } return 0; } @@ -6408,6 +6450,13 @@ static int cam_ife_hw_mgr_handle_hw_err( else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT) error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + spin_lock(&g_ife_hw_mgr.ctx_lock); + if (event_info->err_type == CAM_ISP_HW_ERROR_CSID_FATAL) { + rc = cam_ife_hw_mgr_handle_csid_event(event_info); + spin_unlock(&g_ife_hw_mgr.ctx_lock); + return rc; + } + core_idx = event_info->hw_idx; if (g_ife_hw_mgr.debug_cfg.enable_recovery) @@ -6418,6 +6467,8 @@ static int cam_ife_hw_mgr_handle_hw_err( rc = cam_ife_hw_mgr_find_affected_ctx(&error_event_data, core_idx, &recovery_data); + if (rc || !(recovery_data.no_of_context)) + goto end; if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; @@ -6425,7 +6476,8 @@ static int cam_ife_hw_mgr_handle_hw_err( recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; cam_ife_hw_mgr_do_error_recovery(&recovery_data); - +end: + spin_unlock(&g_ife_hw_mgr.ctx_lock); return rc; } @@ -6875,6 +6927,14 @@ static int cam_ife_hw_mgr_debug_register(void) goto err; } + if (!debugfs_create_u32("enable_csid_recovery", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.enable_csid_recovery)) { + CAM_ERR(CAM_ISP, "failed to create enable_csid_recovery"); + goto err; + } + if (!debugfs_create_bool("enable_req_dump", 0644, g_ife_hw_mgr.debug_cfg.dentry, @@ -6921,6 +6981,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr)); mutex_init(&g_ife_hw_mgr.ctx_mutex); + spin_lock_init(&g_ife_hw_mgr.ctx_lock); if (CAM_IFE_HW_NUM_MAX != CAM_IFE_CSID_HW_NUM_MAX) { CAM_ERR(CAM_ISP, "CSID num is different then IFE num"); diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 18183cb76bb1..63ac13323a41 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -24,6 +24,7 @@ * @dentry: Debugfs entry * @csid_debug: csid debug information * @enable_recovery: enable recovery + * @enable_csid_recovery: enable csid recovery * @enable_diag_sensor_status: enable sensor diagnosis status * @enable_req_dump: Enable request dump on HW errors * @per_req_reg_dump: Enable per request reg dump @@ -33,6 +34,7 @@ struct cam_ife_hw_mgr_debug { struct dentry *dentry; uint64_t csid_debug; uint32_t enable_recovery; + uint32_t enable_csid_recovery; uint32_t camif_debug; bool enable_req_dump; bool per_req_reg_dump; @@ -148,6 +150,7 @@ struct cam_ife_hw_mgr_ctx { * @ife_dev_caps ife device capability per core * @work q work queue for IFE hw manager * @debug_cfg debug configuration + * @ctx_lock Spinlock for HW manager */ struct cam_ife_hw_mgr { struct cam_isp_hw_mgr mgr_common; @@ -166,6 +169,7 @@ struct cam_ife_hw_mgr { struct cam_vfe_hw_get_hw_cap ife_dev_caps[CAM_IFE_HW_NUM_MAX]; struct cam_req_mgr_core_workq *workq; struct cam_ife_hw_mgr_debug debug_cfg; + spinlock_t ctx_lock; }; /** 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 dcdfeff17458..db9a93ced4e5 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 @@ -1458,6 +1458,8 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_rdi( csid_acquire.out_port = out_port; csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; csid_acquire.node_res = NULL; + csid_acquire.event_cb = cam_tfe_hw_mgr_event_handler; + csid_acquire.event_cb_prv = tfe_ctx; if (tfe_ctx->is_tpg) { if (tfe_ctx->res_list_tpg.hw_res[0]->hw_intf->hw_idx == @@ -4904,6 +4906,12 @@ static int cam_tfe_hw_mgr_find_affected_ctx( affected_core, CAM_TFE_HW_NUM_MAX)) continue; + if (atomic_read(&tfe_hwr_mgr_ctx->overflow_pending)) { + CAM_INFO(CAM_ISP, "CTX:%d already error reported", + tfe_hwr_mgr_ctx->ctx_index); + continue; + } + atomic_set(&tfe_hwr_mgr_ctx->overflow_pending, 1); notify_err_cb = tfe_hwr_mgr_ctx->common.event_cb[event_type]; @@ -4919,8 +4927,13 @@ static int cam_tfe_hw_mgr_find_affected_ctx( * In the call back function corresponding ISP context * will update CRM about fatal Error */ - notify_err_cb(tfe_hwr_mgr_ctx->common.cb_priv, + if (notify_err_cb) { + notify_err_cb(tfe_hwr_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_ERROR, error_event_data); + } else { + CAM_WARN(CAM_ISP, "Error call back is not set"); + goto end; + } } /* fill the affected_core in recovery data */ @@ -4929,7 +4942,34 @@ static int cam_tfe_hw_mgr_find_affected_ctx( CAM_DBG(CAM_ISP, "tfe core %d is affected (%d)", i, recovery_data->affected_core[i]); } +end: + return 0; +} + +static int cam_tfe_hw_mgr_handle_csid_event( + struct cam_isp_hw_event_info *event_info) +{ + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_tfe_hw_event_recovery_data recovery_data = {0}; + + /* this can be extended based on the types of error + * received from CSID + */ + switch (event_info->err_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: { + + if (!g_tfe_hw_mgr.debug_cfg.enable_csid_recovery) + break; + error_event_data.error_type = event_info->err_type; + cam_tfe_hw_mgr_find_affected_ctx(&error_event_data, + event_info->hw_idx, + &recovery_data); + break; + } + default: + break; + } return 0; } @@ -4950,6 +4990,13 @@ static int cam_tfe_hw_mgr_handle_hw_err( else if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT) error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + spin_lock(&g_tfe_hw_mgr.ctx_lock); + if (event_info->err_type == CAM_ISP_HW_ERROR_CSID_FATAL) { + rc = cam_tfe_hw_mgr_handle_csid_event(event_info); + spin_unlock(&g_tfe_hw_mgr.ctx_lock); + return rc; + } + core_idx = event_info->hw_idx; if (g_tfe_hw_mgr.debug_cfg.enable_recovery) @@ -4959,9 +5006,13 @@ static int cam_tfe_hw_mgr_handle_hw_err( rc = cam_tfe_hw_mgr_find_affected_ctx(&error_event_data, core_idx, &recovery_data); + if (rc || !(recovery_data.no_of_context)) + goto end; - if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT) + if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT) { + spin_unlock(&g_tfe_hw_mgr.ctx_lock); return rc; + } if (g_tfe_hw_mgr.debug_cfg.enable_recovery) { /* Trigger for recovery */ @@ -4974,7 +5025,8 @@ static int cam_tfe_hw_mgr_handle_hw_err( CAM_DBG(CAM_ISP, "recovery is not enabled"); rc = 0; } - +end: + spin_unlock(&g_tfe_hw_mgr.ctx_lock); return rc; } @@ -5422,6 +5474,14 @@ static int cam_tfe_hw_mgr_debug_register(void) goto err; } + if (!debugfs_create_u32("enable_csid_recovery", + 0644, + g_tfe_hw_mgr.debug_cfg.dentry, + &g_tfe_hw_mgr.debug_cfg.enable_csid_recovery)) { + CAM_ERR(CAM_ISP, "failed to create enable_csid_recovery"); + goto err; + } + if (!debugfs_create_u32("enable_reg_dump", 0644, g_tfe_hw_mgr.debug_cfg.dentry, @@ -5469,6 +5529,7 @@ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) memset(&g_tfe_hw_mgr, 0, sizeof(g_tfe_hw_mgr)); mutex_init(&g_tfe_hw_mgr.ctx_mutex); + spin_lock_init(&g_tfe_hw_mgr.ctx_lock); if (CAM_TFE_HW_NUM_MAX != CAM_TFE_CSID_HW_NUM_MAX) { CAM_ERR(CAM_ISP, "CSID num is different then TFE num"); 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 d8205cd9097a..7b3d62b92c6a 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 @@ -28,6 +28,7 @@ * @dentry: Debugfs entry * @csid_debug: csid debug information * @enable_recovery: enable recovery + * @enable_csid_recovery: enable csid recovery * @camif_debug: enable sensor diagnosis status * @enable_reg_dump: enable reg dump on error; * @per_req_reg_dump: Enable per request reg dump @@ -37,6 +38,7 @@ struct cam_tfe_hw_mgr_debug { struct dentry *dentry; uint64_t csid_debug; uint32_t enable_recovery; + uint32_t enable_csid_recovery; uint32_t camif_debug; uint32_t enable_reg_dump; uint32_t per_req_reg_dump; @@ -152,6 +154,7 @@ struct cam_tfe_hw_mgr_ctx { * @tfe_dev_caps tfe device capability per core * @work q work queue for TFE hw manager * @debug_cfg debug configuration + * @ctx_lock Spinlock for HW manager */ struct cam_tfe_hw_mgr { struct cam_isp_hw_mgr mgr_common; @@ -170,6 +173,7 @@ struct cam_tfe_hw_mgr { struct cam_tfe_hw_get_hw_cap tfe_dev_caps[CAM_TFE_HW_NUM_MAX]; struct cam_req_mgr_core_workq *workq; struct cam_tfe_hw_mgr_debug debug_cfg; + spinlock_t ctx_lock; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 4ad63a7a0a8c..7b2bea80ffc8 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -52,6 +52,7 @@ enum cam_isp_hw_err_type { CAM_ISP_HW_ERROR_P2I_ERROR, CAM_ISP_HW_ERROR_VIOLATION, CAM_ISP_HW_ERROR_BUSIF_OVERFLOW, + CAM_ISP_HW_ERROR_CSID_FATAL, CAM_ISP_HW_ERROR_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 02bbe73925de..0da6d5117e27 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -10,6 +10,7 @@ #include #include +#include "cam_isp_hw_mgr_intf.h" #include "cam_ife_csid_core.h" #include "cam_isp_hw.h" #include "cam_soc_util.h" @@ -17,6 +18,7 @@ #include "cam_debug_util.h" #include "cam_cpas_api.h" #include "cam_subdev.h" +#include "cam_tasklet_util.h" /* Timeout value in msec */ #define IFE_CSID_TIMEOUT 1000 @@ -1168,6 +1170,8 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->hw_intf->hw_idx, reserve->res_id, path_data->width, path_data->height); reserve->node_res = res; + csid_hw->event_cb = reserve->event_cb; + csid_hw->priv = reserve->priv; end: return rc; @@ -1266,8 +1270,10 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) csid_hw->hw_intf->hw_idx, val); spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->fatal_err_detected = false; csid_hw->device_enabled = 1; spin_unlock_irqrestore(&csid_hw->lock_state, flags); + cam_tasklet_start(csid_hw->tasklet); return 0; @@ -1319,6 +1325,7 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", csid_hw->hw_intf->hw_idx); + cam_tasklet_stop(csid_hw->tasklet); spin_lock_irqsave(&csid_hw->lock_state, flags); csid_hw->device_enabled = 0; spin_unlock_irqrestore(&csid_hw->lock_state, flags); @@ -3163,6 +3170,8 @@ int cam_ife_csid_release(void *hw_priv, res = (struct cam_isp_resource_node *)release_args; mutex_lock(&csid_hw->hw_info->hw_mutex); + csid_hw->event_cb = NULL; + csid_hw->priv = NULL; if ((res->res_type == CAM_ISP_RESOURCE_CID && res->res_id >= CAM_IFE_CSID_CID_MAX) || (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && @@ -3876,16 +3885,209 @@ static int cam_ife_csid_process_cmd(void *hw_priv, } +static int cam_csid_get_evt_payload( + struct cam_ife_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + + spin_lock(&csid_hw->lock_state); + + if (list_empty(&csid_hw->free_payload_list)) { + *evt_payload = NULL; + spin_unlock(&csid_hw->lock_state); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return -ENOMEM; + } + + *evt_payload = list_first_entry(&csid_hw->free_payload_list, + struct cam_csid_evt_payload, list); + list_del_init(&(*evt_payload)->list); + spin_unlock(&csid_hw->lock_state); + + return 0; +} + +static int cam_csid_put_evt_payload( + struct cam_ife_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + unsigned long flags; + + if (*evt_payload == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid payload core %d", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + spin_lock_irqsave(&csid_hw->lock_state, flags); + list_add_tail(&(*evt_payload)->list, + &csid_hw->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + + return 0; +} +static char *cam_csid_status_to_str(uint32_t status) +{ + switch (status) { + case CAM_IFE_CSID_IRQ_REG_TOP: + return "TOP"; + case CAM_IFE_CSID_IRQ_REG_RX: + return "RX"; + case CAM_IFE_CSID_IRQ_REG_IPP: + return "IPP"; + case CAM_IFE_CSID_IRQ_REG_PPP: + return "PPP"; + case CAM_IFE_CSID_IRQ_REG_RDI_0: + return "RDI0"; + case CAM_IFE_CSID_IRQ_REG_RDI_1: + return "RDI1"; + case CAM_IFE_CSID_IRQ_REG_RDI_2: + return "RDI2"; + case CAM_IFE_CSID_IRQ_REG_RDI_3: + return "RDI3"; + case CAM_IFE_CSID_IRQ_REG_UDI_0: + return "UDI0"; + case CAM_IFE_CSID_IRQ_REG_UDI_1: + return "UDI1"; + case CAM_IFE_CSID_IRQ_REG_UDI_2: + return "UDI2"; + default: + return "Invalid IRQ"; + } +} + +static int cam_csid_evt_bottom_half_handler( + void *handler_priv, + void *evt_payload_priv) +{ + struct cam_ife_csid_hw *csid_hw; + struct cam_csid_evt_payload *evt_payload; + int i; + int rc = 0; + struct cam_isp_hw_event_info event_info; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, + "Invalid Param handler_priv %pK evt_payload_priv %pK", + handler_priv, evt_payload_priv); + return 0; + } + + csid_hw = (struct cam_ife_csid_hw *)handler_priv; + evt_payload = (struct cam_csid_evt_payload *)evt_payload_priv; + + if (!csid_hw->event_cb || !csid_hw->priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d Invalid args %pK %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->event_cb, + csid_hw->priv); + goto end; + } + + if (csid_hw->priv != evt_payload->priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d priv mismatch %pK, %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->priv, + evt_payload->priv); + goto end; + } + + CAM_ERR_RATE_LIMIT(CAM_ISP, "idx %d err %d phy %d cnt %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type, + csid_hw->csi2_rx_cfg.phy_sel, + csid_hw->csi2_cfg_cnt); + + for (i = 0; i < CAM_IFE_CSID_IRQ_REG_MAX; i++) + CAM_ERR_RATE_LIMIT(CAM_ISP, "status %s: %x", + cam_csid_status_to_str(i), + evt_payload->irq_status[i]); + + /* this hunk can be extended to handle more cases + * which we want to offload to bottom half from + * irq handlers + */ + event_info.err_type = evt_payload->evt_type; + event_info.hw_idx = evt_payload->hw_idx; + + switch (evt_payload->evt_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: + if (csid_hw->fatal_err_detected) + break; + csid_hw->fatal_err_detected = true; + rc = csid_hw->event_cb(NULL, + CAM_ISP_HW_EVENT_ERROR, (void *)&event_info); + break; + + default: + CAM_DBG(CAM_ISP, "CSID[%d] invalid error type %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type); + break; + } +end: + cam_csid_put_evt_payload(csid_hw, &evt_payload); + return 0; +} + +static int cam_csid_handle_hw_err_irq( + struct cam_ife_csid_hw *csid_hw, + int evt_type, + uint32_t *irq_status) +{ + int rc = 0; + int i; + void *bh_cmd = NULL; + struct cam_csid_evt_payload *evt_payload; + + CAM_DBG(CAM_ISP, "CSID[%d] error %d", + csid_hw->hw_intf->hw_idx, evt_type); + + rc = cam_csid_get_evt_payload(csid_hw, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return rc; + } + + rc = tasklet_bh_api.get_bh_payload_func(csid_hw->tasklet, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID[%d] Can not get cmd for tasklet, evt_type %d", + csid_hw->hw_intf->hw_idx, + evt_type); + cam_csid_put_evt_payload(csid_hw, &evt_payload); + return rc; + } + + evt_payload->evt_type = evt_type; + evt_payload->priv = csid_hw->priv; + evt_payload->hw_idx = csid_hw->hw_intf->hw_idx; + + for (i = 0; i < CAM_IFE_CSID_IRQ_REG_MAX; i++) + evt_payload->irq_status[i] = irq_status[i]; + + tasklet_bh_api.bottom_half_enqueue_func(csid_hw->tasklet, + bh_cmd, + csid_hw, + evt_payload, + cam_csid_evt_bottom_half_handler); + + return rc; +} + irqreturn_t cam_ife_csid_irq(int irq_num, void *data) { struct cam_ife_csid_hw *csid_hw; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; - uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; - uint32_t irq_status_rdi[CAM_IFE_CSID_RDI_MAX] = {0, 0, 0, 0}; - uint32_t irq_status_udi[CAM_IFE_CSID_UDI_MAX] = {0, 0, 0}; - uint32_t val, irq_status_ppp = 0; + uint32_t i, val; + uint32_t irq_status[CAM_IFE_CSID_IRQ_REG_MAX] = {0}; bool fatal_err_detected = false; uint32_t sof_irq_debug_en = 0; unsigned long flags; @@ -3904,23 +4106,27 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csi2_reg = csid_reg->csi2_reg; /* read */ - irq_status_top = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_TOP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_status_addr); - irq_status_rx = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_RX] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_status_addr); if (csid_reg->cmn_reg->num_pix) - irq_status_ipp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_IPP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_pxl_irq_status_addr); if (csid_reg->cmn_reg->num_ppp) - irq_status_ppp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_PPP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_irq_status_addr); if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - irq_status_rdi[i] = + irq_status[i] = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); } @@ -3928,7 +4134,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { - irq_status_udi[i] = + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->udi_reg[i]->csid_udi_irq_status_addr); } @@ -3936,22 +4142,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); /* clear */ - cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_TOP], + soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); - cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_RX], + soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); if (csid_reg->cmn_reg->num_pix) - cam_io_w_mb(irq_status_ipp, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_IPP], + soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); if (csid_reg->cmn_reg->num_ppp) - cam_io_w_mb(irq_status_ppp, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_PPP], + soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - cam_io_w_mb(irq_status_rdi[i], + cam_io_w_mb(irq_status[i], soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); } @@ -3959,7 +4169,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { - cam_io_w_mb(irq_status_udi[i], + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i], soc_info->reg_map[0].mem_base + csid_reg->udi_reg[i]->csid_udi_irq_clear_addr); } @@ -3970,94 +4180,120 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); - CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); - CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); - CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); - CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", irq_status_ppp); + CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_TOP]); + CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_RX]); + CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_IPP]); + CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_PPP]); CAM_DBG(CAM_ISP, "irq_status_rdi0= 0x%x irq_status_rdi1= 0x%x irq_status_rdi2= 0x%x", - irq_status_rdi[0], irq_status_rdi[1], irq_status_rdi[2]); + irq_status[0], irq_status[1], irq_status[2]); CAM_DBG(CAM_ISP, "irq_status_udi0= 0x%x irq_status_udi1= 0x%x irq_status_udi2= 0x%x", - irq_status_udi[0], irq_status_udi[1], irq_status_udi[2]); + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0], + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_1], + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_2]); - if (irq_status_top & CSID_TOP_IRQ_DONE) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_TOP] & CSID_TOP_IRQ_DONE) { CAM_DBG(CAM_ISP, "csid top reset complete"); complete(&csid_hw->csid_top_complete); } - if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); complete(&csid_hw->csid_csi2_complete); } spin_lock_irqsave(&csid_hw->lock_state, flags); if (csid_hw->device_enabled == 1) { - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_EOT_RECEPTION", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_SOT_RECEPTION", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CRC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_ECC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_STREAM_UNDERFLOW", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } } +handle_fatal_error: spin_unlock_irqrestore(&csid_hw->lock_state, flags); if (csid_hw->error_irq_count > @@ -4066,26 +4302,33 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->error_irq_count = 0; } - if (fatal_err_detected) + if (fatal_err_detected) { cam_ife_csid_halt_csi2(csid_hw); + cam_csid_handle_hw_err_irq(csid_hw, + CAM_ISP_HW_ERROR_CSID_FATAL, irq_status); + } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL0_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL1_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL2_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL3_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); @@ -4093,22 +4336,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) { - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL0_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL1_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL2_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL3_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); @@ -4116,7 +4363,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) && - (irq_status_rx & CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED)) { + (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d LONG_PKT_CAPTURED", csid_hw->hw_intf->hw_idx); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -4136,7 +4385,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->hw_intf->hw_idx, (val >> 16), (val & 0xFFFF)); } if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) && - (irq_status_rx & CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED)) { + (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d SHORT_PKT_CAPTURED", csid_hw->hw_intf->hw_idx); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -4152,7 +4403,8 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) && - (irq_status_rx & CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED)) { + (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PKT_HDR_CAPTURED", csid_hw->hw_intf->hw_idx); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -4166,13 +4418,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /*read the IPP errors */ if (csid_reg->cmn_reg->num_pix) { /* IPP reset done bit */ - if (irq_status_ipp & + if (irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID IPP reset complete"); complete(&csid_hw->csid_ipp_complete); } - if ((irq_status_ipp & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP SOF received", csid_hw->hw_intf->hw_idx); @@ -4180,22 +4433,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP CCIF violation", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP Overflow due to back pressure", csid_hw->hw_intf->hw_idx); - if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d IPP fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4209,13 +4466,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /*read PPP errors */ if (csid_reg->cmn_reg->num_ppp) { /* PPP reset done bit */ - if (irq_status_ppp & + if (irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID PPP reset complete"); complete(&csid_hw->csid_ppp_complete); } - if ((irq_status_ppp & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP SOF received", csid_hw->hw_intf->hw_idx); @@ -4223,22 +4481,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_ppp & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ppp & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP CCIF violation", csid_hw->hw_intf->hw_idx); - if ((irq_status_ppp & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP Overflow due to back pressure", csid_hw->hw_intf->hw_idx); - if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d PPP fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4250,13 +4512,13 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - if (irq_status_rdi[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); complete(&csid_hw->csid_rdin_complete[i]); } - if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[i] & CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d SOF received", i); @@ -4264,21 +4526,21 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[i] & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d EOF received", i); - if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI :%d CCIF violation", i); - if ((irq_status_rdi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[i] & CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI :%d Overflow due to back pressure", i); - if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d RDI fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4290,13 +4552,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { - if (irq_status_udi[i] & + if (irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID UDI%d reset complete", i); complete(&csid_hw->csid_udin_complete[i]); } - if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID UDI:%d SOF received", i); @@ -4304,21 +4567,25 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID UDI:%d EOF received", i); - if ((irq_status_udi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_WARN_RATE_LIMIT(CAM_ISP, "CSID UDI :%d CCIF violation", i); - if ((irq_status_udi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_OVERFLOW_RECOVERY)) CAM_WARN_RATE_LIMIT(CAM_ISP, "CSID UDI :%d Overflow due to back pressure", i); - if (irq_status_udi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UDI fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4497,6 +4764,19 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->udi_res[i].res_priv = path_data; } + rc = cam_tasklet_init(&ife_csid_hw->tasklet, ife_csid_hw, csid_idx); + if (rc) { + CAM_ERR(CAM_ISP, "Unable to create CSID tasklet rc %d", rc); + goto err; + } + + INIT_LIST_HEAD(&ife_csid_hw->free_payload_list); + for (i = 0; i < CAM_CSID_EVT_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&ife_csid_hw->evt_payload[i].list); + list_add_tail(&ife_csid_hw->evt_payload[i].list, + &ife_csid_hw->free_payload_list); + } + ife_csid_hw->csid_debug = 0; ife_csid_hw->error_irq_count = 0; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 6d7a9c3aa0c2..a65783c29d18 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.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 _CAM_IFE_CSID_HW_H_ @@ -72,6 +72,8 @@ #define CSID_DEBUG_ENABLE_HBI_VBI_INFO BIT(7) #define CSID_DEBUG_DISABLE_EARLY_EOF BIT(8) +#define CAM_CSID_EVT_PAYLOAD_MAX 10 + /* enum cam_csid_path_halt_mode select the path halt mode control */ enum cam_csid_path_halt_mode { CSID_HALT_MODE_INTERNAL, @@ -91,6 +93,24 @@ enum cam_csid_path_timestamp_stb_sel { CSID_TIMESTAMP_STB_MAX, }; +/** + * enum cam_ife_pix_path_res_id - Specify the csid patch + */ +enum cam_ife_csid_irq_reg { + CAM_IFE_CSID_IRQ_REG_RDI_0, + CAM_IFE_CSID_IRQ_REG_RDI_1, + CAM_IFE_CSID_IRQ_REG_RDI_2, + CAM_IFE_CSID_IRQ_REG_RDI_3, + CAM_IFE_CSID_IRQ_REG_TOP, + CAM_IFE_CSID_IRQ_REG_RX, + CAM_IFE_CSID_IRQ_REG_IPP, + CAM_IFE_CSID_IRQ_REG_PPP, + CAM_IFE_CSID_IRQ_REG_UDI_0, + CAM_IFE_CSID_IRQ_REG_UDI_1, + CAM_IFE_CSID_IRQ_REG_UDI_2, + CAM_IFE_CSID_IRQ_REG_MAX, +}; + struct cam_ife_csid_pxl_reg_offset { /* Pxl path register offsets*/ uint32_t csid_pxl_irq_status_addr; @@ -517,12 +537,32 @@ struct cam_ife_csid_path_cfg { uint32_t num_bytes_out; }; +/** + * struct cam_csid_evt_payload- payload for csid hw event + * @list : list head + * @evt_type : Event type from CSID + * @irq_status : IRQ Status register + * @hw_idx : Hw index + * @priv : Private data of payload + */ +struct cam_csid_evt_payload { + struct list_head list; + uint32_t evt_type; + uint32_t irq_status[CAM_IFE_CSID_IRQ_REG_MAX]; + uint32_t hw_idx; + void *priv; +}; + /** * struct cam_ife_csid_hw- csid hw device resources data * * @hw_intf: contain the csid hw interface information * @hw_info: csid hw device information * @csid_info: csid hw specific information + * @tasklet: tasklet to handle csid errors + * @priv: private data to be sent with callback + * @free_payload_list: list head for payload + * @evt_payload: Event payload to be passed to tasklet * @res_type: CSID in resource type * @csi2_rx_cfg: Csi2 rx decoder configuration for csid * @tpg_cfg: TPG configuration @@ -553,11 +593,17 @@ struct cam_ife_csid_path_cfg { * * @prev_boot_timestamp first bootime stamp at the start * @prev_qtimer_ts stores csid timestamp + * @fatal_err_detected flag to indicate fatal errror is reported + * @event_cb Callback to hw manager if CSID event reported */ struct cam_ife_csid_hw { struct cam_hw_intf *hw_intf; struct cam_hw_info *hw_info; struct cam_ife_csid_hw_info *csid_info; + void *tasklet; + void *priv; + struct list_head free_payload_list; + struct cam_csid_evt_payload evt_payload[CAM_CSID_EVT_PAYLOAD_MAX]; uint32_t res_type; struct cam_ife_csid_csi2_rx_cfg csi2_rx_cfg; struct cam_ife_csid_tpg_cfg tpg_cfg; @@ -586,6 +632,8 @@ struct cam_ife_csid_hw { uint32_t binning_supported; uint64_t prev_boot_timestamp; uint64_t prev_qtimer_ts; + bool fatal_err_detected; + cam_hw_mgr_event_cb_func event_cb; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 56ce59636dda..62c49ed8be9e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_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 _CAM_CSID_HW_INTF_H_ @@ -123,6 +123,8 @@ struct cam_isp_in_port_generic_info { * @node_res : Reserved resource structure pointer * @crop_enable : Flag to indicate CSID crop enable * @drop_enable : Flag to indicate CSID drop enable + * @priv: private data to be sent in callback + * @event_cb: CSID event callback to hw manager * */ struct cam_csid_hw_reserve_resource_args { @@ -136,6 +138,8 @@ struct cam_csid_hw_reserve_resource_args { struct cam_isp_resource_node *node_res; bool crop_enable; bool drop_enable; + void *priv; + cam_hw_mgr_event_cb_func event_cb; }; /** 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 97282ede31c3..8a90958c2065 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 @@ -18,6 +18,7 @@ #include "cam_isp_hw_mgr_intf.h" #include #include "cam_subdev.h" +#include "cam_tasklet_util.h" /* Timeout value in msec */ #define TFE_CSID_TIMEOUT 1000 @@ -908,8 +909,10 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw *csid_hw) goto disable_soc; spin_lock_irqsave(&csid_hw->spin_lock, flags); + csid_hw->fatal_err_detected = false; csid_hw->device_enabled = 1; spin_unlock_irqrestore(&csid_hw->spin_lock, flags); + cam_tasklet_start(csid_hw->tasklet); return rc; @@ -964,6 +967,7 @@ static int cam_tfe_csid_disable_hw(struct cam_tfe_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", csid_hw->hw_intf->hw_idx); + cam_tasklet_stop(csid_hw->tasklet); spin_lock_irqsave(&csid_hw->spin_lock, flags); csid_hw->device_enabled = 0; spin_unlock_irqrestore(&csid_hw->spin_lock, flags); @@ -1846,6 +1850,9 @@ static int cam_tfe_csid_release(void *hw_priv, goto end; } + csid_hw->event_cb = NULL; + csid_hw->event_cb_priv = NULL; + if ((res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE) || (res->res_state >= CAM_ISP_RESOURCE_STATE_STREAMING)) { CAM_WARN(CAM_ISP, @@ -2498,6 +2505,189 @@ static int cam_tfe_csid_process_cmd(void *hw_priv, return rc; } +static int cam_csid_get_evt_payload( + struct cam_tfe_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + + spin_lock(&csid_hw->spin_lock); + + if (list_empty(&csid_hw->free_payload_list)) { + *evt_payload = NULL; + spin_unlock(&csid_hw->spin_lock); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return -ENOMEM; + } + + *evt_payload = list_first_entry(&csid_hw->free_payload_list, + struct cam_csid_evt_payload, list); + list_del_init(&(*evt_payload)->list); + spin_unlock(&csid_hw->spin_lock); + + return 0; +} + +static int cam_csid_put_evt_payload( + struct cam_tfe_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + unsigned long flags; + + if (*evt_payload == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid payload core %d", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + spin_lock_irqsave(&csid_hw->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, + &csid_hw->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&csid_hw->spin_lock, flags); + + return 0; +} +static char *cam_csid_status_to_str(uint32_t status) +{ + switch (status) { + case TFE_CSID_IRQ_REG_TOP: + return "TOP"; + case TFE_CSID_IRQ_REG_RX: + return "RX"; + case TFE_CSID_IRQ_REG_IPP: + return "IPP"; + case TFE_CSID_IRQ_REG_RDI0: + return "RDI0"; + case TFE_CSID_IRQ_REG_RDI1: + return "RDI1"; + case TFE_CSID_IRQ_REG_RDI2: + return "RDI2"; + default: + return "Invalid IRQ"; + } +} + +static int cam_csid_evt_bottom_half_handler( + void *handler_priv, + void *evt_payload_priv) +{ + struct cam_tfe_csid_hw *csid_hw; + struct cam_csid_evt_payload *evt_payload; + int i; + int rc = 0; + struct cam_isp_hw_event_info event_info; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, + "Invalid Param handler_priv %pK evt_payload_priv %pK", + handler_priv, evt_payload_priv); + return 0; + } + + csid_hw = (struct cam_tfe_csid_hw *)handler_priv; + evt_payload = (struct cam_csid_evt_payload *)evt_payload_priv; + + if (!csid_hw->event_cb || !csid_hw->event_cb_priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d Invalid args %pK %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->event_cb, + csid_hw->event_cb_priv); + goto end; + } + + if (csid_hw->event_cb_priv != evt_payload->priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d priv mismatch %pK, %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->event_cb_priv, + evt_payload->priv); + goto end; + } + + CAM_ERR_RATE_LIMIT(CAM_ISP, "idx %d err %d phy %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type, + csid_hw->csi2_rx_cfg.phy_sel); + + for (i = 0; i < TFE_CSID_IRQ_REG_MAX; i++) + CAM_ERR_RATE_LIMIT(CAM_ISP, "status %s: %x", + cam_csid_status_to_str(i), + evt_payload->irq_status[i]); + + /* this hunk can be extended to handle more cases + * which we want to offload to bottom half from + * irq handlers + */ + event_info.err_type = evt_payload->evt_type; + event_info.hw_idx = evt_payload->hw_idx; + + switch (evt_payload->evt_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: + if (csid_hw->fatal_err_detected) + break; + csid_hw->fatal_err_detected = true; + rc = csid_hw->event_cb(NULL, + CAM_ISP_HW_EVENT_ERROR, (void *)&event_info); + break; + + default: + CAM_DBG(CAM_ISP, "CSID[%d] invalid error type %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type); + break; + } +end: + cam_csid_put_evt_payload(csid_hw, &evt_payload); + return 0; +} + +static int cam_csid_handle_hw_err_irq( + struct cam_tfe_csid_hw *csid_hw, + int evt_type, + uint32_t *irq_status) +{ + int rc = 0; + int i; + void *bh_cmd = NULL; + struct cam_csid_evt_payload *evt_payload; + + CAM_DBG(CAM_ISP, "CSID[%d] error %d", + csid_hw->hw_intf->hw_idx, evt_type); + + rc = cam_csid_get_evt_payload(csid_hw, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return rc; + } + + rc = tasklet_bh_api.get_bh_payload_func(csid_hw->tasklet, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID[%d] Can not get cmd for tasklet, evt_type %d", + csid_hw->hw_intf->hw_idx, + evt_type); + return rc; + } + + evt_payload->evt_type = evt_type; + evt_payload->priv = csid_hw->event_cb_priv; + evt_payload->hw_idx = csid_hw->hw_intf->hw_idx; + + for (i = 0; i < TFE_CSID_IRQ_REG_MAX; i++) + evt_payload->irq_status[i] = irq_status[i]; + + tasklet_bh_api.bottom_half_enqueue_func(csid_hw->tasklet, + bh_cmd, + csid_hw, + evt_payload, + cam_csid_evt_bottom_half_handler); + + return rc; +} + irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) { struct cam_tfe_csid_hw *csid_hw; @@ -2576,20 +2766,24 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) if (irq_status[TFE_CSID_IRQ_REG_RX] & TFE_CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status[TFE_CSID_IRQ_REG_RX] & TFE_CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status[TFE_CSID_IRQ_REG_RX] & TFE_CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status[TFE_CSID_IRQ_REG_RX] & TFE_CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { fatal_err_detected = true; + goto handle_fatal_error; } if (irq_status[TFE_CSID_IRQ_REG_RX] & @@ -2620,6 +2814,7 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) TFE_CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) is_error_irq = true; } +handle_fatal_error: spin_unlock_irqrestore(&csid_hw->spin_lock, flags); if (csid_hw->error_irq_count || fatal_err_detected) @@ -2645,6 +2840,8 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) CAM_SUBDEV_MESSAGE_IRQ_ERR, (csid_hw->csi2_rx_cfg.phy_sel - 1)); } + cam_csid_handle_hw_err_irq(csid_hw, + CAM_ISP_HW_ERROR_CSID_FATAL, irq_status); } if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOT_IRQ) { @@ -2993,6 +3190,19 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, tfe_csid_hw->rdi_res[i].res_priv = path_data; } + rc = cam_tasklet_init(&tfe_csid_hw->tasklet, tfe_csid_hw, csid_idx); + if (rc) { + CAM_ERR(CAM_ISP, "Unable to create CSID tasklet rc %d", rc); + goto err; + } + + INIT_LIST_HEAD(&tfe_csid_hw->free_payload_list); + for (i = 0; i < CAM_CSID_EVT_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&tfe_csid_hw->evt_payload[i].list); + list_add_tail(&tfe_csid_hw->evt_payload[i].list, + &tfe_csid_hw->free_payload_list); + } + tfe_csid_hw->csid_debug = 0; tfe_csid_hw->error_irq_count = 0; tfe_csid_hw->prev_boot_timestamp = 0; 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 481fbe9b611f..4b50eeb4bbd6 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 @@ -73,6 +73,8 @@ #define TFE_CSID_DEBUG_DISABLE_EARLY_EOF BIT(8) #define TFE_CSID_DEBUG_ENABLE_RST_IRQ_LOG BIT(9) +#define CAM_CSID_EVT_PAYLOAD_MAX 10 + /* enum cam_csid_path_halt_mode select the path halt mode control */ enum cam_tfe_csid_path_halt_mode { TFE_CSID_HALT_MODE_INTERNAL, @@ -353,12 +355,31 @@ struct cam_tfe_csid_path_cfg { uint32_t sensor_vbi; }; +/** + * struct cam_csid_evt_payload- payload for csid hw event + * @list : list head + * @evt_type : Event type from CSID + * @irq_status : IRQ Status register + * @hw_idx : Hw index + * @priv : Private data of payload + */ +struct cam_csid_evt_payload { + struct list_head list; + uint32_t evt_type; + uint32_t irq_status[TFE_CSID_IRQ_REG_MAX]; + uint32_t hw_idx; + void *priv; +}; + /** * struct cam_tfe_csid_hw- csid hw device resources data * * @hw_intf: contain the csid hw interface information * @hw_info: csid hw device information * @csid_info: csid hw specific information + * @tasklet: tasklet to handle csid errors + * @free_payload_list: list head for payload + * @evt_payload: Event payload to be passed to tasklet * @in_res_id: csid in resource type * @csi2_rx_cfg: csi2 rx decoder configuration for csid * @csi2_rx_reserve_cnt: csi2 reservations count value @@ -381,6 +402,7 @@ struct cam_tfe_csid_path_cfg { * @device_enabled Device enabled will set once CSID powered on and * initial configuration are done. * @lock_state csid spin lock + * @fatal_err_detected flag to indicate fatal errror is reported * @event_cb: Callback function to hw mgr in case of hw events * @event_cb_priv: Context data * @prev_boot_timestamp previous frame bootime stamp @@ -391,6 +413,9 @@ struct cam_tfe_csid_hw { struct cam_hw_intf *hw_intf; struct cam_hw_info *hw_info; struct cam_tfe_csid_hw_info *csid_info; + void *tasklet; + struct list_head free_payload_list; + struct cam_csid_evt_payload evt_payload[CAM_CSID_EVT_PAYLOAD_MAX]; uint32_t in_res_id; struct cam_tfe_csid_csi2_rx_cfg csi2_rx_cfg; uint32_t csi2_reserve_cnt; @@ -409,6 +434,7 @@ struct cam_tfe_csid_hw { uint32_t error_irq_count; uint32_t device_enabled; spinlock_t spin_lock; + bool fatal_err_detected; cam_hw_mgr_event_cb_func event_cb; void *event_cb_priv; uint64_t prev_boot_timestamp; diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 4b11c6a3a9ed..ebec0b04b916 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -422,12 +422,14 @@ struct cam_mem_cache_ops_cmd { * @CAM_REQ_MGR_ERROR_TYPE_BUFFER: Buffer was not filled, not fatal * @CAM_REQ_MGR_ERROR_TYPE_RECOVERY: Fatal error, can be recovered * @CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE: SOF freeze, can be recovered + * @CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY: Full recovery, can be recovered */ #define CAM_REQ_MGR_ERROR_TYPE_DEVICE 0 #define CAM_REQ_MGR_ERROR_TYPE_REQUEST 1 #define CAM_REQ_MGR_ERROR_TYPE_BUFFER 2 #define CAM_REQ_MGR_ERROR_TYPE_RECOVERY 3 #define CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE 4 +#define CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY 5 /** * struct cam_req_mgr_error_msg -- GitLab From f76c2819d6fba18b09d86efcdf7f1823d2cfe4c2 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Thu, 16 Jul 2020 22:17:01 +0530 Subject: [PATCH 232/295] msm: camera: ope: Maintain current clock value during acquire OPE driver maintain the current clock value field per instance based on clock rate set for OPE clock. OPE driver sets the clock to turbo during acquire time but doesn't update the internal field for multiple acquire request. This causes power regression as further clock calculation happens on previously set clock values for multiple acquire request. Corrected the logic to always update current clock value based on clock rate set during acquire time. CRs-Fixed: 2724827 Change-Id: Iba377d8918bda37b4d3267e677414a7b9e5a82ce Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 a25d951ef5ec..00b797752b1c 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 @@ -1333,7 +1333,7 @@ static int cam_ope_mgr_calculate_num_path( ((clk_info->axi_path[i].path_data_type - CAM_AXI_PATH_DATA_OPE_START_OFFSET) >= CAM_OPE_MAX_PER_PATH_VOTES)) { - CAM_WARN(CAM_OPE, + CAM_DBG(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, @@ -1641,11 +1641,11 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, if (!rc) goto end; } else { - CAM_ERR(CAM_OPE, + CAM_INFO(CAM_OPE, "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", + CAM_INFO(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); @@ -2642,8 +2642,6 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) hw_mgr->clk_info.base_clk = soc_info->clk_rate[CAM_TURBO_VOTE][idx]; - hw_mgr->clk_info.curr_clk = - soc_info->clk_rate[CAM_TURBO_VOTE][idx]; hw_mgr->clk_info.threshold = 5; hw_mgr->clk_info.over_clked = 0; @@ -2674,6 +2672,8 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) soc_info = &dev->soc_info; idx = soc_info->src_clk_idx; clk_update.clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][idx]; + hw_mgr->clk_info.curr_clk = + soc_info->clk_rate[CAM_TURBO_VOTE][idx]; rc = hw_mgr->ope_dev_intf[i]->hw_ops.process_cmd( hw_mgr->ope_dev_intf[i]->hw_priv, OPE_HW_CLK_UPDATE, -- GitLab From f0a73a6c7574145a7615dc6d81978a23ddd54397 Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Tue, 14 Jul 2020 00:13:35 +0530 Subject: [PATCH 233/295] msm: camera: csiphy: reset the secure bits on provider exit If camera service exits after configdev and before startdev the phy variables to keep track of the secure bits will be modified and the next session will be based on this secure bits that was previously set. This change clears the phy secure bits if the service exits. CRs-Fixed: 2726185 Change-Id: I69420aed164f66f221569ff60f8771eff40e1548 Signed-off-by: Tony Lijo Jose --- .../cam_csiphy/cam_csiphy_core.c | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) 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 dbd2141cc5c6..956b09001442 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -589,29 +589,37 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) return rc; } +void cam_csiphy_clear_secbits(struct csiphy_device *csiphy_dev) +{ + int32_t i = 0; + + for (i = 0; i < csiphy_dev->acquire_count; i++) { + if (csiphy_dev->csiphy_info.secure_mode[i]) + cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, i); + + csiphy_dev->csiphy_info.secure_mode[i] = + CAM_SECURE_MODE_NON_SECURE; + + csiphy_dev->csiphy_cpas_cp_reg_mask[i] = 0; + } +} + void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) { struct cam_hw_soc_info *soc_info; - int32_t i = 0; if (csiphy_dev->csiphy_state == CAM_CSIPHY_INIT) return; + /* + * clear the secure bits if the provider crashed + */ + cam_csiphy_clear_secbits(csiphy_dev); if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { soc_info = &csiphy_dev->soc_info; - for (i = 0; i < csiphy_dev->acquire_count; i++) { - if (csiphy_dev->csiphy_info.secure_mode[i]) - cam_csiphy_notify_secure_mode( - csiphy_dev, - CAM_SECURE_MODE_NON_SECURE, i); - - csiphy_dev->csiphy_info.secure_mode[i] = - CAM_SECURE_MODE_NON_SECURE; - - csiphy_dev->csiphy_cpas_cp_reg_mask[i] = 0; - } - cam_csiphy_reset(csiphy_dev); cam_soc_util_disable_platform_resource(soc_info, true, true); -- GitLab From 76d1c90e23958f8415de18faf2e558582e99620c Mon Sep 17 00:00:00 2001 From: Fernando Pacheco Date: Wed, 17 Jun 2020 12:37:39 -0700 Subject: [PATCH 234/295] msm: camera: cci: Fix incorrect use of cci config ioctl The cci configuration will be transitioned to a new API that does not require routing through the v4l layer. This is work-in-progrss so in the mean time prevent the device from being exposed as configurable from userspace. The ioctl will still be exposed to kernel users so fix the arg size as well. We want size of struct not pointer. CRs-Fixed: 2702760 Change-Id: I9c7bd8f76980603dbf27e1c5bc9b19f8a3b8a39a Signed-off-by: Fernando Pacheco --- drivers/cam_sensor_module/cam_cci/cam_cci_dev.c | 5 ++--- drivers/cam_sensor_module/cam_cci/cam_cci_dev.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index e52e16cb5f96..1881ea420e7e 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.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 "cam_cci_dev.h" @@ -403,8 +403,7 @@ static int cam_cci_platform_probe(struct platform_device *pdev) sizeof(new_cci_dev->device_name)); new_cci_dev->v4l2_dev_str.name = new_cci_dev->device_name; - new_cci_dev->v4l2_dev_str.sd_flags = - (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + new_cci_dev->v4l2_dev_str.sd_flags = V4L2_SUBDEV_FL_HAS_EVENTS; new_cci_dev->v4l2_dev_str.ent_function = CAM_CCI_DEVICE_TYPE; new_cci_dev->v4l2_dev_str.token = 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 2d7e8390acca..1c6d5030cee0 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -304,6 +304,6 @@ irqreturn_t cam_cci_irq(int irq_num, void *data); struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index); #define VIDIOC_MSM_CCI_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl) #endif /* _CAM_CCI_DEV_H_ */ -- GitLab From 100ee9dc14f1de0e78c7ffcc144b7b7183f4ea57 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Wed, 8 Jul 2020 16:06:40 -0700 Subject: [PATCH 235/295] msm: camera: req_mgr: Remove unwanted v4l2 operation CCI hardware is no longer register as device node with v4l2 layer. At time of notify message, there is missing check to read subdev name, which cause the null pointer issue. This change removes the sudbev node reading operation with devnode pointer as it is not being use anywhere in functionality. CRs-Fixed: 2702760, 2727771 Change-Id: Id362bd2edf4eea35f05115ae3a5b6c1d761bb437 Signed-off-by: Jigarkumar Zala --- drivers/cam_req_mgr/cam_req_mgr_dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 9c4fdb1e06b5..72a34c5bae20 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -644,7 +644,6 @@ void cam_subdev_notify_message(u32 subdev_type, struct cam_subdev *csd = NULL; list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { - sd->entity.name = video_device_node_name(sd->devnode); if (sd->entity.function == subdev_type) { csd = container_of(sd, struct cam_subdev, sd); if (csd->msg_cb != NULL) -- GitLab From fff3bad10fa6930c83a442a689a9c717237ae6b7 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Fri, 17 Jul 2020 01:20:45 +0530 Subject: [PATCH 236/295] msm: camera: flash: Add support for regulator disable Add support to disable regulator in release dev CRs-Fixed: 2726194 Change-Id: I9c14989c9902ecdba8a84af0a0a029d8b98a2362 Signed-off-by: shiwgupt --- drivers/cam_sensor_module/cam_flash/cam_flash_core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 6d45ef26eed8..2caeecc80014 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -201,8 +201,13 @@ int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl, } if (!regulator_enable) { - if ((fctrl->flash_state == CAM_FLASH_STATE_START) && + if (((fctrl->flash_state == CAM_FLASH_STATE_START) || + (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) && (fctrl->is_regulator_enabled == true)) { + /* + * Release dev is called after stop dev and in + * stop dev flash state is set to acquire dev. + */ rc = cam_flash_prepare(fctrl, false); if (rc) CAM_ERR(CAM_FLASH, -- GitLab From 7493e80fe18038a1cc63747d1ea6281b54d6c13f Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Wed, 5 Aug 2020 14:28:13 +0530 Subject: [PATCH 237/295] msm: camera: ope: remove the check for dev_type Calculate the total clk of all the ctx irrespective of the use case for the ctx. Remove dev_type check to add all the ctx clk while calculating total clk. CRs-Fixed: 2754351 Change-Id: I5c1681ac1a88cfec752ff58fd8b1f6ac5d05b28a Signed-off-by: Tejas Prajapati --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 a25d951ef5ec..b98636036a7e 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 @@ -1083,8 +1083,7 @@ static int cam_ope_calc_total_clk(struct cam_ope_hw_mgr *hw_mgr, hw_mgr_clk_info->base_clk = 0; for (i = 0; i < OPE_CTX_MAX; i++) { ctx_data = &hw_mgr->ctx[i]; - if (ctx_data->ctx_state == OPE_CTX_STATE_ACQUIRED && - ctx_data->ope_acquire.dev_type == dev_type) + if (ctx_data->ctx_state == OPE_CTX_STATE_ACQUIRED) hw_mgr_clk_info->base_clk += ctx_data->clk_info.base_clk; } -- GitLab From 1b036ca1598f7ec8910daae5e964f612645dcfcc Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Fri, 12 Jun 2020 16:18:05 +0530 Subject: [PATCH 238/295] msm: camera: sensor: unregister subdev if cpas registration fails In case if the CPAS registration is failed before freeing the memory of the subdev, subdev need to be unregistered so that subdev list entry will not become NULL and other subdev can be added. CRs-Fixed: 2708016 Change-Id: I464c73411596fc562fc7a190ddfa130f23ee487a Signed-off-by: Tejas Prajapati --- drivers/cam_sensor_module/cam_cci/cam_cci_dev.c | 5 ++++- drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index 1881ea420e7e..047d477a580d 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -442,13 +442,16 @@ static int cam_cci_platform_probe(struct platform_device *pdev) rc = cam_cpas_register_client(&cpas_parms); if (rc) { CAM_ERR(CAM_CCI, "CPAS registration failed"); - goto cci_no_resource; + goto cci_unregister_subdev; } CAM_DBG(CAM_CCI, "CPAS registration successful handle=%d", cpas_parms.client_handle); new_cci_dev->cpas_handle = cpas_parms.client_handle; return rc; + +cci_unregister_subdev: + cam_unregister_subdev(&(new_cci_dev->v4l2_dev_str)); cci_no_resource: kfree(new_cci_dev); return rc; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index 0719f42d654d..987da8efbd21 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -202,13 +202,16 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) rc = cam_cpas_register_client(&cpas_parms); if (rc) { CAM_ERR(CAM_CSIPHY, "CPAS registration failed rc: %d", rc); - goto csiphy_no_resource; + goto csiphy_unregister_subdev; } CAM_DBG(CAM_CSIPHY, "CPAS registration successful handle=%d", cpas_parms.client_handle); new_csiphy_dev->cpas_handle = cpas_parms.client_handle; return rc; + +csiphy_unregister_subdev: + cam_unregister_subdev(&(new_csiphy_dev->v4l2_dev_str)); csiphy_no_resource: mutex_destroy(&new_csiphy_dev->mutex); kfree(new_csiphy_dev->ctrl_reg); -- GitLab From abc609e3b27cf02202a3893a741927ab310596e1 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Sun, 9 Aug 2020 17:54:19 +0530 Subject: [PATCH 239/295] msm: camera: cdm: Avoid submitting BL if FIFO is full Check for available slots in FIFO before submitting gen_irq and debug_gen_irq BL. CRs-Fixed: 2747279 Change-Id: Iff47aa861f13221e5295d9a3f3521a2514351933 Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 42 ++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 4491c5234c4a..043b7175e4f2 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -543,7 +543,7 @@ int cam_hw_cdm_wait_for_bl_fifo( CAM_DBG(CAM_CDM, "BL slot available_cnt=%d requested=%d", (available_bl_slots - 1), bl_count); - rc = bl_count; + rc = available_bl_slots - 1; break; } else if (0 == (available_bl_slots - 1)) { rc = cam_hw_cdm_enable_bl_done_irq(cdm_hw, @@ -569,7 +569,7 @@ int cam_hw_cdm_wait_for_bl_fifo( if (cam_hw_cdm_enable_bl_done_irq(cdm_hw, false, fifo_idx)) CAM_ERR(CAM_CDM, "Disable BL done irq failed"); - rc = 0; + rc = 1; CAM_DBG(CAM_CDM, "CDM HW is ready for data"); } else { rc = (bl_count - (available_bl_slots - 1)); @@ -898,8 +898,6 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, rc = -EIO; break; } - } else { - write_count--; } if (req->data->type == CAM_CDM_BL_CMD_TYPE_MEM_HANDLE) { @@ -966,6 +964,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, rc = -EIO; break; } + write_count--; } } else { CAM_ERR(CAM_CDM, @@ -1002,27 +1001,58 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, rc = -EIO; break; } + write_count--; CAM_DBG(CAM_CDM, "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) { + if (write_count == 0) { + write_count = + cam_hw_cdm_wait_for_bl_fifo( + cdm_hw, 1, fifo_idx); + if (write_count < 0) { + CAM_ERR(CAM_CDM, + "wait for bl fifo failed %d:%d", + i, req->data->cmd_arrary_count); + rc = -EIO; + break; + } + } + rc = cam_hw_cdm_submit_debug_gen_irq(cdm_hw, fifo_idx); - if (rc == 0) + if (rc == 0) { + write_count--; core->bl_fifo[fifo_idx].bl_tag++; + } if (core->bl_fifo[fifo_idx].bl_tag >= (bl_fifo->bl_depth - 1)) core->bl_fifo[fifo_idx].bl_tag = 0; } - if ((req->data->flag == true) && + if ((!rc) && (req->data->flag == true) && (i == (req->data->cmd_arrary_count - 1))) { + + if (write_count == 0) { + write_count = + cam_hw_cdm_wait_for_bl_fifo( + cdm_hw, 1, fifo_idx); + if (write_count < 0) { + CAM_ERR(CAM_CDM, + "wait for bl fifo failed %d:%d", + i, req->data->cmd_arrary_count); + rc = -EIO; + break; + } + } + 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); -- GitLab From c8475ebeb84716fb040126c243dffc266abafb4e Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Tue, 18 Aug 2020 14:31:48 +0530 Subject: [PATCH 240/295] msm: camera: req_mgr: Limit CAM_ERR log in case of no empty task Limit CAM_ERR log in case of no empty task. CRs-Fixed: 2756270 Change-Id: I688bcff64af135ede221cab0a83c2582efb81330 Signed-off-by: Shravya Samala --- drivers/cam_req_mgr/cam_req_mgr_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index cff711500abc..38cfef654cdd 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -2930,7 +2930,7 @@ static int cam_req_mgr_cb_notify_trigger( task = cam_req_mgr_workq_get_task(link->workq); if (!task) { - CAM_ERR(CAM_CRM, "no empty task frame %lld", + CAM_ERR_RATE_LIMIT(CAM_CRM, "no empty task frame %lld", trigger_data->frame_id); rc = -EBUSY; goto end; -- GitLab From 320836c10e72cd603ed1dbf681c71e89308e52a4 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Mon, 17 Aug 2020 11:35:28 +0530 Subject: [PATCH 241/295] msm: camera: ope: Handle race while dumping ope req list While dumping OPE req list we were not protecting it in context mutex, this can result into unexpected behaviors. This change take care of protecting the dump logic with mutex. CRs-Fixed: 2750458 Change-Id: I916822b498cde3922274c18a06b98c898bff1d65 Signed-off-by: Vikram Sharma --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 8 ++++++++ 1 file changed, 8 insertions(+) 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 00b797752b1c..3c2d384b4d78 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 @@ -43,6 +43,8 @@ static struct cam_ope_hw_mgr *ope_hw_mgr; +static int cam_ope_req_timer_reset(struct cam_ope_ctx *ctx_data); + static int cam_ope_mgr_get_rsc_idx(struct cam_ope_ctx *ctx_data, struct ope_io_buf_info *in_io_buf) { @@ -125,6 +127,8 @@ static int cam_ope_mgr_process_cmd(void *priv, void *data) if (task_data->req_id > ctx_data->last_flush_req) ctx_data->last_flush_req = 0; + cam_ope_req_timer_reset(ctx_data); + rc = cam_cdm_submit_bls(ctx_data->ope_cdm.cdm_handle, cdm_cmd); if (!rc) @@ -3626,6 +3630,7 @@ static int cam_ope_mgr_hw_dump(void *hw_priv, void *hw_dump_args) } mutex_lock(&hw_mgr->hw_mgr_mutex); + mutex_lock(&ctx_data->ctx_mutex); CAM_INFO(CAM_OPE, "Req %lld", dump_args->request_id); for (idx = 0; idx < CAM_CTX_REQ_MAX; idx++) { @@ -3639,6 +3644,7 @@ static int cam_ope_mgr_hw_dump(void *hw_priv, void *hw_dump_args) /* no matching request found */ if (idx == CAM_CTX_REQ_MAX) { + mutex_unlock(&ctx_data->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); return 0; } @@ -3656,6 +3662,7 @@ static int cam_ope_mgr_hw_dump(void *hw_priv, void *hw_dump_args) req_ts.tv_nsec/NSEC_PER_USEC, cur_ts.tv_sec, cur_ts.tv_nsec/NSEC_PER_USEC); + mutex_unlock(&ctx_data->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); return 0; } @@ -3667,6 +3674,7 @@ static int cam_ope_mgr_hw_dump(void *hw_priv, void *hw_dump_args) cur_ts.tv_sec, cur_ts.tv_nsec/NSEC_PER_USEC); + mutex_unlock(&ctx_data->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); return 0; } -- GitLab From d7fd56eb46275c166f8fbc553b1dece7fa61f336 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Mon, 29 Jun 2020 15:56:03 +0530 Subject: [PATCH 242/295] msm: camera: cci: Enable compilation for cci dump code CCI register dump is only enable when dump flag is defined. Remove this flag and add control via debugfs entry. This change helps debugfs entry to control cci device individually on the fly for debugging rather than rebuild. CRs-Fixed: 2692379 Change-Id: Ic13dc903e861e7c49bf3b375a66b96bfbe5d9c70 Signed-off-by: shiwgupt --- .../cam_sensor_module/cam_cci/cam_cci_core.c | 33 +++--- .../cam_sensor_module/cam_cci/cam_cci_dev.c | 105 +++++++++++++++++- .../cam_sensor_module/cam_cci/cam_cci_dev.h | 9 ++ .../cam_sensor_module/cam_cci/cam_cci_hwreg.h | 6 +- 4 files changed, 134 insertions(+), 19 deletions(-) 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 5085527d1c06..c34e7ccebedc 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -177,10 +177,11 @@ static int32_t cam_cci_lock_queue(struct cci_device *cci_dev, return cam_cci_write_i2c_queue(cci_dev, val, master, queue); } -#ifdef DUMP_CCI_REGISTERS -static void cam_cci_dump_registers(struct cci_device *cci_dev, + +void cam_cci_dump_registers(struct cci_device *cci_dev, enum cci_i2c_master_t master, enum cci_i2c_queue_t queue) { + uint32_t dump_en = 0; uint32_t read_val = 0; uint32_t i = 0; uint32_t reg_offset = 0; @@ -188,6 +189,14 @@ static void cam_cci_dump_registers(struct cci_device *cci_dev, uint32_t read_data_reg_offset = 0x0; void __iomem *base = cci_dev->soc_info.reg_map[0].mem_base; + dump_en = cci_dev->dump_en; + if (!(dump_en & CAM_CCI_NACK_DUMP_EN) && + !(dump_en & CAM_CCI_TIMEOUT_DUMP_EN)) { + CAM_DBG(CAM_CCI, + "Nack and Timeout dump is not enabled"); + return; + } + /* CCI Top Registers */ CAM_INFO(CAM_CCI, "****CCI TOP Registers ****"); for (i = 0; i < DEBUG_TOP_REG_COUNT; i++) { @@ -238,7 +247,7 @@ static void cam_cci_dump_registers(struct cci_device *cci_dev, reg_offset, read_val); } } -#endif +EXPORT_SYMBOL(cam_cci_dump_registers); static uint32_t cam_cci_wait(struct cci_device *cci_dev, enum cci_i2c_master_t master, @@ -256,9 +265,8 @@ static uint32_t cam_cci_wait(struct cci_device *cci_dev, CAM_DBG(CAM_CCI, "wait DONE_for_completion_timeout"); if (rc <= 0) { -#ifdef DUMP_CCI_REGISTERS cam_cci_dump_registers(cci_dev, master, queue); -#endif + CAM_ERR(CAM_CCI, "wait for queue: %d", queue); if (rc == 0) rc = -ETIMEDOUT; @@ -1031,9 +1039,8 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, CAM_ERR(CAM_CCI, "wait_for_completion_timeout rc = %d FIFO buf_lvl:0x%x", rc, val); -#ifdef DUMP_CCI_REGISTERS cam_cci_dump_registers(cci_dev, master, queue); -#endif + cam_cci_flush_queue(cci_dev, master); goto rel_mutex_q; } @@ -1111,11 +1118,10 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, CAM_ERR(CAM_CCI, "Failed to receive RD_DONE irq rc = %d FIFO buf_lvl:0x%x", rc, val); - #ifdef DUMP_CCI_REGISTERS - cam_cci_dump_registers(cci_dev, - master, queue); - #endif - cam_cci_flush_queue(cci_dev, master); + cam_cci_dump_registers(cci_dev, + master, queue); + + cam_cci_flush_queue(cci_dev, master); goto rel_mutex_q; } break; @@ -1288,9 +1294,8 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, rc = wait_for_completion_timeout( &cci_dev->cci_master_info[master].rd_done, CCI_TIMEOUT); if (rc <= 0) { -#ifdef DUMP_CCI_REGISTERS cam_cci_dump_registers(cci_dev, master, queue); -#endif + if (rc == 0) rc = -ETIMEDOUT; val = cam_io_r_mb(base + diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index 1881ea420e7e..9c989ece0d02 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -11,6 +11,7 @@ #define CCI_MAX_DELAY 1000000 static struct v4l2_subdev *g_cci_subdev[MAX_CCI]; +static struct dentry *debugfs_root; struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) { @@ -223,9 +224,22 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_0].status = -EINVAL; - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) - CAM_ERR(CAM_CCI, "Base:%pK, M0 NACK ERROR: 0x%x", + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M0_Q0 NACK ERROR: 0x%x", base, irq_status0); + cam_cci_dump_registers(cci_dev, MASTER_0, + QUEUE_0); + complete_all(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_0]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M0_Q1 NACK ERROR: 0x%x", + base, irq_status0); + cam_cci_dump_registers(cci_dev, MASTER_0, + QUEUE_1); + complete_all(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_1]); + } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) CAM_ERR(CAM_CCI, "Base:%pK, M0 QUEUE_OVER/UNDER_FLOW OR CMD ERR: 0x%x", @@ -238,9 +252,22 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_1].status = -EINVAL; - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) - CAM_ERR(CAM_CCI, "Base:%pK, M1 NACK ERROR: 0x%x", + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M1_Q0 NACK ERROR: 0x%x", + base, irq_status0); + cam_cci_dump_registers(cci_dev, MASTER_1, + QUEUE_0); + complete_all(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_0]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M1_Q1 NACK ERROR: 0x%x", base, irq_status0); + cam_cci_dump_registers(cci_dev, MASTER_1, + QUEUE_1); + complete_all(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_1]); + } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) CAM_ERR(CAM_CCI, "Base:%pK, M1 QUEUE_OVER_UNDER_FLOW OR CMD ERROR:0x%x", @@ -369,6 +396,70 @@ static long cam_cci_subdev_fops_compat_ioctl(struct file *file, } #endif +static int cam_cci_get_debug(void *data, u64 *val) +{ + struct cci_device *cci_dev = (struct cci_device *)data; + + *val = cci_dev->dump_en; + + return 0; +} + +static int cam_cci_set_debug(void *data, u64 val) +{ + struct cci_device *cci_dev = (struct cci_device *)data; + + cci_dev->dump_en = val; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(cam_cci_debug, + cam_cci_get_debug, + cam_cci_set_debug, "%16llu\n"); + +static int cam_cci_create_debugfs_entry(struct cci_device *cci_dev) +{ + int rc = 0; + struct dentry *dbgfileptr = NULL; + + if (!debugfs_root) { + dbgfileptr = debugfs_create_dir("cam_cci", NULL); + if (!dbgfileptr) { + CAM_ERR(CAM_CCI, "debugfs directory creation fail"); + rc = -ENOENT; + goto end; + } + debugfs_root = dbgfileptr; + } + + if (cci_dev->soc_info.index == 0) { + dbgfileptr = debugfs_create_file("en_dump_cci0", 0644, + debugfs_root, cci_dev, &cam_cci_debug); + if (IS_ERR(dbgfileptr)) { + if (PTR_ERR(dbgfileptr) == -ENODEV) + CAM_WARN(CAM_CCI, "DebugFS not enabled"); + else { + rc = PTR_ERR(dbgfileptr); + goto end; + } + } + } else { + dbgfileptr = debugfs_create_file("en_dump_cci1", 0644, + debugfs_root, cci_dev, &cam_cci_debug); + if (IS_ERR(dbgfileptr)) { + if (PTR_ERR(dbgfileptr) == -ENODEV) + CAM_WARN(CAM_CCI, "DebugFS not enabled"); + else { + rc = PTR_ERR(dbgfileptr); + goto end; + } + } + } +end: + return rc; +} + static int cam_cci_platform_probe(struct platform_device *pdev) { struct cam_cpas_register_params cpas_parms; @@ -448,6 +539,11 @@ static int cam_cci_platform_probe(struct platform_device *pdev) cpas_parms.client_handle); new_cci_dev->cpas_handle = cpas_parms.client_handle; + rc = cam_cci_create_debugfs_entry(new_cci_dev); + if (rc) { + CAM_WARN(CAM_CCI, "debugfs creation failed"); + rc = 0; + } return rc; cci_no_resource: kfree(new_cci_dev); @@ -461,6 +557,7 @@ static int cam_cci_device_remove(struct platform_device *pdev) v4l2_get_subdevdata(subdev); cam_cpas_unregister_client(cci_dev->cpas_handle); + debugfs_remove_recursive(debugfs_root); cam_cci_soc_remove(pdev, cci_dev); devm_kfree(&pdev->dev, cci_dev); return 0; 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 1c6d5030cee0..00dabdfd6256 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +72,11 @@ #define PRIORITY_QUEUE (QUEUE_0) #define SYNC_QUEUE (QUEUE_1) +#define CAM_CCI_NACK_DUMP_EN BIT(1) +#define CAM_CCI_TIMEOUT_DUMP_EN BIT(2) + #define CCI_VERSION_1_2_9 0x10020009 + enum cci_i2c_sync { MSM_SYNC_DISABLE, MSM_SYNC_ENABLE, @@ -201,6 +206,7 @@ enum cam_cci_state_t { * @irqs_disabled: Mask for IRQs that are disabled * @init_mutex: Mutex for maintaining refcount for attached * devices to cci during init/deinit. + * @dump_en: To enable the selective dump */ struct cci_device { struct v4l2_subdev subdev; @@ -230,6 +236,7 @@ struct cci_device { bool is_burst_read; uint32_t irqs_disabled; struct mutex init_mutex; + uint64_t dump_en; }; enum cam_cci_i2c_cmd_type { @@ -302,6 +309,8 @@ struct cci_write_async { irqreturn_t cam_cci_irq(int irq_num, void *data); struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index); +void cam_cci_dump_registers(struct cci_device *cci_dev, + enum cci_i2c_master_t master, enum cci_i2c_queue_t queue); #define VIDIOC_MSM_CCI_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h index f00b854e9533..069a1ac01c1f 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2015, 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CCI_HWREG_ @@ -56,6 +56,10 @@ #define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 #define CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK 0x18000000 #define CCI_IRQ_STATUS_0_I2C_M1_NACK_ERROR_BMSK 0x60000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK 0x8000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK 0x10000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK 0x20000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK 0x40000000 #define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK 0xEE0 #define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK 0xEE0000 #define CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK 0x6 -- GitLab From 0d3f721ed9bfd2b264ccf1cc269a97a15aa54a4a Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Fri, 12 Jun 2020 16:18:05 +0530 Subject: [PATCH 243/295] msm: camera: sensor: unregister subdev if cpas registration fails In case if the CPAS registration is failed before freeing the memory of the subdev, subdev need to be unregistered so that subdev list entry will not become NULL and other subdev can be added. CRs-Fixed: 2708016 Change-Id: I464c73411596fc562fc7a190ddfa130f23ee487a Signed-off-by: Tejas Prajapati --- drivers/cam_sensor_module/cam_cci/cam_cci_dev.c | 5 ++++- drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index 1881ea420e7e..047d477a580d 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -442,13 +442,16 @@ static int cam_cci_platform_probe(struct platform_device *pdev) rc = cam_cpas_register_client(&cpas_parms); if (rc) { CAM_ERR(CAM_CCI, "CPAS registration failed"); - goto cci_no_resource; + goto cci_unregister_subdev; } CAM_DBG(CAM_CCI, "CPAS registration successful handle=%d", cpas_parms.client_handle); new_cci_dev->cpas_handle = cpas_parms.client_handle; return rc; + +cci_unregister_subdev: + cam_unregister_subdev(&(new_cci_dev->v4l2_dev_str)); cci_no_resource: kfree(new_cci_dev); return rc; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index 0719f42d654d..987da8efbd21 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -202,13 +202,16 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) rc = cam_cpas_register_client(&cpas_parms); if (rc) { CAM_ERR(CAM_CSIPHY, "CPAS registration failed rc: %d", rc); - goto csiphy_no_resource; + goto csiphy_unregister_subdev; } CAM_DBG(CAM_CSIPHY, "CPAS registration successful handle=%d", cpas_parms.client_handle); new_csiphy_dev->cpas_handle = cpas_parms.client_handle; return rc; + +csiphy_unregister_subdev: + cam_unregister_subdev(&(new_csiphy_dev->v4l2_dev_str)); csiphy_no_resource: mutex_destroy(&new_csiphy_dev->mutex); kfree(new_csiphy_dev->ctrl_reg); -- GitLab From 397738b97949edc10f761c46fd28ab7b9189febe Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Fri, 11 Sep 2020 15:46:09 +0530 Subject: [PATCH 244/295] msm: camera: ope: Increase max bl limit Increase max bl limit for OPE to 24 to support maximum 48 stripes. CRs-Fixed: 2761455 Change-Id: I961be1344fac0084649df321225e94a50d4e5a98 Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 2 +- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 98d3587ac929..3d3d11598701 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 @@ -50,7 +50,7 @@ #define OPE_CMDS OPE_MAX_CMD_BUFS #define CAM_MAX_IN_RES 8 -#define OPE_MAX_CDM_BLS 16 +#define OPE_MAX_CDM_BLS 24 #define CAM_OPE_MAX_PER_PATH_VOTES 6 #define CAM_OPE_BW_CONFIG_UNKNOWN 0 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 12f5d1750cc2..4b39b6770c30 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 @@ -393,6 +393,7 @@ static int cam_ope_dev_prepare_cdm_request( ope_request->ope_kmd_buf.offset; cdm_cmd->cmd[i].len = len; cdm_cmd->cmd[i].arbitrate = arbitrate; + cdm_cmd->cmd[i].enable_debug_gen_irq = false; cdm_cmd->cmd_arrary_count++; -- GitLab From 92a550e9626e180d93d44d695b019862aa281e30 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Fri, 4 Sep 2020 14:31:08 +0530 Subject: [PATCH 245/295] msm: camera: cdm: Decrement write-count only after Bl commit After Hw Bl cmd write, we are decrementing write count. Again after committing BL we are decrementing write count. Due to this there is a chance of write count becoming -1 thus leading to CDM overflow issue. Hence decrement write count only after committing BL. CRs-Fixed: 2768031 Change-Id: I8faf6ea7d5e9e34e1e034c89132ed131b4d6cafc Signed-off-by: Shravya Samala --- drivers/cam_cdm/cam_cdm_hw_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 043b7175e4f2..4be9e62f261b 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -964,7 +964,6 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, rc = -EIO; break; } - write_count--; } } else { CAM_ERR(CAM_CDM, -- GitLab From 7bacf1d4c156e92ca978cd15374e57c07ee8e1f1 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Thu, 3 Sep 2020 17:38:27 +0530 Subject: [PATCH 246/295] msm: camera: tfe: TPG stop Call Move TPG stop call before checking if Deinit call is required or not. CRs-Fixed: 2777023 Change-Id: I9c7be620c2ba2762324129e547efc1d2a8dd6f40 Signed-off-by: Shravya Samala --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 db9a93ced4e5..298a2b0c1933 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 @@ -2787,15 +2787,15 @@ static int cam_tfe_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) wait_for_completion(&ctx->config_done_complete); + if (ctx->is_tpg) + cam_tfe_hw_mgr_stop_hw_res(&ctx->res_list_tpg); + if (stop_isp->stop_only) goto end; if (cam_cdm_stream_off(ctx->cdm_handle)) CAM_ERR(CAM_ISP, "CDM stream off failed %d", ctx->cdm_handle); - if (ctx->is_tpg) - cam_tfe_hw_mgr_stop_hw_res(&ctx->res_list_tpg); - cam_tfe_hw_mgr_deinit_hw(ctx); CAM_DBG(CAM_ISP, -- GitLab From b91c235d7fcb970f24f02543e93ce0093d8ccc80 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Tue, 13 Oct 2020 16:55:34 +0530 Subject: [PATCH 247/295] msm: camera: ope: Avoid submitting NULL request to CDM In corner case, there is a chance that userspace can submit request while flush is ongoing. In some cases submitted request can get flushed and corresponding data structures memory gets freed. Add a logic to check for pending request before submitting request to cdm hw. CRs-Fixed: 2815901 Change-Id: I74096201e204f204c4f15d14698b4e9af6435f55 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) 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 543804099c9a..3a8a26d1d8bb 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 @@ -81,6 +81,11 @@ static int cam_ope_mgr_get_rsc_idx(struct cam_ope_ctx *ctx_data, return rsc_idx; } +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_ope_mgr_process_cmd(void *priv, void *data) { int rc; @@ -96,14 +101,16 @@ static int cam_ope_mgr_process_cmd(void *priv, void *data) ctx_data = priv; task_data = (struct ope_cmd_work_data *)data; + + mutex_lock(&hw_mgr->hw_mgr_mutex); cdm_cmd = task_data->data; if (!cdm_cmd) { CAM_ERR(CAM_OPE, "Invalid params%pK", cdm_cmd); + mutex_unlock(&hw_mgr->hw_mgr_mutex); return -EINVAL; } - mutex_lock(&hw_mgr->hw_mgr_mutex); if (ctx_data->ctx_state != OPE_CTX_STATE_ACQUIRED) { mutex_unlock(&hw_mgr->hw_mgr_mutex); CAM_ERR(CAM_OPE, "ctx id :%u is not in use", @@ -119,6 +126,13 @@ static int cam_ope_mgr_process_cmd(void *priv, void *data) return -EINVAL; } + if (!cam_ope_is_pending_request(ctx_data)) { + CAM_WARN(CAM_OPE, "no pending req, req %lld last flush %lld", + task_data->req_id, ctx_data->last_flush_req); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + 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, @@ -256,11 +270,6 @@ static int cam_ope_mgr_reapply_config(struct cam_ope_hw_mgr *hw_mgr, return rc; } -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; -- GitLab From 9466904129f8bc3d2dae4a8a2c317ee8d1a533b5 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Thu, 5 Nov 2020 16:20:35 +0530 Subject: [PATCH 248/295] msm: camera: ope: Add support to dynamic switch pix_pattern Add support to dynamically switch pix_pattern of read clients based on data received in each request. CRs-Fixed: 2811530 Change-Id: Icb3ebd33cae59b8db87bc0011d6560492ad29c3a Signed-off-by: Rishabh Jain --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 8 ++++++++ drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 1 + drivers/cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.c | 2 +- include/uapi/media/cam_ope.h | 4 ++-- 4 files changed, 12 insertions(+), 3 deletions(-) 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 543804099c9a..7a08eebc864c 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 @@ -1947,6 +1947,14 @@ static int cam_ope_mgr_process_cmd_io_buf_req(struct cam_ope_hw_mgr *hw_mgr, alignment = in_res->alignment; unpack_format = in_res->unpacker_format; pack_format = 0; + if (in_io_buf->pix_pattern > + PIXEL_PATTERN_CRYCBY) { + CAM_ERR(CAM_OPE, + "Invalid pix pattern = %u", + in_io_buf->pix_pattern); + return -EINVAL; + } + io_buf->pix_pattern = in_io_buf->pix_pattern; } else if (in_io_buf->direction == CAM_BUF_OUTPUT) { out_res = &ctx_data->ope_acquire.out_res[rsc_idx]; 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 3d3d11598701..3bc09be0b88c 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 @@ -363,6 +363,7 @@ struct ope_io_buf { uint32_t format; uint32_t fence; uint32_t num_planes; + uint32_t pix_pattern; uint32_t num_stripes[OPE_MAX_PLANES]; struct ope_stripe_io s_io[OPE_MAX_PLANES][OPE_MAX_STRIPES]; }; 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 0042675f1821..033df2b6666d 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 @@ -244,7 +244,7 @@ static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info, temp = 0; temp |= stripe_io->s_location & rd_res_val_client->stripe_location_mask; - temp |= (io_port_info->pixel_pattern[rsc_type] & + temp |= (io_buf->pix_pattern & rd_res_val_client->pix_pattern_mask) << rd_res_val_client->pix_pattern_shift; temp_reg[count++] = temp; diff --git a/include/uapi/media/cam_ope.h b/include/uapi/media/cam_ope.h index 812212f3170b..a7d800844103 100644 --- a/include/uapi/media/cam_ope.h +++ b/include/uapi/media/cam_ope.h @@ -104,7 +104,7 @@ struct ope_stripe_info { * @direction: Direction of a buffer of a port(Input/Output) * @resource_type: Port type * @num_planes: Number of planes for a port - * @reserved: Reserved + * @pix_pattern: Pixel pattern for raw input * @num_stripes: Stripes per plane * @mem_handle: Memhandles of each Input/Output Port * @plane_offset: Offsets of planes @@ -120,7 +120,7 @@ struct ope_io_buf_info { uint32_t direction; uint32_t resource_type; uint32_t num_planes; - uint32_t reserved; + uint32_t pix_pattern; uint32_t num_stripes[OPE_MAX_PLANES]; uint32_t mem_handle[OPE_MAX_PLANES]; uint32_t plane_offset[OPE_MAX_PLANES]; -- GitLab From 43188bce45e521df53249b041d2a01cb4dbcba27 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Mon, 9 Nov 2020 18:56:10 +0530 Subject: [PATCH 249/295] msm: camera: ope: handle unlocking in process timer In process timer, if there are no empty taks then it returns without unlocking context mutext. This lead to deadlock later if other tasks are waiting on this lock. CRs-Fixed: 2823721 Change-Id: I478d1797be59d975e9d58e005a5fad5c22656f51 Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 1 + 1 file changed, 1 insertion(+) 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 3a8a26d1d8bb..a9ef85678757 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 @@ -707,6 +707,7 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) 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; -- GitLab From 55ad64a296d0cf159003d30755b1db66e449b16e Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Tue, 24 Nov 2020 16:34:52 +0530 Subject: [PATCH 250/295] msm: camera: cdm: Added cdm power state check There is chance that handle error info get scheduled after cdm deinit. As clock and regulator gets disabled as part of deinit so this can cause issue for cdm hw interaction as part of handle error. Added cdm power state check before dumping CDM HW status at the time of error. CRs-Fixed: 2833653 Change-Id: I4bf01ce3900196909cf66ffdb24607c50ab03295 Signed-off-by: Alok Chauhan --- drivers/cam_cdm/cam_cdm_hw_core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 4be9e62f261b..55209a62f859 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1587,6 +1587,11 @@ int cam_hw_cdm_handle_error_info( set_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); set_bit(CAM_CDM_FLUSH_HW_STATUS, &cdm_core->cdm_status); + if (cdm_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_WARN(CAM_CDM, "CDM is in power down state"); + goto end; + } + /* First pause CDM, If it fails still proceed to dump debug info */ cam_hw_cdm_pause_core(cdm_hw, true); -- GitLab From acb41133c9d04218ed2980429d7bce1fc4dc3846 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Wed, 9 Dec 2020 15:52:22 +0530 Subject: [PATCH 251/295] msm: camera: reqmgr: Do not trigger UMD recovery in WQ congestion In WQ congestion case do not trigger UMD recovery as for back to back apply, apply failure is expected because ISP is in still in applied state. CRs-Fixed: 2840473 Change-Id: Ib57e1db1e5bf8f20e5e454d985efc002d50e3ba6 Signed-off-by: Wyes Karny --- drivers/cam_req_mgr/cam_req_mgr_core.c | 81 ++++++++++++++++---------- drivers/cam_req_mgr/cam_req_mgr_core.h | 6 ++ 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 38cfef654cdd..0001a0e5c6ec 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -198,10 +198,16 @@ static void __cam_req_mgr_find_dev_name( if (masked_val & (1 << dev->dev_bit)) continue; - CAM_INFO(CAM_CRM, - "Skip Frame: req: %lld not ready on link: 0x%x for pd: %d dev: %s open_req count: %d", - req_id, link->link_hdl, pd, dev->dev_info.name, - link->open_req_cnt); + if (link->wq_congestion) + CAM_INFO_RATE_LIMIT(CAM_CRM, + "WQ congestion, Skip Frame: req: %lld not ready on link: 0x%x for pd: %d dev: %s open_req count: %d", + req_id, link->link_hdl, pd, + dev->dev_info.name, link->open_req_cnt); + else + CAM_INFO(CAM_CRM, + "Skip Frame: req: %lld not ready on link: 0x%x for pd: %d dev: %s open_req count: %d", + req_id, link->link_hdl, pd, + dev->dev_info.name, link->open_req_cnt); } } } @@ -1371,18 +1377,18 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, if (slot->status == CRM_SLOT_STATUS_NO_REQ) { CAM_DBG(CAM_CRM, "No Pending req"); rc = 0; - goto error; + goto end; } if ((trigger != CAM_TRIGGER_POINT_SOF) && (trigger != CAM_TRIGGER_POINT_EOF)) - goto error; + goto end; if ((trigger == CAM_TRIGGER_POINT_EOF) && (!(link->trigger_mask & CAM_TRIGGER_POINT_SOF))) { CAM_DBG(CAM_CRM, "Applying for last SOF fails"); rc = -EINVAL; - goto error; + goto end; } if (trigger == CAM_TRIGGER_POINT_SOF) { @@ -1393,11 +1399,19 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, link->prev_sof_timestamp = link->sof_timestamp; link->sof_timestamp = trigger_data->sof_timestamp_val; + /* Check for WQ congestion */ + if (jiffies_to_msecs(jiffies - + link->last_sof_trigger_jiffies) < + MINIMUM_WORKQUEUE_SCHED_TIME_IN_MS) + link->wq_congestion = true; + else + link->wq_congestion = false; + if (link->trigger_mask) { CAM_ERR_RATE_LIMIT(CAM_CRM, "Applying for last EOF fails"); rc = -EINVAL; - goto error; + goto end; } if ((slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) && @@ -1457,7 +1471,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, rc = -EPERM; } spin_unlock_bh(&link->link_state_spin_lock); - goto error; + goto end; } } @@ -1466,24 +1480,30 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, /* Apply req failed retry at next sof */ slot->status = CRM_SLOT_STATUS_REQ_PENDING; - link->retry_cnt++; - if (link->retry_cnt == MAXIMUM_RETRY_ATTEMPTS) { - CAM_DBG(CAM_CRM, - "Max retry attempts reached on link[0x%x] for req [%lld]", - link->link_hdl, - in_q->slot[in_q->rd_idx].req_id); - - cam_req_mgr_debug_delay_detect(); - trace_cam_delay_detect("CRM", - "Max retry attempts reached", - in_q->slot[in_q->rd_idx].req_id, - CAM_DEFAULT_VALUE, - link->link_hdl, - CAM_DEFAULT_VALUE, rc); - - __cam_req_mgr_notify_error_on_link(link, dev); - link->retry_cnt = 0; - } + if (!link->wq_congestion && dev) { + link->retry_cnt++; + if (link->retry_cnt == MAXIMUM_RETRY_ATTEMPTS) { + CAM_DBG(CAM_CRM, + "Max retry attempts reached on link[0x%x] for req [%lld]", + link->link_hdl, + in_q->slot[in_q->rd_idx].req_id); + + cam_req_mgr_debug_delay_detect(); + trace_cam_delay_detect("CRM", + "Max retry attempts reached", + in_q->slot[in_q->rd_idx].req_id, + CAM_DEFAULT_VALUE, + link->link_hdl, + CAM_DEFAULT_VALUE, rc); + + __cam_req_mgr_notify_error_on_link(link, dev); + link->retry_cnt = 0; + } + } else + CAM_WARN_RATE_LIMIT(CAM_CRM, + "workqueue congestion, last applied idx:%d rd idx:%d", + in_q->last_applied_idx, + in_q->rd_idx); } else { if (link->retry_cnt) link->retry_cnt = 0; @@ -1531,10 +1551,9 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, link->open_req_cnt--; } } - - mutex_unlock(&session->lock); - return rc; -error: +end: + if (trigger == CAM_TRIGGER_POINT_SOF) + link->last_sof_trigger_jiffies = jiffies; mutex_unlock(&session->lock); return rc; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 09f95e7072ed..b7677ed36ca9 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -36,6 +36,8 @@ #define MAXIMUM_RETRY_ATTEMPTS 2 +#define MINIMUM_WORKQUEUE_SCHED_TIME_IN_MS 5 + #define VERSION_1 1 #define VERSION_2 2 @@ -346,6 +348,8 @@ struct cam_req_mgr_connected_device { * as part of shutdown. * @sof_timestamp_value : SOF timestamp value * @prev_sof_timestamp : Previous SOF timestamp value + * @last_sof_trigger_jiffies : Record the jiffies of last sof trigger jiffies + * @wq_congestion : Indicates if WQ congestion is detected or not */ struct cam_req_mgr_core_link { int32_t link_hdl; @@ -376,6 +380,8 @@ struct cam_req_mgr_core_link { bool is_shutdown; uint64_t sof_timestamp; uint64_t prev_sof_timestamp; + uint64_t last_sof_trigger_jiffies; + bool wq_congestion; }; /** -- GitLab From 7305ccde1416c2defe600f1f6cabc97e6bfd196b Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Tue, 23 Feb 2021 16:45:30 -0800 Subject: [PATCH 252/295] msm: camera: cdm: Fix of_match table null entry KASAN identified global-out-of-bounds issue on: msm_cam_hw_cdm_dt_match Due to no null-terminating struct in the array. CRs-Fixed: 2883523 Change-Id: I36e4811f239993e1e6de158df959157217c28bfe Signed-off-by: Karthik Jayakumar --- drivers/cam_cdm/cam_cdm_hw_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 55209a62f859..67161fcde38f 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -60,6 +60,7 @@ static const struct of_device_id msm_cam_hw_cdm_dt_match[] = { .compatible = CAM_HW_CDM_OPE_NAME_2_0, .data = &cam_cdm_2_0_reg_offset, }, + {}, }; static enum cam_cdm_id cam_hw_cdm_get_id_by_name(char *name) -- GitLab From d48a76255ded22425cd2691caab5e8f2a4f024fd Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Thu, 3 Jun 2021 15:49:05 +0530 Subject: [PATCH 253/295] msm: camera: cdm: Add support for CDM 2.1 This change adds CDM 2.1 support. CRs-Fixed: 2960970 Change-Id: I8cca47a59304c15c7673de398454ab0e99506dab Signed-off-by: Ayush Kumar --- drivers/cam_cdm/cam_cdm.h | 5 +- drivers/cam_cdm/cam_cdm_core_common.c | 4 +- drivers/cam_cdm/cam_cdm_core_common.h | 3 +- drivers/cam_cdm/cam_cdm_hw_core.c | 35 +++- drivers/cam_cdm/cam_cdm_hw_reg_2_1.h | 253 ++++++++++++++++++++++++++ drivers/cam_cdm/cam_cdm_soc.h | 5 +- 6 files changed, 300 insertions(+), 5 deletions(-) create mode 100644 drivers/cam_cdm/cam_cdm_hw_reg_2_1.h diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index 1814bcddda97..938c5a2dc190 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_H_ @@ -276,6 +276,7 @@ struct cam_cdm_common_reg_data { * wait, etc. * @core_en: offset to pause/enable CDM * @fe_cfg: offset to configure CDM fetch engine + * @irq_context_status offset to read back irq context status * @bl_fifo_rb: offset to set BL_FIFO read back * @bl_fifo_base_rb: offset to read back base address on offset set by * bl_fifo_rb @@ -319,6 +320,7 @@ struct cam_cdm_common_regs { uint32_t core_cfg; uint32_t core_en; uint32_t fe_cfg; + uint32_t irq_context_status; uint32_t bl_fifo_rb; uint32_t bl_fifo_base_rb; uint32_t bl_fifo_len_rb; @@ -415,6 +417,7 @@ enum cam_cdm_hw_version { CAM_CDM_VERSION_1_1 = 0x10010000, CAM_CDM_VERSION_1_2 = 0x10020000, CAM_CDM_VERSION_2_0 = 0x20000000, + CAM_CDM_VERSION_2_1 = 0x20010000, CAM_CDM_VERSION_MAX, }; diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index 8859fa833546..238af5282b5f 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -49,6 +49,7 @@ bool cam_cdm_set_cam_hw_version( case CAM_CDM110_VERSION: case CAM_CDM120_VERSION: case CAM_CDM200_VERSION: + case CAM_CDM210_VERSION: cam_version->major = (ver & 0xF0000000); cam_version->minor = (ver & 0xFFF0000); cam_version->incr = (ver & 0xFFFF); @@ -81,6 +82,7 @@ struct cam_cdm_utils_ops *cam_cdm_get_ops( case CAM_CDM110_VERSION: case CAM_CDM120_VERSION: case CAM_CDM200_VERSION: + case CAM_CDM210_VERSION: return &CDM170_ops; default: CAM_ERR(CAM_CDM, "CDM Version=%x not supported in util", diff --git a/drivers/cam_cdm/cam_cdm_core_common.h b/drivers/cam_cdm/cam_cdm_core_common.h index 5545f15903e0..9b6741ce6653 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.h +++ b/drivers/cam_cdm/cam_cdm_core_common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_CORE_COMMON_H_ @@ -12,6 +12,7 @@ #define CAM_CDM110_VERSION 0x10010000 #define CAM_CDM120_VERSION 0x10020000 #define CAM_CDM200_VERSION 0x20000000 +#define CAM_CDM210_VERSION 0x20010000 #define CAM_CDM_AHB_BURST_LEN_1 (BIT(1) - 1) #define CAM_CDM_AHB_BURST_LEN_4 (BIT(2) - 1) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 67161fcde38f..6a95c1cc6bf1 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -22,6 +22,7 @@ #include "cam_cdm_hw_reg_1_1.h" #include "cam_cdm_hw_reg_1_2.h" #include "cam_cdm_hw_reg_2_0.h" +#include "cam_cdm_hw_reg_2_1.h" #include "cam_trace.h" #include "cam_req_mgr_workq.h" @@ -60,6 +61,18 @@ static const struct of_device_id msm_cam_hw_cdm_dt_match[] = { .compatible = CAM_HW_CDM_OPE_NAME_2_0, .data = &cam_cdm_2_0_reg_offset, }, + { + .compatible = CAM_HW_CDM_CPAS_NAME_2_1, + .data = &cam_cdm_2_1_reg_offset, + }, + { + .compatible = CAM_HW_CDM_OPE_NAME_2_1, + .data = &cam_cdm_2_1_reg_offset, + }, + { + .compatible = CAM_HW_CDM_IFE_NAME_2_1, + .data = &cam_cdm_2_1_reg_offset, + }, {}, }; @@ -86,6 +99,15 @@ static enum cam_cdm_id cam_hw_cdm_get_id_by_name(char *name) if (strnstr(name, CAM_HW_CDM_OPE_NAME_2_0, strlen(CAM_HW_CDM_CPAS_NAME_2_0))) return CAM_CDM_OPE; + if (strnstr(name, CAM_HW_CDM_CPAS_NAME_2_1, + strlen(CAM_HW_CDM_CPAS_NAME_2_1))) + return CAM_CDM_CPAS; + if (strnstr(name, CAM_HW_CDM_OPE_NAME_2_1, + strlen(CAM_HW_CDM_OPE_NAME_2_1))) + return CAM_CDM_OPE; + if (strnstr(name, CAM_HW_CDM_IFE_NAME_2_1, + strlen(CAM_HW_CDM_IFE_NAME_2_1))) + return CAM_CDM_IFE; return CAM_CDM_MAX; } @@ -1339,17 +1361,28 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) struct cam_cdm_work_payload *payload[CAM_CDM_BL_FIFO_MAX] = {0}; uint32_t user_data = 0; uint32_t irq_status[CAM_CDM_BL_FIFO_MAX] = {0}; + uint32_t irq_context_summary = 0xF; bool work_status; int i; - CAM_DBG(CAM_CDM, "Got irq"); + CAM_DBG(CAM_CDM, "Got irq hw_version 0x%x", cdm_core->hw_version); 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; } + if (cdm_core->hw_version >= CAM_CDM_VERSION_2_1) { + if (cam_cdm_read_hw_reg(cdm_hw, + cdm_core->offsets->cmn_reg->irq_context_status, + &irq_context_summary)) { + CAM_ERR(CAM_CDM, "Failed to read CDM HW IRQ status"); + } + } for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo_irq; i++) { + if (!(BIT(i) & irq_context_summary)) + continue; + if (cam_cdm_read_hw_reg(cdm_hw, cdm_core->offsets->irq_reg[i]->irq_status, &irq_status[i])) { diff --git a/drivers/cam_cdm/cam_cdm_hw_reg_2_1.h b/drivers/cam_cdm/cam_cdm_hw_reg_2_1.h new file mode 100644 index 000000000000..a12be17a3c4a --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_hw_reg_2_1.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#include "cam_cdm.h" + +struct cam_cdm_bl_pending_req_reg_params cdm_hw_2_1_bl_pending_req0 = { + .rb_offset = 0x6c, + .rb_mask = 0x1ff, + .rb_num_fifo = 0x2, + .rb_next_fifo_shift = 0x10, +}; + +struct cam_cdm_bl_pending_req_reg_params cdm_hw_2_1_bl_pending_req1 = { + .rb_offset = 0x70, + .rb_mask = 0x1ff, + .rb_num_fifo = 0x2, + .rb_next_fifo_shift = 0x10, +}; + +static struct cam_cdm_irq_regs cdm_hw_2_1_irq0 = { + .irq_mask = 0x30, + .irq_clear = 0x34, + .irq_clear_cmd = 0x38, + .irq_set = 0x3c, + .irq_set_cmd = 0x40, + .irq_status = 0x44, +}; + +static struct cam_cdm_irq_regs cdm_hw_2_1_irq1 = { + .irq_mask = 0x130, + .irq_clear = 0x134, + .irq_clear_cmd = 0x138, + .irq_set = 0x13c, + .irq_set_cmd = 0x140, + .irq_status = 0x144, +}; + +static struct cam_cdm_irq_regs cdm_hw_2_1_irq2 = { + .irq_mask = 0x230, + .irq_clear = 0x234, + .irq_clear_cmd = 0x238, + .irq_set = 0x23c, + .irq_set_cmd = 0x240, + .irq_status = 0x244, +}; + +static struct cam_cdm_irq_regs cdm_hw_2_1_irq3 = { + .irq_mask = 0x330, + .irq_clear = 0x334, + .irq_clear_cmd = 0x338, + .irq_set = 0x33c, + .irq_set_cmd = 0x340, + .irq_status = 0x344, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_2_1_bl_fifo0 = { + .bl_fifo_base = 0x50, + .bl_fifo_len = 0x54, + .bl_fifo_store = 0x58, + .bl_fifo_cfg = 0x5c, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_2_1_bl_fifo1 = { + .bl_fifo_base = 0x150, + .bl_fifo_len = 0x154, + .bl_fifo_store = 0x158, + .bl_fifo_cfg = 0x15c, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_2_1_bl_fifo2 = { + .bl_fifo_base = 0x250, + .bl_fifo_len = 0x254, + .bl_fifo_store = 0x258, + .bl_fifo_cfg = 0x25c, +}; + +static struct cam_cdm_bl_fifo_regs cdm_hw_2_1_bl_fifo3 = { + .bl_fifo_base = 0x350, + .bl_fifo_len = 0x354, + .bl_fifo_store = 0x358, + .bl_fifo_cfg = 0x35c, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg0 = { + .scratch_reg = 0x90, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg1 = { + .scratch_reg = 0x94, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg2 = { + .scratch_reg = 0x98, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg3 = { + .scratch_reg = 0x9c, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg4 = { + .scratch_reg = 0xa0, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg5 = { + .scratch_reg = 0xa4, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg6 = { + .scratch_reg = 0xa8, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg7 = { + .scratch_reg = 0xac, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg8 = { + .scratch_reg = 0xb0, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg9 = { + .scratch_reg = 0xb4, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg10 = { + .scratch_reg = 0xb8, +}; + +static struct cam_cdm_scratch_reg cdm_2_1_scratch_reg11 = { + .scratch_reg = 0xbc, +}; + +static struct cam_cdm_perf_mon_regs cdm_2_1_perf_mon0 = { + .perf_mon_ctrl = 0x110, + .perf_mon_0 = 0x114, + .perf_mon_1 = 0x118, + .perf_mon_2 = 0x11c, +}; + +static struct cam_cdm_perf_mon_regs cdm_2_1_perf_mon1 = { + .perf_mon_ctrl = 0x120, + .perf_mon_0 = 0x124, + .perf_mon_1 = 0x128, + .perf_mon_2 = 0x12c, +}; + +static struct cam_cdm_comp_wait_status cdm_2_1_comp_wait_status0 = { + .comp_wait_status = 0x88, +}; + +static struct cam_cdm_comp_wait_status cdm_2_1_comp_wait_status1 = { + .comp_wait_status = 0x8c, +}; + +static struct cam_cdm_icl_data_regs cdm_2_1_icl_data = { + .icl_last_data_0 = 0x1c0, + .icl_last_data_1 = 0x1c4, + .icl_last_data_2 = 0x1c8, + .icl_inv_data = 0x1cc, +}; + +static struct cam_cdm_icl_misc_regs cdm_2_1_icl_misc = { + .icl_inv_bl_addr = 0x1d0, + .icl_status = 0x1d8, +}; + +static struct cam_cdm_icl_regs cdm_2_1_icl = { + .data_regs = &cdm_2_1_icl_data, + .misc_regs = &cdm_2_1_icl_misc, +}; + +static struct cam_cdm_common_regs cdm_hw_2_1_cmn_reg_offset = { + .cdm_hw_version = 0x0, + .cam_version = NULL, + .rst_cmd = 0x10, + .cgc_cfg = 0x14, + .core_cfg = 0x18, + .core_en = 0x1c, + .fe_cfg = 0x20, + .irq_context_status = 0x2c, + .bl_fifo_rb = 0x60, + .bl_fifo_base_rb = 0x64, + .bl_fifo_len_rb = 0x68, + .usr_data = 0x80, + .wait_status = 0x84, + .last_ahb_addr = 0xd0, + .last_ahb_data = 0xd4, + .core_debug = 0xd8, + .last_ahb_err_addr = 0xe0, + .last_ahb_err_data = 0xe4, + .current_bl_base = 0xe8, + .current_bl_len = 0xec, + .current_used_ahb_base = 0xf0, + .debug_status = 0xf4, + .bus_misr_cfg0 = 0x100, + .bus_misr_cfg1 = 0x104, + .bus_misr_rd_val = 0x108, + .pending_req = { + &cdm_hw_2_1_bl_pending_req0, + &cdm_hw_2_1_bl_pending_req1, + }, + .comp_wait = { + &cdm_2_1_comp_wait_status0, + &cdm_2_1_comp_wait_status1, + }, + .perf_mon = { + &cdm_2_1_perf_mon0, + &cdm_2_1_perf_mon1, + }, + .scratch = { + &cdm_2_1_scratch_reg0, + &cdm_2_1_scratch_reg1, + &cdm_2_1_scratch_reg2, + &cdm_2_1_scratch_reg3, + &cdm_2_1_scratch_reg4, + &cdm_2_1_scratch_reg5, + &cdm_2_1_scratch_reg6, + &cdm_2_1_scratch_reg7, + &cdm_2_1_scratch_reg8, + &cdm_2_1_scratch_reg9, + &cdm_2_1_scratch_reg10, + &cdm_2_1_scratch_reg11, + }, + .perf_reg = NULL, + .icl_reg = &cdm_2_1_icl, + .spare = 0x3fc, +}; + +static struct cam_cdm_common_reg_data cdm_hw_2_1_cmn_reg_data = { + .num_bl_fifo = 0x4, + .num_bl_fifo_irq = 0x4, + .num_bl_pending_req_reg = 0x2, + .num_scratch_reg = 0xc, +}; + +struct cam_cdm_hw_reg_offset cam_cdm_2_1_reg_offset = { + .cmn_reg = &cdm_hw_2_1_cmn_reg_offset, + .bl_fifo_reg = { + &cdm_hw_2_1_bl_fifo0, + &cdm_hw_2_1_bl_fifo1, + &cdm_hw_2_1_bl_fifo2, + &cdm_hw_2_1_bl_fifo3, + }, + .irq_reg = { + &cdm_hw_2_1_irq0, + &cdm_hw_2_1_irq1, + &cdm_hw_2_1_irq2, + &cdm_hw_2_1_irq3, + }, + .reg_data = &cdm_hw_2_1_cmn_reg_data, +}; + diff --git a/drivers/cam_cdm/cam_cdm_soc.h b/drivers/cam_cdm/cam_cdm_soc.h index 137922e1bd35..320c406feac3 100644 --- a/drivers/cam_cdm/cam_cdm_soc.h +++ b/drivers/cam_cdm/cam_cdm_soc.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-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_SOC_H_ @@ -13,6 +13,9 @@ #define CAM_HW_CDM_IFE_NAME_1_2 "qcom,cam-ife-cdm1_2" #define CAM_HW_CDM_CPAS_NAME_2_0 "qcom,cam-cpas-cdm2_0" #define CAM_HW_CDM_OPE_NAME_2_0 "qcom,cam-ope-cdm2_0" +#define CAM_HW_CDM_CPAS_NAME_2_1 "qcom,cam-cpas-cdm2_1" +#define CAM_HW_CDM_OPE_NAME_2_1 "qcom,cam-ope-cdm2_1" +#define CAM_HW_CDM_IFE_NAME_2_1 "qcom,cam-ife-cdm2_1" int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw, const struct of_device_id *table); -- GitLab From b06743ea615f3d401e0fa3bb4a7d95d1fcfed86b Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Mon, 5 Apr 2021 10:21:18 +0530 Subject: [PATCH 254/295] msm: camera: isp: Check ife out res validity This change adds validity check for ife out res. If ife out res is NULL we can run into crash or issues. CRs-Fixed: 2915741 Change-Id: I8722b2a4e2634bda42f0080e00bf09050bbd6b91 Signed-off-by: Vikram Sharma --- .../isp_hw_mgr/hw_utils/cam_isp_packet_parser.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index e0c2f55ef704..c5666158bd19 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.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-2021, The Linux Foundation. All rights reserved. */ #include @@ -140,6 +140,14 @@ static int cam_isp_update_dual_config( } hw_mgr_res = &res_list_isp_out[i]; + if (!hw_mgr_res) { + CAM_ERR(CAM_ISP, + "Invalid isp out resource i %d num_out_res %d", + i, dual_config->num_ports); + rc = -EINVAL; + goto end; + } + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { if (!hw_mgr_res->hw_res[j]) continue; -- GitLab From d86bddbd787edce25f8ab40848b9fb7ba0cd7308 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Mon, 24 May 2021 22:52:19 +0530 Subject: [PATCH 255/295] msm: camera: cpas: Add support for Khaje Camera Khaje has different version of CPAS version which requires camnoc interface changes and CPAS version change. This change adds the same. CRs-Fixed: 2960970 Change-Id: Iff58b7872129966879ecadab058d1d57cd439bea Signed-off-by: Ayush Kumar --- Makefile | 9 + config/khajecamera.conf | 6 + config/khajecameraconf.h | 8 + drivers/cam_cpas/cam_cpas_soc.c | 6 +- drivers/cam_cpas/cam_cpas_soc.h | 5 +- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 18 +- drivers/cam_cpas/cpas_top/cam_cpastop_hw.h | 6 +- .../cam_cpas/cpas_top/cpastop_v545_110_518.h | 320 ++++++++++++++++++ drivers/cam_cpas/include/cam_cpas_api.h | 12 +- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 22 +- 10 files changed, 399 insertions(+), 13 deletions(-) create mode 100644 config/khajecamera.conf create mode 100644 config/khajecameraconf.h create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v545_110_518.h diff --git a/Makefile b/Makefile index 9e0b13785b58..c32d9b5b8726 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,10 @@ ifeq ($(CONFIG_ARCH_BENGAL), y) include $(srctree)/techpack/camera/config/bengalcamera.conf endif +ifeq ($(CONFIG_ARCH_KHAJE), y) +include $(srctree)/techpack/camera/config/khajecamera.conf +endif + ifeq ($(CONFIG_ARCH_KONA), y) LINUXINCLUDE += \ -include $(srctree)/techpack/camera/config/konacameraconf.h @@ -28,6 +32,11 @@ LINUXINCLUDE += \ -include $(srctree)/techpack/camera/config/bengalcameraconf.h endif +ifeq ($(CONFIG_ARCH_KHAJE), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/khajecameraconf.h +endif + ifdef CONFIG_SPECTRA_CAMERA # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE += \ diff --git a/config/khajecamera.conf b/config/khajecamera.conf new file mode 100644 index 000000000000..d84667d275dd --- /dev/null +++ b/config/khajecamera.conf @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2021, The Linux Foundation. All rights reserved. + +export CONFIG_SPECTRA_CAMERA_OPE=y +export CONFIG_SPECTRA_CAMERA_TFE=y +export CONFIG_SPECTRA_CAMERA_SENSOR=y diff --git a/config/khajecameraconf.h b/config/khajecameraconf.h new file mode 100644 index 000000000000..583e5ec8b1d2 --- /dev/null +++ b/config/khajecameraconf.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_SPECTRA_CAMERA 1 +#define CONFIG_SPECTRA_CAMERA_OPE 1 +#define CONFIG_SPECTRA_CAMERA_TFE 1 diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index f6906025f368..2694c5ebaa1d 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/drivers/cam_cpas/cam_cpas_soc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. */ #include @@ -529,6 +529,10 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, (u32 *)&soc_private->camnoc_axi_min_ib_bw); } + soc_private->custom_id = 0; + rc = of_property_read_u32(of_node, + "custom-id", + &soc_private->custom_id); if (rc) { CAM_DBG(CAM_CPAS, "failed to read camnoc-axi-min-ib-bw rc:%d", rc); diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index 46c748fbb12f..c1e65803aff8 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/drivers/cam_cpas/cam_cpas_soc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_SOC_H_ @@ -109,6 +109,8 @@ struct cam_cpas_feature_info { * @feature_info: fuse based feature info for hw supported features * @cx_ipeak_gpu_limit: Flag for Cx Ipeak GPU mitigation * @gpu_pwr_limit: Handle for Cx Ipeak GPU Mitigation + * @custom_id: Custom id to differentiate between target if + * cpas version is same * */ struct cam_cpas_private_soc { @@ -129,6 +131,7 @@ struct cam_cpas_private_soc { struct cam_cpas_feature_info feature_info[CAM_CPAS_MAX_FUSE_FEATURE]; uint32_t cx_ipeak_gpu_limit; struct kgsl_pwr_limit *gpu_pwr_limit; + uint32_t custom_id; }; void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private); diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index f6af26fc579d..c8d96bd3672e 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -24,6 +24,7 @@ #include "cpastop_v480_100.h" #include "cpastop_v540_100.h" #include "cpastop_v520_100.h" +#include "cpastop_v545_110_518.h" #include "cam_req_mgr_workq.h" struct cam_camnoc_info *camnoc_info; @@ -133,6 +134,14 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, (hw_caps->camera_version.minor == 2) && (hw_caps->camera_version.incr == 0)) { soc_info->hw_version = CAM_CPAS_TITAN_520_V100; + } else if ((hw_caps->camera_version.major == 5) && + (hw_caps->camera_version.minor == 4) && + (hw_caps->camera_version.incr == 5)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 1) && + (hw_caps->cpas_version.incr == 0)) { + soc_info->hw_version = CAM_CPAS_TITAN_545_V110; + } } CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); @@ -605,6 +614,7 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, { int rc = 0; struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + struct cam_cpas_private_soc *soc_private; CAM_DBG(CAM_CPAS, "hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d", @@ -647,6 +657,12 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, case CAM_CPAS_TITAN_520_V100: camnoc_info = &cam520_cpas100_camnoc_info; break; + case CAM_CPAS_TITAN_545_V110: + soc_private = (struct cam_cpas_private_soc *) + soc_info->soc_private; + if (soc_private->custom_id == CAM_CPAS_TITAN_SOC_ID_518) + camnoc_info = &cam545_cpas110_socid518_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/cam_cpastop_hw.h b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h index 597f988f7de9..6a13d35b3e39 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPASTOP_HW_H_ @@ -107,6 +107,8 @@ enum cam_camnoc_hw_irq_type { * @CAM_CAMNOC_FD: Indicates FD HW connection to camnoc * @CAM_CAMNOC_ICP: Indicates ICP HW connection to camnoc * @CAM_CAMNOC_TFE: Indicates TFE HW connection to camnoc + * @CAM_CAMNOC_TFE_1 : Indicates TFE1 HW connection to camnoc + * @CAM_CAMNOC_TFE_2 : Indicates TFE2 HW connection to camnoc * @CAM_CAMNOC_OPE: Indicates OPE HW connection to camnoc */ enum cam_camnoc_port_type { @@ -131,6 +133,8 @@ enum cam_camnoc_port_type { CAM_CAMNOC_FD, CAM_CAMNOC_ICP, CAM_CAMNOC_TFE, + CAM_CAMNOC_TFE_1, + CAM_CAMNOC_TFE_2, CAM_CAMNOC_OPE, }; diff --git a/drivers/cam_cpas/cpas_top/cpastop_v545_110_518.h b/drivers/cam_cpas/cpas_top/cpastop_v545_110_518.h new file mode 100644 index 000000000000..2948f4217878 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v545_110_518.h @@ -0,0 +1,320 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V545_110_518_H_ +#define _CPASTOP_V545_110_518_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v545_110_socid518_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_v545_110_socid518_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_v545_110_socid518_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_TFE_1, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_LOW */ + .offset = 0x4030, + .value = 0x44443333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_HIGH */ + .offset = 0x4034, + .value = 0x66665555, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4038, /* TFE_URGENCY_LOW */ + .value = 0x00001030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x4040, /* TFE_DANGERLUT_LOW */ + .value = 0xFFFF0000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x4048, /* TFE_SAFELUT_LOW */ + .value = 0x00000003, + }, + }, + { + .port_type = CAM_CAMNOC_TFE_2, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_LOW */ + .offset = 0x5030, + .value = 0x44443333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_HIGH */ + .offset = 0x5034, + .value = 0x66665555, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5038, /* TFE_URGENCY_LOW */ + .value = 0x00001030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5040, /* TFE_DANGERLUT_LOW */ + .value = 0xFFFF0000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5048, /* TFE_SAFELUT_LOW */ + .value = 0x00000003, + }, + }, + { + .port_type = CAM_CAMNOC_OPE, + .enable = true, + .priority_lut_low = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* OPE_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = false, + .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 + cam545_cpas110_socid518_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 cam545_cpas110_socid518_camnoc_info = { + .specific = &cam_cpas_v545_110_socid518_camnoc_specific[0], + .specific_size = + ARRAY_SIZE(cam_cpas_v545_110_socid518_camnoc_specific), + .irq_sbm = &cam_cpas_v545_110_socid518_irq_sbm, + .irq_err = &cam_cpas_v545_110_socid518_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v545_110_socid518_irq_err), + .err_logger = &cam545_cpas110_socid518_err_logger_offsets, + .errata_wa_list = NULL, +}; + +#endif /* _CPASTOP_V545_110_518_H_ */ diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 9dd3be1ff0d6..4c1a51119693 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_API_H_ @@ -48,9 +48,19 @@ enum cam_cpas_hw_version { CAM_CPAS_TITAN_480_V100 = 0x480100, CAM_CPAS_TITAN_540_V100 = 0x540100, CAM_CPAS_TITAN_520_V100 = 0x520100, + CAM_CPAS_TITAN_545_V110 = 0x545110, CAM_CPAS_TITAN_MAX }; +/** + * enum cam_cpas_hw_soc_id - Enum for Titan soc id + */ +enum cam_cpas_hw_soc_id { + CAM_CPAS_TITAN_SOC_ID_507 = 507, + CAM_CPAS_TITAN_SOC_ID_518 = 518, + CAM_CPAS_TITAN_SOC_ID_MAX +}; + /** * enum cam_camnoc_irq_type - Enum for camnoc irq types * 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 2eb42ce2673d..5618d1ec6c23 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -1902,6 +1902,7 @@ static int cam_tfe_camif_resource_start( uint32_t epoch0_irq_mask; uint32_t epoch1_irq_mask; uint32_t computed_epoch_line_cfg; + uint32_t camera_hw_version = 0; if (!camif_res || !core_info) { CAM_ERR(CAM_ISP, "Error Invalid input arguments"); @@ -1947,13 +1948,18 @@ static int cam_tfe_camif_resource_start( CAM_DBG(CAM_ISP, "TFE:%d core_cfg 0 val:0x%x", core_info->core_index, val); - val = cam_io_r(rsrc_data->mem_base + - rsrc_data->common_reg->core_cfg_1); - val &= ~BIT(0); - cam_io_w_mb(val, rsrc_data->mem_base + - rsrc_data->common_reg->core_cfg_1); - CAM_DBG(CAM_ISP, "TFE:%d core_cfg 1 val:0x%x", core_info->core_index, - val); + if (cam_cpas_get_cpas_hw_version(&camera_hw_version)) + CAM_ERR(CAM_ISP, "Failed to get HW version"); + + if (camera_hw_version == CAM_CPAS_TITAN_540_V100) { + val = cam_io_r(rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_1); + val &= ~BIT(0); + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_1); + CAM_DBG(CAM_ISP, "TFE:%d core_cfg 1 val:0x%x", + core_info->core_index, val); + } /* Epoch config */ epoch0_irq_mask = ((rsrc_data->last_line - -- GitLab From 66dc2207fee3973a92378e454ee466eca561fc46 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Sun, 6 Jun 2021 01:22:47 +0530 Subject: [PATCH 256/295] msm: camera: isp: Added PPI driver functionality PPI is a bridge between CSIPHY and CSID. Responsibilty of this driver is to enable and configure PPI bridge from CSID as per the configuration. CRs-Fixed: 2960970 Change-Id: I0606b8ee06f6fbc2f84c3be628f356192a79f5a5 Signed-off-by: Ayush Kumar --- drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile | 2 +- .../cam_isp/isp_hw_mgr/isp_hw/ppi_hw/Makefile | 14 + .../isp_hw/ppi_hw/cam_csid_ppi100.c | 50 +++ .../isp_hw/ppi_hw/cam_csid_ppi100.h | 25 ++ .../isp_hw/ppi_hw/cam_csid_ppi_core.c | 392 ++++++++++++++++++ .../isp_hw/ppi_hw/cam_csid_ppi_core.h | 95 +++++ .../isp_hw/ppi_hw/cam_csid_ppi_dev.c | 139 +++++++ .../isp_hw/ppi_hw/cam_csid_ppi_dev.h | 15 + .../isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile | 1 + .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 57 ++- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.h | 8 +- 11 files changed, 794 insertions(+), 4 deletions(-) create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_dev.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_dev.h diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile index 67cf169a3569..cdbc6779b9dc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_SPECTRA_CAMERA) += top_tpg/ ifdef CONFIG_SPECTRA_CAMERA_TFE -obj-$(CONFIG_SPECTRA_CAMERA) += tfe_csid_hw/ tfe_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += tfe_csid_hw/ tfe_hw/ ppi_hw/ endif ifdef CONFIG_SPECTRA_CAMERA_IFE diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/Makefile new file mode 100644 index 000000000000..9c21987f7e70 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_csid_ppi_dev.o cam_csid_ppi_core.o cam_csid_ppi100.o diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.c new file mode 100644 index 000000000000..7b2f449f277f --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_csid_ppi_core.h" +#include "cam_csid_ppi100.h" +#include "cam_csid_ppi_dev.h" + +#define CAM_PPI_DRV_NAME "ppi_100" +#define CAM_PPI_VERSION_V100 0x10000000 + +static struct cam_csid_ppi_hw_info cam_csid_ppi100_hw_info = { + .ppi_reg = &cam_csid_ppi_100_reg_offset, +}; + +static const struct of_device_id cam_csid_ppi100_dt_match[] = { + { + .compatible = "qcom,ppi100", + .data = &cam_csid_ppi100_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_csid_ppi100_dt_match); + +static struct platform_driver cam_csid_ppi100_driver = { + .probe = cam_csid_ppi_probe, + .remove = cam_csid_ppi_remove, + .driver = { + .name = CAM_PPI_DRV_NAME, + .of_match_table = cam_csid_ppi100_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_csid_ppi100_init_module(void) +{ + return platform_driver_register(&cam_csid_ppi100_driver); +} + +static void __exit cam_csid_ppi100_exit_module(void) +{ + platform_driver_unregister(&cam_csid_ppi100_driver); +} + +module_init(cam_csid_ppi100_init_module); +MODULE_DESCRIPTION("CAM CSID_PPI100 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.h new file mode 100644 index 000000000000..8aee24c13aef --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSID_PPI_100_H_ +#define _CAM_CSID_PPI_100_H_ + +#include "cam_csid_ppi_core.h" + +static struct cam_csid_ppi_reg_offset cam_csid_ppi_100_reg_offset = { + .ppi_hw_version_addr = 0, + .ppi_module_cfg_addr = 0x60, + .ppi_irq_status_addr = 0x68, + .ppi_irq_mask_addr = 0x6c, + .ppi_irq_set_addr = 0x70, + .ppi_irq_clear_addr = 0x74, + .ppi_irq_cmd_addr = 0x78, + .ppi_rst_cmd_addr = 0x7c, + .ppi_test_bus_ctrl_addr = 0x1f4, + .ppi_debug_addr = 0x1f8, + .ppi_spare_addr = 0x1fc, +}; + +#endif /*_CAM_CSID_PPI_100_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c new file mode 100644 index 000000000000..78f16ee9dba2 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include + +#include "cam_csid_ppi_core.h" +#include "cam_csid_ppi_dev.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" +#include "cam_io_util.h" + +static int cam_csid_ppi_reset(struct cam_csid_ppi_hw *ppi_hw) +{ + struct cam_hw_soc_info *soc_info; + const struct cam_csid_ppi_reg_offset *ppi_reg; + int rc = 0; + uint32_t status; + + soc_info = &ppi_hw->hw_info->soc_info; + ppi_reg = ppi_hw->ppi_info->ppi_reg; + + CAM_DBG(CAM_ISP, "PPI:%d reset", ppi_hw->hw_intf->hw_idx); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_mask_addr); + cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_set_addr); + cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_rst_cmd_addr); + cam_io_w_mb(PPI_IRQ_CMD_SET, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_cmd_addr); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_status_addr, status, + (status & 0x1) == 0x1, 1000, 500000); + CAM_DBG(CAM_ISP, "PPI:%d reset status %d", ppi_hw->hw_intf->hw_idx, + status); + if (rc < 0) { + CAM_ERR(CAM_ISP, "PPI:%d ppi_reset fail rc = %d status = %d", + ppi_hw->hw_intf->hw_idx, rc, status); + return rc; + } + cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_clear_addr); + cam_io_w_mb(PPI_IRQ_CMD_CLEAR, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_cmd_addr); + + return 0; +} + +static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw *ppi_hw) +{ + int rc = 0; + int32_t i; + uint64_t val; + const struct cam_csid_ppi_reg_offset *ppi_reg; + struct cam_hw_soc_info *soc_info; + uint32_t err_irq_mask; + + ppi_reg = ppi_hw->ppi_info->ppi_reg; + soc_info = &ppi_hw->hw_info->soc_info; + + CAM_DBG(CAM_ISP, "PPI:%d init PPI HW", ppi_hw->hw_intf->hw_idx); + + ppi_hw->hw_info->open_count++; + if (ppi_hw->hw_info->open_count > 1) { + CAM_DBG(CAM_ISP, "PPI:%d dual vfe already enabled", + ppi_hw->hw_intf->hw_idx); + return 0; + } + + for (i = 0; i < soc_info->num_clk; i++) { + rc = cam_soc_util_clk_enable(soc_info->clk[i], + soc_info->clk_name[i], 0); + if (rc) + goto clk_disable; + } + + rc = cam_csid_ppi_reset(ppi_hw); + if (rc) + goto clk_disable; + + err_irq_mask = PPI_IRQ_FIFO0_OVERFLOW | PPI_IRQ_FIFO1_OVERFLOW | + PPI_IRQ_FIFO2_OVERFLOW; + cam_io_w_mb(err_irq_mask, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_mask_addr); + rc = cam_soc_util_irq_enable(soc_info); + if (rc) + goto clk_disable; + + cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_clear_addr); + cam_io_w_mb(PPI_IRQ_CMD_CLEAR, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_cmd_addr); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + ppi_reg->ppi_hw_version_addr); + CAM_DBG(CAM_ISP, "PPI:%d PPI HW version: 0x%x", + ppi_hw->hw_intf->hw_idx, val); + ppi_hw->device_enabled = 1; + + return 0; +clk_disable: + for (--i; i >= 0; i--) + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + ppi_hw->hw_info->open_count--; + return rc; +} + +static int cam_csid_ppi_disable_hw(struct cam_csid_ppi_hw *ppi_hw) +{ + int rc = 0; + int i; + struct cam_hw_soc_info *soc_info; + const struct cam_csid_ppi_reg_offset *ppi_reg; + uint64_t ppi_cfg_val = 0; + + CAM_DBG(CAM_ISP, "PPI:%d De-init PPI HW", + ppi_hw->hw_intf->hw_idx); + + if (!ppi_hw->hw_info->open_count) { + CAM_WARN(CAM_ISP, "ppi[%d] unbalanced disable hw", + ppi_hw->hw_intf->hw_idx); + return -EINVAL; + } + ppi_hw->hw_info->open_count--; + + if (ppi_hw->hw_info->open_count) + return rc; + + soc_info = &ppi_hw->hw_info->soc_info; + ppi_reg = ppi_hw->ppi_info->ppi_reg; + + CAM_DBG(CAM_ISP, "Calling PPI Reset"); + cam_csid_ppi_reset(ppi_hw); + CAM_DBG(CAM_ISP, "PPI Reset Done"); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_mask_addr); + cam_soc_util_irq_disable(soc_info); + + for (i = 0; i < CAM_CSID_PPI_LANES_MAX; i++) + ppi_cfg_val &= ~PPI_CFG_CPHY_DLX_EN(i); + + cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_module_cfg_addr); + + ppi_hw->device_enabled = 0; + + for (i = 0; i < soc_info->num_clk; i++) + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + + return rc; +} + +static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, + uint32_t arg_size) +{ + int i, rc = 0; + uint32_t num_lanes; + uint32_t lanes[CAM_CSID_PPI_HW_MAX] = {0, 0, 0, 0}; + uint32_t cphy; + bool dl0, dl1; + uint32_t ppi_cfg_val = 0; + struct cam_csid_ppi_hw *ppi_hw; + struct cam_hw_info *ppi_hw_info; + const struct cam_csid_ppi_reg_offset *ppi_reg; + struct cam_hw_soc_info *soc_info; + struct cam_csid_ppi_cfg ppi_cfg; + + if (!hw_priv || !init_args || + (arg_size != sizeof(struct cam_csid_ppi_cfg))) { + CAM_ERR(CAM_ISP, "PPI: Invalid args"); + rc = -EINVAL; + goto end; + } + + dl0 = dl1 = false; + ppi_hw_info = (struct cam_hw_info *)hw_priv; + ppi_hw = (struct cam_csid_ppi_hw *)ppi_hw_info->core_info; + ppi_reg = ppi_hw->ppi_info->ppi_reg; + ppi_cfg = *((struct cam_csid_ppi_cfg *)init_args); + + rc = cam_csid_ppi_enable_hw(ppi_hw); + if (rc) + goto end; + + num_lanes = ppi_cfg.lane_num; + cphy = ppi_cfg.lane_type; + CAM_DBG(CAM_ISP, "lane_cfg 0x%x | num_lanes 0x%x | lane_type 0x%x", + ppi_cfg.lane_cfg, num_lanes, cphy); + + for (i = 0; i < num_lanes; i++) { + lanes[i] = ppi_cfg.lane_cfg & (0x3 << (4 * i)); + (lanes[i] < 2) ? (dl0 = true) : (dl1 = true); + CAM_DBG(CAM_ISP, "lanes[%d] %d", i, lanes[i]); + } + + if (num_lanes) { + if (cphy) { + for (i = 0; i < num_lanes; i++) { + ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(lanes[i]); + ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(lanes[i]); + } + } else { + if (dl0) + ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(0); + if (dl1) + ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(1); + } + } else { + CAM_ERR(CAM_ISP, + "Number of lanes to enable is cannot be zero"); + rc = -1; + goto end; + } + + CAM_DBG(CAM_ISP, "ppi_cfg_val 0x%x", ppi_cfg_val); + soc_info = &ppi_hw->hw_info->soc_info; + cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_module_cfg_addr); + + CAM_DBG(CAM_ISP, "ppi cfg 0x%x", + cam_io_r_mb(soc_info->reg_map[0].mem_base + + ppi_reg->ppi_module_cfg_addr)); +end: + return rc; +} + +static int cam_csid_ppi_deinit_hw(void *hw_priv, void *deinit_args, + uint32_t arg_size) +{ + int rc = 0; + struct cam_csid_ppi_hw *ppi_hw; + struct cam_hw_info *ppi_hw_info; + + CAM_DBG(CAM_ISP, "Enter"); + + if (!hw_priv) { + CAM_ERR(CAM_ISP, "PPI:Invalid arguments"); + rc = -EINVAL; + goto end; + } + + ppi_hw_info = (struct cam_hw_info *)hw_priv; + ppi_hw = (struct cam_csid_ppi_hw *)ppi_hw_info->core_info; + + CAM_DBG(CAM_ISP, "Disabling PPI Hw"); + rc = cam_csid_ppi_disable_hw(ppi_hw); + if (rc < 0) + CAM_DBG(CAM_ISP, "Exit with %d", rc); +end: + return rc; +} + +int cam_csid_ppi_hw_probe_init(struct cam_hw_intf *ppi_hw_intf, + uint32_t ppi_idx) +{ + int rc = -EINVAL; + struct cam_hw_info *ppi_hw_info; + struct cam_csid_ppi_hw *csid_ppi_hw = NULL; + + if (ppi_idx >= CAM_CSID_PPI_HW_MAX) { + CAM_ERR(CAM_ISP, "Invalid ppi index:%d", ppi_idx); + goto err; + } + + ppi_hw_info = (struct cam_hw_info *) ppi_hw_intf->hw_priv; + csid_ppi_hw = (struct cam_csid_ppi_hw *) ppi_hw_info->core_info; + + csid_ppi_hw->hw_intf = ppi_hw_intf; + csid_ppi_hw->hw_info = ppi_hw_info; + + CAM_DBG(CAM_ISP, "type %d index %d", + csid_ppi_hw->hw_intf->hw_type, ppi_idx); + + rc = cam_csid_ppi_init_soc_resources(&csid_ppi_hw->hw_info->soc_info, + cam_csid_ppi_irq, csid_ppi_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "PPI:%d Failed to init_soc", ppi_idx); + goto err; + } + + csid_ppi_hw->hw_intf->hw_ops.init = cam_csid_ppi_init_hw; + csid_ppi_hw->hw_intf->hw_ops.deinit = cam_csid_ppi_deinit_hw; + return 0; +err: + return rc; +} + +int cam_csid_ppi_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t ppi_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_ISP, "PPI: Failed to get dt properties"); + goto end; + } + + rc = cam_soc_util_request_platform_resource(soc_info, ppi_irq_handler, + irq_data); + if (rc) { + CAM_ERR(CAM_ISP, + "PPI: Error Request platform resources failed rc=%d", + rc); + goto err; + } +end: + return rc; +err: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} + +irqreturn_t cam_csid_ppi_irq(int irq_num, void *data) +{ + uint32_t irq_status = 0; + uint32_t i, ppi_cfg_val = 0; + bool fatal_err_detected = false; + + struct cam_csid_ppi_hw *ppi_hw; + struct cam_hw_soc_info *soc_info; + const struct cam_csid_ppi_reg_offset *ppi_reg; + + if (!data) { + CAM_ERR(CAM_ISP, "PPI: Invalid arguments"); + return IRQ_HANDLED; + } + + ppi_hw = (struct cam_csid_ppi_hw *)data; + ppi_reg = ppi_hw->ppi_info->ppi_reg; + soc_info = &ppi_hw->hw_info->soc_info; + + if (ppi_hw->device_enabled != 1) + goto ret; + + irq_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_status_addr); + + cam_io_w_mb(irq_status, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_clear_addr); + + cam_io_w_mb(PPI_IRQ_CMD_CLEAR, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_irq_cmd_addr); + + CAM_DBG(CAM_ISP, "PPI %d irq status 0x%x", ppi_hw->hw_intf->hw_idx, + irq_status); + + if (irq_status & PPI_IRQ_RST_DONE) { + CAM_DBG(CAM_ISP, "PPI Reset Done"); + goto ret; + } + if ((irq_status & PPI_IRQ_FIFO0_OVERFLOW) || + (irq_status & PPI_IRQ_FIFO1_OVERFLOW) || + (irq_status & PPI_IRQ_FIFO2_OVERFLOW)) { + fatal_err_detected = true; + goto handle_fatal_error; + } + +handle_fatal_error: + if (fatal_err_detected) { + CAM_ERR(CAM_ISP, "PPI: %d irq_status:0x%x", + ppi_hw->hw_intf->hw_idx, irq_status); + for (i = 0; i < CAM_CSID_PPI_LANES_MAX; i++) + ppi_cfg_val &= ~PPI_CFG_CPHY_DLX_EN(i); + + cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + + ppi_reg->ppi_module_cfg_addr); + } +ret: + CAM_DBG(CAM_ISP, "IRQ Handling exit"); + return IRQ_HANDLED; +} + +int cam_csid_ppi_hw_deinit(struct cam_csid_ppi_hw *csid_ppi_hw) +{ + if (!csid_ppi_hw) { + CAM_ERR(CAM_ISP, "Invalid param"); + return -EINVAL; + } + return cam_soc_util_release_platform_resource( + &csid_ppi_hw->hw_info->soc_info); +} + + diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h new file mode 100644 index 000000000000..84d0e2e67376 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSID_PPI_HW_H_ +#define _CAM_CSID_PPI_HW_H_ + +#include "cam_hw.h" +#include "cam_hw_intf.h" + +#define CAM_CSID_PPI_HW_MAX 4 +#define CAM_CSID_PPI_LANES_MAX 3 + +#define PPI_IRQ_RST_DONE BIT(0) +#define PPI_IRQ_FIFO0_OVERFLOW BIT(1) +#define PPI_IRQ_FIFO1_OVERFLOW BIT(2) +#define PPI_IRQ_FIFO2_OVERFLOW BIT(3) + +#define PPI_IRQ_CMD_SET BIT(1) + +#define PPI_IRQ_CMD_CLEAR BIT(0) + +#define PPI_RST_CONTROL BIT(0) +/* + * Select the PHY (CPHY set '1' or DPHY set '0') + */ +#define PPI_CFG_CPHY_DLX_SEL(X) ((X < 2) ? BIT(X) : 0) + +#define PPI_CFG_CPHY_DLX_EN(X) BIT(4+X) + +struct cam_csid_ppi_reg_offset { + uint32_t ppi_hw_version_addr; + uint32_t ppi_module_cfg_addr; + + uint32_t ppi_irq_status_addr; + uint32_t ppi_irq_mask_addr; + uint32_t ppi_irq_set_addr; + uint32_t ppi_irq_clear_addr; + uint32_t ppi_irq_cmd_addr; + uint32_t ppi_rst_cmd_addr; + uint32_t ppi_test_bus_ctrl_addr; + uint32_t ppi_debug_addr; + uint32_t ppi_spare_addr; +}; + +/** + * struct cam_csid_ppi_hw_info- ppi HW info + * + * @ppi_reg: ppi register offsets + * + */ +struct cam_csid_ppi_hw_info { + const struct cam_csid_ppi_reg_offset *ppi_reg; +}; + +/** + * struct cam_csid_ppi_hw- ppi hw device resources data + * + * @hw_intf: contain the ppi hw interface information + * @hw_info: ppi hw device information + * @ppi_info: ppi hw specific information + * @device_enabled Device enabled will set once ppi powered on and + * initial configuration are done. + * + */ +struct cam_csid_ppi_hw { + struct cam_hw_intf *hw_intf; + struct cam_hw_info *hw_info; + struct cam_csid_ppi_hw_info *ppi_info; + uint32_t device_enabled; +}; + +/** + * struct cam_csid_ppi_cfg - ppi lane configuration data + * @lane_type: lane type: c-phy or d-phy + * @lane_num : active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * + */ +struct cam_csid_ppi_cfg { + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; +}; + +int cam_csid_ppi_hw_probe_init(struct cam_hw_intf *ppi_hw_intf, + uint32_t ppi_idx); +int cam_csid_ppi_hw_deinit(struct cam_csid_ppi_hw *csid_ppi_hw); +int cam_csid_ppi_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t ppi_irq_handler, void *irq_data); +int cam_csid_ppi_deinit_soc_resources(struct cam_hw_soc_info *soc_info); +int cam_csid_ppi_hw_init(struct cam_hw_intf **csid_ppi_hw, + uint32_t hw_idx); +#endif /* _CAM_CSID_PPI_HW_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_dev.c new file mode 100644 index 000000000000..1467815d5e65 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_dev.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "cam_isp_hw.h" +#include "cam_hw_intf.h" +#include "cam_csid_ppi_core.h" +#include "cam_csid_ppi_dev.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_csid_ppi_hw_list[CAM_CSID_PPI_HW_MAX] = { + NULL, NULL, NULL, NULL}; +static char ppi_dev_name[8]; + +int cam_csid_ppi_probe(struct platform_device *pdev) +{ + struct cam_hw_intf *ppi_hw_intf; + struct cam_hw_info *ppi_hw_info; + struct cam_csid_ppi_hw *ppi_dev = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_csid_ppi_hw_info *ppi_hw_data = NULL; + uint32_t ppi_dev_idx; + int rc = 0; + + CAM_DBG(CAM_ISP, "PPI probe called"); + + ppi_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!ppi_hw_intf) { + rc = -ENOMEM; + goto err; + } + + ppi_hw_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!ppi_hw_info) { + rc = -ENOMEM; + goto free_hw_intf; + } + + ppi_dev = kzalloc(sizeof(struct cam_csid_ppi_hw), GFP_KERNEL); + if (!ppi_dev) { + rc = -ENOMEM; + goto free_hw_info; + } + + of_property_read_u32(pdev->dev.of_node, "cell-index", &ppi_dev_idx); + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ISP, "No matching table for the CSID PPI HW!"); + rc = -EINVAL; + goto free_dev; + } + + memset(ppi_dev_name, 0, sizeof(ppi_dev_name)); + snprintf(ppi_dev_name, sizeof(ppi_dev_name), "ppi%1u", ppi_dev_idx); + + ppi_hw_intf->hw_idx = ppi_dev_idx; + ppi_hw_intf->hw_priv = ppi_hw_info; + + if (ppi_hw_intf->hw_idx < CAM_CSID_PPI_HW_MAX) + cam_csid_ppi_hw_list[ppi_hw_intf->hw_idx] = ppi_hw_intf; + else { + rc = -EINVAL; + goto free_dev; + } + + ppi_hw_info->core_info = ppi_dev; + ppi_hw_info->soc_info.pdev = pdev; + ppi_hw_info->soc_info.dev = &pdev->dev; + ppi_hw_info->soc_info.dev_name = ppi_dev_name; + ppi_hw_info->soc_info.index = ppi_dev_idx; + + ppi_hw_data = (struct cam_csid_ppi_hw_info *)match_dev->data; + ppi_dev->ppi_info = ppi_hw_data; + + rc = cam_csid_ppi_hw_probe_init(ppi_hw_intf, ppi_dev_idx); + if (rc) { + CAM_ERR(CAM_ISP, "PPI: Probe init failed!"); + goto free_dev; + } + + platform_set_drvdata(pdev, ppi_dev); + CAM_DBG(CAM_ISP, "PPI:%d probe successful", + ppi_hw_intf->hw_idx); + + return 0; +free_dev: + kfree(ppi_dev); +free_hw_info: + kfree(ppi_hw_info); +free_hw_intf: + kfree(ppi_hw_intf); +err: + return rc; +} + +int cam_csid_ppi_remove(struct platform_device *pdev) +{ + struct cam_csid_ppi_hw *ppi_dev = NULL; + struct cam_hw_intf *ppi_hw_intf; + struct cam_hw_info *ppi_hw_info; + + ppi_dev = (struct cam_csid_ppi_hw *)platform_get_drvdata(pdev); + ppi_hw_intf = ppi_dev->hw_intf; + ppi_hw_info = ppi_dev->hw_info; + + CAM_DBG(CAM_ISP, "PPI:%d remove", ppi_dev->hw_intf->hw_idx); + + cam_csid_ppi_hw_deinit(ppi_dev); + + kfree(ppi_dev); + kfree(ppi_hw_info); + kfree(ppi_hw_intf); + + return 0; +} + +int cam_csid_ppi_hw_init(struct cam_hw_intf **csid_ppi_hw, + uint32_t hw_idx) +{ + int rc = 0; + + if (cam_csid_ppi_hw_list[hw_idx]) { + *csid_ppi_hw = cam_csid_ppi_hw_list[hw_idx]; + } else { + *csid_ppi_hw = NULL; + rc = -1; + } + + return rc; +} +EXPORT_SYMBOL(cam_csid_ppi_hw_init); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_dev.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_dev.h new file mode 100644 index 000000000000..2992c2243732 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_dev.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSID_PPI_DEV_H_ +#define _CAM_CSID_PPI_DEV_H_ + +#include "cam_isp_hw.h" + +irqreturn_t cam_csid_ppi_irq(int irq_num, void *data); +int cam_csid_ppi_probe(struct platform_device *pdev); +int cam_csid_ppi_remove(struct platform_device *pdev); + +#endif /*_CAM_CSID_PPI_DEV_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile index dcb41c82af58..956d9ca20bb5 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/Makefile @@ -8,6 +8,7 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ 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 8a90958c2065..f2e03ce3200a 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -10,6 +10,7 @@ #include #include "cam_tfe_csid_core.h" +#include "cam_csid_ppi_core.h" #include "cam_isp_hw.h" #include "cam_soc_util.h" #include "cam_io_util.h" @@ -738,6 +739,8 @@ static int cam_tfe_csid_enable_csi2( { const struct cam_tfe_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; + struct cam_csid_ppi_cfg ppi_lane_cfg; + uint32_t ppi_index = 0, rc; uint32_t val = 0; csid_reg = csid_hw->csid_info->csid_reg; @@ -802,6 +805,23 @@ static int cam_tfe_csid_enable_csi2( cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + ppi_index = csid_hw->csi2_rx_cfg.phy_sel; + if (csid_hw->ppi_hw_intf[ppi_index] && csid_hw->ppi_enable) { + ppi_lane_cfg.lane_type = csid_hw->csi2_rx_cfg.lane_type; + ppi_lane_cfg.lane_num = csid_hw->csi2_rx_cfg.lane_num; + ppi_lane_cfg.lane_cfg = csid_hw->csi2_rx_cfg.lane_cfg; + + CAM_DBG(CAM_ISP, "ppi_index to init %d", ppi_index); + rc = csid_hw->ppi_hw_intf[ppi_index]->hw_ops.init( + csid_hw->ppi_hw_intf[ppi_index]->hw_priv, + &ppi_lane_cfg, + sizeof(struct cam_csid_ppi_cfg)); + if (rc < 0) { + CAM_ERR(CAM_ISP, "PPI:%d Init Failed", ppi_index); + return rc; + } + } + return 0; } @@ -810,6 +830,7 @@ static int cam_tfe_csid_disable_csi2( { const struct cam_tfe_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; + uint32_t ppi_index = 0, rc; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; @@ -826,6 +847,19 @@ static int cam_tfe_csid_disable_csi2( cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + ppi_index = csid_hw->csi2_rx_cfg.phy_sel; + if (csid_hw->ppi_hw_intf[ppi_index] && csid_hw->ppi_enable) { + /* De-Initialize the PPI bridge */ + CAM_DBG(CAM_ISP, "ppi_index to de-init %d\n", ppi_index); + rc = csid_hw->ppi_hw_intf[ppi_index]->hw_ops.deinit( + csid_hw->ppi_hw_intf[ppi_index]->hw_priv, + NULL, 0); + if (rc < 0) { + CAM_ERR(CAM_ISP, "PPI:%d De-Init Failed", ppi_index); + return rc; + } + } + return 0; } @@ -2700,13 +2734,15 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data) unsigned long flags; uint32_t i, val; - csid_hw = (struct cam_tfe_csid_hw *)data; if (!data) { CAM_ERR(CAM_ISP, "CSID: Invalid arguments"); return IRQ_HANDLED; } + csid_hw = (struct cam_tfe_csid_hw *)data; + CAM_DBG(CAM_ISP, "CSID %d IRQ Handling", csid_hw->hw_intf->hw_idx); + csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; csi2_reg = csid_reg->csi2_reg; @@ -3207,6 +3243,23 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, tfe_csid_hw->error_irq_count = 0; tfe_csid_hw->prev_boot_timestamp = 0; + /* Check if ppi bridge is present or not? */ + tfe_csid_hw->ppi_enable = of_property_read_bool( + csid_hw_info->soc_info.pdev->dev.of_node, + "ppi-enable"); + + if (!tfe_csid_hw->ppi_enable) + return 0; + + /* Initialize the PPI bridge */ + for (i = 0; i < CAM_CSID_PPI_HW_MAX; i++) { + rc = cam_csid_ppi_hw_init(&tfe_csid_hw->ppi_hw_intf[i], i); + if (rc < 0) { + CAM_ERR(CAM_ISP, "PPI init failed for PPI %d", i); + break; + } + } + return 0; err: if (rc) { 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 4b50eeb4bbd6..3eba8333470b 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 @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_TFE_CSID_HW_H_ @@ -9,6 +9,7 @@ #include "cam_hw.h" #include "cam_tfe_csid_hw_intf.h" #include "cam_tfe_csid_soc.h" +#include "cam_csid_ppi_core.h" #define CAM_TFE_CSID_CID_MAX 4 @@ -407,6 +408,9 @@ struct cam_csid_evt_payload { * @event_cb_priv: Context data * @prev_boot_timestamp previous frame bootime stamp * @prev_qtimer_ts previous frame qtimer csid timestamp + * @ppi_hw_intf interface to ppi hardware + * @ppi_enabled flag to specify if the hardware has ppi bridge + * or not * */ struct cam_tfe_csid_hw { @@ -439,6 +443,8 @@ struct cam_tfe_csid_hw { void *event_cb_priv; uint64_t prev_boot_timestamp; uint64_t prev_qtimer_ts; + struct cam_hw_intf *ppi_hw_intf[CAM_CSID_PPI_HW_MAX]; + bool ppi_enable; }; int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, -- GitLab From d1785b6f9f507bbffbf5619d4c33310c1adf5867 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Thu, 10 Jun 2021 11:01:33 +0530 Subject: [PATCH 257/295] msm: camera: csiphy: Propagate CSIPHY settings for 1.2.1 CSIPHY settings are propagated for version 1.2.1 from 4.0 to 3.1. CRs-Fixed: 2966344 Change-Id: Id315bfcde4c29d2fa491be17d46544371716c5a9 Signed-off-by: shiwgupt --- .../include/cam_csiphy_1_2_1_hwreg.h | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index b2b813df8e90..08c6d6cd9a78 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_2_1_HWREG_H_ @@ -13,10 +13,10 @@ struct csiphy_reg_parms_t csiphy_v1_2_1 = { .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_interrupt_status_size = 11, - .csiphy_common_array_size = 6, + .csiphy_common_array_size = 7, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 20, - .csiphy_3ph_config_array_size = 34, + .csiphy_3ph_config_array_size = 33, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -26,6 +26,7 @@ struct csiphy_reg_t csiphy_common_reg_1_2_1[] = { {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, }; @@ -34,7 +35,7 @@ struct csiphy_reg_t csiphy_reset_reg_1_2_1[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; @@ -59,7 +60,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0900, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0908, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0904, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -81,7 +82,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0C80, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C88, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C84, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -103,7 +104,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0A00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -125,7 +126,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0B00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -147,7 +148,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0C00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -289,10 +290,11 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0xAF, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x010C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -307,28 +309,27 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09AC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x030C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -343,16 +344,14 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AAC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -361,10 +360,11 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0xAF, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x050C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -379,16 +379,14 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BAC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; -- GitLab From 1540124a6e2920e7ccff06d4121bdcac16c648f0 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Wed, 9 Jun 2021 12:24:14 +0530 Subject: [PATCH 258/295] msm: camera: flash: Add support for I2C flash - Add Regulator power up for I2C flash - Add GPIO support in probe call for I2C flash - Add flash type in query capability call of flash. CRs-Fixed: 3660915 Change-Id: I64ecba3fa4176972e819b11f2a65340c24f85d4f Signed-off-by: shiwgupt --- .../cam_flash/cam_flash_dev.c | 29 ++++++++++++++++--- .../cam_flash/cam_flash_dev.h | 5 +++- .../cam_flash/cam_flash_soc.c | 10 ++++++- include/uapi/media/cam_sensor.h | 4 ++- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index 4d07bd8186a9..2b646c6786ec 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -130,7 +130,8 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, struct cam_flash_query_cap_info flash_cap = {0}; CAM_DBG(CAM_FLASH, "CAM_QUERY_CAP"); - flash_cap.slot_info = fctrl->soc_info.index; + flash_cap.slot_info = fctrl->soc_info.index; + flash_cap.flash_type = soc_private->flash_type; for (i = 0; i < fctrl->flash_num_sources; i++) { flash_cap.max_current_flash[i] = soc_private->flash_max_current[i]; @@ -401,8 +402,9 @@ static int cam_flash_init_subdev(struct cam_flash_ctrl *fctrl) static int32_t cam_flash_platform_probe(struct platform_device *pdev) { int32_t rc = 0, i = 0; - struct cam_flash_ctrl *fctrl = NULL; - struct device_node *of_parent = NULL; + struct cam_flash_ctrl *fctrl = NULL; + struct device_node *of_parent = NULL; + struct cam_hw_soc_info *soc_info = NULL; CAM_DBG(CAM_FLASH, "Enter"); if (!pdev->dev.of_node) { @@ -458,6 +460,25 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev) fctrl->io_master_info.cci_client->cci_device = fctrl->cci_num; CAM_DBG(CAM_FLASH, "cci-index %d", fctrl->cci_num, rc); + soc_info = &fctrl->soc_info; + if (!soc_info->gpio_data) { + CAM_INFO(CAM_FLASH, "No GPIO found"); + rc = 0; + return rc; + } + + if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { + CAM_INFO(CAM_FLASH, "No GPIO found"); + return -EINVAL; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &fctrl->power_info.gpio_num_info); + if ((rc < 0) || (!fctrl->power_info.gpio_num_info)) { + CAM_ERR(CAM_FLASH, "No/Error Flash GPIOs"); + return -EINVAL; + } + fctrl->i2c_data.per_frame = kzalloc(sizeof(struct i2c_settings_array) * MAX_PER_FRAME_ARRAY, GFP_KERNEL); diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h index 29e352e47ce9..8ca525c14940 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.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-2019, 2021 The Linux Foundation. All rights reserved. */ #ifndef _CAM_FLASH_DEV_H_ @@ -24,6 +24,7 @@ #include "cam_subdev.h" #include "cam_mem_mgr.h" #include "cam_sensor_cmn_header.h" +#include "cam_sensor_util.h" #include "cam_soc_util.h" #include "cam_debug_util.h" #include "cam_sensor_io.h" @@ -130,6 +131,7 @@ struct cam_flash_frame_setting { * @torch_op_current : Torch operational current * @torch_max_current : Max supported current for LED in torch mode * @is_wled_flash : Detection between WLED/LED flash + * @flash_type : Flash type */ struct cam_flash_private_soc { @@ -142,6 +144,7 @@ struct cam_flash_private_soc { uint32_t torch_op_current[CAM_FLASH_MAX_LED_TRIGGERS]; uint32_t torch_max_current[CAM_FLASH_MAX_LED_TRIGGERS]; bool is_wled_flash; + uint32_t flash_type; }; struct cam_flash_func_tbl { diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c index 4c544b1170f3..106f7e335e7b 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, 2020, 2021 The Linux Foundation. All rights reserved. */ #include #include #include "cam_flash_soc.h" #include "cam_res_mgr_api.h" +#include static int32_t cam_get_source_node_info( struct device_node *of_node, @@ -22,6 +23,13 @@ static int32_t cam_get_source_node_info( soc_private->is_wled_flash = of_property_read_bool(of_node, "wled-flash-support"); + rc = of_property_read_u32(of_node, + "flash-type", &soc_private->flash_type); + if (rc) { + CAM_ERR(CAM_FLASH, "flash-type read failed rc=%d", rc); + soc_private->flash_type = CAM_FLASH_TYPE_PMIC; + } + switch_src_node = of_parse_phandle(of_node, "switch-source", 0); if (!switch_src_node) { CAM_WARN(CAM_FLASH, "switch_src_node NULL"); diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h index cc86f2706c63..9d16af961904 100644 --- a/include/uapi/media/cam_sensor.h +++ b/include/uapi/media/cam_sensor.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, 2021 The Linux Foundation. All rights reserved. */ #ifndef __UAPI_CAM_SENSOR_H__ @@ -474,6 +474,7 @@ struct cam_flash_query_curr { * @max_current_flash : max supported current for flash * @max_duration_flash : max flash turn on duration * @max_current_torch : max supported current for torch + * @flash_type : Indicates about the flash type -I2C,GPIO,PMIC * */ struct cam_flash_query_cap_info { @@ -481,6 +482,7 @@ struct cam_flash_query_cap_info { uint32_t max_current_flash[CAM_FLASH_MAX_LED_TRIGGERS]; uint32_t max_duration_flash[CAM_FLASH_MAX_LED_TRIGGERS]; uint32_t max_current_torch[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t flash_type; } __attribute__ ((packed)); #endif -- GitLab From 09c9c132ce1ed6abef626ea37569a2b5eae57a1c Mon Sep 17 00:00:00 2001 From: Anil Kumar Kanakanti Date: Tue, 22 Jun 2021 14:17:41 +0530 Subject: [PATCH 259/295] msm: camera: csiphy: Update CSIPHY settings as per HPG CSIPHY settings updated based on latest HPG settings. CRs-Fixed: 2974853 Change-Id: I3cb3d25bddf707ee9d57a145e0506487b12e487e Signed-off-by: Anil Kumar Kanakanti --- .../include/cam_csiphy_1_2_1_hwreg.h | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index 08c6d6cd9a78..c7d6deef2bf6 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -71,7 +71,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0024, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -93,7 +93,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0724, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -115,7 +115,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0224, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -137,7 +137,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0424, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -159,7 +159,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0600, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0624, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -185,7 +185,7 @@ struct csiphy_reg_t {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0024, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -207,7 +207,7 @@ struct csiphy_reg_t {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0724, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -229,7 +229,7 @@ struct csiphy_reg_t {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0224, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -251,7 +251,7 @@ struct csiphy_reg_t {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0424, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -273,7 +273,7 @@ struct csiphy_reg_t {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -- GitLab From 3e723e5d21307801fef2b651387b3aea369c5be9 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Thu, 15 Jul 2021 17:33:41 +0530 Subject: [PATCH 260/295] msm: camera: tfe: Fix CSID probe CSID probe is failing due to PPI getting probed later than CSID. Fix: - PPI initialization failure as non-fatal. - Reordering compilation to call PPI probe before csid. CRs-Fixed: 2994159 External Impact: No Change-Id: I43948b28ef044eaaef2c72027e991f1fa63bee02 Signed-off-by: Alok Pandey --- drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile | 3 ++- .../cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile index cdbc6779b9dc..e5158b69f19b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile @@ -3,7 +3,8 @@ obj-$(CONFIG_SPECTRA_CAMERA) += top_tpg/ ifdef CONFIG_SPECTRA_CAMERA_TFE -obj-$(CONFIG_SPECTRA_CAMERA) += tfe_csid_hw/ tfe_hw/ ppi_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += ppi_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += tfe_csid_hw/ tfe_hw/ endif ifdef CONFIG_SPECTRA_CAMERA_IFE 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 f2e03ce3200a..d3dbf7b30c64 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 @@ -3255,7 +3255,8 @@ int cam_tfe_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, for (i = 0; i < CAM_CSID_PPI_HW_MAX; i++) { rc = cam_csid_ppi_hw_init(&tfe_csid_hw->ppi_hw_intf[i], i); if (rc < 0) { - CAM_ERR(CAM_ISP, "PPI init failed for PPI %d", i); + CAM_INFO(CAM_ISP, "PPI init failed for PPI %d", i); + rc = 0; break; } } -- GitLab From 47cb7dc083b89dd96c015642640c48428f60d204 Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Thu, 15 Jul 2021 13:22:56 +0530 Subject: [PATCH 261/295] msm: camera: sensor: Read gpios property from dt node Currently cam-res-mgr uses the virtual gpio number (A global gpio number among all the gpio modules) in case of shared gpio. We cannot know this upfront as the mapping varies between targets. This change allows to use the shared gpios using gpios property, where we can mention the gpio module and the gpio number used. CRs-Fixed: 2994159 Change-Id: Ic60eeace89e5223eaeee5a7709bb3beee4127bb0 Signed-off-by: Tony Lijo Jose --- .../cam_res_mgr/cam_res_mgr.c | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c index c87540f7950f..58a927426d86 100644 --- a/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c +++ b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -9,6 +9,7 @@ #include #include #include +#include #include "cam_debug_util.h" #include "cam_res_mgr_api.h" #include "cam_res_mgr_private.h" @@ -604,15 +605,13 @@ EXPORT_SYMBOL(cam_res_mgr_shared_clk_config); static int cam_res_mgr_parse_dt(struct device *dev) { - int rc = 0; + int rc = 0, i = 0; struct device_node *of_node = NULL; struct cam_res_mgr_dt *dt = &cam_res->dt; of_node = dev->of_node; - dt->num_shared_gpio = of_property_count_u32_elems(of_node, - "shared-gpios"); - + dt->num_shared_gpio = of_gpio_count(of_node); if (dt->num_shared_gpio > MAX_SHARED_GPIO_SIZE || dt->num_shared_gpio <= 0) { /* @@ -624,11 +623,14 @@ static int cam_res_mgr_parse_dt(struct device *dev) return -EINVAL; } - rc = of_property_read_u32_array(of_node, "shared-gpios", - dt->shared_gpio, dt->num_shared_gpio); - if (rc) { - CAM_ERR(CAM_RES, "Get shared gpio array failed."); - return -EINVAL; + for (i = 0; i < dt->num_shared_gpio; i++) { + dt->shared_gpio[i] = of_get_gpio(of_node, i); + if (dt->shared_gpio[i] < 0) { + CAM_ERR(CAM_RES, "Get shared gpio array failed."); + return -EINVAL; + } + CAM_DBG(CAM_UTIL, "shared_gpio[%d] = %d", + i, dt->shared_gpio[i]); } dt->pinctrl_info.pinctrl = devm_pinctrl_get(dev); -- GitLab From d59ab976dd92c030693828420d498e53e935cc62 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Thu, 15 Jul 2021 17:21:49 +0530 Subject: [PATCH 262/295] msm: camera: ope: Correctng OPE version for KHAJE OPE probe is failing due to incorrect OPE version. Correcting OPE version as a fix. CRs-Fixed: 2994159 External Impact: No Change-Id: I8c4de8aa76c1da883a922b1ca873b31e8937ca03 Signed-off-by: Alok Pandey --- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c | 3 ++- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c index e7d1528a63d1..8a5f629e7fd9 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -66,6 +66,7 @@ static int cam_ope_init_hw_version(struct cam_hw_soc_info *soc_info, switch (core_info->hw_version) { case OPE_HW_VER_1_0_0: + case OPE_HW_VER_1_1_0: core_info->ope_hw_info->ope_hw = &ope_hw_100; break; default: 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 bb5a2bbff27f..a8e891b6a4be 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 @@ -1,12 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef CAM_OPE_HW_H #define CAM_OPE_HW_H #define OPE_HW_VER_1_0_0 0x10000000 +#define OPE_HW_VER_1_1_0 0x10010000 #define OPE_DEV_OPE 0 #define OPE_DEV_MAX 1 -- GitLab From 2b619fd2689f29dab96e573d75c57c6e11b87854 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Mon, 2 Aug 2021 19:03:04 +0530 Subject: [PATCH 263/295] msm: camera: flash: Handle I2C flash request deletion Handle I2C flash request deletion in the buffer so that new request can be added. CRs-Fixed: 3002966 Change-Id: I774a49c687832ef566071ae3ec4249bf425e94c2 Signed-off-by: shiwgupt --- .../cam_flash/cam_flash_core.c | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) 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 2caeecc80014..ba964dfab60f 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -600,6 +600,21 @@ static int cam_flash_i2c_delete_req(struct cam_flash_ctrl *fctrl, CAM_DBG(CAM_FLASH, "top: %llu, del_req_id:%llu", top, del_req_id); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + if ((del_req_id > + fctrl->i2c_data.per_frame[i].request_id) && ( + fctrl->i2c_data.per_frame[i].is_settings_valid + == 1)) { + fctrl->i2c_data.per_frame[i].request_id = 0; + rc = delete_request( + &(fctrl->i2c_data.per_frame[i])); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "Delete request Fail:%lld rc:%d", + del_req_id, rc); + } + } } cam_flash_i2c_flush_nrt(fctrl); @@ -699,7 +714,7 @@ int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, struct i2c_settings_list *i2c_list; struct i2c_settings_array *i2c_set = NULL; int frame_offset = 0, rc = 0; - + CAM_DBG(CAM_FLASH, "req_id=%llu", req_id); if (req_id == 0) { /* NonRealTime Init settings*/ if (fctrl->i2c_data.init_settings.is_settings_valid == true) { @@ -1196,6 +1211,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) i2c_reg_settings = &fctrl->i2c_data.per_frame[frm_offset]; if (i2c_reg_settings->is_settings_valid == true) { + CAM_DBG(CAM_FLASH, "settings already valid"); i2c_reg_settings->request_id = 0; i2c_reg_settings->is_settings_valid = false; goto update_req_mgr; @@ -1250,17 +1266,21 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) return rc; } case CAM_PKT_NOP_OPCODE: { + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) { CAM_WARN(CAM_FLASH, "Rxed NOP packets without linking"); - frm_offset = csl_packet->header.request_id % - MAX_PER_FRAME_ARRAY; fctrl->i2c_data.per_frame[frm_offset].is_settings_valid = false; return 0; } - + i2c_reg_settings = + &fctrl->i2c_data.per_frame[frm_offset]; + i2c_reg_settings->is_settings_valid = true; + i2c_reg_settings->request_id = + csl_packet->header.request_id; CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u", csl_packet->header.request_id); goto update_req_mgr; -- GitLab From 9535366b658a9af22d47abe1f9eeb800d46be759 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Mon, 16 Aug 2021 00:30:44 +0530 Subject: [PATCH 264/295] msm: camera: isp: Reapply bubble request in RDI path For recovery of the bubble the request from active list should be added back to pending request list. Change-Id: I8d7d6726ddc3e720665e53e4979a7907b09d86aa CRs-Fixed: 3011917 Signed-off-by: Wyes Karny --- drivers/cam_isp/cam_isp_context.c | 48 ++++++++++++++++++++++++++++++- drivers/cam_isp/cam_isp_context.h | 4 ++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 1e772dedc24f..be86fe9176a5 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -3066,6 +3066,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( ctx_isp->frame_id, ctx->ctx_id); ctx->ctx_crm_intf->notify_err(¬ify); + atomic_set(&ctx_isp->process_bubble, 1); } else { req_isp->bubble_report = 0; } @@ -3123,6 +3124,44 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( ctx_isp->boot_timestamp = sof_event_data->boot_time; CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + + if (atomic_read(&ctx_isp->process_bubble)) { + if (list_empty(&ctx->active_req_list)) { + CAM_ERR(CAM_ISP, "No available active req in bubble"); + atomic_set(&ctx_isp->process_bubble, 0); + return -EINVAL; + } + + if (ctx_isp->last_sof_timestamp == + ctx_isp->sof_timestamp_val) { + CAM_DBG(CAM_ISP, + "Tasklet delay detected! Bubble frame: %lld check skipped, sof_timestamp: %lld, ctx_id: %d", + ctx_isp->frame_id, + ctx_isp->sof_timestamp_val, + ctx->ctx_id); + goto end; + } + + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + if (req_isp->bubble_detected) { + req_isp->num_acked = 0; + req_isp->bubble_detected = false; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + atomic_set(&ctx_isp->process_bubble, 0); + ctx_isp->active_req_cnt--; + CAM_DBG(CAM_REQ, + "Move active req: %lld to pending list(cnt = %d) [bubble re-apply],ctx %u", + req->request_id, + ctx_isp->active_req_cnt, ctx->ctx_id); + goto end; + } + } + /* * Signal all active requests with error and move the all the active * requests to free list @@ -3144,6 +3183,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( ctx_isp->active_req_cnt--; } +end: /* notify reqmgr with sof signal */ if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { notify.link_hdl = ctx->link_hdl; @@ -3174,6 +3214,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( __cam_isp_ctx_substate_val_to_type( ctx_isp->substate_activated)); + ctx_isp->last_sof_timestamp = ctx_isp->sof_timestamp_val; return 0; } @@ -3426,6 +3467,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, ctx_isp->hw_acquired = false; ctx_isp->init_received = false; ctx_isp->req_info.last_bufdone_req_id = 0; + ctx_isp->last_sof_timestamp = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -3490,6 +3532,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx_isp->init_received = false; ctx_isp->rdi_only_context = false; ctx_isp->req_info.last_bufdone_req_id = 0; + ctx_isp->last_sof_timestamp = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) @@ -3830,6 +3873,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, ctx_isp->hw_acquired = true; ctx_isp->split_acquire = false; ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + ctx_isp->last_sof_timestamp = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) @@ -3987,6 +4031,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, ctx_isp->hw_ctx = param.ctxt_to_hw_map; ctx_isp->hw_acquired = true; ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + ctx_isp->last_sof_timestamp = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -4132,6 +4177,7 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, ctx_isp->hw_ctx = param.ctxt_to_hw_map; ctx_isp->hw_acquired = true; ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + ctx_isp->last_sof_timestamp = 0; trace_cam_context_state("ISP", ctx); CAM_DBG(CAM_ISP, diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index a98f1d874d5a..b378a71fbf53 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_CONTEXT_H_ @@ -232,6 +232,7 @@ struct cam_isp_context_event_record { * @req_isp: ISP private request object storage * @hw_ctx: HW object returned by the acquire device command * @sof_timestamp_val: Captured time stamp value at sof hw event + * @last_sof_timestamp: Time stamp value for last SOF event * @boot_timestamp: Boot time stamp for a given req_id * @active_req_cnt: Counter for the active request * @reported_req_id: Last reported request id @@ -268,6 +269,7 @@ struct cam_isp_context { void *hw_ctx; uint64_t sof_timestamp_val; + uint64_t last_sof_timestamp; uint64_t boot_timestamp; int32_t active_req_cnt; int64_t reported_req_id; -- GitLab From 0c9bd2865b451e4739dfaf657058dd41dac1b5cd Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Tue, 27 Jul 2021 15:06:04 +0530 Subject: [PATCH 265/295] msm: camera: flash: Add support for flash stream off - Apply flash off register settings at the time of stream off. - Add support to send fire command in initial config command. CRs-Fixed: 2998772 Change-Id: I8897a68e637d283afd98e386b6a7b1fbaaf63c61 Signed-off-by: shiwgupt --- .../cam_flash/cam_flash_core.c | 83 ++++++++++++++++++- .../cam_flash/cam_flash_dev.c | 5 ++ .../cam_flash/cam_flash_dev.h | 5 ++ 3 files changed, 90 insertions(+), 3 deletions(-) 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 2caeecc80014..6454c26e661d 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -505,6 +505,8 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) { + int rc = 0; + if (!flash_ctrl) { CAM_ERR(CAM_FLASH, "Flash control Null"); return -EINVAL; @@ -515,6 +517,17 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) (enum led_brightness)LED_SWITCH_OFF); flash_ctrl->flash_state = CAM_FLASH_STATE_START; + + if ((flash_ctrl->i2c_data.streamoff_settings.is_settings_valid) && + (flash_ctrl->i2c_data.streamoff_settings.request_id == 0)) { + flash_ctrl->apply_streamoff = true; + rc = cam_flash_i2c_apply_setting(flash_ctrl, 0); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply streamoff settings"); + } + } + return 0; } @@ -702,7 +715,24 @@ int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, if (req_id == 0) { /* NonRealTime Init settings*/ - if (fctrl->i2c_data.init_settings.is_settings_valid == true) { + if (fctrl->apply_streamoff == true) { + fctrl->apply_streamoff = false; + i2c_set = &fctrl->i2c_data.streamoff_settings; + list_for_each_entry(i2c_list, + &(i2c_set->list_head), + list) { + rc = cam_sensor_util_i2c_apply_setting + (&(fctrl->io_master_info), i2c_list); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed to apply stream on settings: %d", + rc); + return rc; + } + break; + } + } else if (fctrl->i2c_data.init_settings.is_settings_valid == + true) { list_for_each_entry(i2c_list, &(fctrl->i2c_data.init_settings.list_head), list) { @@ -1180,7 +1210,8 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = fctrl->func_tbl.apply_setting(fctrl, 0); if (rc) { - CAM_ERR(CAM_FLASH, "cannot apply settings rc = %d", rc); + CAM_ERR(CAM_FLASH, + "cannot apply settings rc = %d", rc); return rc; } @@ -1212,6 +1243,18 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) "Failed in parsing i2c packets"); return rc; } + if ((fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE) || + (fctrl->flash_state == CAM_FLASH_STATE_CONFIG)) { + fctrl->flash_state = CAM_FLASH_STATE_CONFIG; + rc = fctrl->func_tbl.apply_setting(fctrl, 1); + if (rc) { + CAM_ERR(CAM_FLASH, + "cannot apply fire settings rc = %d", + rc); + return rc; + } + return rc; + } break; } case CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS: { @@ -1265,6 +1308,29 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) csl_packet->header.request_id); goto update_req_mgr; } + case CAM_FLASH_PACKET_OPCODE_STREAM_OFF: { + if (fctrl->streamoff_count > 0) + return rc; + + CAM_DBG(CAM_FLASH, "Received Stream off Settings"); + i2c_data = &(fctrl->i2c_data); + fctrl->streamoff_count = fctrl->streamoff_count + 1; + i2c_reg_settings = &i2c_data->streamoff_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_sensor_i2c_command_parser(&fctrl->io_master_info, + i2c_reg_settings, + cmd_desc, 1, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed in parsing i2c Stream off packets"); + return rc; + } + break; + } default: CAM_ERR(CAM_FLASH, "Wrong Opcode : %d", (csl_packet->header.op_code & 0xFFFFFF)); @@ -1805,6 +1871,16 @@ int cam_flash_release_dev(struct cam_flash_ctrl *fctrl) { int rc = 0; + if (fctrl->i2c_data.streamoff_settings.is_settings_valid == true) { + fctrl->i2c_data.streamoff_settings.is_settings_valid = false; + rc = delete_request(&fctrl->i2c_data.streamoff_settings); + if (rc) { + CAM_WARN(CAM_FLASH, + "Failed to delete Stream off i2c_setting: %d", + rc); + } + } + if (fctrl->bridge_intf.device_hdl != 1) { rc = cam_destroy_device_hdl(fctrl->bridge_intf.device_hdl); if (rc) @@ -1815,6 +1891,7 @@ int cam_flash_release_dev(struct cam_flash_ctrl *fctrl) fctrl->bridge_intf.link_hdl = -1; fctrl->bridge_intf.session_hdl = -1; fctrl->last_flush_req = 0; + fctrl->streamoff_count = 0; } return rc; diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index 2b646c6786ec..9bbdaa80e755 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -71,6 +71,7 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, flash_acq_dev.device_handle; fctrl->bridge_intf.session_hdl = flash_acq_dev.session_handle; + fctrl->apply_streamoff = false; rc = copy_to_user(u64_to_user_ptr(cmd->handle), &flash_acq_dev, @@ -123,6 +124,7 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, if (fctrl->func_tbl.power_ops(fctrl, false)) CAM_WARN(CAM_FLASH, "Power Down Failed"); + fctrl->streamoff_count = 0; fctrl->flash_state = CAM_FLASH_STATE_INIT; break; } @@ -162,6 +164,7 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, goto release_mutex; } + fctrl->apply_streamoff = false; fctrl->flash_state = CAM_FLASH_STATE_START; break; } @@ -490,6 +493,7 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev) INIT_LIST_HEAD(&(fctrl->i2c_data.init_settings.list_head)); INIT_LIST_HEAD(&(fctrl->i2c_data.config_settings.list_head)); + INIT_LIST_HEAD(&(fctrl->i2c_data.streamoff_settings.list_head)); for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) INIT_LIST_HEAD( &(fctrl->i2c_data.per_frame[i].list_head)); @@ -592,6 +596,7 @@ static int32_t cam_flash_i2c_driver_probe(struct i2c_client *client, INIT_LIST_HEAD(&(fctrl->i2c_data.init_settings.list_head)); INIT_LIST_HEAD(&(fctrl->i2c_data.config_settings.list_head)); + INIT_LIST_HEAD(&(fctrl->i2c_data.streamoff_settings.list_head)); for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) INIT_LIST_HEAD(&(fctrl->i2c_data.per_frame[i].list_head)); diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h index 8ca525c14940..28f2fa14e167 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -40,6 +40,7 @@ #define CAM_FLASH_PACKET_OPCODE_INIT 0 #define CAM_FLASH_PACKET_OPCODE_SET_OPS 1 #define CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS 2 +#define CAM_FLASH_PACKET_OPCODE_STREAM_OFF 3 struct cam_flash_ctrl; @@ -182,6 +183,8 @@ struct cam_flash_func_tbl { * @io_master_info : Information about the communication master * @i2c_data : I2C register settings * @last_flush_req : last request to flush + * @streamoff_count : Count to hold the number of times stream off called + * @apply_streamoff : variable to store when to apply stream off */ struct cam_flash_ctrl { char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; @@ -210,6 +213,8 @@ struct cam_flash_ctrl { struct camera_io_master io_master_info; struct i2c_data_settings i2c_data; uint32_t last_flush_req; + uint32_t streamoff_count; + int32_t apply_streamoff; }; int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg); -- GitLab From 85689be9836ecd08ce44002690788a51f73958c0 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 10 Aug 2021 06:47:52 +0000 Subject: [PATCH 266/295] msm: camera: sync: Prevent OOB access of sync name Issue: strlcpy calls strlen on src ptr. If src is not NULL terminated then OOB access will occur in below stack. strlen strlcpy cam_sync_init_row cam_sync_handle_create cam_sync_dev_ioctl Fix: Pad user-space supplied name with NULL. CRs-Fixed: 3010262 Change-Id: Ib5c2fbfe395025ec05e0bb2980f86111e95ff54c Signed-off-by: Trishansh Bhardwaj --- drivers/cam_sync/cam_sync.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index 6daadc3120e4..d548933f2320 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -471,6 +471,7 @@ static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl) u64_to_user_ptr(k_ioctl->ioctl_ptr), k_ioctl->size)) return -EFAULT; + sync_create.name[SYNC_DEBUG_NAME_LEN] = '\0'; result = cam_sync_create(&sync_create.sync_obj, sync_create.name); -- GitLab From 893c1a8295f1caf5a0e5960b97ed449e640e0278 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Wed, 11 Aug 2021 11:06:27 +0530 Subject: [PATCH 267/295] msm: camera: cdm: Acquire mutex lock before accessing client data There is a chance of use after release of client data in cdm internal operation calls. Hence acquire mutex lock whenever accessing client data to avoid use after release scenario. CRs-Fixed: 3010261 Change-Id: Iaf7f41d56301299a6f63a5dc1090334063019881 Signed-off-by: Shravya Samala --- drivers/cam_cdm/cam_cdm_core_common.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index 238af5282b5f..cd7cae3d274d 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -180,10 +180,12 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, (struct cam_cdm_bl_cb_request_entry *)data; client_idx = CAM_CDM_GET_CLIENT_IDX(node->client_hdl); + mutex_lock(&cdm_hw->hw_mutex); client = core->clients[client_idx]; if ((!client) || (client->handle != node->client_hdl)) { CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, node->client_hdl); + mutex_unlock(&cdm_hw->hw_mutex); return; } cam_cdm_get_client_refcount(client); @@ -202,6 +204,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, } mutex_unlock(&client->lock); cam_cdm_put_client_refcount(client); + mutex_unlock(&cdm_hw->hw_mutex); return; } else if (status == CAM_CDM_CB_STATUS_HW_RESET_DONE || status == CAM_CDM_CB_STATUS_HW_FLUSH || @@ -217,7 +220,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, if ((!client) || (client->handle != node->client_hdl)) { CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, node->client_hdl); - return; + return; } cam_cdm_get_client_refcount(client); mutex_lock(&client->lock); @@ -239,6 +242,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) { if (core->clients[i] != NULL) { + mutex_lock(&cdm_hw->hw_mutex); client = core->clients[i]; cam_cdm_get_client_refcount(client); mutex_lock(&client->lock); @@ -261,6 +265,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, } mutex_unlock(&client->lock); cam_cdm_put_client_refcount(client); + mutex_unlock(&cdm_hw->hw_mutex); } } } @@ -320,35 +325,34 @@ int cam_cdm_stream_ops_internal(void *hw_priv, return -EINVAL; core = (struct cam_cdm *)cdm_hw->core_info; + mutex_lock(&cdm_hw->hw_mutex); client_idx = CAM_CDM_GET_CLIENT_IDX(*handle); client = core->clients[client_idx]; if (!client) { CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, *handle); + mutex_unlock(&cdm_hw->hw_mutex); return -EINVAL; } cam_cdm_get_client_refcount(client); if (*handle != client->handle) { CAM_ERR(CAM_CDM, "client id given handle=%x invalid", *handle); - cam_cdm_put_client_refcount(client); - return -EINVAL; + rc = -EINVAL; + goto end; } if (operation == true) { if (true == client->stream_on) { CAM_ERR(CAM_CDM, "Invalid CDM client is already streamed ON"); - cam_cdm_put_client_refcount(client); - return rc; + goto end; } } else { if (client->stream_on == false) { CAM_ERR(CAM_CDM, "Invalid CDM client is already streamed Off"); - cam_cdm_put_client_refcount(client); - return rc; + goto end; } } - mutex_lock(&cdm_hw->hw_mutex); if (operation == true) { if (!cdm_hw->open_count) { struct cam_ahb_vote ahb_vote; -- GitLab From bbdbe08137f86fd11b3e014f8b7b5fec2e1f5a50 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Wed, 8 Sep 2021 16:54:11 +0530 Subject: [PATCH 268/295] msm: camera: flash: Maintain flash state in flash off Maintain flash state in flash off for I2C flash. Change-Id: Ieb605a79881b4091c8c3e4fac3a84731339b573f Signed-off-by: shiwgupt --- drivers/cam_sensor_module/cam_flash/cam_flash_core.c | 1 + 1 file changed, 1 insertion(+) 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 00ef73759356..087753c5ab78 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -526,6 +526,7 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) CAM_ERR(CAM_SENSOR, "cannot apply streamoff settings"); } + flash_ctrl->flash_state = CAM_FLASH_STATE_CONFIG; } return 0; -- GitLab From cedd2aa5d6fa4adc62251500c8723457858b3a8d Mon Sep 17 00:00:00 2001 From: Dharmender Sharma Date: Tue, 1 Sep 2020 18:12:19 -0700 Subject: [PATCH 269/295] msm: camera: common: Merge camera-kernel.4.0 changes in camera-kernel.3.1 msm: camera: cdm: Add CDM hang detect and debug registers dump support msm: camera: ope: free unused memory in ope acquire msm: camera: cdm: Improve error handling during cdm hang msm: camera: ope: Dump stripe info at the time of hang. CRs-Fixed: 2878214 Change-Id: I998a71fb614be92c3a012a1823bdd2512d3af3d5 Signed-off-by: Dharmender Sharma --- drivers/cam_cdm/cam_cdm.h | 2 + drivers/cam_cdm/cam_cdm_core_common.c | 16 ++ drivers/cam_cdm/cam_cdm_core_common.h | 2 + drivers/cam_cdm/cam_cdm_hw_core.c | 218 +++++++++++------- drivers/cam_cdm/cam_cdm_intf.c | 28 ++- drivers/cam_cdm/cam_cdm_intf_api.h | 11 +- drivers/cam_isp/cam_isp_context.c | 15 +- drivers/cam_isp/cam_isp_context.h | 6 +- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 20 +- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 18 +- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_hw.h | 1 + .../cam_ope/ope_hw_mgr/ope_hw/ope_hw_100.h | 8 +- .../cam_ope/ope_hw_mgr/ope_hw/top/ope_top.c | 22 +- 13 files changed, 262 insertions(+), 105 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index 938c5a2dc190..8c8e6a4bd2d6 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -83,6 +83,7 @@ #define CAM_CDM_RESET_HW_STATUS 0x4 #define CAM_CDM_ERROR_HW_STATUS 0x5 #define CAM_CDM_FLUSH_HW_STATUS 0x6 +#define CAM_CDM_RESET_ERR_STATUS 0x7 /* Curent BL command masks and shifts */ #define CAM_CDM_CURRENT_BL_LEN 0xFFFFF @@ -376,6 +377,7 @@ enum cam_cdm_hw_process_intf_cmd { 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_DUMP_DBG_REGS, CAM_CDM_HW_INTF_CMD_INVALID, }; diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index 238af5282b5f..0deb7a14d9c9 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -819,6 +819,22 @@ int cam_cdm_process_cmd(void *hw_priv, rc = cam_hw_cdm_hang_detect(cdm_hw, *handle); break; } + case CAM_CDM_HW_INTF_DUMP_DBG_REGS: + { + uint32_t *handle = cmd_args; + + if (sizeof(uint32_t) != arg_size) { + CAM_ERR(CAM_CDM, + "Invalid CDM cmd %d size=%x for handle=0x%x", + cmd, arg_size, *handle); + return -EINVAL; + } + + mutex_lock(&cdm_hw->hw_mutex); + cam_hw_cdm_dump_core_debug_registers(cdm_hw, true); + 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 9b6741ce6653..96fd8b36d037 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.h +++ b/drivers/cam_cdm/cam_cdm_core_common.h @@ -56,5 +56,7 @@ 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, enum cam_cdm_cb_status status, void *data); +void cam_hw_cdm_dump_core_debug_registers( + struct cam_hw_info *cdm_hw, bool pause_core); #endif /* _CAM_CDM_CORE_COMMON_H_ */ diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 6a95c1cc6bf1..22dbcf59251a 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -170,14 +170,14 @@ static int cam_hw_cdm_pause_core(struct cam_hw_info *cdm_hw, bool pause) return rc; } -int cam_hw_cdm_enable_core_dbg(struct cam_hw_info *cdm_hw) +int cam_hw_cdm_enable_core_dbg(struct cam_hw_info *cdm_hw, uint32_t value) { int rc = 0; struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; if (cam_cdm_write_hw_reg(cdm_hw, core->offsets->cmn_reg->core_debug, - 0x10100)) { + value)) { CAM_ERR(CAM_CDM, "Failed to Write CDM HW core debug"); rc = -EIO; } @@ -264,24 +264,7 @@ int cam_hw_cdm_bl_fifo_pending_bl_rb_in_fifo( return rc; } -int cam_hw_cdm_enable_core_dbg_per_fifo( - struct cam_hw_info *cdm_hw, - uint32_t fifo_idx) -{ - int rc = 0; - struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; - - if (cam_cdm_write_hw_reg(cdm_hw, - core->offsets->cmn_reg->core_debug, - (0x10100 | fifo_idx << 20))) { - CAM_ERR(CAM_CDM, "Failed to Write CDM HW core debug"); - rc = -EIO; - } - - return rc; -} - -void cam_hw_cdm_dump_bl_fifo_data(struct cam_hw_info *cdm_hw) +static void cam_hw_cdm_dump_bl_fifo_data(struct cam_hw_info *cdm_hw) { struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; int i, j; @@ -290,13 +273,7 @@ void cam_hw_cdm_dump_bl_fifo_data(struct cam_hw_info *cdm_hw) for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) { cam_hw_cdm_bl_fifo_pending_bl_rb_in_fifo(cdm_hw, i, &num_pending_req); - - if (cam_hw_cdm_enable_core_dbg_per_fifo(cdm_hw, i)) { - CAM_ERR(CAM_CDM, - "Problem in selecting the fifo for readback"); - continue; - } - for (j = 0 ; j < num_pending_req ; j++) { + for (j = 0; j < num_pending_req ; j++) { cam_cdm_write_hw_reg(cdm_hw, core->offsets->cmn_reg->bl_fifo_rb, j); cam_cdm_read_hw_reg(cdm_hw, @@ -317,89 +294,152 @@ void cam_hw_cdm_dump_bl_fifo_data(struct cam_hw_info *cdm_hw) } } -void cam_hw_cdm_dump_core_debug_registers( - struct cam_hw_info *cdm_hw) +void cam_hw_cdm_dump_core_debug_registers(struct cam_hw_info *cdm_hw, + bool pause_core) { - uint32_t dump_reg, core_dbg; + uint32_t dump_reg[4], core_dbg = 0x100; int i; + bool is_core_paused_already; struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + const struct cam_cdm_icl_regs *inv_cmd_log = + core->offsets->cmn_reg->icl_reg; - cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->core_en, &dump_reg); - CAM_INFO(CAM_CDM, "CDM HW core status=%x", dump_reg); + cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->core_en, + &dump_reg[0]); - 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); + if (pause_core) { + cam_hw_cdm_pause_core(cdm_hw, true); + usleep_range(1000, 1010); + } + cam_hw_cdm_enable_core_dbg(cdm_hw, core_dbg); - usleep_range(1000, 1010); + cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->usr_data, + &dump_reg[1]); cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->debug_status, - &dump_reg); - CAM_INFO(CAM_CDM, "CDM HW Debug status reg=%x", dump_reg); - cam_cdm_read_hw_reg(cdm_hw, - core->offsets->cmn_reg->core_debug, - &core_dbg); + &dump_reg[2]); + + CAM_INFO(CAM_CDM, "Core stat 0x%x udata 0x%x dbg_stat 0x%x", + dump_reg[0], dump_reg[1], dump_reg[2]); + if (core_dbg & 0x100) { cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->last_ahb_addr, - &dump_reg); - CAM_INFO(CAM_CDM, "AHB dump reglastaddr=%x", dump_reg); + &dump_reg[0]); cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->last_ahb_data, - &dump_reg); - CAM_INFO(CAM_CDM, "AHB dump reglastdata=%x", dump_reg); + &dump_reg[1]); + CAM_INFO(CAM_CDM, "AHB dump lastaddr=0x%x lastdata=0x%x", + dump_reg[0], dump_reg[1]); } else { CAM_INFO(CAM_CDM, "CDM HW AHB dump not enable"); } - cam_hw_cdm_dump_bl_fifo_data(cdm_hw); + if (inv_cmd_log) { + if (inv_cmd_log->misc_regs) { + cam_cdm_read_hw_reg(cdm_hw, + inv_cmd_log->misc_regs->icl_status, + &dump_reg[0]); + cam_cdm_read_hw_reg(cdm_hw, + inv_cmd_log->misc_regs->icl_inv_bl_addr, + &dump_reg[1]); + CAM_INFO(CAM_CDM, + "Last Inv Cmd Log(ICL)Status: 0x%x bl_addr: 0x%x", + dump_reg[0], dump_reg[1]); + } + if (inv_cmd_log->data_regs) { + cam_cdm_read_hw_reg(cdm_hw, + inv_cmd_log->data_regs->icl_inv_data, + &dump_reg[0]); + CAM_INFO(CAM_CDM, "First word of Last Inv cmd: 0x%x", + dump_reg[0]); + + cam_cdm_read_hw_reg(cdm_hw, + inv_cmd_log->data_regs->icl_last_data_0, + &dump_reg[0]); + cam_cdm_read_hw_reg(cdm_hw, + inv_cmd_log->data_regs->icl_last_data_1, + &dump_reg[1]); + cam_cdm_read_hw_reg(cdm_hw, + inv_cmd_log->data_regs->icl_last_data_2, + &dump_reg[2]); + + + CAM_INFO(CAM_CDM, "Last good cmd word 0x%x 0x%x 0x%x", + dump_reg[0], dump_reg[1], dump_reg[2]); + } + } + + if (core_dbg & 0x10000) { + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->core_en, &dump_reg[0]); + is_core_paused_already = (bool)(dump_reg[0] & 0x20); + if (!is_core_paused_already) { + cam_hw_cdm_pause_core(cdm_hw, true); + usleep_range(1000, 1010); + } + + cam_hw_cdm_dump_bl_fifo_data(cdm_hw); + + if (!is_core_paused_already) + cam_hw_cdm_pause_core(cdm_hw, false); + } - CAM_INFO(CAM_CDM, "CDM HW default dump"); cam_cdm_read_hw_reg(cdm_hw, - core->offsets->cmn_reg->core_cfg, &dump_reg); - CAM_INFO(CAM_CDM, "CDM HW core cfg=%x", dump_reg); + core->offsets->cmn_reg->core_cfg, &dump_reg[0]); + CAM_INFO(CAM_CDM, "CDM HW core cfg=0x%x", dump_reg[0]); for (i = 0; i < core->offsets->reg_data->num_bl_fifo_irq; i++) { cam_cdm_read_hw_reg(cdm_hw, - core->offsets->irq_reg[i]->irq_status, &dump_reg); - CAM_INFO(CAM_CDM, "CDM HW irq status%d=%x", i, dump_reg); - + core->offsets->irq_reg[i]->irq_status, &dump_reg[0]); cam_cdm_read_hw_reg(cdm_hw, - core->offsets->irq_reg[i]->irq_set, &dump_reg); - CAM_INFO(CAM_CDM, "CDM HW irq set%d=%x", i, dump_reg); - + core->offsets->irq_reg[i]->irq_set, &dump_reg[1]); cam_cdm_read_hw_reg(cdm_hw, - core->offsets->irq_reg[i]->irq_mask, &dump_reg); - CAM_INFO(CAM_CDM, "CDM HW irq mask%d=%x", i, dump_reg); - + core->offsets->irq_reg[i]->irq_mask, &dump_reg[2]); cam_cdm_read_hw_reg(cdm_hw, - core->offsets->irq_reg[i]->irq_clear, &dump_reg); - CAM_INFO(CAM_CDM, "CDM HW irq clear%d=%x", i, dump_reg); + core->offsets->irq_reg[i]->irq_clear, &dump_reg[3]); + + CAM_INFO(CAM_CDM, + "cnt %d irq status 0x%x set 0x%x mask 0x%x clear 0x%x", + i, dump_reg[0], dump_reg[1], dump_reg[2], dump_reg[3]); } cam_cdm_read_hw_reg(cdm_hw, - core->offsets->cmn_reg->current_bl_base, &dump_reg); - CAM_INFO(CAM_CDM, "CDM HW current BL base=%x", dump_reg); + core->offsets->cmn_reg->current_bl_base, &dump_reg[0]); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->current_used_ahb_base, &dump_reg[1]); + CAM_INFO(CAM_CDM, "curr BL base 0x%x AHB base 0x%x", + dump_reg[0], dump_reg[1]); + + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->wait_status, &dump_reg[0]); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->comp_wait[0]->comp_wait_status, + &dump_reg[1]); + cam_cdm_read_hw_reg(cdm_hw, + core->offsets->cmn_reg->comp_wait[1]->comp_wait_status, + &dump_reg[2]); + CAM_INFO(CAM_CDM, "wait status 0x%x comp wait status 0x%x: 0x%x", + dump_reg[0], dump_reg[1], dump_reg[2]); cam_cdm_read_hw_reg(cdm_hw, - core->offsets->cmn_reg->current_bl_len, &dump_reg); + core->offsets->cmn_reg->current_bl_len, &dump_reg[0]); CAM_INFO(CAM_CDM, "CDM HW current BL len=%d ARB %d FIFO %d tag=%d, ", - (dump_reg & CAM_CDM_CURRENT_BL_LEN), - (dump_reg & CAM_CDM_CURRENT_BL_ARB) >> + (dump_reg[0] & CAM_CDM_CURRENT_BL_LEN), + (dump_reg[0] & CAM_CDM_CURRENT_BL_ARB) >> CAM_CDM_CURRENT_BL_ARB_SHIFT, - (dump_reg & CAM_CDM_CURRENT_BL_FIFO) >> + (dump_reg[0] & CAM_CDM_CURRENT_BL_FIFO) >> CAM_CDM_CURRENT_BL_FIFO_SHIFT, - (dump_reg & CAM_CDM_CURRENT_BL_TAG) >> + (dump_reg[0] & CAM_CDM_CURRENT_BL_TAG) >> CAM_CDM_CURRENT_BL_TAG_SHIFT); - cam_cdm_read_hw_reg(cdm_hw, - core->offsets->cmn_reg->current_used_ahb_base, &dump_reg); - CAM_INFO(CAM_CDM, "CDM HW current AHB base=%x", dump_reg); - + cam_hw_cdm_disable_core_dbg(cdm_hw); + if (pause_core) + cam_hw_cdm_pause_core(cdm_hw, false); } enum cam_cdm_arbitration cam_cdm_get_arbitration_type( @@ -1107,11 +1147,15 @@ static void cam_hw_cdm_reset_cleanup( int i; struct cam_cdm_bl_cb_request_entry *node, *tnode; bool flush_hw = false; + bool reset_err = false; if (test_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status) || test_bit(CAM_CDM_FLUSH_HW_STATUS, &core->cdm_status)) flush_hw = true; + if (test_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status)) + reset_err = true; + for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) { list_for_each_entry_safe(node, tnode, &core->bl_fifo[i].bl_request_list, entry) { @@ -1120,12 +1164,19 @@ static void cam_hw_cdm_reset_cleanup( CAM_DBG(CAM_CDM, "Notifying client %d for tag %d", node->client_hdl, node->bl_tag); - if (flush_hw) + if (flush_hw) { + enum cam_cdm_cb_status status; + + status = reset_err ? + CAM_CDM_CB_STATUS_HW_ERROR : + CAM_CDM_CB_STATUS_HW_RESUBMIT; + cam_cdm_notify_clients(cdm_hw, (node->client_hdl == handle) ? CAM_CDM_CB_STATUS_HW_FLUSH : - CAM_CDM_CB_STATUS_HW_RESUBMIT, + status, (void *)node); + } else cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_HW_RESET_DONE, @@ -1268,7 +1319,7 @@ static void cam_hw_cdm_work(struct work_struct *work) * to dump debug info */ cam_hw_cdm_pause_core(cdm_hw, true); - cam_hw_cdm_dump_core_debug_registers(cdm_hw); + cam_hw_cdm_dump_core_debug_registers(cdm_hw, true); if (payload->irq_status & CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK) { @@ -1307,6 +1358,8 @@ static void cam_hw_cdm_work(struct work_struct *work) CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK)) clear_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status); + } else { + CAM_ERR(CAM_CDM, "NULL payload"); } kfree(payload); payload = NULL; @@ -1329,16 +1382,8 @@ static void cam_hw_cdm_iommu_fault_handler(struct iommu_domain *domain, for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) mutex_lock(&core->bl_fifo[i].fifo_lock); 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_hw_cdm_dump_core_debug_registers(cdm_hw, true); + } 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); @@ -1647,7 +1692,7 @@ int cam_hw_cdm_handle_error_info( current_fifo, current_tag); /* dump cdm registers for further debug */ - cam_hw_cdm_dump_core_debug_registers(cdm_hw); + cam_hw_cdm_dump_core_debug_registers(cdm_hw, false); for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { reset_val = reset_val | @@ -1673,7 +1718,7 @@ int cam_hw_cdm_handle_error_info( if (time_left <= 0) { rc = -ETIMEDOUT; CAM_ERR(CAM_CDM, "CDM HW reset Wait failed rc=%d", rc); - goto end; + set_bit(CAM_CDM_RESET_ERR_STATUS, &cdm_core->cdm_status); } rc = cam_hw_cdm_set_cdm_core_cfg(cdm_hw); @@ -1712,6 +1757,7 @@ int cam_hw_cdm_handle_error_info( end: clear_bit(CAM_CDM_FLUSH_HW_STATUS, &cdm_core->cdm_status); clear_bit(CAM_CDM_RESET_HW_STATUS, &cdm_core->cdm_status); + clear_bit(CAM_CDM_RESET_ERR_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); diff --git a/drivers/cam_cdm/cam_cdm_intf.c b/drivers/cam_cdm/cam_cdm_intf.c index 3d50beb4cf43..4beeb71d2181 100644 --- a/drivers/cam_cdm/cam_cdm_intf.c +++ b/drivers/cam_cdm/cam_cdm_intf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -506,6 +506,32 @@ int cam_cdm_detect_hang_error(uint32_t handle) } EXPORT_SYMBOL(cam_cdm_detect_hang_error); +int cam_cdm_dump_debug_registers(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_DUMP_DBG_REGS, + &handle, + sizeof(handle)); + } + put_cdm_mgr_refcount(); + + return rc; +} + 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 25d0a5db88ed..1e9cc3455a0f 100644 --- a/drivers/cam_cdm/cam_cdm_intf_api.h +++ b/drivers/cam_cdm/cam_cdm_intf_api.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_API_H_ @@ -296,4 +296,13 @@ struct cam_cdm_utils_ops *cam_cdm_publish_ops(void); * @return 0 on success */ int cam_cdm_detect_hang_error(uint32_t handle); + +/** + * @brief : API to dump the CDM Debug registers + * + * @handle : Input handle of the CDM to dump the registers + * + * @return 0 on success + */ +int cam_cdm_dump_debug_registers(uint32_t handle); #endif /* _CAM_CDM_API_H_ */ diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index be86fe9176a5..f3da6ad1c7e2 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -4436,9 +4436,11 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, /* HW failure. user need to clean up the resource */ CAM_ERR(CAM_ISP, "Start HW failed"); ctx->state = CAM_CTX_READY; - trace_cam_context_state("ISP", ctx); - if (rc == -ETIMEDOUT) + if ((rc == -ETIMEDOUT) && + (isp_ctx_debug.enable_cdm_cmd_buff_dump)) rc = cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false); + + trace_cam_context_state("ISP", ctx); list_del_init(&req->list); list_add(&req->list, &ctx->pending_req_list); goto end; @@ -4999,8 +5001,15 @@ static int cam_isp_context_debug_register(void) goto err; } - return 0; + if (!debugfs_create_u32("enable_cdm_cmd_buffer_dump", + 0644, + isp_ctx_debug.dentry, + &isp_ctx_debug.enable_cdm_cmd_buff_dump)) { + CAM_ERR(CAM_ISP, "failed to create enable_cdm_cmd_buffer_dump"); + goto err; + } + return 0; err: debugfs_remove_recursive(isp_ctx_debug.dentry); return -ENOMEM; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index b378a71fbf53..72d35cb7e9f9 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -110,13 +110,15 @@ enum cam_isp_state_change_trigger { /** * struct cam_isp_ctx_debug - Contains debug parameters * - * @dentry: Debugfs entry - * @enable_state_monitor_dump: Enable isp state monitor dump + * @dentry: Debugfs entry + * @enable_state_monitor_dump: Enable isp state monitor dump + * @enable_cdm_cmd_buff_dump: Enable CDM Command buffer dump * */ struct cam_isp_ctx_debug { struct dentry *dentry; uint32_t enable_state_monitor_dump; + uint32_t enable_cdm_cmd_buff_dump; }; /** 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 dbbd3c89053c..e0670d1702ec 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -695,15 +695,14 @@ static int32_t cam_ope_process_request_timer(void *priv, void *data) } 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", + "pending req at HW, 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"); @@ -1601,6 +1600,7 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, struct timespec64 ts; bool flag = false; bool dump_flag = true; + int i; if (!userdata) { CAM_ERR(CAM_OPE, "Invalid ctx from CDM callback"); @@ -1660,9 +1660,17 @@ static void cam_ope_ctx_cdm_callback(uint32_t handle, void *userdata, ope_req->request_id, ctx->ctx_id); CAM_INFO(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); dump_flag = false; + + CAM_INFO(CAM_OPE, "bach_size: %d", + ctx->req_list[cookie]->num_batch); + for (i = 0; i < ctx->req_list[cookie]->num_batch; i++) + CAM_INFO(CAM_OPE, "i: %d num_stripes: %d", + i, + ctx->req_list[cookie]->num_stripes[i]); } rc = cam_ope_mgr_reset_hw(); flag = true; @@ -2740,6 +2748,10 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) ctx->ctxt_event_cb = args->event_cb; cam_ope_ctx_clk_info_init(ctx); ctx->ctx_state = OPE_CTX_STATE_ACQUIRED; + kzfree(cdm_acquire); + cdm_acquire = NULL; + kzfree(bw_update); + bw_update = NULL; mutex_unlock(&ctx->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); 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 4b39b6770c30..1edc6e313fd5 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -787,6 +787,11 @@ static uint32_t *ope_create_stripe_cmd(struct cam_ope_hw_mgr *hw_mgr, uint32_t *print_ptr; int num_dmi = 0; struct cam_cdm_utils_ops *cdm_ops; + uint32_t reg_val_pair[2]; + struct cam_hw_info *ope_dev; + struct cam_ope_device_core_info *core_info; + struct ope_hw *ope_hw; + struct cam_ope_top_reg *top_reg; if (s_idx >= OPE_MAX_CMD_BUFS || batch_idx >= OPE_MAX_BATCH_SIZE) { @@ -868,10 +873,21 @@ static uint32_t *ope_create_stripe_cmd(struct cam_ope_hw_mgr *hw_mgr, } CAM_DBG(CAM_OPE, "Stripe:%d Indirect:X", stripe_idx); } + if (hw_mgr->frame_dump_enable) dump_stripe_cmd(frm_proc, stripe_idx, i, k, iova_addr, kmd_buf, buf_len); } + + ope_dev = hw_mgr->ope_dev_intf[0]->hw_priv; + core_info = (struct cam_ope_device_core_info *)ope_dev->core_info; + ope_hw = core_info->ope_hw_info->ope_hw; + top_reg = ope_hw->top_reg; + + reg_val_pair[0] = top_reg->offset + top_reg->scratch_reg; + reg_val_pair[1] = stripe_idx; + kmd_buf = cdm_ops->cdm_write_regrandom(kmd_buf, 1, reg_val_pair); + return kmd_buf; } 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 a8e891b6a4be..fc188e69546c 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 @@ -73,6 +73,7 @@ struct cam_ope_top_reg { uint32_t violation_status; uint32_t throttle_cnt_cfg; uint32_t debug_cfg; + uint32_t scratch_reg; uint32_t num_debug_registers; struct cam_ope_debug_register *debug_regs; }; 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 727b43c68512..cdf9c2d64b11 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 @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef CAM_OPE_HW_100_H @@ -70,6 +70,9 @@ static struct cam_ope_debug_register ope_debug_regs[OPE_MAX_DEBUG_REGISTER] = { { .offset = 0xD0, }, + { + .offset = 0xD4, + }, }; static struct cam_ope_top_reg ope_top_reg = { @@ -87,7 +90,8 @@ static struct cam_ope_top_reg ope_top_reg = { .violation_status = 0x28, .throttle_cnt_cfg = 0x2C, .debug_cfg = 0xDC, - .num_debug_registers = 9, + .scratch_reg = 0x1F0, + .num_debug_registers = 10, .debug_regs = ope_debug_regs, }; 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 2ebcafd88842..35f4d85e9632 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -31,15 +31,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; + uint32_t i, val[3]; 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 + + for (i = 0; i < top_reg->num_debug_registers; i = i+3) { + val[0] = 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); + val[1] = ((i+1) < top_reg->num_debug_registers) ? + cam_io_r_mb(top_reg->base + + top_reg->debug_regs[i+1].offset) : 0; + val[2] = ((i+2) < top_reg->num_debug_registers) ? + cam_io_r_mb(top_reg->base + + top_reg->debug_regs[i+2].offset) : 0; + + CAM_INFO(CAM_OPE, "status[%d-%d] : 0x%x 0x%x 0x%x", + i, i+2, val[0], val[1], val[2]); } + + CAM_INFO(CAM_OPE, "scrath reg: 0x%x, stripe_idx: %d", + top_reg->offset + top_reg->scratch_reg, + cam_io_r_mb(top_reg->base + top_reg->scratch_reg)); return 0; } -- GitLab From fa429d92b046926ea7d81e266a2d93bf93953304 Mon Sep 17 00:00:00 2001 From: Pranav Sanwal Date: Mon, 13 Sep 2021 12:34:32 +0530 Subject: [PATCH 270/295] msm: camera: tfe: Correct Configuration of top tpg mux selection In case of concurrent tpg use case, configure top tpg mux sel properly. CRs-Fixed: 2804168 Change-Id: I9955c9f03cebac854a339ff5161a99ecaf27cbdf Signed-off-by: Pranav Sanwal --- .../isp_hw/top_tpg/cam_top_tpg_core.c | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c index ee8cbc5326fc..81b287d1b364 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, The Linux Foundation. All rights reserved. */ #include @@ -469,8 +469,14 @@ static int cam_top_tpg_start(void *hw_priv, void *start_args, soc_info->reg_map[0].mem_base + tpg_reg->tpg_vbi_cfg); /* Set the TOP tpg mux sel*/ - cam_io_w_mb((1 << tpg_hw->hw_intf->hw_idx), + val = cam_io_r_mb(soc_info->reg_map[1].mem_base + + tpg_reg->top_mux_reg_offset); + val |= (1 << tpg_hw->hw_intf->hw_idx); + + cam_io_w_mb(val, soc_info->reg_map[1].mem_base + tpg_reg->top_mux_reg_offset); + CAM_DBG(CAM_ISP, "TPG:%d Set top Mux: 0x%x", + tpg_hw->hw_intf->hw_idx, val); val = ((tpg_data->num_active_lanes - 1) << tpg_reg->tpg_num_active_lines_shift) | @@ -498,6 +504,7 @@ static int cam_top_tpg_stop(void *hw_priv, struct cam_isp_resource_node *tpg_res; const struct cam_top_tpg_reg_offset *tpg_reg; struct cam_top_tpg_cfg *tpg_data; + uint32_t val; if (!hw_priv || !stop_args || (arg_size != sizeof(struct cam_isp_resource_node))) { @@ -524,6 +531,16 @@ static int cam_top_tpg_stop(void *hw_priv, cam_io_w_mb(0, soc_info->reg_map[0].mem_base + tpg_reg->tpg_ctrl); + /* Reset the TOP tpg mux sel*/ + val = cam_io_r_mb(soc_info->reg_map[1].mem_base + + tpg_reg->top_mux_reg_offset); + val &= ~(1 << tpg_hw->hw_intf->hw_idx); + + cam_io_w_mb(val, + soc_info->reg_map[1].mem_base + tpg_reg->top_mux_reg_offset); + CAM_DBG(CAM_ISP, "TPG:%d Reset Top Mux: 0x%x", + tpg_hw->hw_intf->hw_idx, val); + tpg_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; CAM_DBG(CAM_ISP, "TPG:%d stopped", tpg_hw->hw_intf->hw_idx); -- GitLab From 111e9ba957750e516c0b2b8b9e7b9d874f612a8f Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Fri, 20 Nov 2020 11:44:42 +0530 Subject: [PATCH 271/295] msm: camera: ope: Check array size of input sync obj In case of input buffer, check array size of input sync obj before assigning fence. CRs-Fixed: 2821583 Change-Id: I5cd7968cfbe0be86a8967565616bf6eb1cf7fcf7 Signed-off-by: Shravya Samala --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 54 ++++++++++++--------- 1 file changed, 31 insertions(+), 23 deletions(-) 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 dbbd3c89053c..0b742e4aee81 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 @@ -1753,7 +1753,7 @@ static int cam_ope_mgr_create_kmd_buf(struct cam_ope_hw_mgr *hw_mgr, static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, struct cam_packet *packet, - struct cam_hw_prepare_update_args *prep_args, + struct cam_hw_prepare_update_args *prep_arg, struct cam_ope_ctx *ctx_data, uint32_t req_idx) { @@ -1764,8 +1764,8 @@ static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, struct cam_ope_request *ope_request; ope_request = ctx_data->req_list[req_idx]; - prep_args->num_out_map_entries = 0; - prep_args->num_in_map_entries = 0; + prep_arg->num_out_map_entries = 0; + prep_arg->num_in_map_entries = 0; ope_request = ctx_data->req_list[req_idx]; CAM_DBG(CAM_OPE, "E: req_idx = %u %x", req_idx, packet); @@ -1775,8 +1775,16 @@ static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, 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; - prep_args->num_in_map_entries++; + if (j < CAM_MAX_IN_RES) { + sync_in_obj[j++] = + io_buf->fence; + prep_arg->num_in_map_entries++; + } else { + CAM_ERR(CAM_OPE, + "reached max in_res %d %d", + io_buf->resource_type, + ope_request->request_id); + } } else { CAM_ERR(CAM_OPE, "Invalid fence %d %d", io_buf->resource_type, @@ -1784,10 +1792,10 @@ static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, } } else { if (io_buf->fence != -1) { - prep_args->out_map_entries[k].sync_id = + prep_arg->out_map_entries[k].sync_id = io_buf->fence; k++; - prep_args->num_out_map_entries++; + prep_arg->num_out_map_entries++; } else { if (io_buf->resource_type != OPE_OUT_RES_STATS_LTM) { @@ -1808,38 +1816,38 @@ static int cam_ope_mgr_process_io_cfg(struct cam_ope_hw_mgr *hw_mgr, } } - if (prep_args->num_in_map_entries > 1 && - prep_args->num_in_map_entries <= CAM_MAX_IN_RES) - prep_args->num_in_map_entries = + if (prep_arg->num_in_map_entries > 1 && + prep_arg->num_in_map_entries <= CAM_MAX_IN_RES) + prep_arg->num_in_map_entries = cam_common_util_remove_duplicate_arr( - sync_in_obj, prep_args->num_in_map_entries); + sync_in_obj, prep_arg->num_in_map_entries); - if (prep_args->num_in_map_entries > 1 && - prep_args->num_in_map_entries <= CAM_MAX_IN_RES) { + if (prep_arg->num_in_map_entries > 1 && + prep_arg->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); + prep_arg->num_in_map_entries, &merged_sync_in_obj); if (rc) { - prep_args->num_out_map_entries = 0; - prep_args->num_in_map_entries = 0; + prep_arg->num_out_map_entries = 0; + prep_arg->num_in_map_entries = 0; return rc; } ope_request->in_resource = merged_sync_in_obj; - prep_args->in_map_entries[0].sync_id = merged_sync_in_obj; - prep_args->num_in_map_entries = 1; + prep_arg->in_map_entries[0].sync_id = merged_sync_in_obj; + prep_arg->num_in_map_entries = 1; CAM_DBG(CAM_REQ, "ctx_id: %u req_id: %llu Merged Sync obj: %d", ctx_data->ctx_id, packet->header.request_id, merged_sync_in_obj); - } else if (prep_args->num_in_map_entries == 1) { - prep_args->in_map_entries[0].sync_id = sync_in_obj[0]; - prep_args->num_in_map_entries = 1; + } else if (prep_arg->num_in_map_entries == 1) { + prep_arg->in_map_entries[0].sync_id = sync_in_obj[0]; + prep_arg->num_in_map_entries = 1; ope_request->in_resource = 0; CAM_DBG(CAM_OPE, "fence = %d", sync_in_obj[0]); } else { CAM_DBG(CAM_OPE, "Invalid count of input fences, count: %d", - prep_args->num_in_map_entries); - prep_args->num_in_map_entries = 0; + prep_arg->num_in_map_entries); + prep_arg->num_in_map_entries = 0; ope_request->in_resource = 0; rc = -EINVAL; } -- GitLab From fda10d28b0680180dc5e4e7011f4a45d9616d42d Mon Sep 17 00:00:00 2001 From: Shadul Shaikh Date: Fri, 17 Sep 2021 17:14:16 +0530 Subject: [PATCH 272/295] msm: camera: smmu: Unmap secure buffers in secure camera use case Dettach and unmap DMA buffers obtained previously from DMA attach and mappings respectively. CRs-Fixed: 3010444 Change-Id: I5c28a78f3ddc791743e298a1216ad661e4209e63 Signed-off-by: Shadul Shaikh --- drivers/cam_smmu/cam_smmu_api.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 034de6ee564b..49db0ec16079 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. */ #include @@ -203,6 +203,8 @@ struct cam_dma_buff_info { struct cam_sec_buff_info { struct dma_buf *buf; + struct dma_buf_attachment *attach; + struct sg_table *table; enum dma_data_direction dir; int ref_count; dma_addr_t paddr; @@ -2674,6 +2676,8 @@ static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd, mapping_info->dir = dma_dir; mapping_info->ref_count = 1; mapping_info->buf = dmabuf; + mapping_info->attach = attach; + mapping_info->table = table; CAM_DBG(CAM_SMMU, "idx=%d, ion_fd=%d, dev=%pK, paddr=%pK, len=%u", idx, ion_fd, @@ -2774,11 +2778,28 @@ static int cam_smmu_secure_unmap_buf_and_remove_from_list( struct cam_sec_buff_info *mapping_info, int idx) { - if (!mapping_info) { - CAM_ERR(CAM_SMMU, "Error: List doesn't exist"); + if ((!mapping_info->buf) || (!mapping_info->table) || + (!mapping_info->attach)) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params dev = %pK, table = %pK", + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)mapping_info->table); + CAM_ERR(CAM_SMMU, "Error:dma_buf = %pK, attach = %pK\n", + (void *)mapping_info->buf, + (void *)mapping_info->attach); return -EINVAL; } + + /* skip cache operations */ + mapping_info->attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; + + /* iommu buffer clean up */ + dma_buf_unmap_attachment(mapping_info->attach, + mapping_info->table, mapping_info->dir); + dma_buf_detach(mapping_info->buf, mapping_info->attach); dma_buf_put(mapping_info->buf); + mapping_info->buf = NULL; + list_del_init(&mapping_info->list); CAM_DBG(CAM_SMMU, "unmap fd: %d, idx : %d", mapping_info->ion_fd, idx); -- GitLab From 080521b70d0cfb2f080f4e33b7824c76bb7ad4f7 Mon Sep 17 00:00:00 2001 From: Dharmender Sharma Date: Tue, 14 Sep 2021 22:42:55 +0530 Subject: [PATCH 273/295] msm: camera: isp: Support all patterns for TOP TPG It provide support for differeent TPG patterns like color bar, incrementing and user defined. CRs-Fixed: 3026095 Change-Id: I8f7c4f3bb4c1c0d0026ff098d76b5664a66baca2 Signed-off-by: Dharmender Sharma --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 22 +++++- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h | 4 +- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 3 +- .../isp_hw/include/cam_top_tpg_hw_intf.h | 5 +- .../isp_hw/top_tpg/cam_top_tpg_core.c | 67 +++++++++++++++++++ .../isp_hw/top_tpg/cam_top_tpg_core.h | 6 +- .../isp_hw/top_tpg/cam_top_tpg_v1.h | 3 +- 7 files changed, 102 insertions(+), 8 deletions(-) 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 298a2b0c1933..8a783915e4c9 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -2971,6 +2971,17 @@ static int cam_tfe_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) sizeof(g_tfe_hw_mgr.debug_cfg.csid_debug)); } + /* set tpg debug information for top tpg */ + for (i = 0; i < CAM_TOP_TPG_HW_NUM_MAX; i++) { + if (g_tfe_hw_mgr.tpg_devices[i]) { + rc = g_tfe_hw_mgr.tpg_devices[i]->hw_ops.process_cmd( + g_tfe_hw_mgr.tpg_devices[i]->hw_priv, + CAM_ISP_HW_CMD_TPG_SET_PATTERN, + &g_tfe_hw_mgr.debug_cfg.set_tpg_pattern, + sizeof(g_tfe_hw_mgr.debug_cfg.set_tpg_pattern)); + } + } + camif_debug = g_tfe_hw_mgr.debug_cfg.camif_debug; list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) { for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { @@ -5450,6 +5461,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(cam_tfe_camif_debug, static int cam_tfe_hw_mgr_debug_register(void) { + g_tfe_hw_mgr.debug_cfg.set_tpg_pattern = CAM_TOP_TPG_DEFAULT_PATTERN; g_tfe_hw_mgr.debug_cfg.dentry = debugfs_create_dir("camera_tfe", NULL); @@ -5482,6 +5494,14 @@ static int cam_tfe_hw_mgr_debug_register(void) goto err; } + if (!debugfs_create_u32("set_tpg_pattern", + 0644, + g_tfe_hw_mgr.debug_cfg.dentry, + &g_tfe_hw_mgr.debug_cfg.set_tpg_pattern)) { + CAM_ERR(CAM_ISP, "failed to create set_tpg_pattern"); + goto err; + } + if (!debugfs_create_u32("enable_reg_dump", 0644, g_tfe_hw_mgr.debug_cfg.dentry, 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 7b3d62b92c6a..f66ea4052bd5 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 @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_TFE_HW_MGR_H_ @@ -30,6 +30,7 @@ * @enable_recovery: enable recovery * @enable_csid_recovery: enable csid recovery * @camif_debug: enable sensor diagnosis status + * @set_tpg_pattern: tpg pattern information * @enable_reg_dump: enable reg dump on error; * @per_req_reg_dump: Enable per request reg dump * @@ -40,6 +41,7 @@ struct cam_tfe_hw_mgr_debug { uint32_t enable_recovery; uint32_t enable_csid_recovery; uint32_t camif_debug; + uint32_t set_tpg_pattern; uint32_t enable_reg_dump; uint32_t per_req_reg_dump; }; 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 e5610b98d528..4603b20b6a68 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 @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_H_ @@ -114,6 +114,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE, CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, CAM_ISP_HW_CMD_DUMP_HW, + CAM_ISP_HW_CMD_TPG_SET_PATTERN, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_top_tpg_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_top_tpg_hw_intf.h index a773a23dfda4..224d4bbfb7b7 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_top_tpg_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_top_tpg_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_TOP_TPG_HW_INTF_H_ @@ -13,7 +13,8 @@ #define CAM_TOP_TPG_HW_NUM_MAX 2 /* Max supported number of DT for TPG */ #define CAM_TOP_TPG_MAX_SUPPORTED_DT 4 - +/* TPG default pattern should be color bar */ +#define CAM_TOP_TPG_DEFAULT_PATTERN 0x8 /** * enum cam_top_tpg_id - top tpg hw instance id */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c index 81b287d1b364..7322301f69be 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c @@ -400,6 +400,7 @@ static int cam_top_tpg_start(void *hw_priv, void *start_args, const struct cam_top_tpg_reg_offset *tpg_reg; struct cam_top_tpg_cfg *tpg_data; uint32_t i, val; + uint32_t in_format = 0; if (!hw_priv || !start_args || (arg_size != sizeof(struct cam_isp_resource_node))) { @@ -456,6 +457,56 @@ static int cam_top_tpg_start(void *hw_priv, void *start_args, cam_io_w_mb(0x2581F4, soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc_cfg1); + /* configure tpg pattern */ + in_format = tpg_data->dt_cfg[0].encode_format & 0xF; + val = in_format << tpg_reg->tpg_dt_encode_format_shift; + + switch (tpg_hw->tpg_pattern) { + case 0x0: + val = val | tpg_hw->tpg_pattern; + break; + case 0x1: + val = val | tpg_hw->tpg_pattern; + break; + case 0x2: + val = val | tpg_hw->tpg_pattern; + break; + case 0x3: + val = val | tpg_hw->tpg_pattern; + break; + case 0x4: + val = val | tpg_hw->tpg_pattern; + break; + case 0x5: + val = val | tpg_hw->tpg_pattern; + break; + case 0x6: + val = val | tpg_hw->tpg_pattern; + break; + case 0x7: + val = val | tpg_hw->tpg_pattern; + break; + case 0x8: + /* unicolor bar selection */ + val = 0x1 | (1 << tpg_reg->top_unicolor_bar_shift); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_color_bar_cfg); + val = (in_format << tpg_reg->tpg_dt_encode_format_shift) | + tpg_hw->tpg_pattern; + break; + default: + /* frame with split color bar */ + val = 1 << tpg_reg->tpg_split_en_shift; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_color_bar_cfg); + val = (in_format << tpg_reg->tpg_dt_encode_format_shift) | + CAM_TOP_TPG_DEFAULT_PATTERN; + break; + } + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_dt_0_cfg_2); + val = (1 << tpg_reg->tpg_split_en_shift); cam_io_w_mb(tpg_data->pix_pattern, soc_info->reg_map[0].mem_base + tpg_reg->tpg_common_gen_cfg); @@ -580,6 +631,19 @@ static int cam_top_tpg_set_phy_clock( return 0; } +static int cam_top_tpg_set_top_tpg_pattern(struct cam_top_tpg_hw *tpg_hw, + void *cmd_args) +{ + uint32_t *top_tpg_pattern; + + top_tpg_pattern = (uint32_t *) cmd_args; + tpg_hw->tpg_pattern = *top_tpg_pattern; + CAM_DBG(CAM_ISP, "TPG:%d set tpg debug value:%d", + tpg_hw->hw_intf->hw_idx, tpg_hw->tpg_pattern); + + return 0; +} + static int cam_top_tpg_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -599,6 +663,9 @@ static int cam_top_tpg_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE: rc = cam_top_tpg_set_phy_clock(tpg_hw, cmd_args); break; + case CAM_ISP_HW_CMD_TPG_SET_PATTERN: + rc = cam_top_tpg_set_top_tpg_pattern(tpg_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "TPG:%d unsupported cmd:%d", tpg_hw->hw_intf->hw_idx, cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.h index 5a859ffb5d38..c3aeb228a5bb 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_TOP_TPG_HW_H_ @@ -60,6 +60,7 @@ struct cam_top_tpg_reg_offset { uint32_t tpg_payload_mode_color; uint32_t tpg_split_en_shift; uint32_t top_mux_reg_offset; + uint32_t top_unicolor_bar_shift; }; /** @@ -129,7 +130,7 @@ struct cam_top_tpg_cfg { * @hw_info: tpg hw device information * @tpg_info: tpg hw specific information * @tpg_res: tpg resource - * @tpg_cfg: tpg configuration + * @tpg_pattern: tpg pattern configuration * @clk_rate clock rate * @lock_state lock state * @tpg_complete tpg completion @@ -140,6 +141,7 @@ struct cam_top_tpg_hw { struct cam_hw_info *hw_info; struct cam_top_tpg_hw_info *tpg_info; struct cam_isp_resource_node tpg_res; + uint32_t tpg_pattern; uint64_t clk_rate; spinlock_t lock_state; struct completion tpg_complete; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.h index addd8a2e5988..aedc666bb792 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_v1.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_TOP_TPG_V1_H_ @@ -48,6 +48,7 @@ static struct cam_top_tpg_reg_offset cam_top_tpg_v1_reg_offset = { .tpg_payload_mode_color = 0x8, .tpg_split_en_shift = 5, .top_mux_reg_offset = 0x1C, + .top_unicolor_bar_shift = 2, }; #endif /*_CAM_TOP_TPG_V1_H_ */ -- GitLab From 42922dbe6e9097b5ae473fcf41e3094f51af0beb Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Mon, 6 Sep 2021 21:12:00 +0530 Subject: [PATCH 274/295] msm: camera: jpeg: Ensure in/out map entries are within allowed range Added checks to make sure in_map /out_map entries of packet io configs are within expected maximum value. CRs-Fixed: 3007258 Change-Id: I7e5a652cd8f9ae104a10a2af551fe49930849b2d Signed-off-by: Shravya Samala --- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 24511b904da0..ee353c094d6d 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -732,10 +732,12 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, } if ((packet->num_cmd_buf > 5) || !packet->num_patches || - !packet->num_io_configs) { - CAM_ERR(CAM_JPEG, "wrong number of cmd/patch info: %u %u", - packet->num_cmd_buf, - packet->num_patches); + !packet->num_io_configs || + (packet->num_io_configs > CAM_JPEG_IMAGE_MAX)) { + CAM_ERR(CAM_JPEG, + "wrong number of cmd/patch/io_configs info: %u %u %u", + packet->num_cmd_buf, packet->num_patches, + packet->num_io_configs); return -EINVAL; } -- GitLab From 9144efff1b25248aae85ec56510898f2857e5cd7 Mon Sep 17 00:00:00 2001 From: sokchetra eung Date: Tue, 17 Aug 2021 14:55:38 -0700 Subject: [PATCH 275/295] msm: camera: req_mgr: Table info dump removed Remove dump_tbl_info function and all of its invocations in CRM to prevent dumping all the handle info when holding the spin lock. CRs-Fixed: 3014074, 3014073 Change-Id: Ie98bafb489fc0d1f2d75cf0f3f08efb48d9b4062 Signed-off-by: sokchetra eung --- drivers/cam_req_mgr/cam_req_mgr_util.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c index df180a615104..f4bef0ce0d7b 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "CAM-REQ-MGR_UTIL %s:%d " fmt, __func__, __LINE__ @@ -114,7 +114,7 @@ static int32_t cam_get_free_handle_index(void) idx = find_first_zero_bit(hdl_tbl->bitmap, hdl_tbl->bits); if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2 || idx < 0) { - CAM_DBG(CAM_CRM, "idx: %d", idx); + CAM_ERR(CAM_CRM, "No free index found idx: %d", idx); return -ENOSR; } @@ -123,20 +123,6 @@ static int32_t cam_get_free_handle_index(void) return idx; } -void cam_dump_tbl_info(void) -{ - int i; - - for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES_V2; i++) - CAM_INFO(CAM_CRM, - "i: %d session_hdl=0x%x hdl_value=0x%x type=%d state=%d dev_id=0x%llx", - i, hdl_tbl->hdl[i].session_hdl, - hdl_tbl->hdl[i].hdl_value, - hdl_tbl->hdl[i].type, - hdl_tbl->hdl[i].state, - hdl_tbl->hdl[i].dev_id); -} - int32_t cam_create_session_hdl(void *priv) { int idx; @@ -153,7 +139,6 @@ int32_t cam_create_session_hdl(void *priv) idx = cam_get_free_handle_index(); if (idx < 0) { CAM_ERR(CAM_CRM, "Unable to create session handle"); - cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } @@ -189,7 +174,6 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) if (idx < 0) { CAM_ERR(CAM_CRM, "Unable to create device handle(idx= %d)", idx); - cam_dump_tbl_info(); spin_unlock_bh(&hdl_tbl_lock); return idx; } -- GitLab From cf4b525b4a3134d410e1f86838d88e449dfbe4e4 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Mon, 6 Sep 2021 21:12:00 +0530 Subject: [PATCH 276/295] msm: camera: jpeg: Ensure in/out map entries are within allowed range Added checks to make sure in_map /out_map entries of packet io configs are within expected maximum value. CRs-Fixed: 3007258 Change-Id: I7e5a652cd8f9ae104a10a2af551fe49930849b2d Signed-off-by: Shravya Samala --- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 24511b904da0..ee353c094d6d 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -732,10 +732,12 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, } if ((packet->num_cmd_buf > 5) || !packet->num_patches || - !packet->num_io_configs) { - CAM_ERR(CAM_JPEG, "wrong number of cmd/patch info: %u %u", - packet->num_cmd_buf, - packet->num_patches); + !packet->num_io_configs || + (packet->num_io_configs > CAM_JPEG_IMAGE_MAX)) { + CAM_ERR(CAM_JPEG, + "wrong number of cmd/patch/io_configs info: %u %u %u", + packet->num_cmd_buf, packet->num_patches, + packet->num_io_configs); return -EINVAL; } -- GitLab From 538f7283f9648093de67e65632a158437e061074 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Fri, 22 Oct 2021 11:52:28 +0530 Subject: [PATCH 277/295] msm: camera: csiphy: Update Phy header file for 1.2.1 Update the cphy register settings in 1.2.1 phy header file. CRs-fixed: 3063363 Change-Id: I9a78ccdb6a91305c8b6d5fb014c9f0fe9c622f84 Signed-off-by: shiwgupt --- .../include/cam_csiphy_1_2_1_hwreg.h | 99 +++++++------------ 1 file changed, 36 insertions(+), 63 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index c7d6deef2bf6..8208ca83d09b 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -396,82 +396,55 @@ struct data_rate_settings_t data_rate_delta_table_1_2_1 = { { /* (2.5 * 10**3 * 2.28) rounded value*/ .bandwidth = 5700000000, - .data_rate_reg_array_size = 12, + .data_rate_reg_array_size = 9, .csiphy_data_rate_regs = { - {0x15C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x35C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x55C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x164, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, } }, { /* (3.5 * 10**3 * 2.28) rounded value */ .bandwidth = 7980000000, - .data_rate_reg_array_size = 24, + .data_rate_reg_array_size = 12, .csiphy_data_rate_regs = { - {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }, { /* (4.5 * 10**3 * 2.28) rounded value */ .bandwidth = 10260000000, - .data_rate_reg_array_size = 24, + .data_rate_reg_array_size = 12, .csiphy_data_rate_regs = { - {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x02, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, }, } } -- GitLab From f04fe7dfcfbb9aaf9fb31d52a0bd5e342ead535b Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 7 Oct 2021 18:24:01 +0530 Subject: [PATCH 278/295] msm: camera: flash: Add support for i2c flash Add Support for qup i2c based flash. Update i2c driver probe function and added init for gpio pin control table. Since positive return values are not errors for qup i2c rx and tx data transfer, fix the return type for the APIs. Added check for null pointer in get flash dt data for device node. CRs-Fixed: 3056236 Change-Id: If33086c80bd7d5c1403aedf1a2c01867d6c56687 Signed-off-by: Vishal Verma --- .../cam_flash/cam_flash_dev.c | 80 +++++++++++++------ .../cam_flash/cam_flash_soc.c | 9 ++- .../cam_sensor_io/cam_sensor_qup_i2c.c | 20 +++-- 3 files changed, 80 insertions(+), 29 deletions(-) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index 9bbdaa80e755..cb8e3559a177 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -423,6 +423,7 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev) fctrl->soc_info.pdev = pdev; fctrl->soc_info.dev = &pdev->dev; fctrl->soc_info.dev_name = pdev->name; + fctrl->of_node = pdev->dev.of_node; platform_set_drvdata(pdev, fctrl); @@ -465,21 +466,21 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev) soc_info = &fctrl->soc_info; if (!soc_info->gpio_data) { - CAM_INFO(CAM_FLASH, "No GPIO found"); - rc = 0; - return rc; - } - - if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { - CAM_INFO(CAM_FLASH, "No GPIO found"); - return -EINVAL; - } - - rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + CAM_DBG(CAM_FLASH, "No GPIO found"); + } else { + if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { + CAM_ERR(CAM_FLASH, "Invalid gpio table size"); + rc = -EINVAL; + goto free_cci_resource; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, &fctrl->power_info.gpio_num_info); - if ((rc < 0) || (!fctrl->power_info.gpio_num_info)) { - CAM_ERR(CAM_FLASH, "No/Error Flash GPIOs"); - return -EINVAL; + if ((rc < 0) || (!fctrl->power_info.gpio_num_info)) { + CAM_ERR(CAM_FLASH, "No/Error Flash GPIOs"); + rc = -EINVAL; + goto free_cci_resource; + } } fctrl->i2c_data.per_frame = @@ -551,13 +552,17 @@ static int32_t cam_flash_i2c_driver_probe(struct i2c_client *client, { int32_t rc = 0, i = 0; struct cam_flash_ctrl *fctrl; + struct cam_hw_soc_info *soc_info = NULL; - if (client == NULL || id == NULL) { - CAM_ERR(CAM_FLASH, "Invalid Args client: %pK id: %pK", - client, id); + if (client == NULL) { + CAM_ERR(CAM_FLASH, "Invalid Args client: %pK", client); return -EINVAL; } + if (id == NULL) { + CAM_DBG(CAM_FLASH, "device id is Null"); + } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { CAM_ERR(CAM_FLASH, "%s :: i2c_check_functionality failed", client->name); @@ -566,22 +571,51 @@ static int32_t cam_flash_i2c_driver_probe(struct i2c_client *client, /* Create sensor control structure */ fctrl = kzalloc(sizeof(*fctrl), GFP_KERNEL); - if (!fctrl) + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Failed to allocate memory for fctrl"); return -ENOMEM; + } i2c_set_clientdata(client, fctrl); fctrl->io_master_info.client = client; + fctrl->of_node = client->dev.of_node; fctrl->soc_info.dev = &client->dev; fctrl->soc_info.dev_name = client->name; fctrl->io_master_info.master_type = I2C_MASTER; + rc = cam_flash_init_default_params(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "failed: cam_flash_init_default_params rc %d", rc); + goto free_ctrl; + } + rc = cam_flash_get_dt_data(fctrl, &fctrl->soc_info); if (rc) { CAM_ERR(CAM_FLASH, "failed: cam_sensor_parse_dt rc %d", rc); goto free_ctrl; } + soc_info = &fctrl->soc_info; + if (!soc_info->gpio_data) { + CAM_DBG(CAM_FLASH, "No GPIO found"); + } else { + if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { + CAM_ERR(CAM_FLASH, "Invalid gpio table size"); + rc = -EINVAL; + goto free_ctrl; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &fctrl->power_info.gpio_num_info); + if ((rc < 0) || (!fctrl->power_info.gpio_num_info)) { + CAM_ERR(CAM_FLASH, "No/Error Flash GPIOs"); + rc = -EINVAL; + goto free_ctrl; + } + } + rc = cam_flash_init_subdev(fctrl); if (rc) goto free_ctrl; @@ -650,6 +684,7 @@ static struct i2c_driver cam_flash_i2c_driver = { .remove = cam_flash_i2c_driver_remove, .driver = { .name = FLASH_DRIVER_I2C, + .of_match_table = cam_flash_dt_match, }, }; @@ -658,14 +693,13 @@ static int32_t __init cam_flash_init_module(void) int32_t rc = 0; rc = platform_driver_register(&cam_flash_platform_driver); - if (rc == 0) { - CAM_DBG(CAM_FLASH, "platform probe success"); - return 0; - } + if (rc < 0) + CAM_ERR(CAM_FLASH, "platform probe failed rc: %d", rc); rc = i2c_add_driver(&cam_flash_i2c_driver); - if (rc) + if (rc < 0) CAM_ERR(CAM_FLASH, "i2c_add_driver failed rc: %d", rc); + return rc; } diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c index 106f7e335e7b..4b3ee2f62e73 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -240,7 +240,14 @@ int cam_flash_get_dt_data(struct cam_flash_ctrl *fctrl, rc = -ENOMEM; goto release_soc_res; } - of_node = fctrl->pdev->dev.of_node; + + if (fctrl->of_node == NULL) { + CAM_ERR(CAM_FLASH, "device node is NULL"); + rc = -EINVAL; + goto free_soc_private; + } + + of_node = fctrl->of_node; rc = cam_soc_util_get_dt_properties(soc_info); if (rc) { diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c index a9fd0881aabf..80c8cc8d9a48 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include "cam_sensor_cmn_header.h" @@ -32,9 +32,14 @@ static int32_t cam_qup_i2c_rxdata( }, }; rc = i2c_transfer(dev_client->adapter, msgs, 2); - if (rc < 0) + if (rc < 0) { CAM_ERR(CAM_SENSOR, "failed 0x%x", saddr); - return rc; + return rc; + } + /* Returns negative errno */ + /* else the number of messages executed. */ + /* So positive values are not errors. */ + return 0; } @@ -53,9 +58,14 @@ static int32_t cam_qup_i2c_txdata( }, }; rc = i2c_transfer(dev_client->client->adapter, msg, 1); - if (rc < 0) + if (rc < 0) { CAM_ERR(CAM_SENSOR, "failed 0x%x", saddr); - return rc; + return rc; + } + /* Returns negative errno, */ + /* else the number of messages executed. */ + /* So positive values are not errors. */ + return 0; } int32_t cam_qup_i2c_read(struct i2c_client *client, -- GitLab From 2a841888770b563558d0ee8ba8f044b3acf97c24 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 14 Oct 2021 16:56:51 +0530 Subject: [PATCH 279/295] msm: camera: isp: Fix PPI index based on the phy selection 1) There is one to one mapping for ppi index with phy index but phy select is not always equal to phy number,for some targets "phy_sel = phy_idx + 1", and for some targets it is "phy_sel = phy_idx", ppi_index should be updated accordingly. 2) Updated to configure ppi cfg register as. for cphy, disable dphy in config register. for dphy, do nothing (both cphy and dphy will be selected). then enable all lanes. CRs-Fixed: 3057665 Change-Id: I1d5d66034a5563b5adcb8163acf9a668d10d4a19 Signed-off-by: Vikram Sharma --- .../isp_hw/ppi_hw/cam_csid_ppi_core.c | 32 ++++--------------- .../isp_hw/ppi_hw/cam_csid_ppi_core.h | 2 +- .../isp_hw/tfe_csid_hw/cam_tfe_csid530.h | 3 +- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 12 +++++-- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.h | 1 + 5 files changed, 21 insertions(+), 29 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c index 78f16ee9dba2..63bd4e9a9b6f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c @@ -163,9 +163,7 @@ static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, { int i, rc = 0; uint32_t num_lanes; - uint32_t lanes[CAM_CSID_PPI_HW_MAX] = {0, 0, 0, 0}; uint32_t cphy; - bool dl0, dl1; uint32_t ppi_cfg_val = 0; struct cam_csid_ppi_hw *ppi_hw; struct cam_hw_info *ppi_hw_info; @@ -180,7 +178,6 @@ static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, goto end; } - dl0 = dl1 = false; ppi_hw_info = (struct cam_hw_info *)hw_priv; ppi_hw = (struct cam_csid_ppi_hw *)ppi_hw_info->core_info; ppi_reg = ppi_hw->ppi_info->ppi_reg; @@ -195,31 +192,16 @@ static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, CAM_DBG(CAM_ISP, "lane_cfg 0x%x | num_lanes 0x%x | lane_type 0x%x", ppi_cfg.lane_cfg, num_lanes, cphy); - for (i = 0; i < num_lanes; i++) { - lanes[i] = ppi_cfg.lane_cfg & (0x3 << (4 * i)); - (lanes[i] < 2) ? (dl0 = true) : (dl1 = true); - CAM_DBG(CAM_ISP, "lanes[%d] %d", i, lanes[i]); - } - - if (num_lanes) { - if (cphy) { - for (i = 0; i < num_lanes; i++) { - ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(lanes[i]); - ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(lanes[i]); - } - } else { - if (dl0) - ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(0); - if (dl1) - ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(1); - } + if (cphy) { + ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(0); + ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(1); } else { - CAM_ERR(CAM_ISP, - "Number of lanes to enable is cannot be zero"); - rc = -1; - goto end; + ppi_cfg_val = 0; } + for (i = 0; i < CAM_CSID_PPI_LANES_MAX; i++) + ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(i); + CAM_DBG(CAM_ISP, "ppi_cfg_val 0x%x", ppi_cfg_val); soc_info = &ppi_hw->hw_info->soc_info; cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h index 84d0e2e67376..777c4e3fb573 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h @@ -25,7 +25,7 @@ /* * Select the PHY (CPHY set '1' or DPHY set '0') */ -#define PPI_CFG_CPHY_DLX_SEL(X) ((X < 2) ? BIT(X) : 0) +#define PPI_CFG_CPHY_DLX_SEL(X) BIT(X) #define PPI_CFG_CPHY_DLX_EN(X) BIT(4+X) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h index 7486a35af33e..634c35917396 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_TFE_CSID_530_H_ @@ -134,6 +134,7 @@ static struct cam_tfe_csid_csi2_rx_reg_offset .csid_csi2_rx_irq_set_addr = 0x2c, /*CSI2 rx control */ + .phy_sel_base = 1, .csid_csi2_rx_cfg0_addr = 0x100, .csid_csi2_rx_cfg1_addr = 0x104, .csid_csi2_rx_capture_ctrl_addr = 0x108, 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 d3dbf7b30c64..510ba0f382fb 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 @@ -804,8 +804,15 @@ static int cam_tfe_csid_enable_csi2( cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + /* + * There is one to one mapping for ppi index with phy index + * we do not always update phy sel equal to phy number,for some + * targets "phy_sel = phy_num + 1", and for some targets it is + * "phy_sel = phy_num", ppi_index should be updated accordingly + */ + ppi_index = csid_hw->csi2_rx_cfg.phy_sel - + csid_reg->csi2_reg->phy_sel_base; - ppi_index = csid_hw->csi2_rx_cfg.phy_sel; if (csid_hw->ppi_hw_intf[ppi_index] && csid_hw->ppi_enable) { ppi_lane_cfg.lane_type = csid_hw->csi2_rx_cfg.lane_type; ppi_lane_cfg.lane_num = csid_hw->csi2_rx_cfg.lane_num; @@ -847,7 +854,8 @@ static int cam_tfe_csid_disable_csi2( cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); - ppi_index = csid_hw->csi2_rx_cfg.phy_sel; + ppi_index = csid_hw->csi2_rx_cfg.phy_sel - + csid_reg->csi2_reg->phy_sel_base; if (csid_hw->ppi_hw_intf[ppi_index] && csid_hw->ppi_enable) { /* De-Initialize the PPI bridge */ CAM_DBG(CAM_ISP, "ppi_index to de-init %d\n", ppi_index); 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 3eba8333470b..d0935689fd01 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 @@ -185,6 +185,7 @@ struct cam_tfe_csid_csi2_rx_reg_offset { uint32_t csid_csi2_rx_total_crc_err_addr; /*configurations */ + uint32_t phy_sel_base; uint32_t csi2_rst_srb_all; uint32_t csi2_rst_done_shift_val; uint32_t csi2_irq_mask_all; -- GitLab From 57bf85b69d6bcd826e549bbae923490de62db99e Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 14 Oct 2021 16:56:51 +0530 Subject: [PATCH 280/295] msm: camera: isp: Fix PPI index based on the phy selection 1) There is one to one mapping for ppi index with phy index but phy select is not always equal to phy number,for some targets "phy_sel = phy_idx + 1", and for some targets it is "phy_sel = phy_idx", ppi_index should be updated accordingly. 2) Updated to configure ppi cfg register as. for cphy, disable dphy in config register. for dphy, do nothing (both cphy and dphy will be selected). then enable all lanes. CRs-Fixed: 3057665 Change-Id: I1d5d66034a5563b5adcb8163acf9a668d10d4a19 Signed-off-by: Vikram Sharma --- .../isp_hw/ppi_hw/cam_csid_ppi_core.c | 32 ++++--------------- .../isp_hw/ppi_hw/cam_csid_ppi_core.h | 2 +- .../isp_hw/tfe_csid_hw/cam_tfe_csid530.h | 3 +- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 12 +++++-- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.h | 1 + 5 files changed, 21 insertions(+), 29 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c index 78f16ee9dba2..63bd4e9a9b6f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c @@ -163,9 +163,7 @@ static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, { int i, rc = 0; uint32_t num_lanes; - uint32_t lanes[CAM_CSID_PPI_HW_MAX] = {0, 0, 0, 0}; uint32_t cphy; - bool dl0, dl1; uint32_t ppi_cfg_val = 0; struct cam_csid_ppi_hw *ppi_hw; struct cam_hw_info *ppi_hw_info; @@ -180,7 +178,6 @@ static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, goto end; } - dl0 = dl1 = false; ppi_hw_info = (struct cam_hw_info *)hw_priv; ppi_hw = (struct cam_csid_ppi_hw *)ppi_hw_info->core_info; ppi_reg = ppi_hw->ppi_info->ppi_reg; @@ -195,31 +192,16 @@ static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, CAM_DBG(CAM_ISP, "lane_cfg 0x%x | num_lanes 0x%x | lane_type 0x%x", ppi_cfg.lane_cfg, num_lanes, cphy); - for (i = 0; i < num_lanes; i++) { - lanes[i] = ppi_cfg.lane_cfg & (0x3 << (4 * i)); - (lanes[i] < 2) ? (dl0 = true) : (dl1 = true); - CAM_DBG(CAM_ISP, "lanes[%d] %d", i, lanes[i]); - } - - if (num_lanes) { - if (cphy) { - for (i = 0; i < num_lanes; i++) { - ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(lanes[i]); - ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(lanes[i]); - } - } else { - if (dl0) - ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(0); - if (dl1) - ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(1); - } + if (cphy) { + ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(0); + ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(1); } else { - CAM_ERR(CAM_ISP, - "Number of lanes to enable is cannot be zero"); - rc = -1; - goto end; + ppi_cfg_val = 0; } + for (i = 0; i < CAM_CSID_PPI_LANES_MAX; i++) + ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(i); + CAM_DBG(CAM_ISP, "ppi_cfg_val 0x%x", ppi_cfg_val); soc_info = &ppi_hw->hw_info->soc_info; cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h index 84d0e2e67376..777c4e3fb573 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h @@ -25,7 +25,7 @@ /* * Select the PHY (CPHY set '1' or DPHY set '0') */ -#define PPI_CFG_CPHY_DLX_SEL(X) ((X < 2) ? BIT(X) : 0) +#define PPI_CFG_CPHY_DLX_SEL(X) BIT(X) #define PPI_CFG_CPHY_DLX_EN(X) BIT(4+X) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h index 7486a35af33e..634c35917396 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_TFE_CSID_530_H_ @@ -134,6 +134,7 @@ static struct cam_tfe_csid_csi2_rx_reg_offset .csid_csi2_rx_irq_set_addr = 0x2c, /*CSI2 rx control */ + .phy_sel_base = 1, .csid_csi2_rx_cfg0_addr = 0x100, .csid_csi2_rx_cfg1_addr = 0x104, .csid_csi2_rx_capture_ctrl_addr = 0x108, 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 d3dbf7b30c64..510ba0f382fb 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 @@ -804,8 +804,15 @@ static int cam_tfe_csid_enable_csi2( cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + /* + * There is one to one mapping for ppi index with phy index + * we do not always update phy sel equal to phy number,for some + * targets "phy_sel = phy_num + 1", and for some targets it is + * "phy_sel = phy_num", ppi_index should be updated accordingly + */ + ppi_index = csid_hw->csi2_rx_cfg.phy_sel - + csid_reg->csi2_reg->phy_sel_base; - ppi_index = csid_hw->csi2_rx_cfg.phy_sel; if (csid_hw->ppi_hw_intf[ppi_index] && csid_hw->ppi_enable) { ppi_lane_cfg.lane_type = csid_hw->csi2_rx_cfg.lane_type; ppi_lane_cfg.lane_num = csid_hw->csi2_rx_cfg.lane_num; @@ -847,7 +854,8 @@ static int cam_tfe_csid_disable_csi2( cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); - ppi_index = csid_hw->csi2_rx_cfg.phy_sel; + ppi_index = csid_hw->csi2_rx_cfg.phy_sel - + csid_reg->csi2_reg->phy_sel_base; if (csid_hw->ppi_hw_intf[ppi_index] && csid_hw->ppi_enable) { /* De-Initialize the PPI bridge */ CAM_DBG(CAM_ISP, "ppi_index to de-init %d\n", ppi_index); 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 3eba8333470b..d0935689fd01 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 @@ -185,6 +185,7 @@ struct cam_tfe_csid_csi2_rx_reg_offset { uint32_t csid_csi2_rx_total_crc_err_addr; /*configurations */ + uint32_t phy_sel_base; uint32_t csi2_rst_srb_all; uint32_t csi2_rst_done_shift_val; uint32_t csi2_irq_mask_all; -- GitLab From a27df09f6634be6f80749c9323a8f738e5940a06 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Mon, 8 Nov 2021 09:29:33 +0530 Subject: [PATCH 281/295] msm: camera: csiphy: Update PHY setting in 1+1 combo mode Enable FORCE_TERM_EN for LN6 in 1+1 combo mode. CRs-Fixed: 3071453 Change-Id: I301942c7cecaca175b1d9d3c31bf203bfc683359 Signed-off-by: shiwgupt --- .../cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index 8208ca83d09b..2c273b9d5dd9 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -275,7 +275,7 @@ struct csiphy_reg_t {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, -- GitLab From b2e53366731291c26e660913c71d0284188876bd Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 18 Nov 2021 17:07:47 +0530 Subject: [PATCH 282/295] msm: camera: reqmgr: reader writer locks to avoid memory faults Shared memory is initialized by CRM and used by other drivers; with CRM not active other drivers would fail to access the shared memory if memory manager is deinit. Reader Writer locks can prevent the open/close/ioctl calls from other drivers if CRM open/close is already being processed. Issue observed with the below sequence if drivers are opened from UMD directly without this change. CRM Open successful,ICP open successful, CRM close in progress, ICP open successful, mem mgr deinit and CRM close successful, ICP tries to access HFI memory and result in crash. This change helps to serialze the calls and prevents issue. CRs-Fixed: 3019488 Change-Id: Ifdf198c2e3593050573c66aeba69d50d131435b9 Signed-off-by: Tejas Prajapati --- drivers/cam_core/cam_subdev.c | 2 + drivers/cam_fd/cam_fd_dev.c | 5 ++ drivers/cam_icp/cam_icp_subdev.c | 3 ++ drivers/cam_isp/cam_isp_dev.c | 4 ++ drivers/cam_jpeg/cam_jpeg_dev.c | 2 + drivers/cam_lrme/cam_lrme_dev.c | 5 ++ drivers/cam_ope/cam_ope_subdev.c | 3 ++ drivers/cam_req_mgr/cam_req_mgr_dev.c | 48 +++++++++++++++++++ drivers/cam_req_mgr/cam_req_mgr_dev.h | 2 + drivers/cam_req_mgr/cam_req_mgr_util.c | 9 ++++ drivers/cam_req_mgr/cam_subdev.h | 29 +++++++++++ .../cam_actuator/cam_actuator_core.c | 5 ++ .../cam_csiphy/cam_csiphy_core.c | 5 ++ .../cam_eeprom/cam_eeprom_core.c | 4 ++ .../cam_flash/cam_flash_dev.c | 5 ++ .../cam_sensor_module/cam_ois/cam_ois_core.c | 4 ++ .../cam_sensor/cam_sensor_core.c | 5 ++ 17 files changed, 140 insertions(+) diff --git a/drivers/cam_core/cam_subdev.c b/drivers/cam_core/cam_subdev.c index 1a81a4d59e99..15b5fd84bbc4 100644 --- a/drivers/cam_core/cam_subdev.c +++ b/drivers/cam_core/cam_subdev.c @@ -53,8 +53,10 @@ static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, switch (cmd) { case VIDIOC_CAM_CONTROL: + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); rc = cam_node_handle_ioctl(node, (struct cam_control *) arg); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); break; default: CAM_ERR(CAM_CORE, "Invalid command %d for %s", cmd, diff --git a/drivers/cam_fd/cam_fd_dev.c b/drivers/cam_fd/cam_fd_dev.c index c92cea8fc9e9..f492696ae3a3 100644 --- a/drivers/cam_fd/cam_fd_dev.c +++ b/drivers/cam_fd/cam_fd_dev.c @@ -43,8 +43,11 @@ static int cam_fd_dev_open(struct v4l2_subdev *sd, { struct cam_fd_dev *fd_dev = &g_fd_dev; + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); + if (!fd_dev->probe_done) { CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); return -ENODEV; } @@ -53,6 +56,8 @@ static int cam_fd_dev_open(struct v4l2_subdev *sd, CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); mutex_unlock(&fd_dev->lock); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); + return 0; } diff --git a/drivers/cam_icp/cam_icp_subdev.c b/drivers/cam_icp/cam_icp_subdev.c index bdb2ed5f900b..128b171f8659 100644 --- a/drivers/cam_icp/cam_icp_subdev.c +++ b/drivers/cam_icp/cam_icp_subdev.c @@ -75,6 +75,8 @@ static int cam_icp_subdev_open(struct v4l2_subdev *sd, struct cam_node *node = v4l2_get_subdevdata(sd); int rc = 0; + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); + mutex_lock(&g_icp_dev.icp_lock); if (g_icp_dev.open_cnt >= 1) { CAM_ERR(CAM_ICP, "ICP subdev is already opened"); @@ -97,6 +99,7 @@ static int cam_icp_subdev_open(struct v4l2_subdev *sd, g_icp_dev.open_cnt++; end: mutex_unlock(&g_icp_dev.icp_lock); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); return rc; } diff --git a/drivers/cam_isp/cam_isp_dev.c b/drivers/cam_isp/cam_isp_dev.c index 99959b8a8329..b08956ef957e 100644 --- a/drivers/cam_isp/cam_isp_dev.c +++ b/drivers/cam_isp/cam_isp_dev.c @@ -50,10 +50,14 @@ static const struct of_device_id cam_isp_dt_match[] = { static int cam_isp_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); + mutex_lock(&g_isp_dev.isp_mutex); g_isp_dev.open_cnt++; mutex_unlock(&g_isp_dev.isp_mutex); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); + return 0; } diff --git a/drivers/cam_jpeg/cam_jpeg_dev.c b/drivers/cam_jpeg/cam_jpeg_dev.c index 85da82cea7ba..b123ebe8059a 100644 --- a/drivers/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/cam_jpeg/cam_jpeg_dev.c @@ -49,10 +49,12 @@ static const struct of_device_id cam_jpeg_dt_match[] = { static int cam_jpeg_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); mutex_lock(&g_jpeg_dev.jpeg_mutex); g_jpeg_dev.open_cnt++; mutex_unlock(&g_jpeg_dev.jpeg_mutex); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); return 0; } diff --git a/drivers/cam_lrme/cam_lrme_dev.c b/drivers/cam_lrme/cam_lrme_dev.c index 7c09f2b435f5..656a4dbd726b 100644 --- a/drivers/cam_lrme/cam_lrme_dev.c +++ b/drivers/cam_lrme/cam_lrme_dev.c @@ -58,9 +58,12 @@ static int cam_lrme_dev_open(struct v4l2_subdev *sd, { struct cam_lrme_dev *lrme_dev = g_lrme_dev; + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); + if (!lrme_dev) { CAM_ERR(CAM_LRME, "LRME Dev not initialized, dev=%pK", lrme_dev); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); return -ENODEV; } @@ -68,6 +71,8 @@ static int cam_lrme_dev_open(struct v4l2_subdev *sd, lrme_dev->open_cnt++; mutex_unlock(&lrme_dev->lock); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); + return 0; } diff --git a/drivers/cam_ope/cam_ope_subdev.c b/drivers/cam_ope/cam_ope_subdev.c index 22175ec1b9bc..3a09b71a085d 100644 --- a/drivers/cam_ope/cam_ope_subdev.c +++ b/drivers/cam_ope/cam_ope_subdev.c @@ -70,6 +70,8 @@ static int cam_ope_subdev_open(struct v4l2_subdev *sd, struct cam_node *node = v4l2_get_subdevdata(sd); int rc = 0; + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); + mutex_lock(&g_ope_dev.ope_lock); if (g_ope_dev.open_cnt >= 1) { CAM_ERR(CAM_OPE, "OPE subdev is already opened"); @@ -93,6 +95,7 @@ static int cam_ope_subdev_open(struct v4l2_subdev *sd, CAM_DBG(CAM_OPE, "OPE HW open success: %d", rc); end: mutex_unlock(&g_ope_dev.ope_lock); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); return rc; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 72a34c5bae20..1d2373ef7b09 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include @@ -30,6 +32,8 @@ static struct cam_req_mgr_device g_dev; struct kmem_cache *g_cam_req_mgr_timer_cachep; +DECLARE_RWSEM(rwsem_lock); + static int cam_media_device_setup(struct device *dev) { int rc; @@ -95,10 +99,28 @@ static void cam_v4l2_device_cleanup(void) g_dev.v4l2_dev = NULL; } +void cam_req_mgr_rwsem_read_op(enum cam_subdev_rwsem lock) +{ + if (lock == CAM_SUBDEV_LOCK) + down_read(&rwsem_lock); + else if (lock == CAM_SUBDEV_UNLOCK) + up_read(&rwsem_lock); +} + +static void cam_req_mgr_rwsem_write_op(enum cam_subdev_rwsem lock) +{ + if (lock == CAM_SUBDEV_LOCK) + down_write(&rwsem_lock); + else if (lock == CAM_SUBDEV_UNLOCK) + up_write(&rwsem_lock); +} + static int cam_req_mgr_open(struct file *filep) { int rc; + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_LOCK); + mutex_lock(&g_dev.cam_lock); if (g_dev.open_cnt >= 1) { rc = -EALREADY; @@ -124,12 +146,14 @@ static int cam_req_mgr_open(struct file *filep) } mutex_unlock(&g_dev.cam_lock); + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_UNLOCK); return rc; mem_mgr_init_fail: v4l2_fh_release(filep); end: mutex_unlock(&g_dev.cam_lock); + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_UNLOCK); return rc; } @@ -158,10 +182,14 @@ static int cam_req_mgr_close(struct file *filep) CAM_WARN(CAM_CRM, "release invoked associated userspace process has died, open_cnt: %d", g_dev.open_cnt); + + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_LOCK); + mutex_lock(&g_dev.cam_lock); if (g_dev.open_cnt <= 0) { mutex_unlock(&g_dev.cam_lock); + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_UNLOCK); return -EINVAL; } @@ -188,6 +216,8 @@ static int cam_req_mgr_close(struct file *filep) cam_mem_mgr_deinit(); mutex_unlock(&g_dev.cam_lock); + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_UNLOCK); + return 0; } @@ -653,6 +683,24 @@ void cam_subdev_notify_message(u32 subdev_type, } EXPORT_SYMBOL(cam_subdev_notify_message); +bool cam_req_mgr_is_open(void) +{ + bool crm_status = false; + + mutex_lock(&g_dev.cam_lock); + crm_status = g_dev.open_cnt ? true : false; + mutex_unlock(&g_dev.cam_lock); + + return crm_status; +} +EXPORT_SYMBOL(cam_req_mgr_is_open); + +bool cam_req_mgr_is_shutdown(void) +{ + return g_dev.shutdown_state; +} +EXPORT_SYMBOL(cam_req_mgr_is_shutdown); + int cam_register_subdev(struct cam_subdev *csd) { struct v4l2_subdev *sd; diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.h b/drivers/cam_req_mgr/cam_req_mgr_dev.h index 48ad09ce5ee2..ccf4854a03d2 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.h +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.h @@ -19,6 +19,7 @@ * @cam_lock: per file handle lock * @cam_eventq: event queue * @cam_eventq_lock: lock for event queue + * @shutdown_state: shutdown state */ struct cam_req_mgr_device { struct video_device *video; @@ -31,6 +32,7 @@ struct cam_req_mgr_device { struct mutex cam_lock; struct v4l2_fh *cam_eventq; spinlock_t cam_eventq_lock; + bool shutdown_state; }; #define CAM_REQ_MGR_GET_PAYLOAD_PTR(ev, type) \ diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c index f4bef0ce0d7b..64683eeb29a4 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -14,6 +14,7 @@ #include #include "cam_req_mgr_util.h" #include "cam_debug_util.h" +#include "cam_subdev.h" static struct cam_req_mgr_util_hdl_tbl *hdl_tbl; static DEFINE_SPINLOCK(hdl_tbl_lock); @@ -162,6 +163,14 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) int idx; int rand = 0; int32_t handle; + bool crm_active; + + crm_active = cam_req_mgr_is_open(); + if (!crm_active) { + CAM_ERR(CAM_ICP, "CRM is not ACTIVE"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } spin_lock_bh(&hdl_tbl_lock); if (!hdl_tbl) { diff --git a/drivers/cam_req_mgr/cam_subdev.h b/drivers/cam_req_mgr/cam_subdev.h index 6f8eff420f6c..783b33a55f17 100644 --- a/drivers/cam_req_mgr/cam_subdev.h +++ b/drivers/cam_req_mgr/cam_subdev.h @@ -20,6 +20,11 @@ enum cam_subdev_message_type_t { CAM_SUBDEV_MESSAGE_IRQ_ERR = 0x1 }; +enum cam_subdev_rwsem { + CAM_SUBDEV_LOCK = 1, + CAM_SUBDEV_UNLOCK, +}; + /** * struct cam_subdev - describes a camera sub-device * @@ -127,4 +132,28 @@ int cam_register_subdev(struct cam_subdev *sd); */ int cam_unregister_subdev(struct cam_subdev *sd); +/** + * cam_req_mgr_rwsem_read_op() + * + * @brief : API to acquire read semaphore lock to platform framework. + * + * @lock : value indicates to lock or unlock the read lock + */ +void cam_req_mgr_rwsem_read_op(enum cam_subdev_rwsem lock); + +/** + * cam_req_mgr_is_open() + * + * @brief: This common utility function returns the crm active status + * + */ +bool cam_req_mgr_is_open(void); + +/** + * cam_req_mgr_is_shutdown() + * + * @brief: This common utility function returns the shutdown state + */ +bool cam_req_mgr_is_shutdown(void); + #endif /* _CAM_SUBDEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c index d82eea628532..1555b01b3df5 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -826,6 +826,11 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, actuator_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (actuator_acq_dev.device_handle <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_ACTUATOR, "Can not create device handle"); + goto release_mutex; + } a_ctrl->bridge_intf.device_hdl = actuator_acq_dev.device_handle; a_ctrl->bridge_intf.session_hdl = actuator_acq_dev.session_handle; 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 956b09001442..bc7017f2c39d 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -785,6 +785,11 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, csiphy_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (csiphy_acq_dev.device_handle <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_CSIPHY, "Can not create device handle"); + goto release_mutex; + } bridge_intf = &csiphy_dev->bridge_intf; bridge_intf->device_hdl[csiphy_acq_params.combo_mode] = csiphy_acq_dev.device_handle; diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 8b9bd2adcb63..7284b455e369 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -355,6 +355,10 @@ static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, eeprom_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (eeprom_acq_dev.device_handle <= 0) { + CAM_ERR(CAM_EEPROM, "Can not create device handle"); + return -EFAULT; + } e_ctrl->bridge_intf.device_hdl = eeprom_acq_dev.device_handle; e_ctrl->bridge_intf.session_hdl = eeprom_acq_dev.session_handle; diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index cb8e3559a177..947117c3342a 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -67,6 +67,11 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, flash_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (flash_acq_dev.device_handle <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_FLASH, "Can not create device handle"); + goto release_mutex; + } fctrl->bridge_intf.device_hdl = flash_acq_dev.device_handle; fctrl->bridge_intf.session_hdl = diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index ebfc8ec0557c..2b018dd33222 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -86,6 +86,10 @@ static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, ois_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (ois_acq_dev.device_handle <= 0) { + CAM_ERR(CAM_OIS, "Can not create device handle"); + return -EFAULT; + } o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle; o_ctrl->bridge_intf.session_hdl = ois_acq_dev.session_handle; diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 61d33c5cbaad..f042cf71d6d2 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -778,6 +778,11 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, sensor_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (sensor_acq_dev.device_handle <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_SENSOR, "Can not create device handle"); + goto release_mutex; + } s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle; s_ctrl->bridge_intf.session_hdl = sensor_acq_dev.session_handle; -- GitLab From 375e055dd6ee6b8d59a1bcfbfb328216a37c22fa Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Mon, 20 Dec 2021 15:01:30 +0530 Subject: [PATCH 283/295] msm: camera: cdm: handle deadlock scenario This change handles a race condition in which cdm workqueue is scheduled on one of the cores and cdm flush is executing on another core. We come across a dead lock between fifo_lock and hw_mutex lock. CRs-Fixed: 3106935 Change-Id: Ie0b8982a7e55218fc5655f8e3d08a952fd852ed7 Signed-off-by: Vikram Sharma Signed-off-by: Nirmal Abraham --- drivers/cam_cdm/cam_cdm_core_common.c | 7 +------ drivers/cam_cdm/cam_cdm_hw_core.c | 11 +++++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index fd84b8d6866b..c74f32b64db1 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2022, The Linux Foundation. All rights reserved. */ #include @@ -180,12 +180,10 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, (struct cam_cdm_bl_cb_request_entry *)data; client_idx = CAM_CDM_GET_CLIENT_IDX(node->client_hdl); - mutex_lock(&cdm_hw->hw_mutex); client = core->clients[client_idx]; if ((!client) || (client->handle != node->client_hdl)) { CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, node->client_hdl); - mutex_unlock(&cdm_hw->hw_mutex); return; } cam_cdm_get_client_refcount(client); @@ -204,7 +202,6 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, } mutex_unlock(&client->lock); cam_cdm_put_client_refcount(client); - mutex_unlock(&cdm_hw->hw_mutex); return; } else if (status == CAM_CDM_CB_STATUS_HW_RESET_DONE || status == CAM_CDM_CB_STATUS_HW_FLUSH || @@ -242,7 +239,6 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) { if (core->clients[i] != NULL) { - mutex_lock(&cdm_hw->hw_mutex); client = core->clients[i]; cam_cdm_get_client_refcount(client); mutex_lock(&client->lock); @@ -265,7 +261,6 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, } mutex_unlock(&client->lock); cam_cdm_put_client_refcount(client); - mutex_unlock(&cdm_hw->hw_mutex); } } } diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 22dbcf59251a..e49b5976f547 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2022, The Linux Foundation. All rights reserved. */ #include @@ -1236,8 +1236,8 @@ static void cam_hw_cdm_work(struct work_struct *work) return; } - mutex_lock(&core->bl_fifo[fifo_idx] - .fifo_lock); + mutex_lock(&cdm_hw->hw_mutex); + mutex_lock(&core->bl_fifo[fifo_idx].fifo_lock); if (atomic_read(&core->bl_fifo[fifo_idx].work_record)) atomic_dec( @@ -1251,6 +1251,7 @@ static void cam_hw_cdm_work(struct work_struct *work) core->arbitration); mutex_unlock(&core->bl_fifo[fifo_idx] .fifo_lock); + mutex_unlock(&cdm_hw->hw_mutex); return; } @@ -1292,6 +1293,7 @@ static void cam_hw_cdm_work(struct work_struct *work) } mutex_unlock(&core->bl_fifo[payload->fifo_idx] .fifo_lock); + mutex_unlock(&cdm_hw->hw_mutex); } if (payload->irq_status & @@ -1387,11 +1389,12 @@ static void cam_hw_cdm_iommu_fault_handler(struct iommu_domain *domain, 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); + CAM_ERR_RATE_LIMIT(CAM_CDM, "Page fault iova addr %pK", (void *)iova); cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_PAGEFAULT, (void *)iova); + mutex_unlock(&cdm_hw->hw_mutex); clear_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status); } else { CAM_ERR(CAM_CDM, "Invalid token"); -- GitLab From 2c5dafdb138578aec35cfadf1f2e82ae06d2bddb Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Thu, 1 Oct 2020 16:20:45 +0530 Subject: [PATCH 284/295] msm: camera: ope: Fix false hw hang detection While preparing config packet at HW layer, we are setting Ope request timer even before processing command buffer and IO cfg. This is leading to false hw hang detection. Expectation is Ope request timer has to start after req is submitted to HW. CRs-Fixed: 2788900 Change-Id: Idd1420b2ee1aed4bfe947cf5617bbec9b39147d3 Signed-off-by: Shravya Samala Signed-off-by: Nirmal Abraham --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 26 +++++++++------------ 1 file changed, 11 insertions(+), 15 deletions(-) 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 fd0eeecb6432..a1d5abec777c 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2022, The Linux Foundation. All rights reserved. */ #include @@ -3217,21 +3217,13 @@ 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); + 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; } @@ -3245,14 +3237,12 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, 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; } rc = cam_ope_mgr_process_cmd_desc(hw_mgr, packet, 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 ctx: %d req_id:%d", rc, ctx_data->ctx_id, packet->header.request_id); @@ -3262,7 +3252,6 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, rc = cam_ope_mgr_process_io_cfg(hw_mgr, packet, prepare_args, ctx_data, request_idx); if (rc) { - mutex_unlock(&ctx_data->ctx_mutex); CAM_ERR(CAM_OPE, "IO cfg processing failed: %d ctx: %d req_id:%d", rc, ctx_data->ctx_id, packet->header.request_id); @@ -3272,7 +3261,6 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, rc = cam_ope_mgr_create_kmd_buf(hw_mgr, packet, prepare_args, ctx_data, request_idx, ope_cmd_buf_addr); if (rc) { - mutex_unlock(&ctx_data->ctx_mutex); CAM_ERR(CAM_OPE, "create kmd buf failed: %d ctx: %d request_id:%d", rc, ctx_data->ctx_id, packet->header.request_id); @@ -3282,7 +3270,6 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, rc = cam_ope_process_generic_cmd_buffer(packet, ctx_data, request_idx, NULL); if (rc) { - mutex_unlock(&ctx_data->ctx_mutex); 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); @@ -3294,6 +3281,14 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, prepare_args->priv = ctx_data->req_list[request_idx]; prepare_args->pf_data->packet = packet; ope_req->hang_data.packet = packet; + 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); mutex_unlock(&ctx_data->ctx_mutex); CAM_DBG(CAM_REQ, "Prepare Hw update Successful request_id: %d ctx: %d", @@ -3308,6 +3303,7 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, ctx_data->req_list[request_idx] = NULL; req_mem_alloc_failed: clear_bit(request_idx, ctx_data->bitmap); + mutex_unlock(&ctx_data->ctx_mutex); return rc; } -- GitLab From 497a10ac9800767b409906e6cc254445d30685a4 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Fri, 19 Nov 2021 12:25:48 +0530 Subject: [PATCH 285/295] msm: camera: ope: Update request timeout for NRT/RT context Currently the ope request timeout value for RT and NRT context are same. In some usecases, NRT request processing takes more time. Hence, initialize the RT and NRT request timeout value separately. CRs-Fixed: 3082993 Change-Id: I17e86d26403fb21cdff518a81dee7a19c865144e Signed-off-by: Alok Chauhan --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 20 ++++++++++++-------- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 7 +++++-- 2 files changed, 17 insertions(+), 10 deletions(-) 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 a1d5abec777c..cdcc3910aa68 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 @@ -19,6 +19,7 @@ #include #include #include +#include #include "cam_sync_api.h" #include "cam_packet_util.h" @@ -621,8 +622,8 @@ static bool cam_ope_check_req_delay(struct cam_ope_ctx *ctx_data, ts.tv_nsec); if (ts_ns - req_time < - ((OPE_REQUEST_TIMEOUT - - OPE_REQUEST_TIMEOUT / 10) * 1000000)) { + ((ctx_data->req_timer_timeout - + div_u64(ctx_data->req_timer_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); @@ -845,7 +846,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, - OPE_REQUEST_TIMEOUT, ctx_data, &cam_ope_req_timer_cb); + ctx_data->req_timer_timeout, ctx_data, &cam_ope_req_timer_cb); if (rc) CAM_ERR(CAM_OPE, "Failed to start timer"); @@ -2615,11 +2616,15 @@ static int cam_ope_mgr_acquire_hw(void *hw_priv, void *hw_acquire_args) goto end; } strlcpy(cdm_acquire->identifier, "ope", sizeof("ope")); - if (ctx->ope_acquire.dev_type == OPE_DEV_TYPE_OPE_RT) + if (ctx->ope_acquire.dev_type == OPE_DEV_TYPE_OPE_RT) { cdm_acquire->priority = CAM_CDM_BL_FIFO_3; + ctx->req_timer_timeout = OPE_REQUEST_RT_TIMEOUT; + } else if (ctx->ope_acquire.dev_type == - OPE_DEV_TYPE_OPE_NRT) + OPE_DEV_TYPE_OPE_NRT) { cdm_acquire->priority = CAM_CDM_BL_FIFO_0; + ctx->req_timer_timeout = OPE_REQUEST_NRT_TIMEOUT; + } else goto free_cdm_acquire; @@ -3217,7 +3222,6 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, CAM_ERR(CAM_OPE, "Invalid ctx req slot = %d", request_idx); return -EINVAL; } - ctx_data->req_list[request_idx] = kzalloc(sizeof(struct cam_ope_request), GFP_KERNEL); if (!ctx_data->req_list[request_idx]) { @@ -3287,7 +3291,7 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, 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); + cam_ope_req_timer_modify(ctx_data, ctx_data->req_timer_timeout); set_bit(request_idx, ctx_data->bitmap); mutex_unlock(&ctx_data->ctx_mutex); @@ -3688,7 +3692,7 @@ static int cam_ope_mgr_hw_dump(void *hw_priv, void *hw_dump_args) cur_ts = ktime_to_timespec64(cur_time); req_ts = ktime_to_timespec64(ctx_data->req_list[idx]->submit_timestamp); - if (diff < (OPE_REQUEST_TIMEOUT * 1000)) { + if (diff < (ctx_data->req_timer_timeout * 1000)) { CAM_INFO(CAM_OPE, "No Error req %llu %ld:%06ld %ld:%06ld", dump_args->request_id, req_ts.tv_sec, 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 3bc09be0b88c..c37d638c8164 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 @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, 2022, The Linux Foundation. All rights reserved. */ #ifndef CAM_OPE_HW_MGR_H @@ -60,7 +60,8 @@ #define CLK_HW_MAX 0x1 #define OPE_DEVICE_IDLE_TIMEOUT 400 -#define OPE_REQUEST_TIMEOUT 200 +#define OPE_REQUEST_RT_TIMEOUT 200 +#define OPE_REQUEST_NRT_TIMEOUT 400 /** * struct cam_ope_clk_bw_request_v2 @@ -447,6 +448,7 @@ struct cam_ope_cdm { * @clk_watch_dog: Clock watchdog * @clk_watch_dog_reset_counter: Reset counter * @last_flush_req: last flush req for this ctx + * @req_timer_timeout: req timer timeout value */ struct cam_ope_ctx { void *context_priv; @@ -469,6 +471,7 @@ struct cam_ope_ctx { struct cam_req_mgr_timer *clk_watch_dog; uint32_t clk_watch_dog_reset_counter; uint64_t last_flush_req; + uint64_t req_timer_timeout; }; /** -- GitLab From c4a3b49efc4cf171ba095683fd5e4962754d978a Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Mon, 18 Oct 2021 13:15:15 +0530 Subject: [PATCH 286/295] msm: camera: ope: Increase max bl limit and max stripe to process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase “OPE_MAX_CDM_BLS” to 32 from 24 and MAX_STRIPES to 64 from 48 to process 108M frame. CRs-Fixed: 3082993 Change-Id: I9e3631cc86c5e10e4e2020d4a9b2264ea282e437 Signed-off-by: Vikram Sharma --- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 4 ++-- include/uapi/media/cam_ope.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 3bc09be0b88c..1d172cacc540 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 @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, 2022, The Linux Foundation. All rights reserved. */ #ifndef CAM_OPE_HW_MGR_H @@ -50,7 +50,7 @@ #define OPE_CMDS OPE_MAX_CMD_BUFS #define CAM_MAX_IN_RES 8 -#define OPE_MAX_CDM_BLS 24 +#define OPE_MAX_CDM_BLS 32 #define CAM_OPE_MAX_PER_PATH_VOTES 6 #define CAM_OPE_BW_CONFIG_UNKNOWN 0 diff --git a/include/uapi/media/cam_ope.h b/include/uapi/media/cam_ope.h index a7d800844103..313e049539e5 100644 --- a/include/uapi/media/cam_ope.h +++ b/include/uapi/media/cam_ope.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, 2022, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_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 48 +#define OPE_MAX_STRIPES 64 #define OPE_MAX_BATCH_SIZE 16 /** -- GitLab From 3cce45b5d02678dc050a1817732c90364f98aa39 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Thu, 27 Jan 2022 14:35:06 +0530 Subject: [PATCH 287/295] msm: camera: update copyright markings Update QUIC copyright for new code changes. CRs-Fixed: 3118778 Change-Id: I9e3631cc86c5e10e4e2020d4a9b2264ea282d437 Signed-off-by: Nirmal Abraham --- drivers/cam_cdm/cam_cdm_core_common.c | 3 ++- drivers/cam_cdm/cam_cdm_hw_core.c | 3 ++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 3 ++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 3 ++- include/uapi/media/cam_ope.h | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index c74f32b64db1..7d5f21af9f69 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index e49b5976f547..cf8d6e422eeb 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include 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 cdcc3910aa68..0e7e95fee975 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 @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include 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 b899075082db..244c2d727dbe 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 @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, 2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef CAM_OPE_HW_MGR_H diff --git a/include/uapi/media/cam_ope.h b/include/uapi/media/cam_ope.h index 313e049539e5..a2d9845430a2 100644 --- a/include/uapi/media/cam_ope.h +++ b/include/uapi/media/cam_ope.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2019-2020, 2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __UAPI_OPE_H__ -- GitLab From 5c1776ce70823a4a4363c021a0e928aca1f9654b Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Thu, 27 Jan 2022 14:35:06 +0530 Subject: [PATCH 288/295] msm: camera: update copyright markings Update QUIC copyright for new code changes. CRs-Fixed: 3118778 Change-Id: I9e3631cc86c5e10e4e2020d4a9b2264ea282d437 Signed-off-by: Nirmal Abraham --- drivers/cam_cdm/cam_cdm_core_common.c | 3 ++- drivers/cam_cdm/cam_cdm_hw_core.c | 3 ++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c | 3 ++- drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.h | 3 ++- include/uapi/media/cam_ope.h | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index c74f32b64db1..7d5f21af9f69 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index e49b5976f547..cf8d6e422eeb 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include 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 cdcc3910aa68..0e7e95fee975 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 @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include 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 b899075082db..244c2d727dbe 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 @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, 2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef CAM_OPE_HW_MGR_H diff --git a/include/uapi/media/cam_ope.h b/include/uapi/media/cam_ope.h index 313e049539e5..a2d9845430a2 100644 --- a/include/uapi/media/cam_ope.h +++ b/include/uapi/media/cam_ope.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2019-2020, 2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __UAPI_OPE_H__ -- GitLab From 66de6dd5e0707e740e87c22f096520d8c34c1a83 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Mon, 20 Dec 2021 14:44:36 +0530 Subject: [PATCH 289/295] msm: camera: reqmgr: check if link handle is correctly passed Instead of the link handle if the dev handle is passed for dumping the request information, this can lead to accessing invalid data structure. To avodi accessing invalid data structure based on the dev handle, first check if the link handle passed in IOCTL is matchting with looked up link handle. CRs-Fixed: 3097336 Change-Id: I815457ff96e3b26fe9fa886bd984d53d209e4edb Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_req_mgr_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 0001a0e5c6ec..1d01491e34a2 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3948,7 +3948,7 @@ int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req) link = (struct cam_req_mgr_core_link *) cam_get_device_priv(dump_req->link_hdl); - if (!link) { + if (!link || link->link_hdl != dump_req->link_hdl) { CAM_DBG(CAM_CRM, "link ptr NULL %x", dump_req->link_hdl); rc = -EINVAL; goto end; -- GitLab From e561ca2a21c48d2d452e114c5bf4867cd0599857 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 3 Mar 2022 16:01:22 +0530 Subject: [PATCH 290/295] msm: camera: memmgr: update correct length in bufq In a corner case race condition to free the original ion buf allocated and new ion buffer with same fd but different size after freeing the origianl ion buf might result into mismatches in the real ion buf size assigned in bufq. To avoid this update length in bufq with local variable. CRs-Fixed: 3142221 Change-Id: I8241544dba7609662d01f8d765e8d171b8288baa Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_mem_mgr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index 877618e6d631..85e4b1c097b1 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, 2022 The Linux Foundation. All rights reserved. */ #include @@ -680,7 +680,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) if (rc) { CAM_ERR(CAM_MEM, "Failed in map_hw_va, len=%llu, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", - cmd->len, cmd->flags, fd, region, + len, cmd->flags, fd, region, cmd->num_hdl, rc); goto map_hw_fail; } @@ -709,7 +709,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) tbl.bufq[idx].kmdvaddr = kvaddr; tbl.bufq[idx].vaddr = hw_vaddr; tbl.bufq[idx].dma_buf = dmabuf; - tbl.bufq[idx].len = cmd->len; + tbl.bufq[idx].len = len; tbl.bufq[idx].num_hdl = cmd->num_hdl; memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls, sizeof(int32_t) * cmd->num_hdl); -- GitLab From a04138c83221ddee4dad26bd8382f93f2e3e3f65 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Thu, 3 Feb 2022 12:09:19 +0530 Subject: [PATCH 291/295] msm: camera: reqmgr: Avoid freeing subdev twice The 'l_device' pointer in __cam_req_mgr_destroy_subdev is set to NULL after freeing but this is done on a local copy of the variable in stack. This results in double-free when this function is called again. To avoid this, pass 'l_device' pointer by reference and assign it to NULL after freeing. CRs-Fixed: 3120468 Change-Id: If2dde6f1c702bee26a3c8a68c2f45bafbf0f7cd6 Signed-off-by: Nirmal Abraham --- drivers/cam_req_mgr/cam_req_mgr_core.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 1d01491e34a2..0565a0e4e122 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1850,10 +1851,13 @@ static int __cam_req_mgr_create_subdevs( * */ static void __cam_req_mgr_destroy_subdev( - struct cam_req_mgr_connected_device *l_device) + struct cam_req_mgr_connected_device **l_device) { - kfree(l_device); - l_device = NULL; + CAM_DBG(CAM_CRM, "*l_device %pK", *l_device); + if (*(l_device) != NULL) { + kfree(*(l_device)); + *l_device = NULL; + } } /** @@ -3238,7 +3242,7 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) __cam_req_mgr_destroy_link_info(link); /* Free memory holding data of linked devs */ - __cam_req_mgr_destroy_subdev(link->l_dev); + __cam_req_mgr_destroy_subdev(&link->l_dev); /* Destroy the link handle */ rc = cam_destroy_device_hdl(link->link_hdl); @@ -3403,7 +3407,7 @@ int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) mutex_unlock(&g_crm_core_dev->crm_lock); return rc; setup_failed: - __cam_req_mgr_destroy_subdev(link->l_dev); + __cam_req_mgr_destroy_subdev(&link->l_dev); create_subdev_failed: cam_destroy_device_hdl(link->link_hdl); link_info->u.link_info_v1.link_hdl = -1; @@ -3513,7 +3517,7 @@ int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) mutex_unlock(&g_crm_core_dev->crm_lock); return rc; setup_failed: - __cam_req_mgr_destroy_subdev(link->l_dev); + __cam_req_mgr_destroy_subdev(&link->l_dev); create_subdev_failed: cam_destroy_device_hdl(link->link_hdl); link_info->u.link_info_v2.link_hdl = -1; -- GitLab From d4d1e1402e796e2b7cb062668dab2b7445efb21b Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Tue, 29 Mar 2022 15:13:17 +0530 Subject: [PATCH 292/295] msm: camera: memmgr: Update copyright fix CRs-Fixed: 3161837 Change-Id: Ibf7a6fc9f3ed7b75cad90d88444078621944fbad Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_mem_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index 85e4b1c097b1..7a3378988dd6 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, 2022 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include -- GitLab From d9fc57eaf89ab5c472ec479d1678c6ef104e57ad Mon Sep 17 00:00:00 2001 From: Sridhar Gujje Date: Fri, 25 Mar 2022 15:13:26 +0530 Subject: [PATCH 293/295] msm: camera: reqmgr: Validate the link handle Instead of correct link handle, if some other handle like dev handle is passed then it may access some other data space. To avoid such scenario, need to check whether link handle passed by ioctl is same as retrieved link handle. CRs-Fixed: 3120454 Change-Id: Idff2e3c25b60563788ffb426c7cabc367c3c97f8 Signed-off-by: Yash Upadhyay Signed-off-by: Sridhar Gujje --- drivers/cam_req_mgr/cam_req_mgr_core.c | 105 ++++++++++++++++++------- drivers/cam_req_mgr/cam_req_mgr_core.h | 2 + drivers/cam_utils/cam_debug_util.h | 4 + 3 files changed, 81 insertions(+), 30 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 0565a0e4e122..b0c762c4a280 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3273,8 +3273,12 @@ int cam_req_mgr_destroy_session( mutex_lock(&g_crm_core_dev->crm_lock); cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(ses_info->session_hdl); - if (!cam_session) { - CAM_ERR(CAM_CRM, "failed to get session priv"); + if (!cam_session || + (cam_session->session_hdl != ses_info->session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s ses_info->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), ses_info->session_hdl, + (!cam_session) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : + cam_session->session_hdl); rc = -ENOENT; goto end; @@ -3334,8 +3338,13 @@ int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(link_info->u.link_info_v1.session_hdl); - if (!cam_session) { - CAM_DBG(CAM_CRM, "NULL pointer"); + if (!cam_session || (cam_session->session_hdl != + link_info->u.link_info_v1.session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s lnk_info->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), + link_info->u.link_info_v1.session_hdl, + (!cam_session) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : + cam_session->session_hdl); mutex_unlock(&g_crm_core_dev->crm_lock); return -EINVAL; } @@ -3443,8 +3452,13 @@ int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(link_info->u.link_info_v2.session_hdl); - if (!cam_session) { - CAM_DBG(CAM_CRM, "NULL pointer"); + if (!cam_session || (cam_session->session_hdl != + link_info->u.link_info_v2.session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s lnk_info->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), + link_info->u.link_info_v2.session_hdl, + (!cam_session) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : + cam_session->session_hdl); mutex_unlock(&g_crm_core_dev->crm_lock); return -EINVAL; } @@ -3546,16 +3560,23 @@ int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(unlink_info->session_hdl); - if (!cam_session) { - CAM_ERR(CAM_CRM, "NULL pointer"); + if (!cam_session || (cam_session->session_hdl != + unlink_info->session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s unlink->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), + unlink_info->session_hdl, + (!cam_session) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : + cam_session->session_hdl); mutex_unlock(&g_crm_core_dev->crm_lock); return -EINVAL; } /* link hdl's priv data is core_link struct */ link = cam_get_device_priv(unlink_info->link_hdl); - if (!link) { - CAM_ERR(CAM_CRM, "NULL pointer"); + if (!link || (link->link_hdl != unlink_info->link_hdl)) { + CAM_ERR(CAM_CRM, "link:%s unlink->lnk_hdl:%x link->lnk_hdl:%x", + CAM_IS_NULL_TO_STR(link), unlink_info->link_hdl, + (!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; goto done; } @@ -3587,8 +3608,10 @@ int cam_req_mgr_schedule_request( mutex_lock(&g_crm_core_dev->crm_lock); link = (struct cam_req_mgr_core_link *) cam_get_device_priv(sched_req->link_hdl); - if (!link) { - CAM_DBG(CAM_CRM, "link ptr NULL %x", sched_req->link_hdl); + if (!link || (link->link_hdl != sched_req->link_hdl)) { + CAM_ERR(CAM_CRM, "link:%s sched->lnk_hdl:%x link->lnk_hdl:%x", + CAM_IS_NULL_TO_STR(link), sched_req->link_hdl, + (!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; goto end; } @@ -3699,8 +3722,12 @@ int cam_req_mgr_sync_config( /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(sync_info->session_hdl); - if (!cam_session) { - CAM_ERR(CAM_CRM, "NULL pointer"); + if (!cam_session || + (cam_session->session_hdl != sync_info->session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s sync_info->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), sync_info->session_hdl, + (!cam_session) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : cam_session->session_hdl); mutex_unlock(&g_crm_core_dev->crm_lock); return -EINVAL; } @@ -3712,15 +3739,21 @@ int cam_req_mgr_sync_config( /* only two links existing per session in dual cam use case*/ link1 = cam_get_device_priv(sync_info->link_hdls[0]); - if (!link1) { - CAM_ERR(CAM_CRM, "link1 NULL pointer"); + if (!link1 || (link1->link_hdl != sync_info->link_hdls[0])) { + CAM_ERR(CAM_CRM, "lnk:%s sync_info->lnk_hdl[0]:%x lnk1_hdl:%x", + CAM_IS_NULL_TO_STR(link1), sync_info->link_hdls[0], + (!link1) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : link1->link_hdl); rc = -EINVAL; goto done; } link2 = cam_get_device_priv(sync_info->link_hdls[1]); - if (!link2) { - CAM_ERR(CAM_CRM, "link2 NULL pointer"); + if (!link2 || (link2->link_hdl != sync_info->link_hdls[1])) { + CAM_ERR(CAM_CRM, "lnk:%s sync_info->lnk_hdl[1]:%x lnk2_hdl:%x", + CAM_IS_NULL_TO_STR(link2), sync_info->link_hdls[1], + (!link2) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : link2->link_hdl); rc = -EINVAL; goto done; } @@ -3790,8 +3823,11 @@ int cam_req_mgr_flush_requests( /* session hdl's priv data is cam session struct */ session = (struct cam_req_mgr_core_session *) cam_get_device_priv(flush_info->session_hdl); - if (!session) { - CAM_ERR(CAM_CRM, "Invalid session %x", flush_info->session_hdl); + if (!session || (session->session_hdl != flush_info->session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s flush->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(session), flush_info->session_hdl, + (!session) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : + session->session_hdl); rc = -EINVAL; goto end; } @@ -3803,8 +3839,10 @@ int cam_req_mgr_flush_requests( link = (struct cam_req_mgr_core_link *) cam_get_device_priv(flush_info->link_hdl); - if (!link) { - CAM_DBG(CAM_CRM, "link ptr NULL %x", flush_info->link_hdl); + if (!link || (link->link_hdl != flush_info->link_hdl)) { + CAM_ERR(CAM_CRM, "link:%s flush->link_hdl:%x link->link_hdl:%x", + CAM_IS_NULL_TO_STR(link), flush_info->link_hdl, + (!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; goto end; } @@ -3861,9 +3899,12 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) for (i = 0; i < control->num_links; i++) { link = (struct cam_req_mgr_core_link *) cam_get_device_priv(control->link_hdls[i]); - if (!link) { - CAM_ERR(CAM_CRM, "Link(%d) is NULL on session 0x%x", - i, control->session_hdl); + if (!link || (link->link_hdl != control->link_hdls[i])) { + CAM_ERR(CAM_CRM, + "link:%s control->lnk_hdl:%x link->lnk_hdl:%x", + CAM_IS_NULL_TO_STR(link), control->link_hdls[i], + (!link) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; break; } @@ -3938,9 +3979,11 @@ int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req) /* session hdl's priv data is cam session struct */ session = (struct cam_req_mgr_core_session *) cam_get_device_priv(dump_req->session_handle); - if (!session) { - CAM_ERR(CAM_CRM, "Invalid session %x", - dump_req->session_handle); + if (!session || (session->session_hdl != dump_req->session_handle)) { + CAM_ERR(CAM_CRM, "ses:%s dump_req->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(session), dump_req->session_handle, + (!session) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : session->session_hdl); rc = -EINVAL; goto end; } @@ -3952,8 +3995,10 @@ int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req) link = (struct cam_req_mgr_core_link *) cam_get_device_priv(dump_req->link_hdl); - if (!link || link->link_hdl != dump_req->link_hdl) { - CAM_DBG(CAM_CRM, "link ptr NULL %x", dump_req->link_hdl); + if (!link || (link->link_hdl != dump_req->link_hdl)) { + CAM_ERR(CAM_CRM, "link:%s dump_rq->lnk_hdl:%x link->lnk_hdl:%x", + CAM_IS_NULL_TO_STR(link), dump_req->link_hdl, + (!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; goto end; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index b7677ed36ca9..c638f4f796ec 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_REQ_MGR_CORE_H_ #define _CAM_REQ_MGR_CORE_H_ @@ -18,6 +19,7 @@ #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_DEFAULT_HDL_VAL 0 #define FORCE_DISABLE_RECOVERY 2 #define FORCE_ENABLE_RECOVERY 1 diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h index 03f8019cfea2..1b2000ac08be 100644 --- a/drivers/cam_utils/cam_debug_util.h +++ b/drivers/cam_utils/cam_debug_util.h @@ -1,11 +1,15 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_DEBUG_UTIL_H_ #define _CAM_DEBUG_UTIL_H_ +#define CAM_IS_NULL_TO_STR(ptr) ((ptr) ? "Non-NULL" : "NULL") + +/* Module IDs used for debug logging */ #define CAM_CDM (1 << 0) #define CAM_CORE (1 << 1) #define CAM_CPAS (1 << 2) -- GitLab From 04627d7bfce8ba5c3b1dfdd0b66544b99cd1ba7b Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Tue, 29 Mar 2022 15:13:17 +0530 Subject: [PATCH 294/295] msm: camera: memmgr: Update copyright fix CRs-Fixed: 3161837 Change-Id: Ibf7a6fc9f3ed7b75cad90d88444078621944fbad Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_mem_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index 85e4b1c097b1..7a3378988dd6 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, 2022 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include -- GitLab From c487910c6256409045cc17b8d16d83691488624f Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Tue, 29 Mar 2022 10:54:51 +0530 Subject: [PATCH 295/295] msm: camera: eeprom: Add OOB read check for eeprom memory map Add check to prevent OOB read of eeprom memory map. Change-Id: Ifeeeffdc2a50536edbde5b5d755a052ace86d596 CRs-Fixed: 3003049 Signed-off-by: Shravan Nevatia --- drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 7284b455e369..8ea093fa4ae2 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -992,7 +993,16 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, rc = -EINVAL; goto end; } + + if ((num_map + 1) >= + (MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE)) { + CAM_ERR(CAM_EEPROM, "OOB error"); + rc = -EINVAL; + goto end; + } /* Configure the following map slave address */ + map[num_map + 1].saddr = i2c_info->slave_addr; rc = cam_eeprom_update_slaveInfo(e_ctrl, cmd_buf); -- GitLab