diff --git a/config/waipiocamera.conf b/config/waipiocamera.conf new file mode 100644 index 0000000000..407c5956dd --- /dev/null +++ b/config/waipiocamera.conf @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2020, The Linux Foundation. All rights reserved. + +export CONFIG_SPECTRA_CAMERA=m + +export CONFIG_SPECTRA_ISP=y +export CONFIG_SPECTRA_SFE=y +export CONFIG_SPECTRA_SENSOR=y +export CONFIG_SPECTRA_ICP=y +export CONFIG_SPECTRA_JPEG=y diff --git a/config/waipiocameraconf.h b/config/waipiocameraconf.h new file mode 100644 index 0000000000..91cfae4d85 --- /dev/null +++ b/config/waipiocameraconf.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_SPECTRA_CAMERA 1 +#define CONFIG_SPECTRA_ISP 1 +#define CONFIG_SPECTRA_SFE 1 +#define CONFIG_SPECTRA_SENSOR 1 +#define CONFIG_SPECTRA_ICP 1 +#define CONFIG_SPECTRA_JPEG 1 diff --git a/drivers/Makefile b/drivers/Makefile index b4cd9bb273..7a7b0250f0 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -85,6 +85,13 @@ camera-$(CONFIG_SPECTRA_ISP) += \ cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.o \ cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.o \ cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.o \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.o \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.o \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.o \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.o \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus.o \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.o \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.o \ cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_dev.o \ cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_soc.o \ cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.o \ @@ -97,11 +104,6 @@ camera-$(CONFIG_SPECTRA_ISP) += \ cam_isp/cam_isp_dev.o \ cam_isp/cam_isp_context.o -camera-$(CONFIG_SPECTRA_SFE) += \ - cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.o \ - cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.o \ - cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.o - camera-$(CONFIG_SPECTRA_ICP) += \ cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.o \ cam_icp/icp_hw/ipe_hw/ipe_dev.o \ 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 637257baeb..e01bfeb20b 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 @@ -86,6 +86,9 @@ enum cam_isp_resource_type { CAM_ISP_RESOURCE_TPG, CAM_ISP_RESOURCE_TFE_IN, CAM_ISP_RESOURCE_TFE_OUT, + CAM_ISP_RESOURCE_SFE_IN, + CAM_ISP_RESOURCE_SFE_RD, + CAM_ISP_RESOURCE_SFE_OUT, CAM_ISP_RESOURCE_MAX, }; @@ -131,6 +134,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_TPG_CORE_CFG_CMD, CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE, CAM_ISP_HW_CMD_DISABLE_UBWC_COMP, + CAM_ISP_HW_CMD_SET_SFE_DEBUG_CFG, CAM_ISP_HW_CMD_MAX, }; @@ -245,6 +249,10 @@ struct cam_isp_hw_cmd_buf_update { * @ num_buf: Number of buffers in the image_buf array * @ frame_header: frame header iova * @ local_id: local id for the wm + * @ width: width of scratch buffer + * @ height: height of scratch buffer + * @ stride: stride of scratch buffer + * @ slice_height: slice height of scratch buffer * @ io_cfg: IO buffer config information sent from UMD * */ @@ -254,6 +262,10 @@ struct cam_isp_hw_get_wm_update { uint32_t num_buf; uint64_t frame_header; uint32_t local_id; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t slice_height; struct cam_buf_io_cfg *io_cfg; }; @@ -276,10 +288,11 @@ struct cam_isp_hw_get_res_for_mid { * * @Brief: Get cmd buffer update for different CMD types * - * @res: Resource node - * @cmd_type: Command type for which to get update - * @cdm_id : CDM id - * @cmd: Command buffer information + * @res: Resource node + * @cmd_type: Command type for which to get update + * @cdm_id: CDM id + * @cmd: Command buffer information + * @use_scratch_cfg: To indicate if it's scratch buffer config * */ struct cam_isp_hw_get_cmd_update { @@ -287,6 +300,7 @@ struct cam_isp_hw_get_cmd_update { enum cam_isp_hw_cmd_type cmd_type; enum cam_cdm_id cdm_id; struct cam_isp_hw_cmd_buf_update cmd; + bool use_scratch_cfg; union { void *data; struct cam_isp_hw_get_wm_update *wm_update; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h index 8fab99e212..55f76f30f3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h @@ -8,8 +8,9 @@ #include "cam_isp_hw.h" -#define CAM_SFE_HW_NUM_MAX 2 -#define SFE_CORE_BASE_IDX 0 +#define SFE_CORE_BASE_IDX 0 +#define SFE_RT_CDM_BASE_IDX 1 +#define CAM_SFE_HW_NUM_MAX 2 enum cam_isp_hw_sfe_in { CAM_ISP_HW_SFE_IN_PIX, @@ -32,6 +33,86 @@ enum cam_sfe_hw_irq_status { CAM_SFE_IRQ_STATUS_MAX, }; +enum cam_sfe_bw_control_action { + CAM_SFE_BW_CONTROL_EXCLUDE, + CAM_SFE_BW_CONTROL_INCLUDE, +}; + +enum cam_sfe_hw_irq_regs { + CAM_SFE_IRQ_TOP_REG_STATUS0, + CAM_SFE_IRQ_REGISTERS_MAX, +}; + +enum cam_sfe_bus_irq_regs { + CAM_SFE_IRQ_BUS_REG_STATUS0, + CAM_SFE_BUS_IRQ_REGISTERS_MAX, +}; + +/* + * struct cam_sfe_fe_update_args: + * + * @node_res: Resource to get fetch configuration + * @fe_config: fetch engine configuration + * + */ +struct cam_sfe_fe_update_args { + struct cam_isp_resource_node *node_res; + struct cam_fe_config fe_config; +}; + +/* + * struct cam_sfe_clock_update_args: + * + * @node_res: ISP Resource + * @clk_rate: Clock rate requested + */ +struct cam_sfe_clock_update_args { + struct cam_isp_resource_node *node_res; + uint64_t clk_rate; +}; + +/* + * struct cam_sfe_core_config_args: + * + * @node_res: ISP Resource + * @core_config: Core config for SFE + */ +struct cam_sfe_core_config_args { + struct cam_isp_resource_node *node_res; + struct cam_isp_sfe_core_config core_config; +}; + +/* + * struct cam_sfe_irq_evt_payload: + * + * @Brief: This structure is used to save payload for IRQ + * related to SFE resources + * + * @list: list_head node for the payload + * @core_index: Index of SFE HW that generated this IRQ event + * @evt_id: IRQ event + * @irq_reg_val: IRQ and Error register values, read when IRQ was + * handled + * @bus_irq_val Bus irq register status + * @ccif_violation_status ccif violation status + * @overflow_status bus overflow status + * @image_size_vio_sts image size violations status + * @error_type: Identify different errors + * @ts: Timestamp + */ +struct cam_sfe_irq_evt_payload { + struct list_head list; + uint32_t core_index; + uint32_t evt_id; + uint32_t irq_reg_val[CAM_SFE_IRQ_REGISTERS_MAX]; + uint32_t bus_irq_val[CAM_SFE_BUS_IRQ_REGISTERS_MAX]; + uint32_t ccif_violation_status; + uint32_t overflow_status; + uint32_t image_size_vio_sts; + uint32_t error_type; + struct cam_isp_timestamp ts; +}; + /* * struct cam_sfe_hw_get_hw_cap: * @@ -54,18 +135,18 @@ struct cam_sfe_hw_get_hw_cap { * is successful * @res_id: Unique Identity of port to associate with this * resource. - * @is_dual: Flag to indicate dual SFE usecase * @cdm_ops: CDM operations * @unpacket_fmt: Unpacker format for read engine * @is_offline: Flag to indicate offline usecase + * @secure_mode: If fetch is from secure/non-secure buffer */ struct cam_sfe_hw_sfe_bus_rd_acquire_args { struct cam_isp_resource_node *rsrc_node; uint32_t res_id; - uint32_t is_dual; struct cam_cdm_utils_ops *cdm_ops; uint32_t unpacker_fmt; bool is_offline; + bool secure_mode; }; /* @@ -77,9 +158,7 @@ struct cam_sfe_hw_sfe_bus_rd_acquire_args { * resource. * @cdm_ops: CDM operations * @is_dual: Dual mode usecase - * @sync_mode: If in dual mode, indicates master/slave * @in_port: in port info - * @is_fe_enabled: Flag to indicate if FE is enabled * @is_offline: Flag to indicate Offline IFE */ struct cam_sfe_hw_sfe_in_acquire_args { @@ -87,9 +166,7 @@ struct cam_sfe_hw_sfe_in_acquire_args { uint32_t res_id; struct cam_cdm_utils_ops *cdm_ops; uint32_t is_dual; - enum cam_isp_hw_sync_mode sync_mode; struct cam_isp_in_port_generic_info *in_port; - bool is_fe_enabled; bool is_offline; }; @@ -126,6 +203,7 @@ struct cam_sfe_hw_sfe_out_acquire_args { * with this resource. * @priv: Context data * @event_cb: Callback function to hw mgr in case of hw events + * @buf_done_controller: Buf done controller * @sfe_out: Acquire args for SFE_OUT * @sfe_bus_rd Acquire args for SFE_BUS_READ * @sfe_in: Acquire args for SFE_IN @@ -135,6 +213,7 @@ struct cam_sfe_acquire_args { void *tasklet; void *priv; cam_hw_mgr_event_cb_func event_cb; + void *buf_done_controller; union { struct cam_sfe_hw_sfe_out_acquire_args sfe_out; struct cam_sfe_hw_sfe_in_acquire_args sfe_in; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h new file mode 100644 index 0000000000..2da1d3f35d --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h @@ -0,0 +1,695 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SFE680_H_ +#define _CAM_SFE680_H_ +#include "cam_sfe_core.h" +#include "cam_sfe_bus.h" +#include "cam_sfe_bus_rd.h" +#include "cam_sfe_bus_wr.h" + +static struct cam_sfe_top_common_reg_offset sfe680_top_commong_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .stats_feature = 0x00000008, + .core_cgc_ctrl = 0x00000010, + .ahb_clk_ovd = 0x00000014, + .core_cfg = 0x00000018, + .violation_status = 0x00000030, + .diag_config = 0x00000034, + .diag_sensor_status_0 = 0x00000038, + .diag_sensor_status_1 = 0x0000003C, + .diag_sensor_frame_cnt_status0 = 0x00000040, + .diag_sensor_frame_cnt_status1 = 0x00000044, + .top_debug_0 = 0x0000004C, + .top_debug_1 = 0x00000050, + .top_debug_2 = 0x00000054, + .top_debug_3 = 0x00000058, + .top_debug_4 = 0x0000005C, + .top_debug_5 = 0x00000060, + .top_debug_6 = 0x00000064, + .top_debug_7 = 0x00000068, + .top_debug_8 = 0x0000006C, + .top_debug_9 = 0x00000070, + .top_debug_10 = 0x00000074, + .top_debug_11 = 0x00000078, + .top_debug_cfg = 0x0000007C, + .stats_ch2_throttle_cfg = 0x000000B0, + .stats_ch1_throttle_cfg = 0x000000B4, + .stats_ch0_throttle_cfg = 0x000000B8, + .lcr_throttle_cfg = 0x000000BC, + .hdr_throttle_cfg = 0x000000C0, + .sfe_op_throttle_cfg = 0x000000C4, +}; + +static struct cam_sfe_modules_common_reg_offset sfe680_modules_common_reg = { + .demux_module_cfg = 0x00003060, + .demux_qcfa_cfg = 0x00003064, + .demux_hdr_cfg = 0x00003074, + .demux_lcr_sel = 0x00003078, + .hdrc_remo_mod_cfg = 0x00005860, + .hdrc_remo_qcfa_bin_cfg = 0x00005A78, + .qcfa_hdrc_remo_out_mux_cfg = 0x00005A74, +}; + +static struct cam_sfe_path_common_reg_data sfe_680_pix_reg_data = { + .sof_irq_mask = 0x4, + .eof_irq_mask = 0x8, + .error_irq_mask = 0x1C000, + .subscribe_irq_mask = 0xC, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x3, +}; + +static struct cam_sfe_path_common_reg_data sfe_680_rdi0_reg_data = { + .sof_irq_mask = 0x10, + .eof_irq_mask = 0x20, + .error_irq_mask = 0x1C000, + .subscribe_irq_mask = 0x30, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x3, +}; + +static struct cam_sfe_path_common_reg_data sfe_680_rdi1_reg_data = { + .sof_irq_mask = 0x40, + .eof_irq_mask = 0x80, + .error_irq_mask = 0x1C000, + .subscribe_irq_mask = 0xC0, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x3, +}; + +static struct cam_sfe_path_common_reg_data sfe_680_rdi2_reg_data = { + .sof_irq_mask = 0x100, + .eof_irq_mask = 0x200, + .error_irq_mask = 0x1C000, + .subscribe_irq_mask = 0x300, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x3, +}; + +static struct cam_sfe_path_common_reg_data sfe_680_rdi3_reg_data = { + .sof_irq_mask = 0x400, + .eof_irq_mask = 0x800, + .error_irq_mask = 0x1C000, + .subscribe_irq_mask = 0xC00, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x3, +}; + +static struct cam_sfe_path_common_reg_data sfe_680_rdi4_reg_data = { + .sof_irq_mask = 0x1000, + .eof_irq_mask = 0x2000, + .error_irq_mask = 0x1C000, + .subscribe_irq_mask = 0x3000, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x3, +}; + +static struct cam_sfe_top_hw_info sfe680_top_hw_info = { + .common_reg = &sfe680_top_commong_reg, + .modules_hw_info = &sfe680_modules_common_reg, + .pix_reg_data = &sfe_680_pix_reg_data, + .rdi_reg_data[0] = &sfe_680_rdi0_reg_data, + .rdi_reg_data[1] = &sfe_680_rdi1_reg_data, + .rdi_reg_data[2] = &sfe_680_rdi2_reg_data, + .rdi_reg_data[3] = &sfe_680_rdi3_reg_data, + .rdi_reg_data[4] = &sfe_680_rdi4_reg_data, + .num_inputs = 6, + .input_type = { + CAM_SFE_PIX_VER_1_0, + CAM_SFE_RDI_VER_1_0, + CAM_SFE_RDI_VER_1_0, + CAM_SFE_RDI_VER_1_0, + CAM_SFE_RDI_VER_1_0, + CAM_SFE_RDI_VER_1_0, + }, +}; + +static struct cam_sfe_bus_rd_hw_info sfe680_bus_rd_hw_info = { + .common_reg = { + .hw_version = 0x00000400, + .misr_reset = 0x0000041C, + .pwr_iso_cfg = 0x00000424, + .input_if_cmd = 0x00000414, + .test_bus_ctrl = 0x0000042C, + .security_cfg = 0x00000420, + }, + .num_client = 3, + .bus_client_reg = { + /* BUS Client 0 */ + { + .cfg = 0x00000450, + .image_addr = 0x00000458, + .buf_width = 0x0000045C, + .buf_height = 0x00000460, + .stride = 0x00000464, + .unpacker_cfg = 0x00000468, + .latency_buf_allocation = 0x0000047C, + }, + /* BUS Client 1 */ + { + .cfg = 0x000004F0, + .image_addr = 0x000004F8, + .buf_width = 0x000004FC, + .buf_height = 0x00000500, + .stride = 0x00000504, + .unpacker_cfg = 0x00000508, + .latency_buf_allocation = 0x0000051C, + }, + /* BUS Client 2 */ + { + .cfg = 0x00000590, + .image_addr = 0x00000598, + .buf_width = 0x0000059C, + .buf_height = 0x000005A0, + .stride = 0x000005A4, + .unpacker_cfg = 0x000005A8, + .latency_buf_allocation = 0x000005BC, + }, + }, + .num_bus_rd_resc = 3, + .sfe_bus_rd_info = { + { + .sfe_bus_rd_type = CAM_SFE_BUS_RD_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .sfe_bus_rd_type = CAM_SFE_BUS_RD_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .sfe_bus_rd_type = CAM_SFE_BUS_RD_RDI2, + .max_width = -1, + .max_height = -1, + }, + }, + .top_irq_shift = 0x1, +}; + +static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = { + .common_reg = { + .hw_version = 0x00000800, + .cgc_ovd = 0x00000808, + .if_frameheader_cfg = { + 0x00000834, + 0x00000838, + 0x0000083C, + 0x00000840, + 0x00000844, + 0x00000848, + }, + .pwr_iso_cfg = 0x0000085C, + .overflow_status_clear = 0x00000860, + .ccif_violation_status = 0x00000864, + .overflow_status = 0x00000868, + .image_size_violation_status = 0x00000870, + .debug_status_top_cfg = 0x000008D4, + .debug_status_top = 0x000008D8, + .test_bus_ctrl = 0x000008DC, + .top_irq_mask_0 = 0x00000818, + }, + .num_client = 13, + .bus_client_reg = { + /* BUS Client 0 REMOSAIC */ + { + .cfg = 0x00000A00, + .image_addr = 0x00000A04, + .frame_incr = 0x00000A08, + .image_cfg_0 = 0x00000A0C, + .image_cfg_1 = 0x00000A10, + .image_cfg_2 = 0x00000A14, + .packer_cfg = 0x00000A18, + .frame_header_addr = 0x00000A20, + .frame_header_incr = 0x00000A24, + .frame_header_cfg = 0x00000A28, + .line_done_cfg = 0, + .irq_subsample_period = 0x00000A30, + .irq_subsample_pattern = 0x00000A34, + .framedrop_period = 0x00000A38, + .framedrop_pattern = 0x00000A3C, + .system_cache_cfg = 0x00000A68, + .addr_status_0 = 0x00000A70, + .addr_status_1 = 0x00000A74, + .addr_status_2 = 0x00000A78, + .addr_status_3 = 0x00000A7C, + .debug_status_cfg = 0x00000A80, + .debug_status_0 = 0x00000A84, + .debug_status_1 = 0x00000A88, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_0, + }, + /* BUS Client 1 LCR */ + { + .cfg = 0x00000B00, + .image_addr = 0x00000B04, + .frame_incr = 0x00000B08, + .image_cfg_0 = 0x00000B0C, + .image_cfg_1 = 0x00000B10, + .image_cfg_2 = 0x00000B14, + .packer_cfg = 0x00000B18, + .frame_header_addr = 0x00000B20, + .frame_header_incr = 0x00000B24, + .frame_header_cfg = 0x00000B28, + .line_done_cfg = 0, + .irq_subsample_period = 0x00000B30, + .irq_subsample_pattern = 0x00000B34, + .framedrop_period = 0x00000B38, + .framedrop_pattern = 0x00000B3C, + .system_cache_cfg = 0x00000B68, + .addr_status_0 = 0x00000B70, + .addr_status_1 = 0x00000B74, + .addr_status_2 = 0x00000B78, + .addr_status_3 = 0x00000B7C, + .debug_status_cfg = 0x00000B80, + .debug_status_0 = 0x00000B84, + .debug_status_1 = 0x00000B88, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_1, + }, + /* BUS Client 2 STATS_BE_0 */ + { + .cfg = 0x00000C00, + .image_addr = 0x00000C04, + .frame_incr = 0x00000C08, + .image_cfg_0 = 0x00000C0C, + .image_cfg_1 = 0x00000C10, + .image_cfg_2 = 0x00000C14, + .packer_cfg = 0x00000C18, + .frame_header_addr = 0x00000C20, + .frame_header_incr = 0x00000C24, + .frame_header_cfg = 0x00000C28, + .line_done_cfg = 0, + .irq_subsample_period = 0x00000C30, + .irq_subsample_pattern = 0x00000C34, + .framedrop_period = 0x00000C38, + .framedrop_pattern = 0x00000C3C, + .system_cache_cfg = 0x00000C68, + .addr_status_0 = 0x00000C70, + .addr_status_1 = 0x00000C74, + .addr_status_2 = 0x00000C78, + .addr_status_3 = 0x00000C7C, + .debug_status_cfg = 0x00000C80, + .debug_status_0 = 0x00000C84, + .debug_status_1 = 0x00000C88, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_2, + }, + /* BUS Client 3 STATS_BHIST_0 */ + { + .cfg = 0x00000D00, + .image_addr = 0x00000D04, + .frame_incr = 0x00000D08, + .image_cfg_0 = 0x00000D0C, + .image_cfg_1 = 0x00000D10, + .image_cfg_2 = 0x00000D14, + .packer_cfg = 0x00000D18, + .frame_header_addr = 0x00000D20, + .frame_header_incr = 0x00000D24, + .frame_header_cfg = 0x00000D28, + .line_done_cfg = 0, + .irq_subsample_period = 0x00000D30, + .irq_subsample_pattern = 0x00000D34, + .framedrop_period = 0x00000D38, + .framedrop_pattern = 0x00000D3C, + .system_cache_cfg = 0x00000D68, + .addr_status_0 = 0x00000D70, + .addr_status_1 = 0x00000D74, + .addr_status_2 = 0x00000D78, + .addr_status_3 = 0x00000D7C, + .debug_status_cfg = 0x00000D80, + .debug_status_0 = 0x00000D84, + .debug_status_1 = 0x00000D88, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_2, + }, + /* BUS Client 4 STATS_BE_1 */ + { + .cfg = 0x00000E00, + .image_addr = 0x00000E04, + .frame_incr = 0x00000E08, + .image_cfg_0 = 0x00000E0C, + .image_cfg_1 = 0x00000E10, + .image_cfg_2 = 0x00000E14, + .packer_cfg = 0x00000E18, + .frame_header_addr = 0x00000E20, + .frame_header_incr = 0x00000E24, + .frame_header_cfg = 0x00000E28, + .line_done_cfg = 0, + .irq_subsample_period = 0x00000E30, + .irq_subsample_pattern = 0x00000E34, + .framedrop_period = 0x00000E38, + .framedrop_pattern = 0x00000E3C, + .system_cache_cfg = 0x00000E68, + .addr_status_0 = 0x00000E70, + .addr_status_1 = 0x00000E74, + .addr_status_2 = 0x00000E78, + .addr_status_3 = 0x00000E7C, + .debug_status_cfg = 0x00000E80, + .debug_status_0 = 0x00000E84, + .debug_status_1 = 0x00000E88, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_3, + }, + /* BUS Client 5 STATS_BHIST_1 */ + { + .cfg = 0x00000F00, + .image_addr = 0x00000F04, + .frame_incr = 0x00000F08, + .image_cfg_0 = 0x00000F0C, + .image_cfg_1 = 0x00000F10, + .image_cfg_2 = 0x00000F14, + .packer_cfg = 0x00000F18, + .frame_header_addr = 0x00000F20, + .frame_header_incr = 0x00000F24, + .frame_header_cfg = 0x00000F28, + .line_done_cfg = 0, + .irq_subsample_period = 0x00000F30, + .irq_subsample_pattern = 0x00000F34, + .framedrop_period = 0x00000F38, + .framedrop_pattern = 0x00000F3C, + .system_cache_cfg = 0x00000F68, + .addr_status_0 = 0x00000F70, + .addr_status_1 = 0x00000F74, + .addr_status_2 = 0x00000F78, + .addr_status_3 = 0x00000F7C, + .debug_status_cfg = 0x00000F80, + .debug_status_0 = 0x00000F84, + .debug_status_1 = 0x00000F88, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_3, + }, + /* BUS Client 6 STATS_BE_2 */ + { + .cfg = 0x00001000, + .image_addr = 0x00001004, + .frame_incr = 0x00001008, + .image_cfg_0 = 0x0000100C, + .image_cfg_1 = 0x00001010, + .image_cfg_2 = 0x00001014, + .packer_cfg = 0x00001018, + .frame_header_addr = 0x00001020, + .frame_header_incr = 0x00001024, + .frame_header_cfg = 0x00001028, + .line_done_cfg = 0, + .irq_subsample_period = 0x00001030, + .irq_subsample_pattern = 0x00001034, + .framedrop_period = 0x00001038, + .framedrop_pattern = 0x0000103C, + .system_cache_cfg = 0x00001068, + .addr_status_0 = 0x00001070, + .addr_status_1 = 0x00001074, + .addr_status_2 = 0x00001078, + .addr_status_3 = 0x0000107C, + .debug_status_cfg = 0x00001080, + .debug_status_0 = 0x00001084, + .debug_status_1 = 0x00001088, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_4, + }, + /* BUS Client 7 STATS_BHIST_2 */ + { + .cfg = 0x00001100, + .image_addr = 0x00001104, + .frame_incr = 0x00001108, + .image_cfg_0 = 0x0000110C, + .image_cfg_1 = 0x00001110, + .image_cfg_2 = 0x00001114, + .packer_cfg = 0x00001118, + .frame_header_addr = 0x00001120, + .frame_header_incr = 0x00001124, + .frame_header_cfg = 0x00001128, + .line_done_cfg = 0, + .irq_subsample_period = 0x00001130, + .irq_subsample_pattern = 0x00001134, + .framedrop_period = 0x00001138, + .framedrop_pattern = 0x0000113C, + .system_cache_cfg = 0x00001168, + .addr_status_0 = 0x00001170, + .addr_status_1 = 0x00001174, + .addr_status_2 = 0x00001178, + .addr_status_3 = 0x0000117C, + .debug_status_cfg = 0x00001180, + .debug_status_0 = 0x00001184, + .debug_status_1 = 0x00001188, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_4, + }, + /* BUS Client 8 RDI0 */ + { + .cfg = 0x00001200, + .image_addr = 0x00001204, + .frame_incr = 0x00001208, + .image_cfg_0 = 0x0000120C, + .image_cfg_1 = 0x00001210, + .image_cfg_2 = 0x00001214, + .packer_cfg = 0x00001218, + .frame_header_addr = 0x00001220, + .frame_header_incr = 0x00001224, + .frame_header_cfg = 0x00001228, + .line_done_cfg = 0x0000122C, + .irq_subsample_period = 0x00001230, + .irq_subsample_pattern = 0x00001234, + .framedrop_period = 0x00001238, + .framedrop_pattern = 0x0000123C, + .system_cache_cfg = 0x00001268, + .addr_status_0 = 0x00001270, + .addr_status_1 = 0x00001274, + .addr_status_2 = 0x00001278, + .addr_status_3 = 0x0000127C, + .debug_status_cfg = 0x00001280, + .debug_status_0 = 0x00001284, + .debug_status_1 = 0x00001288, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_5, + }, + /* BUS Client 9 RDI1 */ + { + .cfg = 0x00001300, + .image_addr = 0x00001304, + .frame_incr = 0x00001308, + .image_cfg_0 = 0x0000130C, + .image_cfg_1 = 0x00001310, + .image_cfg_2 = 0x00001314, + .packer_cfg = 0x00001318, + .frame_header_addr = 0x00001320, + .frame_header_incr = 0x00001324, + .frame_header_cfg = 0x00001328, + .line_done_cfg = 0x0000132C, + .irq_subsample_period = 0x00001330, + .irq_subsample_pattern = 0x00001334, + .framedrop_period = 0x00001338, + .framedrop_pattern = 0x0000133C, + .system_cache_cfg = 0x00001368, + .addr_status_0 = 0x00001370, + .addr_status_1 = 0x00001374, + .addr_status_2 = 0x00001378, + .addr_status_3 = 0x0000137C, + .debug_status_cfg = 0x00001380, + .debug_status_0 = 0x00001384, + .debug_status_1 = 0x00001388, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_6, + }, + /* BUS Client 10 RDI2 */ + { + .cfg = 0x00001400, + .image_addr = 0x00001404, + .frame_incr = 0x00001408, + .image_cfg_0 = 0x0000140C, + .image_cfg_1 = 0x00001410, + .image_cfg_2 = 0x00001414, + .packer_cfg = 0x00001418, + .frame_header_addr = 0x00001420, + .frame_header_incr = 0x00001424, + .frame_header_cfg = 0x00001428, + .line_done_cfg = 0x0000142C, + .irq_subsample_period = 0x00001430, + .irq_subsample_pattern = 0x00001434, + .framedrop_period = 0x00001438, + .framedrop_pattern = 0x0000143C, + .system_cache_cfg = 0x00001468, + .addr_status_0 = 0x00001470, + .addr_status_1 = 0x00001474, + .addr_status_2 = 0x00001478, + .addr_status_3 = 0x0000147C, + .debug_status_cfg = 0x00001480, + .debug_status_0 = 0x00001484, + .debug_status_1 = 0x00001488, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_7, + }, + /* BUS Client 11 RDI3 */ + { + .cfg = 0x00001500, + .image_addr = 0x00001504, + .frame_incr = 0x00001508, + .image_cfg_0 = 0x0000150C, + .image_cfg_1 = 0x00001510, + .image_cfg_2 = 0x00001514, + .packer_cfg = 0x00001518, + .frame_header_addr = 0x00001520, + .frame_header_incr = 0x00001524, + .frame_header_cfg = 0x00001528, + .line_done_cfg = 0x0000152C, + .irq_subsample_period = 0x00001530, + .irq_subsample_pattern = 0x00001534, + .framedrop_period = 0x00001538, + .framedrop_pattern = 0x0000153C, + .system_cache_cfg = 0x00001568, + .addr_status_0 = 0x00001570, + .addr_status_1 = 0x00001574, + .addr_status_2 = 0x00001578, + .addr_status_3 = 0x0000157C, + .debug_status_cfg = 0x00001580, + .debug_status_0 = 0x00001584, + .debug_status_1 = 0x00001588, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_8, + }, + /* BUS Client 12 RDI4 */ + { + .cfg = 0x00001600, + .image_addr = 0x00001604, + .frame_incr = 0x00001608, + .image_cfg_0 = 0x0000160C, + .image_cfg_1 = 0x00001610, + .image_cfg_2 = 0x00001614, + .packer_cfg = 0x00001618, + .frame_header_addr = 0x00001620, + .frame_header_incr = 0x00001624, + .frame_header_cfg = 0x00001628, + .line_done_cfg = 0x0000162C, + .irq_subsample_period = 0x00001630, + .irq_subsample_pattern = 0x00001634, + .framedrop_period = 0x00001638, + .framedrop_pattern = 0x0000163C, + .system_cache_cfg = 0x00001668, + .addr_status_0 = 0x00001670, + .addr_status_1 = 0x00001674, + .addr_status_2 = 0x00001678, + .addr_status_3 = 0x0000167C, + .debug_status_cfg = 0x00001680, + .debug_status_0 = 0x00001684, + .debug_status_1 = 0x00001688, + .comp_group = CAM_SFE_BUS_WR_COMP_GRP_9, + }, + }, + .num_out = 13, + .sfe_out_hw_info = { + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_1, + .num_wm = 1, + .wm_idx = 8, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_2, + .num_wm = 1, + .wm_idx = 9, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_3, + .num_wm = 1, + .wm_idx = 10, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_RDI3, + .max_width = -1, + .max_height = -1, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_4, + .num_wm = 1, + .wm_idx = 11, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_RDI4, + .max_width = -1, + .max_height = -1, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_4, + .num_wm = 1, + .wm_idx = 12, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_RAW_DUMP, + .max_width = 9312, + .max_height = 6992, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_0, + .num_wm = 1, + .wm_idx = 0, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_LCR, + .max_width = 9312, + .max_height = 2048, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_0, + .num_wm = 1, + .wm_idx = 1, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_BE_0, + .max_width = 7296, + .max_height = 5472, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_0, + .num_wm = 1, + .wm_idx = 2, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_BHIST_0, + .max_width = 7296, + .max_height = 5472, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_0, + .num_wm = 1, + .wm_idx = 3, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_BE_1, + .max_width = 7296, + .max_height = 5472, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_0, + .num_wm = 1, + .wm_idx = 4, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_BHIST_1, + .max_width = 7296, + .max_height = 5472, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_0, + .num_wm = 1, + .wm_idx = 5, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_BE_2, + .max_width = 7296, + .max_height = 5472, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_0, + .num_wm = 1, + .wm_idx = 6, + }, + { + .sfe_out_type = CAM_SFE_BUS_SFE_OUT_BHIST_2, + .max_width = 7296, + .max_height = 5472, + .source_group = CAM_SFE_BUS_WR_SRC_GRP_0, + .num_wm = 1, + .wm_idx = 7, + }, + }, + .num_comp_grp = 10, + .comp_done_shift = 17, + .top_irq_shift = 0x0, +}; + +struct cam_sfe_hw_info cam_sfe680_hw_info = { + .irq_reg_info = NULL, + + .bus_wr_version = CAM_SFE_BUS_WR_VER_1_0, + .bus_wr_hw_info = &sfe680_bus_wr_hw_info, + + .bus_rd_version = CAM_SFE_BUS_RD_VER_1_0, + .bus_rd_hw_info = &sfe680_bus_rd_hw_info, + + .top_version = CAM_SFE_TOP_VER_1_0, + .top_hw_info = &sfe680_top_hw_info, +}; + +#endif /* _CAM_SFE680_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c index 73e29bee3c..ca0220c10d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c @@ -12,12 +12,29 @@ #include "cam_debug_util.h" static const char drv_name[] = "sfe"; -#define SFE_CORE_BASE_IDX 0 -int cam_sfe_get_hw_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size) +int cam_sfe_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size) { - CAM_DBG(CAM_SFE, "Enter"); - return 0; + return -EPERM; +} + +int cam_sfe_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_sfe_read(void *device_priv, + void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_sfe_write(void *device_priv, + void *write_args, uint32_t arg_size) +{ + return -EPERM; } int cam_sfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) @@ -25,10 +42,8 @@ int cam_sfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) struct cam_hw_info *sfe_hw = hw_priv; struct cam_hw_soc_info *soc_info = NULL; struct cam_sfe_hw_core_info *core_info = NULL; - struct cam_isp_resource_node *isp_res = NULL; int rc = 0; - CAM_DBG(CAM_SFE, "Enter"); if (!hw_priv) { CAM_ERR(CAM_SFE, "Invalid arguments"); return -EINVAL; @@ -38,7 +53,7 @@ int cam_sfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) sfe_hw->open_count++; if (sfe_hw->open_count > 1) { mutex_unlock(&sfe_hw->hw_mutex); - CAM_DBG(CAM_SFE, "SFE has already been initialized cnt %d", + CAM_DBG(CAM_SFE, "SFE has already been initialized cnt: %d", sfe_hw->open_count); return 0; } @@ -55,30 +70,34 @@ int cam_sfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) goto decrement_open_cnt; } - isp_res = (struct cam_isp_resource_node *)init_hw_args; - if (isp_res && isp_res->init) { - rc = isp_res->init(isp_res, NULL, 0); - if (rc) { - CAM_ERR(CAM_SFE, "init Failed rc=%d", rc); - goto disable_soc; - } + CAM_DBG(CAM_SFE, "SFE SOC resource enabled"); + + /* Async Reset as part of power ON */ + /* Sync Reset in CSID */ + + /* INIT SFE BUS WR */ + rc = core_info->sfe_bus_wr->hw_ops.init( + core_info->sfe_bus_wr->bus_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_SFE, + "SFE bus wr init failed rc: %d", rc); + goto disable_soc; } - CAM_DBG(CAM_SFE, "Enable soc done"); - - /* Do HW Reset */ - rc = cam_sfe_reset(hw_priv, NULL, 0); + /* INIT SFE BUS RD */ + rc = core_info->sfe_bus_rd->hw_ops.init( + core_info->sfe_bus_rd->bus_priv, NULL, 0); if (rc) { - CAM_ERR(CAM_SFE, "Reset Failed rc=%d", rc); - goto deinit_sfe_res; + CAM_ERR(CAM_SFE, "SFE bus rd init failed rc: %d", rc); + goto deinit_bus_wr; } sfe_hw->hw_state = CAM_HW_STATE_POWER_UP; return rc; -deinit_sfe_res: - if (isp_res && isp_res->deinit) - isp_res->deinit(isp_res, NULL, 0); +deinit_bus_wr: + core_info->sfe_bus_wr->hw_ops.deinit( + core_info->sfe_bus_wr->bus_priv, NULL, 0); disable_soc: cam_sfe_disable_soc_resources(soc_info); decrement_open_cnt: @@ -93,10 +112,8 @@ int cam_sfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) struct cam_hw_info *sfe_hw = hw_priv; struct cam_hw_soc_info *soc_info = NULL; struct cam_sfe_hw_core_info *core_info = NULL; - struct cam_isp_resource_node *isp_res = NULL; int rc = 0; - CAM_DBG(CAM_SFE, "Enter"); if (!hw_priv) { CAM_ERR(CAM_SFE, "Invalid arguments"); return -EINVAL; @@ -105,13 +122,15 @@ int cam_sfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) mutex_lock(&sfe_hw->hw_mutex); if (!sfe_hw->open_count) { mutex_unlock(&sfe_hw->hw_mutex); - CAM_ERR(CAM_SFE, "Error! Unbalanced deinit"); + CAM_ERR(CAM_SFE, "Unbalanced deinit"); return -EFAULT; } + sfe_hw->open_count--; if (sfe_hw->open_count) { mutex_unlock(&sfe_hw->hw_mutex); - CAM_DBG(CAM_SFE, "open_cnt non-zero =%d", sfe_hw->open_count); + CAM_DBG(CAM_SFE, "open_cnt non-zero: %d", + sfe_hw->open_count); return 0; } mutex_unlock(&sfe_hw->hw_mutex); @@ -119,63 +138,196 @@ int cam_sfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) soc_info = &sfe_hw->soc_info; core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info; - isp_res = (struct cam_isp_resource_node *)deinit_hw_args; - if (isp_res && isp_res->deinit) { - rc = isp_res->deinit(isp_res, NULL, 0); - if (rc) - CAM_ERR(CAM_SFE, "deinit failed"); - } + rc = core_info->sfe_bus_wr->hw_ops.deinit( + core_info->sfe_bus_wr->bus_priv, NULL, 0); + if (rc) + CAM_ERR(CAM_SFE, "SFE bus wr deinit failed rc: %d", + rc); + + rc = core_info->sfe_bus_rd->hw_ops.deinit( + core_info->sfe_bus_rd->bus_priv, NULL, 0); + if (rc) + CAM_ERR(CAM_SFE, "SFE bus rd deinit failed rc: %d", + rc); /* Turn OFF Regulators, Clocks and other SOC resources */ - CAM_DBG(CAM_SFE, "Disable SOC resource"); + CAM_DBG(CAM_SFE, "Disable SFE SOC resource"); rc = cam_sfe_disable_soc_resources(soc_info); if (rc) CAM_ERR(CAM_SFE, "Disable SOC failed"); sfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; - CAM_DBG(CAM_SFE, "Exit"); + CAM_DBG(CAM_SFE, "SFE deinit done rc: %d", rc); return rc; } -int cam_sfe_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) -{ - CAM_DBG(CAM_SFE, "Enter"); - return 0; -} - int cam_sfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size) { - CAM_DBG(CAM_SFE, "Enter"); - return 0; + struct cam_sfe_hw_core_info *core_info = NULL; + struct cam_hw_info *sfe_hw = hw_priv; + struct cam_sfe_acquire_args *acquire; + int rc = -ENODEV; + + if (!hw_priv || !reserve_args || (arg_size != + sizeof(struct cam_sfe_acquire_args))) { + CAM_ERR(CAM_SFE, "Invalid input arguments"); + return -EINVAL; + } + + core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info; + acquire = (struct cam_sfe_acquire_args *)reserve_args; + + CAM_DBG(CAM_SFE, "SFE acquire for res type: %d", + acquire->rsrc_type); + + mutex_lock(&sfe_hw->hw_mutex); + if (acquire->rsrc_type == CAM_ISP_RESOURCE_SFE_IN) + rc = core_info->sfe_top->hw_ops.reserve( + core_info->sfe_top->top_priv, + reserve_args, arg_size); + else if (acquire->rsrc_type == CAM_ISP_RESOURCE_SFE_OUT) + rc = core_info->sfe_bus_wr->hw_ops.reserve( + core_info->sfe_bus_wr->bus_priv, acquire, + sizeof(*acquire)); + else if (acquire->rsrc_type == CAM_ISP_RESOURCE_SFE_RD) + rc = core_info->sfe_bus_rd->hw_ops.reserve( + core_info->sfe_bus_rd->bus_priv, acquire, + sizeof(*acquire)); + else + CAM_ERR(CAM_SFE, "Invalid SFE res_type: %d", + acquire->rsrc_type); + mutex_unlock(&sfe_hw->hw_mutex); + + return rc; } int cam_sfe_release(void *hw_priv, void *release_args, uint32_t arg_size) { - CAM_DBG(CAM_SFE, "Enter"); - return 0; + struct cam_sfe_hw_core_info *core_info = NULL; + struct cam_hw_info *sfe_hw = hw_priv; + struct cam_isp_resource_node *sfe_res; + int rc = -ENODEV; + + if (!hw_priv || !release_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_SFE, "Invalid input arguments"); + return -EINVAL; + } + + core_info = (struct cam_sfe_hw_core_info *) sfe_hw->core_info; + sfe_res = (struct cam_isp_resource_node *) release_args; + + CAM_DBG(CAM_SFE, "SFE release for res type: %d", + sfe_res->res_type); + + mutex_lock(&sfe_hw->hw_mutex); + if (sfe_res->res_type == CAM_ISP_RESOURCE_SFE_IN) + rc = core_info->sfe_top->hw_ops.release( + core_info->sfe_top->top_priv, sfe_res, + sizeof(struct cam_isp_resource_node)); + else if (sfe_res->res_type == CAM_ISP_RESOURCE_SFE_OUT) + rc = core_info->sfe_bus_wr->hw_ops.release( + core_info->sfe_bus_wr->bus_priv, sfe_res, + sizeof(*sfe_res)); + else if (sfe_res->res_type == CAM_ISP_RESOURCE_SFE_RD) + rc = core_info->sfe_bus_rd->hw_ops.release( + core_info->sfe_bus_rd->bus_priv, sfe_res, + sizeof(*sfe_res)); + else + CAM_ERR(CAM_SFE, "Invalid SFE res type: %d", + sfe_res->res_type); + mutex_unlock(&sfe_hw->hw_mutex); + + return rc; } int cam_sfe_start(void *hw_priv, void *start_args, uint32_t arg_size) { - CAM_DBG(CAM_SFE, "Enter"); - return 0; + struct cam_sfe_hw_core_info *core_info = NULL; + struct cam_hw_info *sfe_hw = hw_priv; + struct cam_isp_resource_node *sfe_res; + struct cam_hw_soc_info *soc_info = NULL; + int rc; + + if (!hw_priv || !start_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_SFE, "Invalid input arguments"); + return -EINVAL; + } + + soc_info = &sfe_hw->soc_info; + core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info; + sfe_res = (struct cam_isp_resource_node *)start_args; + core_info->tasklet_info = sfe_res->tasklet_info; + + mutex_lock(&sfe_hw->hw_mutex); + if (sfe_res->res_type == CAM_ISP_RESOURCE_SFE_IN) { + rc = core_info->sfe_top->hw_ops.start( + core_info->sfe_top->top_priv, sfe_res, + sizeof(struct cam_isp_resource_node)); + if (rc) + CAM_ERR(CAM_SFE, "Failed to start SFE IN rc: %d", rc); + } else if (sfe_res->res_type == CAM_ISP_RESOURCE_SFE_OUT) { + rc = core_info->sfe_bus_wr->hw_ops.start(sfe_res, NULL, 0); + if (rc) + CAM_ERR(CAM_SFE, "Failed to start SFE BUS WR rc: %d", + rc); + } else if (sfe_res->res_type == CAM_ISP_RESOURCE_SFE_RD) { + rc = core_info->sfe_bus_rd->hw_ops.start(sfe_res, + NULL, 0); + if (rc) + CAM_ERR(CAM_SFE, "Failed to start SFE BUS RD rc: %d", + rc); + } else { + CAM_ERR(CAM_SFE, "Invalid SFE res type:%d", + sfe_res->res_type); + rc = -EINVAL; + } + + mutex_unlock(&sfe_hw->hw_mutex); + CAM_DBG(CAM_SFE, + "Start for SFE res type: %u res id: %u res_state: %d rc: %d", + sfe_res->res_type, sfe_res->res_id, + sfe_res->res_state, rc); + return rc; } int cam_sfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) { - CAM_DBG(CAM_SFE, "Enter"); - return 0; -} + struct cam_sfe_hw_core_info *core_info = NULL; + struct cam_hw_info *sfe_hw = hw_priv; + struct cam_isp_resource_node *sfe_res; + int rc = -EINVAL; -int cam_sfe_read(void *hw_priv, void *read_args, uint32_t arg_size) -{ - return -EPERM; -} + if (!hw_priv || !stop_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_SFE, "Invalid input arguments"); + return -EINVAL; + } -int cam_sfe_write(void *hw_priv, void *write_args, uint32_t arg_size) -{ - return -EPERM; + core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info; + sfe_res = (struct cam_isp_resource_node *)stop_args; + mutex_lock(&sfe_hw->hw_mutex); + + if (sfe_res->res_type == CAM_ISP_RESOURCE_SFE_IN) + rc = core_info->sfe_top->hw_ops.stop( + core_info->sfe_top->top_priv, sfe_res, + sizeof(struct cam_isp_resource_node)); + else if (sfe_res->res_type == CAM_ISP_RESOURCE_SFE_OUT) + rc = core_info->sfe_bus_wr->hw_ops.stop(sfe_res, NULL, 0); + else if (sfe_res->res_type == CAM_ISP_RESOURCE_SFE_RD) + rc = core_info->sfe_bus_rd->hw_ops.stop(sfe_res, NULL, 0); + else + CAM_ERR(CAM_SFE, "Invalid SFE res type: %d", sfe_res->res_type); + + mutex_unlock(&sfe_hw->hw_mutex); + CAM_DBG(CAM_SFE, + "Stop for SFE res type: %u res id: %u res_state: %d rc: %d", + sfe_res->res_type, sfe_res->res_id, + sfe_res->res_state, rc); + + return rc; } int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type, @@ -185,7 +337,7 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type, struct cam_hw_soc_info *soc_info = NULL; struct cam_sfe_hw_core_info *core_info = NULL; struct cam_sfe_hw_info *hw_info = NULL; - int rc; + int rc = 0; if (!hw_priv) { CAM_ERR(CAM_SFE, "Invalid arguments"); @@ -198,12 +350,35 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type, switch (cmd_type) { case CAM_ISP_HW_CMD_GET_CHANGE_BASE: - case CAM_ISP_HW_CMD_GET_REG_UPDATE: - rc = 0; + case CAM_ISP_HW_CMD_CLOCK_UPDATE: + case CAM_ISP_HW_CMD_BW_UPDATE_V2: + case CAM_ISP_HW_CMD_BW_CONTROL: + case CAM_ISP_HW_CMD_CORE_CONFIG: + rc = core_info->sfe_top->hw_ops.process_cmd( + core_info->sfe_top->top_priv, cmd_type, + 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: + case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = core_info->sfe_bus_wr->hw_ops.process_cmd( + core_info->sfe_bus_wr->bus_priv, cmd_type, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + rc = core_info->sfe_bus_rd->hw_ops.process_cmd( + core_info->sfe_bus_rd->bus_priv, cmd_type, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_UNMASK_BUS_WR_IRQ: + /* Needs to be handled based on hw_mgr change */ break; - default: - CAM_ERR(CAM_SFE, "Invalid cmd type:%d", cmd_type); + CAM_ERR(CAM_SFE, "Invalid cmd type: %d", cmd_type); rc = -EINVAL; break; } @@ -227,37 +402,85 @@ irqreturn_t cam_sfe_irq(int irq_num, void *data) } int cam_sfe_core_init( - struct cam_sfe_hw_core_info *core_info, - struct cam_hw_soc_info *soc_info, - struct cam_hw_intf *hw_intf, - struct cam_sfe_hw_info *sfe_hw_info) + struct cam_sfe_hw_core_info *core_info, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + struct cam_sfe_hw_info *sfe_hw_info) { + int rc; - CAM_DBG(CAM_SFE, "Enter"); + rc = cam_sfe_top_init(sfe_hw_info->top_version, soc_info, hw_intf, + sfe_hw_info->top_hw_info, &core_info->sfe_top); + if (rc) { + CAM_ERR(CAM_SFE, "SFE top init failed rc: %d", rc); + return rc; + } + + rc = cam_sfe_bus_init(sfe_hw_info->bus_wr_version, BUS_TYPE_SFE_WR, + soc_info, hw_intf, sfe_hw_info->bus_wr_hw_info, + &core_info->sfe_bus_wr); + if (rc) { + CAM_ERR(CAM_SFE, "SFE bus wr init failed rc: %d", rc); + goto deinit_top; + } + + rc = cam_sfe_bus_init(sfe_hw_info->bus_rd_version, BUS_TYPE_SFE_RD, + soc_info, hw_intf, sfe_hw_info->bus_rd_hw_info, + &core_info->sfe_bus_rd); + if (rc) { + CAM_ERR(CAM_SFE, "SFE bus rd init failed rc: %d", rc); + goto deinit_bus_wr; + } INIT_LIST_HEAD(&core_info->free_payload_list); spin_lock_init(&core_info->spin_lock); + CAM_DBG(CAM_SFE, "SFE device [%u] INIT success", + hw_intf->hw_idx); + return rc; - return 0; +deinit_bus_wr: + cam_sfe_bus_deinit(BUS_TYPE_SFE_WR, + sfe_hw_info->bus_wr_version, + &core_info->sfe_bus_wr); +deinit_top: + cam_sfe_top_deinit(sfe_hw_info->top_version, + &core_info->sfe_top); + return rc; } int cam_sfe_core_deinit( struct cam_sfe_hw_core_info *core_info, struct cam_sfe_hw_info *sfe_hw_info) { - int rc = -EINVAL; + int rc = -EINVAL, 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_SFE_EVT_MAX; i++) + INIT_LIST_HEAD(&core_info->evt_payload[i].list); - rc = cam_irq_controller_deinit(&core_info->sfe_irq_controller); + rc = cam_sfe_bus_deinit(BUS_TYPE_SFE_RD, + sfe_hw_info->bus_rd_version, + &core_info->sfe_bus_rd); if (rc) CAM_ERR(CAM_SFE, - "Error cam_irq_controller_deinit failed rc=%d", rc); + "SFE bus rd deinit failed rc: %d", rc); + + rc = cam_sfe_bus_deinit(BUS_TYPE_SFE_WR, + sfe_hw_info->bus_wr_version, + &core_info->sfe_bus_wr); + if (rc) + CAM_ERR(CAM_SFE, + "SFE bus wr deinit failed rc: %d", rc); + + rc = cam_sfe_top_deinit(sfe_hw_info->top_version, + &core_info->sfe_top); + if (rc) + CAM_ERR(CAM_SFE, + "SFE 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/sfe_hw/cam_sfe_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h index 4c25b44584..349de9e7e1 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h @@ -9,30 +9,48 @@ #include #include "cam_hw_intf.h" #include "cam_sfe_hw_intf.h" +#include "cam_sfe_bus.h" +#include "cam_sfe_top.h" + +#define CAM_SFE_EVT_MAX 256 struct cam_sfe_hw_info { struct cam_irq_controller_reg_info *irq_reg_info; -}; -#define CAM_SFE_EVT_MAX 256 + uint32_t bus_wr_version; + void *bus_wr_hw_info; + + uint32_t bus_rd_version; + void *bus_rd_hw_info; + + uint32_t top_version; + void *top_hw_info; +}; struct cam_sfe_hw_core_info { struct cam_sfe_hw_info *sfe_hw_info; + struct cam_sfe_top *sfe_top; + struct cam_sfe_bus *sfe_bus_wr; + struct cam_sfe_bus *sfe_bus_rd; void *sfe_irq_controller; void *tasklet_info; + struct cam_sfe_irq_evt_payload evt_payload[CAM_SFE_EVT_MAX]; struct list_head free_payload_list; spinlock_t spin_lock; - int irq_handle; }; int cam_sfe_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size); +int cam_sfe_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size); +int cam_sfe_read(void *device_priv, + void *read_args, uint32_t arg_size); +int cam_sfe_write(void *device_priv, + void *write_args, uint32_t arg_size); int cam_sfe_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size); int cam_sfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size); -int cam_sfe_reset(void *device_priv, - void *reset_core_args, uint32_t arg_size); int cam_sfe_reserve(void *device_priv, void *reserve_args, uint32_t arg_size); int cam_sfe_release(void *device_priv, @@ -41,10 +59,6 @@ int cam_sfe_start(void *device_priv, void *start_args, uint32_t arg_size); int cam_sfe_stop(void *device_priv, void *stop_args, uint32_t arg_size); -int cam_sfe_read(void *device_priv, - void *read_args, uint32_t arg_size); -int cam_sfe_write(void *device_priv, - void *write_args, uint32_t arg_size); int cam_sfe_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c index 3e41a654cf..009d812073 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c @@ -6,65 +6,71 @@ #include #include #include +#include #include "cam_sfe_dev.h" #include "cam_sfe_core.h" #include "cam_sfe_soc.h" -#include "cam_sfe_hw_intf.h" +#include "cam_sfe680.h" #include "cam_debug_util.h" +#include "camera_main.h" -static struct cam_hw_intf *sfe_instance; +static struct cam_hw_intf *cam_sfe_hw_list[CAM_SFE_HW_NUM_MAX]; static char sfe_dev_name[8]; -int cam_sfe_probe(struct platform_device *pdev) +static int cam_sfe_component_bind(struct device *dev, + struct device *master_dev, void *data) { + struct cam_hw_info *sfe_info = NULL; - struct cam_hw_intf *sfe_intf = NULL; + struct cam_hw_intf *sfe_hw_intf = NULL; const struct of_device_id *match_dev = NULL; struct cam_sfe_hw_core_info *core_info = NULL; struct cam_sfe_hw_info *hw_info = NULL; + struct platform_device *pdev = NULL; int rc = 0; - sfe_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); - if (!sfe_intf) { + pdev = to_platform_device(dev); + sfe_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!sfe_hw_intf) { rc = -ENOMEM; goto end; } of_property_read_u32(pdev->dev.of_node, - "cell-index", &sfe_intf->hw_idx); + "cell-index", &sfe_hw_intf->hw_idx); sfe_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); if (!sfe_info) { rc = -ENOMEM; - goto free_sfe_intf; + goto free_sfe_hw_intf; } memset(sfe_dev_name, 0, sizeof(sfe_dev_name)); snprintf(sfe_dev_name, sizeof(sfe_dev_name), - "sfe%1u", sfe_intf->hw_idx); + "sfe%1u", sfe_hw_intf->hw_idx); sfe_info->soc_info.pdev = pdev; sfe_info->soc_info.dev = &pdev->dev; sfe_info->soc_info.dev_name = sfe_dev_name; - sfe_intf->hw_priv = sfe_info; - sfe_intf->hw_ops.get_hw_caps = cam_sfe_get_hw_caps; - sfe_intf->hw_ops.init = cam_sfe_init_hw; - sfe_intf->hw_ops.deinit = cam_sfe_deinit_hw; - sfe_intf->hw_ops.reset = cam_sfe_reset; - sfe_intf->hw_ops.reserve = cam_sfe_reserve; - sfe_intf->hw_ops.release = cam_sfe_release; - sfe_intf->hw_ops.start = cam_sfe_start; - sfe_intf->hw_ops.stop = cam_sfe_stop; - sfe_intf->hw_ops.read = cam_sfe_read; - sfe_intf->hw_ops.write = cam_sfe_write; - sfe_intf->hw_ops.process_cmd = cam_sfe_process_cmd; - sfe_intf->hw_type = CAM_ISP_HW_TYPE_SFE; + sfe_hw_intf->hw_priv = sfe_info; + sfe_hw_intf->hw_ops.get_hw_caps = cam_sfe_get_hw_caps; + sfe_hw_intf->hw_ops.init = cam_sfe_init_hw; + sfe_hw_intf->hw_ops.deinit = cam_sfe_deinit_hw; + sfe_hw_intf->hw_ops.reset = cam_sfe_reset; + sfe_hw_intf->hw_ops.reserve = cam_sfe_reserve; + sfe_hw_intf->hw_ops.release = cam_sfe_release; + sfe_hw_intf->hw_ops.start = cam_sfe_start; + sfe_hw_intf->hw_ops.stop = cam_sfe_stop; + sfe_hw_intf->hw_ops.read = cam_sfe_read; + sfe_hw_intf->hw_ops.write = cam_sfe_write; + sfe_hw_intf->hw_ops.process_cmd = cam_sfe_process_cmd; + sfe_hw_intf->hw_type = CAM_ISP_HW_TYPE_SFE; - CAM_DBG(CAM_SFE, "type %d index %d", - sfe_intf->hw_type, sfe_intf->hw_idx); + CAM_DBG(CAM_SFE, "SFE component bind type %d index %d", + sfe_hw_intf->hw_type, sfe_hw_intf->hw_idx); - platform_set_drvdata(pdev, sfe_intf); + platform_set_drvdata(pdev, sfe_hw_intf); sfe_info->core_info = kzalloc(sizeof(struct cam_sfe_hw_core_info), GFP_KERNEL); @@ -93,7 +99,7 @@ int cam_sfe_probe(struct platform_device *pdev) } rc = cam_sfe_core_init(core_info, &sfe_info->soc_info, - sfe_intf, hw_info); + sfe_hw_intf, hw_info); if (rc < 0) { CAM_ERR(CAM_SFE, "Failed to init core rc=%d", rc); goto deinit_soc; @@ -104,9 +110,11 @@ int cam_sfe_probe(struct platform_device *pdev) spin_lock_init(&sfe_info->hw_lock); init_completion(&sfe_info->hw_complete); - sfe_instance = sfe_intf; + if (sfe_hw_intf->hw_idx < CAM_SFE_HW_NUM_MAX) + cam_sfe_hw_list[sfe_hw_intf->hw_idx] = sfe_hw_intf; - CAM_DBG(CAM_SFE, "SFE%d probe successful", sfe_intf->hw_idx); + CAM_DBG(CAM_SFE, "SFE%d bound successfully", + sfe_hw_intf->hw_idx); return rc; @@ -117,40 +125,45 @@ free_core_info: kfree(sfe_info->core_info); free_sfe_hw: kfree(sfe_info); -free_sfe_intf: - kfree(sfe_intf); +free_sfe_hw_intf: + kfree(sfe_hw_intf); end: return rc; } -int cam_sfe_remove(struct platform_device *pdev) +static void cam_sfe_component_unbind(struct device *dev, + struct device *master_dev, void *data) { + struct cam_hw_info *sfe_info = NULL; - struct cam_hw_intf *sfe_intf = NULL; + struct cam_hw_intf *sfe_hw_intf = NULL; struct cam_sfe_hw_core_info *core_info = NULL; + struct platform_device *pdev = NULL; int rc = 0; - sfe_intf = platform_get_drvdata(pdev); - if (!sfe_intf) { + pdev = to_platform_device(dev); + sfe_hw_intf = platform_get_drvdata(pdev); + if (!sfe_hw_intf) { CAM_ERR(CAM_SFE, "Error! No data in pdev"); - return -EINVAL; + return; } - CAM_DBG(CAM_SFE, "type %d index %d", - sfe_intf->hw_type, sfe_intf->hw_idx); + CAM_DBG(CAM_SFE, "SFE component unbound type %d index %d", + sfe_hw_intf->hw_type, sfe_hw_intf->hw_idx); - sfe_instance = NULL; + if (sfe_hw_intf->hw_idx < CAM_SFE_HW_NUM_MAX) + cam_sfe_hw_list[sfe_hw_intf->hw_idx] = NULL; - sfe_info = sfe_intf->hw_priv; + sfe_info = sfe_hw_intf->hw_priv; if (!sfe_info) { - CAM_ERR(CAM_SFE, "Error! HW data is NULL"); + CAM_ERR(CAM_SFE, "HW data is NULL"); rc = -ENODEV; - goto free_sfe_intf; + goto free_sfe_hw_intf; } core_info = (struct cam_sfe_hw_core_info *)sfe_info->core_info; if (!core_info) { - CAM_ERR(CAM_SFE, "Error! core data NULL"); + CAM_ERR(CAM_SFE, "core data NULL"); rc = -EINVAL; goto deinit_soc; } @@ -169,25 +182,80 @@ deinit_soc: mutex_destroy(&sfe_info->hw_mutex); kfree(sfe_info); - CAM_DBG(CAM_SFE, "SFE%d remove successful", sfe_intf->hw_idx); + CAM_DBG(CAM_SFE, "SFE%d remove successful", sfe_hw_intf->hw_idx); -free_sfe_intf: - kfree(sfe_intf); +free_sfe_hw_intf: + kfree(sfe_hw_intf); +} + +const static struct component_ops cam_sfe_component_ops = { + .bind = cam_sfe_component_bind, + .unbind = cam_sfe_component_unbind, +}; + +int cam_sfe_probe(struct platform_device *pdev) +{ + int rc = 0; + + CAM_DBG(CAM_SFE, "Adding SFE component"); + rc = component_add(&pdev->dev, &cam_sfe_component_ops); + if (rc) + CAM_ERR(CAM_SFE, "failed to add component rc: %d", rc); return rc; } -int cam_sfe_hw_init(struct cam_hw_intf **sfe_intf, uint32_t hw_idx) +int cam_sfe_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &cam_sfe_component_ops); + return 0; +} + +int cam_sfe_hw_init(struct cam_hw_intf **sfe_hw, uint32_t hw_idx) { int rc = 0; - if (sfe_instance) { - *sfe_intf = sfe_instance; + if (cam_sfe_hw_list[hw_idx]) { + *sfe_hw = cam_sfe_hw_list[hw_idx]; rc = 0; } else { - *sfe_intf = NULL; + *sfe_hw = NULL; rc = -ENODEV; } return rc; } + +static const struct of_device_id cam_sfe_dt_match[] = { + { + .compatible = "", + .data = &cam_sfe680_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_sfe_dt_match); + +struct platform_driver cam_sfe_driver = { + .probe = cam_sfe_probe, + .remove = cam_sfe_remove, + .driver = { + .name = "cam_sfe", + .owner = THIS_MODULE, + .of_match_table = cam_sfe_dt_match, + .suppress_bind_attrs = true, + }, +}; + +int cam_sfe_init_module(void) +{ + return platform_driver_register(&cam_sfe_driver); +} + + +void cam_sfe_exit_module(void) +{ + platform_driver_unregister(&cam_sfe_driver); +} + +MODULE_DESCRIPTION("CAM SFE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.h index b49ad32178..d00bcc6144 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.h @@ -6,30 +6,18 @@ #ifndef _CAM_SFE_DEV_H_ #define _CAM_SFE_DEV_H_ -#include - -/* - * cam_sfe_probe() - * - * @brief: Driver probe function called on Boot - * - * @pdev: Platform Device pointer - * +/** + * @brief : API to register SFE hw to platform framework. * @Return: 0: Success * Non-zero: Failure */ -int cam_sfe_probe(struct platform_device *pdev); +int cam_sfe_init_module(void); -/* - * cam_sfe_remove() - * - * @brief: Driver remove function - * - * @pdev: Platform Device pointer - * +/** + * @brief : API to remove SFE Hw from platform framework. * @Return: 0: Success * Non-zero: Failure */ -int cam_sfe_remove(struct platform_device *pdev); +void cam_sfe_exit_module(void); #endif /* _CAM_SFE_DEV_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c index fb72657a15..aa6b42db8c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c @@ -50,11 +50,26 @@ int cam_sfe_init_soc_resources(struct cam_hw_soc_info *soc_info, irq_handler_t irq_handler_func, void *irq_data) { int rc = 0; + struct cam_sfe_soc_private *soc_private; + struct cam_cpas_register_params cpas_register_param; + + soc_private = kzalloc(sizeof(struct cam_sfe_soc_private), + GFP_KERNEL); + if (!soc_private) + return -ENOMEM; + + soc_info->soc_private = soc_private; + rc = cam_cpas_get_cpas_hw_version(&soc_private->cpas_version); + if (rc) { + CAM_ERR(CAM_SFE, "Error! Invalid cpas version rc=%d", rc); + goto free_soc_private; + } + soc_info->hw_version = soc_private->cpas_version; rc = cam_sfe_get_dt_properties(soc_info); if (rc < 0) { CAM_ERR(CAM_SFE, "Error Get DT properties failed rc=%d", rc); - goto end; + goto free_soc_private; } rc = cam_sfe_request_platform_resource(soc_info, @@ -62,41 +77,104 @@ int cam_sfe_init_soc_resources(struct cam_hw_soc_info *soc_info, if (rc < 0) { CAM_ERR(CAM_SFE, "Error Request platform resources failed rc=%d", rc); - goto end; + goto free_soc_private; } -end: + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "sfe", + 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 = NULL; + cpas_register_param.userdata = soc_info; + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_SFE, "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_sfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info) { int rc = 0; + struct cam_sfe_soc_private *soc_private; if (!soc_info) { CAM_ERR(CAM_SFE, "Error soc_info NULL"); return -ENODEV; } + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_SFE, "Error! soc_private NULL"); + return -ENODEV; + } + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_SFE, "CPAS unregistration failed rc=%d", rc); + rc = cam_sfe_release_platform_resource(soc_info); if (rc < 0) CAM_ERR(CAM_SFE, "Error Release platform resources failed rc=%d", rc); + kfree(soc_private); return rc; } int cam_sfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) { - int rc = 0; + int rc = 0; + struct cam_sfe_soc_private *soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; - rc = cam_soc_util_enable_platform_resource(soc_info, true, - CAM_TURBO_VOTE, true); + if (!soc_info) { + CAM_ERR(CAM_SFE, "Error! Invalid params"); + rc = -EINVAL; + goto end; + } + soc_private = soc_info->soc_private; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_SFE_NRDI; + 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_SFE, "Error enable platform failed rc=%d", rc); + CAM_ERR(CAM_SFE, "CPAS start failed rc=%d", rc); + rc = -EFAULT; goto end; } + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_LOWSVS_VOTE, true); + if (rc) { + CAM_ERR(CAM_SFE, "Enable platform failed rc=%d", rc); + goto stop_cpas; + } + + return rc; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); end: return rc; } @@ -113,14 +191,26 @@ int cam_sfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, return -EPERM; } - int cam_sfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc = 0; + struct cam_sfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_SFE, "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_SFE, "Disable platform failed rc=%d", rc); + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_SFE, "CPAS stop failed rc=%d", rc); + return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.h index 37bf2918c5..735e621552 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.h @@ -37,7 +37,7 @@ struct cam_sfe_soc_private { * Non-zero: Failure */ int cam_sfe_init_soc_resources(struct cam_hw_soc_info *soc_info, - irq_handler_t vfe_irq_handler, void *irq_data); + irq_handler_t sfe_irq_handler, void *irq_data); /* * cam_sfe_deinit_soc_resources() diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus.c new file mode 100644 index 0000000000..d713714e1d --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include "cam_sfe_bus.h" +#include "cam_sfe_bus_rd.h" +#include "cam_sfe_bus_wr.h" +#include "cam_debug_util.h" + +int cam_sfe_bus_init( + uint32_t bus_version, + int bus_type, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + struct cam_sfe_bus **sfe_bus) +{ + int rc = -ENODEV; + + switch (bus_type) { + case BUS_TYPE_SFE_WR: + switch (bus_version) { + case CAM_SFE_BUS_WR_VER_1_0: + rc = cam_sfe_bus_wr_init(soc_info, hw_intf, + bus_hw_info, sfe_bus); + break; + default: + CAM_ERR(CAM_SFE, "Unsupported Bus WR Version 0x%x", + bus_version); + break; + } + break; + case BUS_TYPE_SFE_RD: + switch (bus_version) { + case CAM_SFE_BUS_RD_VER_1_0: + rc = cam_sfe_bus_rd_init(soc_info, hw_intf, + bus_hw_info, sfe_bus); + break; + default: + CAM_ERR(CAM_SFE, "Unsupported Bus RD Version 0x%x", + bus_version); + break; + } + break; + default: + CAM_ERR(CAM_SFE, "Unsupported Bus type %d", bus_type); + break; + } + + return rc; +} + +int cam_sfe_bus_deinit( + uint32_t bus_version, + int bus_type, + struct cam_sfe_bus **sfe_bus) +{ + int rc = -ENODEV; + + switch (bus_type) { + case BUS_TYPE_SFE_WR: + switch (bus_version) { + case CAM_SFE_BUS_WR_VER_1_0: + rc = cam_sfe_bus_wr_deinit(sfe_bus); + break; + default: + CAM_ERR(CAM_SFE, "Unsupported Bus WR Version 0x%x", + bus_version); + break; + } + break; + case BUS_TYPE_SFE_RD: + switch (bus_version) { + case CAM_SFE_BUS_RD_VER_1_0: + rc = cam_sfe_bus_rd_deinit(sfe_bus); + break; + default: + CAM_ERR(CAM_SFE, "Unsupported Bus RD Version 0x%x", + bus_version); + break; + } + break; + default: + CAM_ERR(CAM_SFE, "Unsupported Bus type %d", bus_type); + break; + } + + return rc; +} + diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c new file mode 100644 index 0000000000..f9ad59da9f --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.c @@ -0,0 +1,1144 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include + +#include + +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_hw_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_sfe_hw_intf.h" +#include "cam_tasklet_util.h" +#include "cam_sfe_bus.h" +#include "cam_sfe_bus_rd.h" +#include "cam_sfe_core.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "sfe_bus_rd"; + +#define MAX_BUF_UPDATE_REG_NUM \ + (sizeof(struct cam_sfe_bus_rd_reg_offset_bus_client)/4) + +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +#define BUS_RD_DEFAULT_LATENCY_BUF_ALLOC 512 + +enum cam_sfe_bus_rd_unpacker_format { + BUS_RD_UNPACKER_FMT_PLAIN_128 = 0x0, + BUS_RD_UNPACKER_FMT_PLAIN_8 = 0x1, + BUS_RD_UNPACKER_FMT_PLAIN_16_10BPP = 0x2, + BUS_RD_UNPACKER_FMT_PLAIN_16_12BPP = 0x3, + BUS_RD_UNPACKER_FMT_PLAIN_16_14BPP = 0x4, + BUS_RD_UNPACKER_FMT_PLAIN_32_20BPP = 0x5, + BUS_RD_UNPACKER_FMT_ARGB_10 = 0x6, + BUS_RD_UNPACKER_FMT_ARGB_12 = 0x7, + BUS_RD_UNPACKER_FMT_ARGB_14 = 0x8, + BUS_RD_UNPACKER_FMT_PLAIN_32 = 0x9, + BUS_RD_UNPACKER_FMT_PLAIN_64 = 0xA, + BUS_RD_UNPACKER_FMT_TP_10 = 0xB, + BUS_RD_UNPACKER_FMT_MIPI8 = 0xC, + BUS_RD_UNPACKER_FMT_MIPI10 = 0xD, + BUS_RD_UNPACKER_FMT_MIPI12 = 0xE, + BUS_RD_UNPACKER_FMT_MIPI14 = 0xF, + BUS_RD_UNPACKER_FMT_PLAIN_16_16BPP = 0x10, + BUS_RD_UNPACKER_FMT_PLAIN_128_ODD_EVEN = 0x11, + BUS_RD_UNPACKER_FMT_PLAIN_8_ODD_EVEN = 0x12, + BUS_RD_UNPACKER_FMT_MAX = 0x13, +}; + +struct cam_sfe_bus_rd_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_sfe_bus_rd_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + + cam_hw_mgr_event_cb_func event_cb; +}; + +struct cam_sfe_bus_rd_rm_resource_data { + uint32_t index; + struct cam_sfe_bus_rd_common_data *common_data; + struct cam_sfe_bus_rd_reg_offset_bus_client *hw_regs; + void *ctx; + uint32_t min_vbi; + uint32_t fs_mode; + uint32_t hbi_count; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t latency_buf_allocation; + uint32_t unpacker_cfg; + uint32_t burst_len; + uint32_t en_cfg; + uint32_t img_addr; + uint32_t input_if_cmd; +}; + +struct cam_sfe_bus_rd_data { + uint32_t bus_rd_type; + struct cam_sfe_bus_rd_common_data *common_data; + + uint32_t num_rm; + struct cam_isp_resource_node *rm_res[PLANE_MAX]; + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + void *priv; + uint32_t status; + uint32_t secure_mode; + uint32_t fs_sync_enable; + uint32_t fs_line_sync_en; + bool is_offline; +}; + +struct cam_sfe_bus_rd_priv { + struct cam_sfe_bus_rd_common_data common_data; + uint32_t num_client; + uint32_t num_bus_rd_resc; + + struct cam_isp_resource_node bus_client[ + CAM_SFE_BUS_RD_MAX_CLIENTS]; + struct cam_isp_resource_node sfe_bus_rd[ + CAM_SFE_BUS_RD_MAX]; + + void *tasklet_info; + uint32_t top_irq_shift; +}; + +static void cam_sfe_bus_rd_pxls_to_bytes(uint32_t pxls, uint32_t fmt, + uint32_t *bytes) +{ + switch (fmt) { + case BUS_RD_UNPACKER_FMT_PLAIN_128: + *bytes = pxls * 16; + break; + case BUS_RD_UNPACKER_FMT_PLAIN_8: + case BUS_RD_UNPACKER_FMT_PLAIN_8_ODD_EVEN: + case BUS_RD_UNPACKER_FMT_PLAIN_16_10BPP: + case BUS_RD_UNPACKER_FMT_PLAIN_16_12BPP: + case BUS_RD_UNPACKER_FMT_PLAIN_16_14BPP: + case BUS_RD_UNPACKER_FMT_PLAIN_16_16BPP: + case BUS_RD_UNPACKER_FMT_ARGB_10: + case BUS_RD_UNPACKER_FMT_ARGB_12: + case BUS_RD_UNPACKER_FMT_ARGB_14: + *bytes = pxls * 2; + break; + case BUS_RD_UNPACKER_FMT_PLAIN_32_20BPP: + case BUS_RD_UNPACKER_FMT_PLAIN_32: + *bytes = pxls * 4; + break; + case BUS_RD_UNPACKER_FMT_PLAIN_64: + *bytes = pxls * 8; + break; + case BUS_RD_UNPACKER_FMT_TP_10: + *bytes = ALIGNUP(pxls, 3) * 4 / 3; + break; + case BUS_RD_UNPACKER_FMT_MIPI8: + *bytes = pxls; + break; + case BUS_RD_UNPACKER_FMT_MIPI10: + *bytes = ALIGNUP(pxls * 5, 4) / 4; + break; + case BUS_RD_UNPACKER_FMT_MIPI12: + *bytes = ALIGNUP(pxls * 3, 2) / 2; + break; + case BUS_RD_UNPACKER_FMT_MIPI14: + *bytes = ALIGNUP(pxls * 7, 4) / 4; + break; + default: + CAM_ERR(CAM_SFE, "Invalid unpacker_fmt:%d", fmt); + break; + } +} + +static enum cam_sfe_bus_rd_unpacker_format + cam_sfe_bus_get_unpacker_fmt(uint32_t unpack_fmt) +{ + switch (unpack_fmt) { + case CAM_FORMAT_PLAIN128: + return BUS_RD_UNPACKER_FMT_PLAIN_128; + case CAM_FORMAT_PLAIN8: + return BUS_RD_UNPACKER_FMT_PLAIN_8; + case CAM_FORMAT_PLAIN16_10: + return BUS_RD_UNPACKER_FMT_PLAIN_16_10BPP; + case CAM_FORMAT_PLAIN16_12: + return BUS_RD_UNPACKER_FMT_PLAIN_16_12BPP; + case CAM_FORMAT_PLAIN16_14: + return BUS_RD_UNPACKER_FMT_PLAIN_16_14BPP; + case CAM_FORMAT_PLAIN32_20: + return BUS_RD_UNPACKER_FMT_PLAIN_32_20BPP; + case CAM_FORMAT_ARGB_10: + return BUS_RD_UNPACKER_FMT_ARGB_10; + case CAM_FORMAT_ARGB_12: + return BUS_RD_UNPACKER_FMT_ARGB_12; + case CAM_FORMAT_ARGB_14: + return BUS_RD_UNPACKER_FMT_ARGB_14; + case CAM_FORMAT_PLAIN32: + case CAM_FORMAT_ARGB: + return BUS_RD_UNPACKER_FMT_PLAIN_32; + case CAM_FORMAT_PLAIN64: + case CAM_FORMAT_ARGB_16: + case CAM_FORMAT_PD10: + return BUS_RD_UNPACKER_FMT_PLAIN_64; + case CAM_FORMAT_TP10: + return BUS_RD_UNPACKER_FMT_TP_10; + case CAM_FORMAT_MIPI_RAW_8: + return BUS_RD_UNPACKER_FMT_MIPI8; + case CAM_FORMAT_MIPI_RAW_10: + return BUS_RD_UNPACKER_FMT_MIPI10; + case CAM_FORMAT_MIPI_RAW_12: + return BUS_RD_UNPACKER_FMT_MIPI12; + case CAM_FORMAT_MIPI_RAW_14: + return BUS_RD_UNPACKER_FMT_MIPI14; + case CAM_FORMAT_PLAIN16_16: + return BUS_RD_UNPACKER_FMT_PLAIN_16_16BPP; + case CAM_FORMAT_PLAIN8_SWAP: + return BUS_RD_UNPACKER_FMT_PLAIN_8_ODD_EVEN; + default: + return BUS_RD_UNPACKER_FMT_MAX; + } +} + +static enum cam_sfe_bus_rd_type + cam_sfe_bus_get_bus_rd_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_HW_SFE_IN_RD0: + return CAM_SFE_BUS_RD_RDI0; + case CAM_ISP_HW_SFE_IN_RD1: + return CAM_SFE_BUS_RD_RDI1; + case CAM_ISP_HW_SFE_IN_RD2: + return CAM_SFE_BUS_RD_RDI2; + default: + return CAM_SFE_BUS_RD_MAX; + } +} + +static int cam_sfe_bus_get_num_rm( + enum cam_sfe_bus_rd_type res_type) +{ + switch (res_type) { + case CAM_SFE_BUS_RD_RDI0: + case CAM_SFE_BUS_RD_RDI1: + case CAM_SFE_BUS_RD_RDI2: + return 1; + default: + CAM_ERR(CAM_SFE, "Unsupported resource_type %u", res_type); + return -EINVAL; + } +} + +static int cam_sfe_bus_get_rm_idx( + enum cam_sfe_bus_rd_type sfe_bus_rd_res_id, + enum cam_sfe_bus_plane_type plane) +{ + int rm_idx = -1; + + switch (sfe_bus_rd_res_id) { + case CAM_SFE_BUS_RD_RDI0: + switch (plane) { + case PLANE_Y: + rm_idx = 0; + break; + default: + break; + } + break; + case CAM_SFE_BUS_RD_RDI1: + switch (plane) { + case PLANE_Y: + rm_idx = 1; + break; + default: + break; + } + break; + case CAM_SFE_BUS_RD_RDI2: + switch (plane) { + case PLANE_Y: + rm_idx = 2; + break; + default: + break; + } + break; + default: + break; + } + + return rm_idx; +} + +static int cam_sfe_bus_acquire_rm( + struct cam_sfe_bus_rd_priv *bus_rd_priv, + void *tasklet, + void *ctx, + enum cam_sfe_bus_rd_type sfe_bus_rd_res_id, + enum cam_sfe_bus_plane_type plane, + struct cam_isp_resource_node **rm_res, + uint32_t unpacker_fmt) +{ + uint32_t rm_idx = 0; + struct cam_isp_resource_node *rm_res_local = NULL; + struct cam_sfe_bus_rd_rm_resource_data *rsrc_data = NULL; + + *rm_res = NULL; + + rm_idx = cam_sfe_bus_get_rm_idx(sfe_bus_rd_res_id, plane); + if (rm_idx < 0 || rm_idx >= bus_rd_priv->num_client) { + CAM_ERR(CAM_SFE, "Unsupported SFE RM:%d plane:%d", + sfe_bus_rd_res_id, plane); + return -EINVAL; + } + + rm_res_local = &bus_rd_priv->bus_client[rm_idx]; + if (rm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_SFE, "SFE:%d RM:%d res not available state:%d", + bus_rd_priv->common_data.core_index, rm_idx, + rm_res_local->res_state); + return -EALREADY; + } + rm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rm_res_local->tasklet_info = tasklet; + + rsrc_data = rm_res_local->res_priv; + rsrc_data->ctx = ctx; + rsrc_data->unpacker_cfg = + cam_sfe_bus_get_unpacker_fmt(unpacker_fmt); + rsrc_data->latency_buf_allocation = + BUS_RD_DEFAULT_LATENCY_BUF_ALLOC; + + *rm_res = rm_res_local; + + CAM_DBG(CAM_SFE, "SFE:%d RM:%d Acquired", + rsrc_data->common_data->core_index, rsrc_data->index); + return 0; +} + +static int cam_sfe_bus_release_rm(void *bus_priv, + struct cam_isp_resource_node *rm_res) +{ + struct cam_sfe_bus_rd_rm_resource_data *rsrc_data = + rm_res->res_priv; + + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 0; + rsrc_data->format = 0; + rsrc_data->unpacker_cfg = 0; + rsrc_data->burst_len = 0; + rsrc_data->en_cfg = 0; + + rm_res->tasklet_info = NULL; + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + CAM_DBG(CAM_SFE, "SFE:%d RM:%d released", + rsrc_data->common_data->core_index, rsrc_data->index); + return 0; +} + +static int cam_sfe_bus_start_rm(struct cam_isp_resource_node *rm_res) +{ + struct cam_sfe_bus_rd_rm_resource_data *rm_data; + struct cam_sfe_bus_rd_common_data *common_data; + + rm_data = rm_res->res_priv; + common_data = rm_data->common_data; + + cam_io_w_mb(rm_data->width, common_data->mem_base + + rm_data->hw_regs->buf_width); + cam_io_w_mb(rm_data->height, common_data->mem_base + + rm_data->hw_regs->buf_height); + cam_io_w_mb(rm_data->width, common_data->mem_base + + rm_data->hw_regs->stride); + cam_io_w_mb(rm_data->unpacker_cfg, common_data->mem_base + + rm_data->hw_regs->unpacker_cfg); + cam_io_w_mb(rm_data->latency_buf_allocation, common_data->mem_base + + rm_data->hw_regs->latency_buf_allocation); + cam_io_w_mb(0x1, common_data->mem_base + rm_data->hw_regs->cfg); + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + CAM_DBG(CAM_SFE, + "Start SFE:%d RM:%d offset:0x%X en_cfg:0x%X width:%d height:%d", + rm_data->common_data->core_index, rm_data->index, + (uint32_t) rm_data->hw_regs->cfg, rm_data->en_cfg, + rm_data->width, rm_data->height); + CAM_DBG(CAM_SFE, "RM:%d pk_fmt:%d stride:%d", rm_data->index, + rm_data->unpacker_cfg, rm_data->stride); + + return 0; +} + +static int cam_sfe_bus_stop_rm(struct cam_isp_resource_node *rm_res) +{ + struct cam_sfe_bus_rd_rm_resource_data *rsrc_data = + rm_res->res_priv; + struct cam_sfe_bus_rd_common_data *common_data = + rsrc_data->common_data; + + /* Disable RM */ + cam_io_w_mb(0x0, common_data->mem_base + rsrc_data->hw_regs->cfg); + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + CAM_DBG(CAM_SFE, "SFE:%d RM:%d stopped", + rsrc_data->common_data->core_index, rsrc_data->index); + + return 0; +} + +static int cam_sfe_bus_init_rm_resource(uint32_t index, + struct cam_sfe_bus_rd_priv *bus_rd_priv, + struct cam_sfe_bus_rd_hw_info *bus_rd_hw_info, + struct cam_isp_resource_node *rm_res) +{ + struct cam_sfe_bus_rd_rm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_sfe_bus_rd_rm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_SFE, "Failed to alloc SFE:%d RM res priv", + bus_rd_priv->common_data.core_index); + return -ENOMEM; + } + rm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &bus_rd_hw_info->bus_client_reg[index]; + rsrc_data->common_data = &bus_rd_priv->common_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = cam_sfe_bus_start_rm; + rm_res->stop = cam_sfe_bus_stop_rm; + rm_res->hw_intf = bus_rd_priv->common_data.hw_intf; + + return 0; +} + +static int cam_sfe_bus_deinit_rm_resource( + struct cam_isp_resource_node *rm_res) +{ + struct cam_sfe_bus_rd_rm_resource_data *rsrc_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = NULL; + rm_res->stop = NULL; + rm_res->top_half_handler = NULL; + rm_res->bottom_half_handler = NULL; + rm_res->hw_intf = NULL; + + rsrc_data = rm_res->res_priv; + rm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_sfe_bus_rd_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *secure_mode = cmd_args; + struct cam_sfe_bus_rd_data *rsrc_data = NULL; + uint32_t *mode; + + rsrc_data = (struct cam_sfe_bus_rd_data *) + secure_mode->res->res_priv; + mode = (uint32_t *)secure_mode->data; + *mode = (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? + true : false; + + return 0; +} + +static int cam_sfe_bus_acquire_bus_rd(void *bus_priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_sfe_bus_rd_type bus_rd_res_id; + int num_rm; + struct cam_sfe_bus_rd_priv *bus_rd_priv = + bus_priv; + struct cam_sfe_acquire_args *acq_args = acquire_args; + struct cam_sfe_hw_sfe_bus_rd_acquire_args *bus_rd_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_sfe_bus_rd_data *rsrc_data = NULL; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_SFE, "Invalid Param"); + return -EINVAL; + } + + bus_rd_acquire_args = &acq_args->sfe_rd; + + bus_rd_res_id = cam_sfe_bus_get_bus_rd_res_id( + bus_rd_acquire_args->res_id); + if (bus_rd_res_id == CAM_SFE_BUS_RD_MAX) + return -ENODEV; + + num_rm = cam_sfe_bus_get_num_rm(bus_rd_res_id); + if (num_rm < 1) + return -EINVAL; + + rsrc_node = &bus_rd_priv->sfe_bus_rd[bus_rd_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_SFE, "SFE:%d RM:0x%x not available state:%d", + bus_rd_priv->common_data.core_index, + acq_args->rsrc_type, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_node->res_id = bus_rd_acquire_args->res_id; + rsrc_data = rsrc_node->res_priv; + + CAM_DBG(CAM_SFE, "SFE:%d acquire RD type:0x%x", + rsrc_data->common_data->core_index, acq_args->rsrc_type); + + rsrc_data->num_rm = num_rm; + rsrc_node->tasklet_info = acq_args->tasklet; + bus_rd_priv->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = bus_rd_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = bus_rd_acquire_args->cdm_ops; + rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->priv = acq_args->priv; + rsrc_data->is_offline = bus_rd_acquire_args->is_offline; + if (!rsrc_data->secure_mode) { + rsrc_data->secure_mode = + bus_rd_acquire_args->secure_mode; + } else if (rsrc_data->secure_mode != + bus_rd_acquire_args->secure_mode) { + CAM_ERR(CAM_SFE, + "Current Mode %u Requesting Mode %u", + rsrc_data->secure_mode, + bus_rd_acquire_args->secure_mode); + return -EINVAL; + } + + for (i = 0; i < num_rm; i++) { + rc = cam_sfe_bus_acquire_rm(bus_rd_priv, + acq_args->tasklet, + acq_args->priv, + bus_rd_res_id, + i, + &rsrc_data->rm_res[i], + bus_rd_acquire_args->unpacker_fmt); + if (rc) { + CAM_ERR(CAM_SFE, + "SFE:%d RM:%d acquire failed rc:%d", + rsrc_data->common_data->core_index, + bus_rd_res_id, rc); + goto release_rm; + } + } + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + bus_rd_acquire_args->rsrc_node = rsrc_node; + + CAM_DBG(CAM_SFE, "SFE:%d acquire RD 0x%x successful", + rsrc_data->common_data->core_index, acq_args->rsrc_type); + return rc; + +release_rm: + for (i--; i >= 0; i--) + cam_sfe_bus_release_rm(bus_rd_priv, rsrc_data->rm_res[i]); + return rc; +} + +static int cam_sfe_bus_release_bus_rd(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *sfe_bus_rd = NULL; + struct cam_sfe_bus_rd_data *rsrc_data = NULL; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_SFE, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + sfe_bus_rd = release_args; + rsrc_data = sfe_bus_rd->res_priv; + + if (sfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_SFE, + "SFE:%d RD type:0x%x invalid resource state:%d", + rsrc_data->common_data->core_index, + sfe_bus_rd->res_id, sfe_bus_rd->res_state); + } + + for (i = 0; i < rsrc_data->num_rm; i++) + cam_sfe_bus_release_rm(bus_priv, rsrc_data->rm_res[i]); + rsrc_data->num_rm = 0; + + sfe_bus_rd->tasklet_info = NULL; + sfe_bus_rd->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + rsrc_data->secure_mode = 0; + + if (sfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + sfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_sfe_bus_start_bus_rd( + void *hw_priv, void *stop_hw_args, uint32_t arg_size) +{ + int rc, i; + struct cam_isp_resource_node *sfe_bus_rd = NULL; + struct cam_sfe_bus_rd_data *rsrc_data = NULL; + struct cam_sfe_bus_rd_common_data *common_data = NULL; + uint32_t val = 0; + + if (!hw_priv) { + CAM_ERR(CAM_SFE, "Invalid input"); + return -EINVAL; + } + + sfe_bus_rd = (struct cam_isp_resource_node *)hw_priv; + rsrc_data = sfe_bus_rd->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_SFE, "SFE:%d start RD type:0x%x", sfe_bus_rd->res_id); + + if (sfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_SFE, "Invalid resource state:%d", + sfe_bus_rd->res_state); + return -EACCES; + } + + if (!rsrc_data->is_offline) { + val = (rsrc_data->fs_sync_enable << 5); + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->input_if_cmd); + } + + if (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) + cam_io_w_mb(1, common_data->mem_base + + common_data->common_reg->security_cfg); + + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_sfe_bus_start_rm(rsrc_data->rm_res[i]); + + /* Subscribe mask for buf_done */ + + sfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_sfe_bus_stop_bus_rd( + void *hw_priv, void *stop_hw_args, uint32_t arg_size) +{ + int rc = 0, i; + struct cam_isp_resource_node *sfe_bus_rd = NULL; + struct cam_sfe_bus_rd_data *rsrc_data = NULL; + + if (!hw_priv) { + CAM_ERR(CAM_SFE, "Invalid input"); + return -EINVAL; + } + + sfe_bus_rd = (struct cam_isp_resource_node *)hw_priv; + rsrc_data = sfe_bus_rd->res_priv; + + if (sfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + sfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_SFE, "SFE: %d res_id: 0x%x state: %d", + rsrc_data->common_data->core_index, sfe_bus_rd->res_id, + sfe_bus_rd->res_state); + return rc; + } + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_sfe_bus_stop_rm(rsrc_data->rm_res[i]); + + sfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + /* Unsubscribe mask for this wm IRQ controller */ + CAM_DBG(CAM_SFE, "SFE:%d stopped Bus RD:0x%x", + rsrc_data->common_data->core_index, + sfe_bus_rd->res_id); + return rc; +} + +static int cam_sfe_bus_init_sfe_bus_read_resource( + uint32_t index, + struct cam_sfe_bus_rd_priv *bus_rd_priv, + struct cam_sfe_bus_rd_hw_info *bus_rd_hw_info) +{ + struct cam_isp_resource_node *sfe_bus_rd = NULL; + struct cam_sfe_bus_rd_data *rsrc_data = NULL; + int rc = 0; + int32_t sfe_bus_rd_resc_type = + bus_rd_hw_info->sfe_bus_rd_info[index].sfe_bus_rd_type; + + if (sfe_bus_rd_resc_type < 0 || + sfe_bus_rd_resc_type >= CAM_SFE_BUS_RD_MAX) { + CAM_ERR(CAM_SFE, "Init SFE RD failed, Invalid type=%d", + sfe_bus_rd_resc_type); + return -EINVAL; + } + + sfe_bus_rd = &bus_rd_priv->sfe_bus_rd[sfe_bus_rd_resc_type]; + if (sfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + sfe_bus_rd->res_priv) { + CAM_ERR(CAM_SFE, + "Error. Looks like same resource is init again"); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_sfe_bus_rd_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + sfe_bus_rd->res_priv = rsrc_data; + + sfe_bus_rd->res_type = CAM_ISP_RESOURCE_SFE_RD; + sfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&sfe_bus_rd->list); + + rsrc_data->bus_rd_type = + bus_rd_hw_info->sfe_bus_rd_info[index].sfe_bus_rd_type; + rsrc_data->common_data = &bus_rd_priv->common_data; + rsrc_data->max_width = + bus_rd_hw_info->sfe_bus_rd_info[index].max_width; + rsrc_data->max_height = + bus_rd_hw_info->sfe_bus_rd_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + sfe_bus_rd->hw_intf = bus_rd_priv->common_data.hw_intf; + + return 0; +} + +static int cam_sfe_bus_deinit_sfe_bus_rd_resource( + struct cam_isp_resource_node *sfe_bus_rd_res) +{ + struct cam_sfe_bus_rd_data *rsrc_data = + sfe_bus_rd_res->res_priv; + + if (sfe_bus_rd_res->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_SFE, "HW%d Res %d already deinitialized"); + return 0; + } + + sfe_bus_rd_res->start = NULL; + sfe_bus_rd_res->stop = NULL; + sfe_bus_rd_res->top_half_handler = NULL; + sfe_bus_rd_res->bottom_half_handler = NULL; + sfe_bus_rd_res->hw_intf = NULL; + + sfe_bus_rd_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&sfe_bus_rd_res->list); + sfe_bus_rd_res->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_sfe_bus_rd_update_rm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_sfe_bus_rd_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg = NULL; + struct cam_sfe_bus_rd_data *sfe_bus_rd_data = NULL; + struct cam_sfe_bus_rd_rm_resource_data *rm_data = NULL; + uint32_t *reg_val_pair; + uint32_t width = 0, height = 0, stride = 0; + uint32_t i, j, size = 0; + + bus_priv = (struct cam_sfe_bus_rd_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + sfe_bus_rd_data = (struct cam_sfe_bus_rd_data *) + update_buf->res->res_priv; + + if (!sfe_bus_rd_data || !sfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_SFE, "Failed! Invalid data"); + return -EINVAL; + } + + CAM_DBG(CAM_SFE, "#of RM: %d scratch_buf_cfg: %s", + sfe_bus_rd_data->num_rm, + update_buf->use_scratch_cfg ? "true" : "false"); + if (update_buf->rm_update->num_buf != sfe_bus_rd_data->num_rm) { + CAM_ERR(CAM_SFE, + "Failed! Invalid number buffers:%d required:%d", + update_buf->rm_update->num_buf, + sfe_bus_rd_data->num_rm); + return -EINVAL; + } + + reg_val_pair = &sfe_bus_rd_data->common_data->io_buf_update[0]; + if (!update_buf->use_scratch_cfg) + io_cfg = update_buf->rm_update->io_cfg; + + for (i = 0, j = 0; i < sfe_bus_rd_data->num_rm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_SFE, + "reg_val_pair %d exceeds the array limit %lu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + rm_data = sfe_bus_rd_data->rm_res[i]->res_priv; + if (update_buf->use_scratch_cfg) { + stride = update_buf->rm_update->stride; + width = update_buf->rm_update->width; + height = update_buf->rm_update->height; + } else { + stride = io_cfg->planes[i].plane_stride; + width = io_cfg->planes[i].width; + height = io_cfg->planes[i].height; + } + + /* update size register */ + cam_sfe_bus_rd_pxls_to_bytes(width, + rm_data->unpacker_cfg, &rm_data->width); + rm_data->height = height; + + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->buf_width, rm_data->width); + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->buf_height, rm_data->height); + CAM_DBG(CAM_SFE, "SFE:%d RM:%d width:0x%X height:0x%X", + rm_data->common_data->core_index, + rm_data->index, rm_data->width, + rm_data->height); + + rm_data->stride = stride; + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->stride, rm_data->stride); + CAM_DBG(CAM_SFE, "SFE:%d RM:%d image_stride:0x%X", + rm_data->common_data->core_index, + rm_data->index, reg_val_pair[j-1]); + + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->image_addr, + update_buf->rm_update->image_buf[i]); + CAM_DBG(CAM_SFE, "SFE:%d RM:%d image_address:0x%X", + rm_data->common_data->core_index, + rm_data->index, reg_val_pair[j-1]); + rm_data->img_addr = reg_val_pair[j-1]; + } + + size = sfe_bus_rd_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_SFE, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + sfe_bus_rd_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_sfe_bus_rd_update_fs_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_sfe_bus_rd_priv *bus_priv; + struct cam_sfe_bus_rd_data *sfe_bus_rd_data = NULL; + struct cam_sfe_bus_rd_rm_resource_data *rm_data = NULL; + struct cam_sfe_fe_update_args *fe_upd_args; + struct cam_fe_config *fe_cfg; + struct cam_sfe_bus_rd_common_data *common_data; + int i = 0; + + bus_priv = (struct cam_sfe_bus_rd_priv *) priv; + fe_upd_args = (struct cam_sfe_fe_update_args *)cmd_args; + + sfe_bus_rd_data = (struct cam_sfe_bus_rd_data *) + fe_upd_args->node_res->res_priv; + + if (!sfe_bus_rd_data || !sfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_SFE, "Failed! Invalid data"); + return -EINVAL; + } + + fe_cfg = &fe_upd_args->fe_config; + + for (i = 0; i < sfe_bus_rd_data->num_rm; i++) { + + rm_data = sfe_bus_rd_data->rm_res[i]->res_priv; + common_data = rm_data->common_data; + + rm_data->format = fe_cfg->format; + rm_data->unpacker_cfg = fe_cfg->unpacker_cfg; + rm_data->latency_buf_allocation = fe_cfg->latency_buf_size; + rm_data->stride = fe_cfg->stride; + rm_data->hbi_count = fe_cfg->hbi_count; + rm_data->fs_mode = fe_cfg->fs_mode; + rm_data->min_vbi = fe_cfg->min_vbi; + sfe_bus_rd_data->fs_sync_enable = + fe_cfg->fs_sync_enable; + sfe_bus_rd_data->fs_line_sync_en = + fe_cfg->fs_line_sync_en; + + CAM_DBG(CAM_SFE, + "SFE:%d RM:%d format:0x%x unpacker_cfg:0x%x", + rm_data->format, rm_data->unpacker_cfg); + CAM_DBG(CAM_SFE, + "latency_buf_alloc:0x%x stride:0x%x", + rm_data->latency_buf_allocation, rm_data->stride); + CAM_DBG(CAM_SFE, + "fs_sync_en:%d hbi_cnt:0x%x fs_mode:0x%x min_vbi:0x%x", + sfe_bus_rd_data->fs_sync_enable, + rm_data->hbi_count, rm_data->fs_mode, + rm_data->min_vbi); + } + return 0; +} + +static int cam_sfe_bus_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_sfe_bus_rd_priv *bus_priv = hw_priv; + uint32_t sfe_top_irq_mask = 0; + uint32_t offset = 0; + struct cam_sfe_bus_rd_reg_offset_common *common_reg; + + if (!bus_priv) { + CAM_ERR(CAM_SFE, "Invalid args"); + return -EINVAL; + } + common_reg = bus_priv->common_data.common_reg; + sfe_top_irq_mask = (1 << bus_priv->top_irq_shift); + + /* Subscribe for error IRQs */ + + /* BUS_RD_TEST_BUS_CTRL disabling test bus */ + offset = common_reg->test_bus_ctrl; + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + + return 0; +} + +static int cam_sfe_bus_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_sfe_bus_rd_priv *bus_priv = hw_priv; + uint32_t sfe_top_irq_mask = 0; + int rc = 0; + + if (!bus_priv) { + CAM_ERR(CAM_SFE, "Error: Invalid args"); + return -EINVAL; + } + + sfe_top_irq_mask = 1 << bus_priv->top_irq_shift; + + /* Unsubscribe for err irqs */ + + return rc; +} + +static int cam_sfe_bus_rd_process_cmd( + void *priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_SFE, + "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + rc = cam_sfe_bus_rd_update_rm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_sfe_bus_rd_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + rc = cam_sfe_bus_rd_update_fs_cfg(priv, cmd_args, arg_size); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_SFE, + "Invalid SFE BUS RD command type: %d", + cmd_type); + break; + } + + return rc; +} + +int cam_sfe_bus_rd_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + struct cam_sfe_bus **sfe_bus) +{ + int i, rc = 0; + struct cam_sfe_bus_rd_priv *bus_priv = NULL; + struct cam_sfe_bus *sfe_bus_local; + struct cam_sfe_bus_rd_hw_info *bus_rd_hw_info = bus_hw_info; + + if (!soc_info || !hw_intf || !bus_hw_info) { + CAM_ERR(CAM_SFE, + "Invalid_params soc_info:%pK hw_intf:%pK hw_info:%pK data:%pK", + soc_info, hw_intf, bus_rd_hw_info); + rc = -EINVAL; + goto end; + } + + sfe_bus_local = kzalloc(sizeof(struct cam_sfe_bus), GFP_KERNEL); + if (!sfe_bus_local) { + CAM_DBG(CAM_SFE, "Failed to alloc for sfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_sfe_bus_rd_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_SFE, "Failed to alloc for sfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + + sfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = bus_rd_hw_info->num_client; + bus_priv->num_bus_rd_resc = + bus_rd_hw_info->num_bus_rd_resc; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, SFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.common_reg = &bus_rd_hw_info->common_reg; + bus_priv->top_irq_shift = bus_rd_hw_info->top_irq_shift; + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_sfe_bus_init_rm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_SFE, "Init RM failed rc=%d", rc); + goto deinit_rm; + } + } + + for (i = 0; i < bus_priv->num_bus_rd_resc; i++) { + rc = cam_sfe_bus_init_sfe_bus_read_resource(i, bus_priv, + bus_rd_hw_info); + if (rc < 0) { + CAM_ERR(CAM_SFE, "Init SFE RD failed rc=%d", rc); + goto deinit_sfe_bus_rd; + } + } + + sfe_bus_local->hw_ops.reserve = cam_sfe_bus_acquire_bus_rd; + sfe_bus_local->hw_ops.release = cam_sfe_bus_release_bus_rd; + sfe_bus_local->hw_ops.start = cam_sfe_bus_start_bus_rd; + sfe_bus_local->hw_ops.stop = cam_sfe_bus_stop_bus_rd; + sfe_bus_local->hw_ops.init = cam_sfe_bus_init_hw; + sfe_bus_local->hw_ops.deinit = cam_sfe_bus_deinit_hw; + sfe_bus_local->bottom_half_handler = NULL; + sfe_bus_local->hw_ops.process_cmd = cam_sfe_bus_rd_process_cmd; + + *sfe_bus = sfe_bus_local; + + return rc; + +deinit_sfe_bus_rd: + if (i < 0) + i = CAM_SFE_BUS_RD_MAX; + for (--i; i >= 0; i--) + cam_sfe_bus_deinit_sfe_bus_rd_resource( + &bus_priv->sfe_bus_rd[i]); +deinit_rm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_sfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + + kfree(sfe_bus_local->bus_priv); + +free_bus_local: + kfree(sfe_bus_local); + +end: + return rc; +} + +int cam_sfe_bus_rd_deinit( + struct cam_sfe_bus **sfe_bus) +{ + int i, rc = 0; + struct cam_sfe_bus_rd_priv *bus_priv = NULL; + struct cam_sfe_bus *sfe_bus_local; + + if (!sfe_bus || !*sfe_bus) { + CAM_ERR(CAM_SFE, "Invalid input"); + return -EINVAL; + } + sfe_bus_local = *sfe_bus; + + bus_priv = sfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_SFE, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_sfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_SFE, + "Deinit RM failed rc=%d", rc); + } + for (i = 0; i < CAM_SFE_BUS_RD_MAX; i++) { + rc = cam_sfe_bus_deinit_sfe_bus_rd_resource( + &bus_priv->sfe_bus_rd[i]); + if (rc < 0) + CAM_ERR(CAM_SFE, + "Deinit SFE RD failed rc=%d", rc); + } + + kfree(sfe_bus_local->bus_priv); + +free_bus_local: + kfree(sfe_bus_local); + + *sfe_bus = NULL; + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.h new file mode 100644 index 0000000000..e3dd098810 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_rd.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SFE_BUS_RD_H_ +#define _CAM_SFE_BUS_RD_H_ + +#include "cam_sfe_bus.h" + +#define CAM_SFE_BUS_RD_MAX_CLIENTS 3 + +enum cam_sfe_bus_rd_type { + CAM_SFE_BUS_RD_RDI0, + CAM_SFE_BUS_RD_RDI1, + CAM_SFE_BUS_RD_RDI2, + CAM_SFE_BUS_RD_MAX, +}; + +/* + * struct cam_sfe_bus_rd_reg_offset_common: + * + * @Brief: Common registers across BUS RD Clients + */ +struct cam_sfe_bus_rd_reg_offset_common { + uint32_t hw_version; + uint32_t misr_reset; + uint32_t pwr_iso_cfg; + uint32_t input_if_cmd; + uint32_t test_bus_ctrl; + uint32_t security_cfg; +}; + +/* + * struct cam_sfe_bus_rd_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS RD Clients + */ +struct cam_sfe_bus_rd_reg_offset_bus_client { + uint32_t cfg; + uint32_t image_addr; + uint32_t buf_width; + uint32_t buf_height; + uint32_t stride; + uint32_t unpacker_cfg; + uint32_t latency_buf_allocation; +}; + +/* + * struct cam_sfe_bus_rd_hw_info: + * + * @Brief: HW capability of SFE Bus RD Client + */ +struct cam_sfe_bus_rd_info { + enum cam_sfe_bus_rd_type sfe_bus_rd_type; + uint32_t max_width; + uint32_t max_height; +}; + +/* + * struct cam_sfe_bus_rd_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @num_client: Number of bus rd clients + * @bus_client_reg: Bus client register info + * @num_bus_rd_resc: Number of SFE BUS RD masters + * @sfe_bus_rd_info: SFE bus rd client info + * @top_irq_shift: Top irq shift val + */ +struct cam_sfe_bus_rd_hw_info { + struct cam_sfe_bus_rd_reg_offset_common common_reg; + uint32_t num_client; + struct cam_sfe_bus_rd_reg_offset_bus_client + bus_client_reg[CAM_SFE_BUS_RD_MAX_CLIENTS]; + uint32_t num_bus_rd_resc; + struct cam_sfe_bus_rd_info + sfe_bus_rd_info[CAM_SFE_BUS_RD_MAX]; + uint32_t top_irq_shift; +}; + +/* + * cam_sfe_bus_rd_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 + * @sfe_bus: Pointer to sfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_bus_rd_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + struct cam_sfe_bus **sfe_bus); + +/* + * cam_sfe_bus_rd_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @vfe_bus: Pointer to sfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_bus_rd_deinit(struct cam_sfe_bus **sfe_bus); + +#endif /* _CAM_SFE_BUS_RD_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c new file mode 100644 index 0000000000..9dac41227e --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c @@ -0,0 +1,1995 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + + +#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_ife_hw_mgr.h" +#include "cam_sfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_sfe_bus.h" +#include "cam_sfe_bus_wr.h" +#include "cam_sfe_core.h" +#include "cam_sfe_soc.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" +#include "cam_trace.h" + +static const char drv_name[] = "sfe_bus_wr"; + +#define CAM_SFE_BUS_WR_PAYLOAD_MAX 256 + +#define CAM_SFE_RDI_BUS_DEFAULT_WIDTH 0xFFFF +#define CAM_SFE_RDI_BUS_DEFAULT_STRIDE 0xFFFF + +#define MAX_BUF_UPDATE_REG_NUM \ + (sizeof(struct cam_sfe_bus_reg_offset_bus_client) / 4) +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +enum cam_sfe_bus_wr_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, + PACKER_FMT_MIPI10, + PACKER_FMT_MIPI12, + PACKER_FMT_MIPI14, + PACKER_FMT_MIPI20, + PACKER_FMT_PLAIN_32_20BPP, + PACKER_FMT_MAX, +}; + +struct cam_sfe_bus_wr_common_data { + uint32_t core_index; + uint32_t hw_version; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *buf_done_controller; + struct cam_sfe_bus_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + struct list_head free_payload_list; + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t addr_no_sync; + uint32_t comp_done_shift; + bool hw_init; + cam_hw_mgr_event_cb_func event_cb; +}; + +struct cam_sfe_wr_scratch_buf_info { + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t slice_height; + dma_addr_t io_addr; +}; + +struct cam_sfe_bus_wr_wm_resource_data { + uint32_t index; + struct cam_sfe_bus_wr_common_data *common_data; + struct cam_sfe_bus_reg_offset_bus_client *hw_regs; + struct cam_sfe_wr_scratch_buf_info scratch_buf_info; + + bool init_cfg_done; + bool hfr_cfg_done; + + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + enum cam_sfe_bus_wr_packer_format pack_fmt; + + uint32_t packer_cfg; + uint32_t h_init; + + 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; + + uint32_t acquired_width; + uint32_t acquired_height; +}; + +struct cam_sfe_bus_wr_comp_grp_data { + enum cam_sfe_bus_wr_comp_grp_type comp_grp_type; + struct cam_sfe_bus_wr_common_data *common_data; + + uint32_t is_master; + uint32_t is_dual; + uint32_t dual_slave_core; + uint32_t intra_client_mask; + uint32_t addr_sync_mode; + uint32_t composite_mask; + + uint32_t acquire_dev_cnt; + uint32_t irq_trigger_cnt; +}; + +struct cam_sfe_bus_wr_out_data { + uint32_t out_type; + uint32_t source_group; + struct cam_sfe_bus_wr_common_data *common_data; + + uint32_t num_wm; + struct cam_isp_resource_node *wm_res; + + struct cam_isp_resource_node *comp_grp; + struct list_head sfe_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; +}; + +struct cam_sfe_bus_wr_priv { + struct cam_sfe_bus_wr_common_data common_data; + uint32_t num_client; + uint32_t num_out; + uint32_t num_comp_grp; + uint32_t top_irq_shift; + + struct cam_isp_resource_node *comp_grp; + struct cam_isp_resource_node *sfe_out; + + struct list_head free_comp_grp; + struct list_head used_comp_grp; + + //int bus_irq_handle; + //int rup_irq_handle; + //int error_irq_handle; + //void *tasklet_info; +}; + +static int cam_sfe_bus_wr_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, + uint32_t arg_size); + +static bool cam_sfe_bus_can_be_secure(uint32_t out_type) +{ + switch (out_type) { + case CAM_SFE_BUS_SFE_OUT_RAW_DUMP: + case CAM_SFE_BUS_SFE_OUT_RDI0: + case CAM_SFE_BUS_SFE_OUT_RDI1: + case CAM_SFE_BUS_SFE_OUT_RDI2: + case CAM_SFE_BUS_SFE_OUT_RDI3: + case CAM_SFE_BUS_SFE_OUT_RDI4: + return true; + case CAM_SFE_BUS_SFE_OUT_LCR: + case CAM_SFE_BUS_SFE_OUT_BE_0: + case CAM_SFE_BUS_SFE_OUT_BHIST_0: + case CAM_SFE_BUS_SFE_OUT_BE_1: + case CAM_SFE_BUS_SFE_OUT_BHIST_1: + case CAM_SFE_BUS_SFE_OUT_BE_2: + case CAM_SFE_BUS_SFE_OUT_BHIST_2: + default: + return false; + } +} + +static enum cam_sfe_bus_sfe_out_type + cam_sfe_bus_wr_get_out_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_SFE_OUT_RES_RAW_DUMP: + return CAM_SFE_BUS_SFE_OUT_RAW_DUMP; + case CAM_ISP_SFE_OUT_RES_RDI_0: + return CAM_SFE_BUS_SFE_OUT_RDI0; + case CAM_ISP_SFE_OUT_RES_RDI_1: + return CAM_SFE_BUS_SFE_OUT_RDI1; + case CAM_ISP_SFE_OUT_RES_RDI_2: + return CAM_SFE_BUS_SFE_OUT_RDI2; + case CAM_ISP_SFE_OUT_RES_RDI_3: + return CAM_SFE_BUS_SFE_OUT_RDI3; + case CAM_ISP_SFE_OUT_RES_RDI_4: + return CAM_SFE_BUS_SFE_OUT_RDI4; + case CAM_ISP_SFE_OUT_BE_STATS_0: + return CAM_SFE_BUS_SFE_OUT_BE_0; + case CAM_ISP_SFE_OUT_BHIST_STATS_0: + return CAM_SFE_BUS_SFE_OUT_BHIST_0; + case CAM_ISP_SFE_OUT_BE_STATS_1: + return CAM_SFE_BUS_SFE_OUT_BE_1; + case CAM_ISP_SFE_OUT_BHIST_STATS_1: + return CAM_SFE_BUS_SFE_OUT_BHIST_1; + case CAM_ISP_SFE_OUT_BE_STATS_2: + return CAM_SFE_BUS_SFE_OUT_BE_2; + case CAM_ISP_SFE_OUT_BHIST_STATS_2: + return CAM_SFE_BUS_SFE_OUT_BHIST_2; + case CAM_ISP_SFE_OUT_RES_LCR: + return CAM_SFE_BUS_SFE_OUT_LCR; + default: + return CAM_SFE_BUS_SFE_OUT_MAX; + } +} + +static enum cam_sfe_bus_wr_packer_format + cam_sfe_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_16: + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PD8: + return PACKER_FMT_PLAIN_128; + case CAM_FORMAT_MIPI_RAW_10: + if (wm_index == 0) + return PACKER_FMT_MIPI10; + else + return PACKER_FMT_PLAIN_128; + case CAM_FORMAT_MIPI_RAW_12: + if (wm_index == 0) + return PACKER_FMT_MIPI12; + else + return PACKER_FMT_PLAIN_128; + case CAM_FORMAT_MIPI_RAW_14: + if (wm_index == 0) + return PACKER_FMT_MIPI14; + else + return PACKER_FMT_PLAIN_128; + case CAM_FORMAT_MIPI_RAW_20: + if (wm_index == 0) + return PACKER_FMT_MIPI20; + else + return PACKER_FMT_PLAIN_128; + case CAM_FORMAT_PLAIN8: + return PACKER_FMT_PLAIN_8; + case CAM_FORMAT_NV12: + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + 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_PLAIN32: + case CAM_FORMAT_ARGB: + return PACKER_FMT_PLAIN_32; + case CAM_FORMAT_PLAIN64: + case CAM_FORMAT_ARGB_16: + case CAM_FORMAT_PD10: + return PACKER_FMT_PLAIN_64; + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_TP10: + return PACKER_FMT_TP_10; + default: + return PACKER_FMT_MAX; + } +} + +static int cam_sfe_bus_acquire_wm( + struct cam_sfe_bus_wr_priv *bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + enum cam_sfe_bus_sfe_out_type sfe_out_res_id, + enum cam_sfe_bus_plane_type plane, + struct cam_isp_resource_node *wm_res, + uint32_t *comp_done_mask, + uint32_t is_dual, + enum cam_sfe_bus_wr_comp_grp_type *comp_grp_id) +{ + int32_t wm_idx = 0; + struct cam_sfe_bus_wr_wm_resource_data *rsrc_data = NULL; + char wm_mode[50] = {0}; + + if (wm_res->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_SFE, "WM:%d not available state:%d", + wm_idx, wm_res->res_state); + return -EALREADY; + } + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + wm_res->tasklet_info = tasklet; + + rsrc_data = wm_res->res_priv; + wm_idx = rsrc_data->index; + rsrc_data->format = out_port_info->format; + rsrc_data->pack_fmt = cam_sfe_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->is_dual = is_dual; + /* Set WM offset value to default */ + rsrc_data->offset = 0; + CAM_DBG(CAM_SFE, "WM:%d width %d height %d", rsrc_data->index, + rsrc_data->width, rsrc_data->height); + + if ((sfe_out_res_id >= CAM_SFE_BUS_SFE_OUT_RDI0) && + (sfe_out_res_id <= CAM_SFE_BUS_SFE_OUT_RDI4)) { + + rsrc_data->pack_fmt = 0x0; + 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_MIPI_RAW_20: + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PLAIN32_20: + rsrc_data->width = CAM_SFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = CAM_SFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + break; + case CAM_FORMAT_PLAIN8: + rsrc_data->en_cfg = 0x1; + 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 = + ALIGNUP(rsrc_data->width * 2, 16) / 16; + rsrc_data->en_cfg = 0x1; + break; + case CAM_FORMAT_PLAIN64: + rsrc_data->width = + ALIGNUP(rsrc_data->width * 8, 16) / 16; + rsrc_data->en_cfg = 0x1; + break; + default: + CAM_ERR(CAM_SFE, "Unsupported RDI format %d", + rsrc_data->format); + return -EINVAL; + } + + } else if (sfe_out_res_id == CAM_SFE_BUS_SFE_OUT_RAW_DUMP) { + rsrc_data->stride = rsrc_data->width; + rsrc_data->en_cfg = 0x1; + } else if ((sfe_out_res_id >= CAM_SFE_BUS_SFE_OUT_BE_0) && + (sfe_out_res_id <= CAM_SFE_BUS_SFE_OUT_BHIST_2)) { + + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + + } else if (sfe_out_res_id == CAM_SFE_BUS_SFE_OUT_LCR) { + + switch (rsrc_data->format) { + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + rsrc_data->stride = ALIGNUP(rsrc_data->width * 2, 8); + rsrc_data->en_cfg = 0x1; + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x20; + break; + default: + CAM_ERR(CAM_SFE, "Invalid format %d out_type:%d", + rsrc_data->format, sfe_out_res_id); + return -EINVAL; + } + + } else { + CAM_ERR(CAM_SFE, "Invalid out_type:%d requested", + sfe_out_res_id); + return -EINVAL; + } + + *comp_grp_id = rsrc_data->hw_regs->comp_group; + *comp_done_mask |= (1 << sfe_out_res_id); + + switch (rsrc_data->en_cfg) { + case 0x1: + strlcpy(wm_mode, "line-based", sizeof(wm_mode)); + break; + case ((0x1 << 16) | 0x1): + strlcpy(wm_mode, "frame-based", sizeof(wm_mode)); + break; + case ((0x2 << 16) | 0x1): + strlcpy(wm_mode, "index-based", sizeof(wm_mode)); + break; + } + + CAM_DBG(CAM_SFE, + "SFE:%d WM:%d processed width:%d height:%d format:0x%X pack_fmt 0x%x %s", + rsrc_data->common_data->core_index, rsrc_data->index, + rsrc_data->width, rsrc_data->height, rsrc_data->format, + rsrc_data->pack_fmt, wm_mode); + return 0; +} + +static int cam_sfe_bus_release_wm(void *bus_priv, + struct cam_isp_resource_node *wm_res) +{ + struct cam_sfe_bus_wr_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->irq_subsample_period = 0; + rsrc_data->irq_subsample_pattern = 0; + rsrc_data->framedrop_period = 0; + rsrc_data->framedrop_pattern = 0; + rsrc_data->packer_cfg = 0; + rsrc_data->h_init = 0; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + 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_SFE, "SFE:%d Release WM:%d", + rsrc_data->common_data->core_index, rsrc_data->index); + + return 0; +} + +static int cam_sfe_bus_start_wm(struct cam_isp_resource_node *wm_res) +{ + const uint32_t image_cfg_height_shift_val = 16; + struct cam_sfe_bus_wr_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_sfe_bus_wr_common_data *common_data = + rsrc_data->common_data; + + cam_io_w((rsrc_data->height << image_cfg_height_shift_val) + | 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); + + /* Enable WM */ + cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + + rsrc_data->hw_regs->cfg); + + CAM_DBG(CAM_SFE, + "Start SFE:%d WM:%d offset:0x%X en_cfg:0x%X width:%d height:%d", + rsrc_data->common_data->core_index, rsrc_data->index, + (uint32_t) rsrc_data->hw_regs->cfg, rsrc_data->en_cfg, + rsrc_data->width, rsrc_data->height); + CAM_DBG(CAM_SFE, "WM:%d pk_fmt:%d stride:%d", + rsrc_data->index, rsrc_data->pack_fmt & PACKER_FMT_MAX, + rsrc_data->stride); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_sfe_bus_stop_wm(struct cam_isp_resource_node *wm_res) +{ + struct cam_sfe_bus_wr_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_sfe_bus_wr_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_SFE, "Stop SFE:%d WM:%d", + rsrc_data->common_data->core_index, rsrc_data->index); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + + return 0; +} + +static int cam_sfe_bus_handle_wm_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_sfe_bus_handle_wm_done_bottom_half(void *wm_node, + void *evt_payload_priv) +{ + return -EPERM; +} + +static int cam_sfe_bus_init_wm_resource(uint32_t index, + struct cam_sfe_bus_wr_priv *bus_priv, + struct cam_sfe_bus_wr_hw_info *hw_info, + struct cam_isp_resource_node *wm_res) +{ + struct cam_sfe_bus_wr_wm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_sfe_bus_wr_wm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_SFE, "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_sfe_bus_start_wm; + wm_res->stop = cam_sfe_bus_stop_wm; + wm_res->top_half_handler = cam_sfe_bus_handle_wm_done_top_half; + wm_res->bottom_half_handler = + cam_sfe_bus_handle_wm_done_bottom_half; + wm_res->hw_intf = bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_sfe_bus_deinit_wm_resource( + struct cam_isp_resource_node *wm_res) +{ + struct cam_sfe_bus_wr_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_sfe_bus_add_wm_to_comp_grp( + struct cam_isp_resource_node *comp_grp, + uint32_t composite_mask) +{ + struct cam_sfe_bus_wr_comp_grp_data *rsrc_data = comp_grp->res_priv; + + rsrc_data->composite_mask |= composite_mask; +} + +static bool cam_sfe_bus_match_comp_grp( + struct cam_sfe_bus_wr_priv *bus_priv, + struct cam_isp_resource_node **comp_grp, + uint32_t comp_grp_id) +{ + struct cam_sfe_bus_wr_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_type == 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_type == 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_sfe_bus_acquire_comp_grp( + struct cam_sfe_bus_wr_priv *bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + uint32_t is_dual, + uint32_t is_master, + struct cam_isp_resource_node **comp_grp, + enum cam_sfe_bus_wr_comp_grp_type comp_grp_id) +{ + int rc = 0; + struct cam_isp_resource_node *comp_grp_local = NULL; + struct cam_sfe_bus_wr_comp_grp_data *rsrc_data = NULL; + bool previously_acquired = false; + + /* Check if matching comp_grp has already been acquired */ + previously_acquired = cam_sfe_bus_match_comp_grp( + bus_priv, &comp_grp_local, comp_grp_id); + + if (!comp_grp_local) { + CAM_ERR(CAM_SFE, "Invalid comp_grp:%d", comp_grp_id); + return -ENODEV; + } + + rsrc_data = comp_grp_local->res_priv; + + if (!previously_acquired) { + rsrc_data->intra_client_mask = 0x1; + 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_SFE, "Invalid State %d comp_grp:%u", + comp_grp_local->res_state, + rsrc_data->comp_grp_type); + return -EBUSY; + } + } + + CAM_DBG(CAM_SFE, "Acquire SFE:%d comp_grp:%u", + rsrc_data->common_data->core_index, rsrc_data->comp_grp_type); + + rsrc_data->acquire_dev_cnt++; + *comp_grp = comp_grp_local; + + return rc; +} + +static int cam_sfe_bus_release_comp_grp( + struct cam_sfe_bus_wr_priv *bus_priv, + struct cam_isp_resource_node *in_comp_grp) +{ + struct cam_isp_resource_node *comp_grp = NULL; + struct cam_sfe_bus_wr_comp_grp_data *in_rsrc_data = NULL; + int match_found = 0; + + if (!in_comp_grp) { + CAM_ERR(CAM_SFE, "Invalid Params comp_grp %pK", in_comp_grp); + return -EINVAL; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_SFE, "Already released comp_grp"); + return 0; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_SFE, "Invalid State %d", + in_comp_grp->res_state); + return -EBUSY; + } + + in_rsrc_data = in_comp_grp->res_priv; + CAM_DBG(CAM_SFE, "Release SFE:%d comp_grp:%u", + bus_priv->common_data.core_index, + in_rsrc_data->comp_grp_type); + + list_for_each_entry(comp_grp, &bus_priv->used_comp_grp, list) { + if (comp_grp == in_comp_grp) { + match_found = 1; + break; + } + } + + if (!match_found) { + CAM_ERR(CAM_SFE, "Could not find comp_grp:%u", + in_rsrc_data->comp_grp_type); + return -ENODEV; + } + + in_rsrc_data->acquire_dev_cnt--; + if (in_rsrc_data->acquire_dev_cnt == 0) { + list_del(&comp_grp->list); + + in_rsrc_data->dual_slave_core = CAM_SFE_BUS_SFE_CORE_MAX; + in_rsrc_data->addr_sync_mode = 0; + in_rsrc_data->composite_mask = 0; + + comp_grp->tasklet_info = NULL; + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + list_add_tail(&comp_grp->list, &bus_priv->free_comp_grp); + } + + return 0; +} + +static int cam_sfe_bus_start_comp_grp( + struct cam_isp_resource_node *comp_grp, + uint32_t *bus_irq_reg_mask) +{ + int rc = 0; + struct cam_sfe_bus_wr_comp_grp_data *rsrc_data = NULL; + struct cam_sfe_bus_wr_common_data *common_data = NULL; + + rsrc_data = comp_grp->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_SFE, + "Start SFE:%d comp_grp:%d streaming state:%d comp_mask:0x%X", + rsrc_data->common_data->core_index, + rsrc_data->comp_grp_type, comp_grp->res_state, + rsrc_data->composite_mask); + + if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + return 0; + + /* TO DO Enable top irq */ + + CAM_DBG(CAM_SFE, "Start Done SFE:%d comp_grp:%d", + rsrc_data->common_data->core_index, + rsrc_data->comp_grp_type, + bus_irq_reg_mask[0]); + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return rc; +} + +static inline int cam_sfe_bus_stop_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return 0; +} + +static int cam_sfe_bus_wr_init_comp_grp(uint32_t index, + struct cam_hw_soc_info *soc_info, + struct cam_sfe_bus_wr_priv *bus_priv, + struct cam_sfe_bus_wr_hw_info *hw_info, + struct cam_isp_resource_node *comp_grp) +{ + struct cam_sfe_bus_wr_comp_grp_data *rsrc_data = NULL; + + rsrc_data = kzalloc(sizeof(struct cam_sfe_bus_wr_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); + + rsrc_data->comp_grp_type = index; + rsrc_data->common_data = &bus_priv->common_data; + rsrc_data->dual_slave_core = CAM_SFE_BUS_SFE_CORE_MAX; + + list_add_tail(&comp_grp->list, &bus_priv->free_comp_grp); + + /* TO DO set top half */ + comp_grp->top_half_handler = NULL; + comp_grp->hw_intf = bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_sfe_bus_deinit_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + struct cam_sfe_bus_wr_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_SFE, "comp_grp_priv is NULL"); + return -ENODEV; + } + kfree(rsrc_data); + + return 0; +} + +static int cam_sfe_bus_wr_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *secure_mode = cmd_args; + struct cam_sfe_bus_wr_out_data *rsrc_data; + uint32_t *mode; + + rsrc_data = (struct cam_sfe_bus_wr_out_data *) + secure_mode->res->res_priv; + mode = (uint32_t *)secure_mode->data; + *mode = (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? + true : false; + + return 0; +} + +static int cam_sfe_bus_acquire_sfe_out(void *priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_sfe_bus_sfe_out_type sfe_out_res_id; + uint32_t format; + struct cam_sfe_bus_wr_priv *bus_priv = priv; + struct cam_sfe_acquire_args *acq_args = acquire_args; + struct cam_sfe_hw_sfe_out_acquire_args *out_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_sfe_bus_wr_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0, mode; + enum cam_sfe_bus_wr_comp_grp_type comp_grp_id; + uint32_t client_done_mask = 0; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_SFE, "Invalid Param"); + return -EINVAL; + } + + out_acquire_args = &acq_args->sfe_out; + format = out_acquire_args->out_port_info->format; + + CAM_DBG(CAM_SFE, "SFE:%d Acquire out_type:0x%X", + bus_priv->common_data.core_index, + out_acquire_args->out_port_info->res_type); + + sfe_out_res_id = cam_sfe_bus_wr_get_out_res_id( + out_acquire_args->out_port_info->res_type); + if (sfe_out_res_id == CAM_SFE_BUS_SFE_OUT_MAX) + return -ENODEV; + + rsrc_node = &bus_priv->sfe_out[sfe_out_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_SFE, + "SFE:%d out_type:0x%X resource not available state:%d", + bus_priv->common_data.core_index, + sfe_out_res_id, rsrc_node->res_state); + return -EBUSY; + } + + if (!acq_args->buf_done_controller) { + CAM_ERR(CAM_SFE, "Invalid buf done controller"); + return -EINVAL; + } + + rsrc_data = rsrc_node->res_priv; + rsrc_data->common_data->buf_done_controller = + acq_args->buf_done_controller; + rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->priv = acq_args->priv; + secure_caps = cam_sfe_bus_can_be_secure( + rsrc_data->out_type); + 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_SFE, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return rc; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + //bus_priv->tasklet_info = acq_args->tasklet; + rsrc_node->rdi_only_ctx = 0; + rsrc_node->res_id = out_acquire_args->out_port_info->res_type; + rsrc_node->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = out_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = out_acquire_args->cdm_ops; + rsrc_data->format = out_acquire_args->out_port_info->format; + + /* Acquire WM and retrieve COMP GRP ID */ + for (i = 0; i < rsrc_data->num_wm; i++) { + rc = cam_sfe_bus_acquire_wm(bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + sfe_out_res_id, + i, + &rsrc_data->wm_res[i], + &client_done_mask, + out_acquire_args->is_dual, + &comp_grp_id); + if (rc) { + CAM_ERR(CAM_SFE, + "Failed to acquire WM SFE:%d out_type:%d rc:%d", + rsrc_data->common_data->core_index, + sfe_out_res_id, rc); + goto release_wm; + } + } + + /* Acquire composite group using COMP GRP ID */ + rc = cam_sfe_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); + if (rc) { + CAM_ERR(CAM_SFE, + "Failed to acquire comp_grp SFE:%d out_type:%d rc:%d", + rsrc_data->common_data->core_index, + sfe_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_sfe_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; + + CAM_DBG(CAM_SFE, "Acquire successful"); + return rc; + +release_wm: + for (i--; i >= 0; i--) + cam_sfe_bus_release_wm(bus_priv, + &rsrc_data->wm_res[i]); + + cam_sfe_bus_release_comp_grp(bus_priv, rsrc_data->comp_grp); + + return rc; +} + +static int cam_sfe_bus_release_sfe_out(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *sfe_out = NULL; + struct cam_sfe_bus_wr_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_SFE, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + sfe_out = release_args; + rsrc_data = sfe_out->res_priv; + + if (sfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_SFE, + "Invalid resource state:%d SFE:%d out_type:0x%X", + sfe_out->res_state, rsrc_data->common_data->core_index, + sfe_out->res_id); + } + + for (i = 0; i < rsrc_data->num_wm; i++) + cam_sfe_bus_release_wm(bus_priv, &rsrc_data->wm_res[i]); + rsrc_data->num_wm = 0; + + if (rsrc_data->comp_grp) + cam_sfe_bus_release_comp_grp(bus_priv, + rsrc_data->comp_grp); + rsrc_data->comp_grp = NULL; + + sfe_out->tasklet_info = NULL; + sfe_out->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_sfe_bus_can_be_secure(rsrc_data->out_type); + 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_SFE, "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 (sfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + sfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_sfe_bus_start_sfe_out( + struct cam_isp_resource_node *sfe_out) +{ + int rc = 0, i; + struct cam_sfe_bus_wr_out_data *rsrc_data = NULL; + struct cam_sfe_bus_wr_common_data *common_data = NULL; + uint32_t bus_irq_reg_mask[2]; + uint32_t source_group = 0; + + if (!sfe_out) { + CAM_ERR(CAM_SFE, "Invalid input"); + return -EINVAL; + } + + rsrc_data = sfe_out->res_priv; + common_data = rsrc_data->common_data; + source_group = rsrc_data->source_group; + + if (sfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_SFE, + "Invalid resource state:%d SFE:%d out_type:0x%X", + sfe_out->res_state, rsrc_data->common_data->core_index, + rsrc_data->out_type); + return -EACCES; + } + + CAM_DBG(CAM_SFE, "Start SFE:%d out_type:0x%X", + rsrc_data->common_data->core_index, rsrc_data->out_type); + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_sfe_bus_start_wm(&rsrc_data->wm_res[i]); + + memset(bus_irq_reg_mask, 0, sizeof(bus_irq_reg_mask)); + rc = cam_sfe_bus_start_comp_grp(rsrc_data->comp_grp, + bus_irq_reg_mask); + + if (rsrc_data->is_dual && !rsrc_data->is_master) + goto end; + + /* TO DO IRQ handling */ + +end: + sfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_sfe_bus_stop_sfe_out( + struct cam_isp_resource_node *sfe_out) +{ + int rc = 0, i; + struct cam_sfe_bus_wr_out_data *rsrc_data = NULL; + struct cam_sfe_bus_wr_common_data *common_data = NULL; + + if (!sfe_out) { + CAM_ERR(CAM_SFE, "Invalid input"); + return -EINVAL; + } + + rsrc_data = sfe_out->res_priv; + common_data = rsrc_data->common_data; + + if (sfe_out->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + sfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_SFE, "Stop SFE:%d out_type:0x%X state:%d", + rsrc_data->common_data->core_index, rsrc_data->out_type, + sfe_out->res_state); + return rc; + } + + rc = cam_sfe_bus_stop_comp_grp(rsrc_data->comp_grp); + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_sfe_bus_stop_wm(&rsrc_data->wm_res[i]); + + /* TO DO any IRQ handling */ + sfe_out->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_sfe_bus_init_sfe_out_resource( + uint32_t index, + struct cam_sfe_bus_wr_priv *bus_priv, + struct cam_sfe_bus_wr_hw_info *hw_info) +{ + struct cam_isp_resource_node *sfe_out = NULL; + struct cam_sfe_bus_wr_out_data *rsrc_data = NULL; + int rc = 0, i = 0; + int32_t sfe_out_type = + hw_info->sfe_out_hw_info[index].sfe_out_type; + + if (sfe_out_type < 0 || + sfe_out_type >= CAM_SFE_BUS_SFE_OUT_MAX) { + CAM_ERR(CAM_SFE, "Init SFE Out failed, Invalid type=%d", + sfe_out_type); + return -EINVAL; + } + + sfe_out = &bus_priv->sfe_out[sfe_out_type]; + if (sfe_out->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + sfe_out->res_priv) { + CAM_ERR(CAM_SFE, "sfe_out_type %d has already been initialized", + sfe_out_type); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_sfe_bus_wr_out_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + sfe_out->res_priv = rsrc_data; + + sfe_out->res_type = CAM_ISP_RESOURCE_SFE_OUT; + sfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&sfe_out->list); + + rsrc_data->source_group = + hw_info->sfe_out_hw_info[index].source_group; + rsrc_data->out_type = + hw_info->sfe_out_hw_info[index].sfe_out_type; + rsrc_data->common_data = &bus_priv->common_data; + rsrc_data->max_width = + hw_info->sfe_out_hw_info[index].max_width; + rsrc_data->max_height = + hw_info->sfe_out_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + rsrc_data->num_wm = hw_info->sfe_out_hw_info[index].num_wm; + + rsrc_data->wm_res = kzalloc((sizeof(struct cam_isp_resource_node) * + rsrc_data->num_wm), GFP_KERNEL); + if (!rsrc_data->wm_res) { + CAM_ERR(CAM_SFE, "Failed to alloc for wm_res"); + return -ENOMEM; + } + + rc = cam_sfe_bus_init_wm_resource( + hw_info->sfe_out_hw_info[index].wm_idx, + bus_priv, hw_info, + &rsrc_data->wm_res[i]); + if (rc < 0) { + CAM_ERR(CAM_SFE, "SFE:%d init WM:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + return rc; + } + + /* TO DO top & bh */ + sfe_out->start = cam_sfe_bus_start_sfe_out; + sfe_out->stop = cam_sfe_bus_stop_sfe_out; + sfe_out->top_half_handler = NULL; + sfe_out->bottom_half_handler = NULL; + sfe_out->process_cmd = cam_sfe_bus_wr_process_cmd; + sfe_out->hw_intf = bus_priv->common_data.hw_intf; + sfe_out->irq_handle = 0; + + return 0; +} + +static int cam_sfe_bus_deinit_sfe_out_resource( + struct cam_isp_resource_node *sfe_out) +{ + struct cam_sfe_bus_wr_out_data *rsrc_data = sfe_out->res_priv; + int rc = 0, i = 0; + + if (sfe_out->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + return 0; + } + + sfe_out->start = NULL; + sfe_out->stop = NULL; + sfe_out->top_half_handler = NULL; + sfe_out->bottom_half_handler = NULL; + sfe_out->hw_intf = NULL; + sfe_out->irq_handle = 0; + + sfe_out->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&sfe_out->list); + sfe_out->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + + for (i = 0; i < rsrc_data->num_wm; i++) { + rc = cam_sfe_bus_deinit_wm_resource(&rsrc_data->wm_res[i]); + if (rc < 0) + CAM_ERR(CAM_SFE, + "SFE:%d deinit WM:%d failed rc:%d", + rsrc_data->common_data->core_index, i, rc); + } + + kfree(rsrc_data); + + return 0; +} + +static int cam_sfe_bus_wr_print_dimensions( + enum cam_sfe_bus_sfe_out_type sfe_out_res_id, + struct cam_sfe_bus_wr_priv *bus_priv) +{ + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_sfe_bus_wr_out_data *rsrc_data = NULL; + struct cam_sfe_bus_wr_wm_resource_data *wm_data = NULL; + int i, wm_idx; + + rsrc_node = &bus_priv->sfe_out[sfe_out_res_id]; + rsrc_data = rsrc_node->res_priv; + for (i = 0; i < rsrc_data->num_wm; i++) { + wm_data = (struct cam_sfe_bus_wr_wm_resource_data *) + &rsrc_data->wm_res[i].res_priv; + wm_idx = wm_data->index; + if (wm_idx < 0 || wm_idx >= bus_priv->num_client) { + CAM_ERR(CAM_SFE, "Unsupported SFE out %d", + sfe_out_res_id); + return -EINVAL; + } + + CAM_INFO(CAM_SFE, + "SFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u acquired width:%u height:%u", + wm_data->common_data->core_index, wm_idx, + wm_data->width, + wm_data->height, + wm_data->stride, wm_data->h_init, + wm_data->en_cfg, + wm_data->acquired_width, + wm_data->acquired_height); + } + return 0; +} + +static int cam_sfe_bus_wr_update_wm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_sfe_bus_wr_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg = NULL; + struct cam_sfe_bus_wr_out_data *sfe_out_data = NULL; + struct cam_sfe_bus_wr_wm_resource_data *wm_data = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, k, size = 0; + uint32_t frame_inc = 0, val; + uint32_t loop_size = 0, stride = 0, slice_h = 0; + + bus_priv = (struct cam_sfe_bus_wr_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + sfe_out_data = (struct cam_sfe_bus_wr_out_data *) + update_buf->res->res_priv; + + if (!sfe_out_data || !sfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_SFE, "Failed! Invalid data"); + return -EINVAL; + } + + if (update_buf->wm_update->num_buf != sfe_out_data->num_wm) { + CAM_ERR(CAM_SFE, + "Failed! Invalid number buffers:%d required:%d", + update_buf->wm_update->num_buf, sfe_out_data->num_wm); + return -EINVAL; + } + + reg_val_pair = &sfe_out_data->common_data->io_buf_update[0]; + if (update_buf->use_scratch_cfg) + CAM_DBG(CAM_SFE, "Using scratch buf config"); + else + io_cfg = update_buf->wm_update->io_cfg; + + for (i = 0, j = 0; i < sfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_SFE, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = (struct cam_sfe_bus_wr_wm_resource_data *) + sfe_out_data->wm_res[i].res_priv; + + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->cfg, wm_data->en_cfg); + CAM_DBG(CAM_SFE, "WM:%d en_cfg 0x%X", + wm_data->index, reg_val_pair[j-1]); + + val = (wm_data->height << 16) | wm_data->width; + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_0, val); + CAM_DBG(CAM_SFE, "WM:%d image height and width 0x%X", + wm_data->index, reg_val_pair[j-1]); + + /* For initial configuration program all bus registers */ + if (update_buf->use_scratch_cfg) { + stride = update_buf->wm_update->stride; + slice_h = update_buf->wm_update->slice_height; + } else { + stride = io_cfg->planes[i].plane_stride; + slice_h = io_cfg->planes[i].slice_height; + } + + val = stride; + CAM_DBG(CAM_SFE, "before stride %d", val); + val = ALIGNUP(val, 16); + if (val != stride && + val != wm_data->stride) + CAM_WARN(CAM_SFE, "Warning stride %u expected %u", + stride, val); + + if (wm_data->stride != val || !wm_data->init_cfg_done) { + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_2, + stride); + wm_data->stride = val; + CAM_DBG(CAM_SFE, "WM:%d image stride 0x%X", + wm_data->index, reg_val_pair[j-1]); + } + + frame_inc = stride * slice_h; + + if (!(wm_data->en_cfg & (0x3 << 16))) { + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_1, wm_data->h_init); + CAM_DBG(CAM_SFE, "WM:%d h_init 0x%X", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->index > 7) + loop_size = wm_data->irq_subsample_period + 1; + else + loop_size = 1; + + /* WM Image address */ + for (k = 0; k < loop_size; k++) { + if (wm_data->en_cfg & (0x3 << 16)) + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + (update_buf->wm_update->image_buf[i] + + wm_data->offset + k * frame_inc)); + else + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + (update_buf->wm_update->image_buf[i] + + k * frame_inc)); + + CAM_DBG(CAM_SFE, "WM:%d image address 0x%X", + wm_data->index, reg_val_pair[j-1]); + } + + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->frame_incr, frame_inc); + CAM_DBG(CAM_SFE, "WM:%d frame_inc %d", + wm_data->index, reg_val_pair[j-1]); + + /* enable the WM */ + CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->cfg, + wm_data->en_cfg); + + /* set initial configuration done */ + if (!wm_data->init_cfg_done) + wm_data->init_cfg_done = true; + } + + size = sfe_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_SFE, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + sfe_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_sfe_bus_wr_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_sfe_bus_wr_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_hfr; + struct cam_sfe_bus_wr_out_data *sfe_out_data = NULL; + struct cam_sfe_bus_wr_wm_resource_data *wm_data = NULL; + struct cam_isp_port_hfr_config *hfr_cfg = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + + bus_priv = (struct cam_sfe_bus_wr_priv *) priv; + update_hfr = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + sfe_out_data = (struct cam_sfe_bus_wr_out_data *) + update_hfr->res->res_priv; + + if (!sfe_out_data || !sfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_SFE, "Failed! Invalid data"); + return -EINVAL; + } + + reg_val_pair = &sfe_out_data->common_data->io_buf_update[0]; + hfr_cfg = (struct cam_isp_port_hfr_config *)update_hfr->data; + + for (i = 0, j = 0; i < sfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_SFE, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = sfe_out_data->wm_res[i].res_priv; + if ((wm_data->framedrop_pattern != + hfr_cfg->framedrop_pattern) || + !wm_data->hfr_cfg_done) { + CAM_SFE_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_SFE, "WM:%d framedrop pattern 0x%X", + wm_data->index, wm_data->framedrop_pattern); + } + + if (wm_data->framedrop_period != hfr_cfg->framedrop_period || + !wm_data->hfr_cfg_done) { + CAM_SFE_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_SFE, "WM:%d framedrop period 0x%X", + wm_data->index, wm_data->framedrop_period); + } + + if (wm_data->irq_subsample_period != hfr_cfg->subsample_period + || !wm_data->hfr_cfg_done) { + CAM_SFE_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_SFE, "WM:%d irq subsample period 0x%X", + wm_data->index, wm_data->irq_subsample_period); + } + + if (wm_data->irq_subsample_pattern != hfr_cfg->subsample_pattern + || !wm_data->hfr_cfg_done) { + CAM_SFE_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_SFE, "WM:%d irq subsample pattern 0x%X", + wm_data->index, wm_data->irq_subsample_pattern); + } + + /* set initial configuration done */ + if (!wm_data->hfr_cfg_done) + wm_data->hfr_cfg_done = true; + } + + size = sfe_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_SFE, + "Failed! Buf size:%d insufficient, expected size:%d", + update_hfr->cmd.size, size); + return -ENOMEM; + } + + sfe_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_sfe_bus_wr_update_stripe_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_sfe_bus_wr_priv *bus_priv; + struct cam_isp_hw_dual_isp_update_args *stripe_args; + struct cam_sfe_bus_wr_out_data *sfe_out_data = NULL; + struct cam_sfe_bus_wr_wm_resource_data *wm_data = NULL; + struct cam_isp_dual_stripe_config *stripe_config; + uint32_t outport_id, ports_plane_idx, i; + + bus_priv = (struct cam_sfe_bus_wr_priv *) priv; + stripe_args = (struct cam_isp_hw_dual_isp_update_args *)cmd_args; + + sfe_out_data = (struct cam_sfe_bus_wr_out_data *) + stripe_args->res->res_priv; + + if (!sfe_out_data) { + CAM_ERR(CAM_SFE, "Failed! Invalid data"); + return -EINVAL; + } + + outport_id = stripe_args->res->res_id & 0xFF; + if (stripe_args->res->res_id < CAM_ISP_SFE_OUT_RES_BASE || + stripe_args->res->res_id >= CAM_ISP_SFE_OUT_RES_MAX) + return 0; + + ports_plane_idx = (stripe_args->split_id * + (stripe_args->dual_cfg->num_ports * CAM_PACKET_MAX_PLANES)) + + (outport_id * CAM_PACKET_MAX_PLANES); + for (i = 0; i < sfe_out_data->num_wm; i++) { + wm_data = sfe_out_data->wm_res[i].res_priv; + stripe_config = (struct cam_isp_dual_stripe_config *) + &stripe_args->dual_cfg->stripes[ports_plane_idx + i]; + wm_data->width = stripe_config->width; + + /* + * UMD sends buffer offset address as offset for clients + * programmed to operate in frame/index based mode and h_init + * value as offset for clients programmed to operate in line + * based mode. + */ + + if (wm_data->en_cfg & (0x3 << 16)) + wm_data->offset = stripe_config->offset; + else + wm_data->h_init = stripe_config->offset; + + CAM_DBG(CAM_SFE, + "out_type:0x%X WM:%d width:%d offset:0x%X h_init:%d", + stripe_args->res->res_id, wm_data->index, + wm_data->width, wm_data->offset, wm_data->h_init); + } + + return 0; +} + +static int cam_sfe_bus_wr_update_wm_config( + void *cmd_args) +{ + int i; + struct cam_isp_hw_get_cmd_update *wm_config_update; + struct cam_sfe_bus_wr_out_data *sfe_out_data = NULL; + struct cam_sfe_bus_wr_wm_resource_data *wm_data = NULL; + struct cam_isp_vfe_wm_config *wm_config = NULL; + + if (!cmd_args) { + CAM_ERR(CAM_SFE, "Invalid args"); + return -EINVAL; + } + + wm_config_update = cmd_args; + sfe_out_data = wm_config_update->res->res_priv; + wm_config = (struct cam_isp_vfe_wm_config *) + wm_config_update->data; + + if (!sfe_out_data || !sfe_out_data->cdm_util_ops || !wm_config) { + CAM_ERR(CAM_SFE, "Invalid data"); + return -EINVAL; + } + + for (i = 0; i < sfe_out_data->num_wm; i++) { + wm_data = sfe_out_data->wm_res[i].res_priv; + + if (wm_config->wm_mode > 0x2) { + CAM_ERR(CAM_SFE, "Invalid wm_mode: 0x%X WM:%d", + wm_config->wm_mode, wm_data->index); + return -EINVAL; + } + + wm_data->en_cfg = (wm_config->wm_mode << 16) | 0x1; + wm_data->width = wm_config->width; + + if (i == PLANE_C) + wm_data->height = wm_config->height / 2; + else + wm_data->height = wm_config->height; + + CAM_DBG(CAM_SFE, + "WM:%d en_cfg:0x%X height:%d width:%d", + wm_data->index, wm_data->en_cfg, wm_data->height, + wm_data->width); + } + + return 0; +} + +static int cam_sfe_bus_wr_start_hw(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + return cam_sfe_bus_start_sfe_out(hw_priv); +} + +static int cam_sfe_bus_wr_stop_hw(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + return cam_sfe_bus_stop_sfe_out(hw_priv); +} + +static int cam_sfe_bus_wr_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_sfe_bus_wr_priv *bus_priv = hw_priv; + + if (!bus_priv) { + CAM_ERR(CAM_SFE, "Invalid args"); + return -EINVAL; + } + + if (bus_priv->common_data.hw_init) + return 0; + + /* To Do Subscribe IRQs */ + + /* BUS_WR_TEST_BUS_CTRL */ + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->test_bus_ctrl); + + bus_priv->common_data.hw_init = true; + + return 0; +} + +static int cam_sfe_bus_wr_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_sfe_bus_wr_priv *bus_priv = hw_priv; + int rc = 0; + + if (!bus_priv) { + CAM_ERR(CAM_SFE, "Error: Invalid args"); + return -EINVAL; + } + + if (!bus_priv->common_data.hw_init) + return 0; + + /* To Do Unsubscribe IRQs */ + + return rc; +} + +static int __cam_sfe_bus_wr_process_cmd( + void *priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + return cam_sfe_bus_wr_process_cmd(priv, cmd_type, + cmd_args, arg_size); +} + +static int cam_sfe_bus_wr_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, + uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_sfe_bus_wr_priv *bus_priv; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_SFE, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + rc = cam_sfe_bus_wr_update_wm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE: + rc = cam_sfe_bus_wr_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_sfe_bus_wr_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STRIPE_UPDATE: + rc = cam_sfe_bus_wr_update_stripe_cfg(priv, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + bus_priv = (struct cam_sfe_bus_wr_priv *) priv; + /* Handle bus err IRQ */ + break; + case CAM_ISP_HW_CMD_DUMP_BUS_INFO: { + struct cam_isp_hw_event_info *event_info; + enum cam_sfe_bus_sfe_out_type sfe_out_res_id; + + event_info = + (struct cam_isp_hw_event_info *)cmd_args; + bus_priv = (struct cam_sfe_bus_wr_priv *) priv; + sfe_out_res_id = + cam_sfe_bus_wr_get_out_res_id(event_info->res_id); + rc = cam_sfe_bus_wr_print_dimensions( + sfe_out_res_id, bus_priv); + break; + } + case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: + rc = cam_sfe_bus_wr_update_wm_config(cmd_args); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_SFE, "Invalid HW command type:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_sfe_bus_wr_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + struct cam_sfe_bus **sfe_bus) +{ + int i, rc = 0; + struct cam_sfe_bus_wr_priv *bus_priv = NULL; + struct cam_sfe_bus *sfe_bus_local; + struct cam_sfe_bus_wr_hw_info *hw_info = bus_hw_info; + struct cam_sfe_soc_private *soc_private = NULL; + + CAM_DBG(CAM_SFE, "Enter"); + + if (!soc_info || !hw_intf || !bus_hw_info) { + CAM_ERR(CAM_SFE, + "Inval_prms soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_hw_info); + rc = -EINVAL; + goto end; + } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_SFE, "Invalid soc_private"); + rc = -ENODEV; + goto end; + } + + sfe_bus_local = kzalloc(sizeof(struct cam_sfe_bus), GFP_KERNEL); + if (!sfe_bus_local) { + CAM_DBG(CAM_SFE, "Failed to alloc for sfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_sfe_bus_wr_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_SFE, "Failed to alloc for sfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + sfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = hw_info->num_client; + bus_priv->num_out = hw_info->num_out; + bus_priv->num_comp_grp = hw_info->num_comp_grp; + bus_priv->top_irq_shift = hw_info->top_irq_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, SFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.common_reg = &hw_info->common_reg; + bus_priv->common_data.comp_done_shift = hw_info->comp_done_shift; + bus_priv->common_data.hw_init = false; + + rc = cam_cpas_get_cpas_hw_version(&bus_priv->common_data.hw_version); + if (rc) { + CAM_ERR(CAM_SFE, "Failed to get hw_version rc:%d", rc); + goto end; + } + + bus_priv->comp_grp = kzalloc((sizeof(struct cam_isp_resource_node) * + bus_priv->num_comp_grp), GFP_KERNEL); + if (!bus_priv->comp_grp) { + CAM_ERR(CAM_SFE, "Failed to alloc for bus comp groups"); + rc = -ENOMEM; + goto free_bus_priv; + } + + bus_priv->sfe_out = kzalloc((sizeof(struct cam_isp_resource_node) * + CAM_SFE_BUS_SFE_OUT_MAX), GFP_KERNEL); + if (!bus_priv->sfe_out) { + CAM_ERR(CAM_SFE, "Failed to alloc for bus out res"); + rc = -ENOMEM; + goto free_comp_grp; + } + + 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_comp_grp; i++) { + rc = cam_sfe_bus_wr_init_comp_grp(i, soc_info, + bus_priv, bus_hw_info, + &bus_priv->comp_grp[i]); + if (rc < 0) { + CAM_ERR(CAM_SFE, "SFE:%d init comp_grp:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + goto deinit_comp_grp; + } + } + + for (i = 0; i < bus_priv->num_out; i++) { + rc = cam_sfe_bus_init_sfe_out_resource(i, bus_priv, + bus_hw_info); + if (rc < 0) { + CAM_ERR(CAM_SFE, + "SFE:%d init out_type:0x%X failed rc:%d", + bus_priv->common_data.core_index, i, rc); + goto deinit_sfe_out; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + + sfe_bus_local->hw_ops.reserve = cam_sfe_bus_acquire_sfe_out; + sfe_bus_local->hw_ops.release = cam_sfe_bus_release_sfe_out; + sfe_bus_local->hw_ops.start = cam_sfe_bus_wr_start_hw; + sfe_bus_local->hw_ops.stop = cam_sfe_bus_wr_stop_hw; + sfe_bus_local->hw_ops.init = cam_sfe_bus_wr_init_hw; + sfe_bus_local->hw_ops.deinit = cam_sfe_bus_wr_deinit_hw; + sfe_bus_local->top_half_handler = NULL; + sfe_bus_local->bottom_half_handler = NULL; + sfe_bus_local->hw_ops.process_cmd = __cam_sfe_bus_wr_process_cmd; + + *sfe_bus = sfe_bus_local; + + CAM_DBG(CAM_SFE, "Exit"); + return rc; + +deinit_sfe_out: + if (i < 0) + i = CAM_SFE_BUS_SFE_OUT_MAX; + for (--i; i >= 0; i--) + cam_sfe_bus_deinit_sfe_out_resource(&bus_priv->sfe_out[i]); + +deinit_comp_grp: + if (i < 0) + i = bus_priv->num_comp_grp; + for (--i; i >= 0; i--) + cam_sfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]); + kfree(bus_priv->sfe_out); + +free_comp_grp: + kfree(bus_priv->comp_grp); + +free_bus_priv: + kfree(sfe_bus_local->bus_priv); + +free_bus_local: + kfree(sfe_bus_local); + +end: + return rc; +} + +int cam_sfe_bus_wr_deinit( + struct cam_sfe_bus **sfe_bus) +{ + int i, rc = 0; + struct cam_sfe_bus_wr_priv *bus_priv = NULL; + struct cam_sfe_bus *sfe_bus_local; + unsigned long flags; + + if (!sfe_bus || !*sfe_bus) { + CAM_ERR(CAM_SFE, "Invalid input"); + return -EINVAL; + } + sfe_bus_local = *sfe_bus; + + bus_priv = sfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_SFE, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + //for (i = 0; i < CAM_SFE_BUS_WR_PAYLOAD_MAX; i++) + //INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + bus_priv->common_data.hw_init = false; + spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags); + + for (i = 0; i < CAM_SFE_BUS_WR_COMP_GRP_MAX; i++) { + rc = cam_sfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]); + if (rc < 0) + CAM_ERR(CAM_SFE, + "SFE:%d deinit comp_grp:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + } + + for (i = 0; i < CAM_SFE_BUS_SFE_OUT_MAX; i++) { + rc = cam_sfe_bus_deinit_sfe_out_resource( + &bus_priv->sfe_out[i]); + if (rc < 0) + CAM_ERR(CAM_SFE, + "SFE:%d deinit out_type:0x%X failed rc:%d", + bus_priv->common_data.core_index, i, 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(sfe_bus_local->bus_priv); + +free_bus_local: + kfree(sfe_bus_local); + + *sfe_bus = NULL; + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.h new file mode 100644 index 0000000000..54ea96bb3d --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.h @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_SFE_BUS_WR_H_ +#define _CAM_SFE_BUS_WR_H_ + +#include "cam_irq_controller.h" +#include "cam_sfe_bus.h" + +#define CAM_SFE_BUS_WR_MAX_CLIENTS 13 +#define CAM_SFE_BUS_WR_MAX_SUB_GRPS 6 + +enum cam_sfe_bus_wr_src_grp { + CAM_SFE_BUS_WR_SRC_GRP_0, + CAM_SFE_BUS_WR_SRC_GRP_1, + CAM_SFE_BUS_WR_SRC_GRP_2, + CAM_SFE_BUS_WR_SRC_GRP_3, + CAM_SFE_BUS_WR_SRC_GRP_4, + CAM_SFE_BUS_WR_SRC_GRP_5, + CAM_SFE_BUS_WR_SRC_GRP_MAX, +}; + +enum cam_sfe_bus_wr_comp_grp_type { + CAM_SFE_BUS_WR_COMP_GRP_0, + CAM_SFE_BUS_WR_COMP_GRP_1, + CAM_SFE_BUS_WR_COMP_GRP_2, + CAM_SFE_BUS_WR_COMP_GRP_3, + CAM_SFE_BUS_WR_COMP_GRP_4, + CAM_SFE_BUS_WR_COMP_GRP_5, + CAM_SFE_BUS_WR_COMP_GRP_6, + CAM_SFE_BUS_WR_COMP_GRP_7, + CAM_SFE_BUS_WR_COMP_GRP_8, + CAM_SFE_BUS_WR_COMP_GRP_9, + CAM_SFE_BUS_WR_COMP_GRP_MAX, +}; + +enum cam_sfe_bus_sfe_out_type { + CAM_SFE_BUS_SFE_OUT_RDI0, + CAM_SFE_BUS_SFE_OUT_RDI1, + CAM_SFE_BUS_SFE_OUT_RDI2, + CAM_SFE_BUS_SFE_OUT_RDI3, + CAM_SFE_BUS_SFE_OUT_RDI4, + CAM_SFE_BUS_SFE_OUT_RAW_DUMP, + CAM_SFE_BUS_SFE_OUT_LCR, + CAM_SFE_BUS_SFE_OUT_BE_0, + CAM_SFE_BUS_SFE_OUT_BHIST_0, + CAM_SFE_BUS_SFE_OUT_BE_1, + CAM_SFE_BUS_SFE_OUT_BHIST_1, + CAM_SFE_BUS_SFE_OUT_BE_2, + CAM_SFE_BUS_SFE_OUT_BHIST_2, + CAM_SFE_BUS_SFE_OUT_MAX, +}; + +/* + * struct cam_sfe_bus_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_sfe_bus_reg_offset_common { + uint32_t hw_version; + uint32_t cgc_ovd; + uint32_t if_frameheader_cfg[CAM_SFE_BUS_WR_MAX_SUB_GRPS]; + 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 debug_status_top_cfg; + uint32_t debug_status_top; + uint32_t test_bus_ctrl; + uint32_t top_irq_mask_0; +}; + +/* + * struct cam_sfe_bus_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_sfe_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 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 system_cache_cfg; + 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_sfe_bus_sfe_out_hw_info: + * + * @Brief: HW capability of SFE Bus Client + */ +struct cam_sfe_bus_sfe_out_hw_info { + enum cam_sfe_bus_sfe_out_type sfe_out_type; + uint32_t max_width; + uint32_t max_height; + uint32_t source_group; + uint32_t num_wm; + uint32_t wm_idx; +}; + +/* + * struct cam_sfe_bus_wr_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 + * @sfe_out_hw_info: SFE output capability + * @num_comp_grp: Number of composite groups + * @comp_done_shift: Mask shift for comp done mask + * @top_irq_shift: Mask shift for top level BUS WR irq + */ +struct cam_sfe_bus_wr_hw_info { + struct cam_sfe_bus_reg_offset_common common_reg; + uint32_t num_client; + struct cam_sfe_bus_reg_offset_bus_client + bus_client_reg[CAM_SFE_BUS_WR_MAX_CLIENTS]; + uint32_t num_out; + struct cam_sfe_bus_sfe_out_hw_info + sfe_out_hw_info[CAM_SFE_BUS_SFE_OUT_MAX]; + uint32_t num_comp_grp; + uint32_t comp_done_shift; + uint32_t top_irq_shift; +}; + +/* + * cam_sfe_bus_wr_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 + * @sfe_bus: Pointer to sfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_bus_wr_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + struct cam_sfe_bus **sfe_bus); + +/* + * cam_sfe_bus_wr_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @sfe_bus: Pointer to sfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_bus_wr_deinit(struct cam_sfe_bus **sfe_bus); + +#endif /* _CAM_SFE_BUS_WR_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/include/cam_sfe_bus.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/include/cam_sfe_bus.h new file mode 100644 index 0000000000..7cac810839 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/include/cam_sfe_bus.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SFE_BUS_H_ +#define _CAM_SFE_BUS_H_ + +#include "cam_isp_hw.h" +#include "cam_sfe_hw_intf.h" + +#define CAM_SFE_BUS_WR_VER_1_0 0x1000 +#define CAM_SFE_BUS_RD_VER_1_0 0x1000 + +#define CAM_SFE_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) + +enum cam_sfe_bus_sfe_core_id { + CAM_SFE_BUS_SFE_CORE_0, + CAM_SFE_BUS_SFE_CORE_1, + CAM_SFE_BUS_SFE_CORE_MAX, +}; + +enum cam_sfe_bus_plane_type { + PLANE_Y, + PLANE_C, + PLANE_MAX, +}; + +enum cam_sfe_bus_type { + BUS_TYPE_SFE_WR, + BUS_TYPE_SFE_RD, + BUS_TYPE_SFE_MAX, +}; + +/* + * struct cam_sfe_bus: + * + * @Brief: Bus interface structure + * + * @bus_priv: Private data of BUS + * @hw_ops: Hardware interface functions + * @top_half_handler: Top Half handler function + * @bottom_half_handler: Bottom Half handler function + */ +struct cam_sfe_bus { + void *bus_priv; + + struct cam_hw_ops hw_ops; + CAM_IRQ_HANDLER_TOP_HALF top_half_handler; + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; +}; + +/* + * cam_sfe_bus_init() + * + * @Brief: Initialize Bus layer + * + * @bus_version: Version of BUS to initialize + * @bus_type: Bus Type RD/WR + * @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 + * @sfe_bus: Pointer to sfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_bus_init(uint32_t bus_version, + int bus_type, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + struct cam_sfe_bus **sfe_bus); + +/* + * cam_sfe_bus_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @bus_version: Version of BUS to deinitialize + * @sfe_bus: Pointer to sfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_bus_deinit( + uint32_t bus_version, + int bus_type, + struct cam_sfe_bus **sfe_bus); + +#endif /* _CAM_SFE_BUS_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c new file mode 100644 index 0000000000..a61a539fdb --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c @@ -0,0 +1,682 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_io_util.h" +#include "cam_cdm_util.h" +#include "cam_sfe_hw_intf.h" +#include "cam_sfe_top.h" +#include "cam_debug_util.h" +#include "cam_sfe_soc.h" + +struct cam_sfe_core_cfg { + uint32_t mode_sel; + uint32_t ops_mode_cfg; + uint32_t fs_mode_cfg; +}; + +struct cam_sfe_top_common_data { + struct cam_hw_soc_info *soc_info; + struct cam_hw_intf *hw_intf; + struct cam_sfe_top_common_reg_offset *common_reg; +}; + +struct cam_sfe_top_priv { + struct cam_sfe_top_common_data common_data; + struct cam_isp_resource_node in_rsrc[CAM_SFE_TOP_IN_PORT_MAX]; + uint32_t num_in_ports; + unsigned long hw_clk_rate; + unsigned long req_clk_rate[CAM_SFE_TOP_IN_PORT_MAX]; + uint32_t last_counter; + uint64_t total_bw_applied; + struct cam_axi_vote req_axi_vote[CAM_SFE_TOP_IN_PORT_MAX]; + struct cam_axi_vote last_vote[ + CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES]; + enum cam_sfe_bw_control_action axi_vote_control[ + CAM_SFE_TOP_IN_PORT_MAX]; + struct cam_sfe_core_cfg core_cfg; + uint32_t sfe_debug_cfg; +}; + +struct cam_sfe_path_data { + void __iomem *mem_base; + void *priv; + struct cam_hw_intf *hw_intf; + struct cam_sfe_top_common_reg_offset *common_reg; + struct cam_sfe_modules_common_reg_offset *modules_reg; + struct cam_sfe_path_common_reg_data *path_reg_data; + struct cam_hw_soc_info *soc_info; + uint32_t min_hblank_cnt; + cam_hw_mgr_event_cb_func event_cb; +}; + +static int cam_sfe_top_core_cfg( + struct cam_sfe_top_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_sfe_core_config_args *sfe_core_cfg = NULL; + + if ((!cmd_args) || + (arg_size != sizeof(struct cam_sfe_core_config_args))) { + CAM_ERR(CAM_SFE, "Invalid inputs"); + return -EINVAL; + } + + sfe_core_cfg = (struct cam_sfe_core_config_args *)cmd_args; + top_priv->core_cfg.mode_sel = + sfe_core_cfg->core_config.mode_sel; + top_priv->core_cfg.fs_mode_cfg = + sfe_core_cfg->core_config.fs_mode_cfg; + top_priv->core_cfg.ops_mode_cfg = + sfe_core_cfg->core_config.ops_mode_cfg; + + return 0; +} + +static int cam_sfe_top_set_hw_clk_rate( + struct cam_sfe_top_priv *top_priv) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_sfe_soc_private *soc_private = NULL; + struct cam_ahb_vote ahb_vote; + int rc, clk_lvl = -1, i; + unsigned long max_clk_rate = 0; + + soc_info = top_priv->common_data.soc_info; + for (i = 0; i < top_priv->num_in_ports; 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; + + soc_private = (struct cam_sfe_soc_private *) + soc_info->soc_private; + CAM_DBG(CAM_PERF, "SFE [%u]: clk: %s idx: %d rate: %llu", + soc_info->index, + soc_info->clk_name[soc_info->src_clk_idx], + soc_info->src_clk_idx, top_priv->req_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; + rc = cam_soc_util_get_clk_level(soc_info, + max_clk_rate, + soc_info->src_clk_idx, &clk_lvl); + if (rc) { + CAM_WARN(CAM_SFE, + "Failed to get clk level for %s with clk_rate %llu src_idx %d rc: %d", + soc_info->dev_name, max_clk_rate, + soc_info->src_clk_idx, rc); + rc = 0; + goto end; + } + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = clk_lvl; + cam_cpas_update_ahb_vote(soc_private->cpas_handle, &ahb_vote); + } else { + CAM_ERR(CAM_PERF, + "Set clk rate failed for SFE [%u] clk: %s rate: %llu rc: %d", + soc_info->index, + soc_info->clk_name[soc_info->src_clk_idx], + max_clk_rate, rc); + } + +end: + return rc; +} + +static int cam_sfe_top_get_base( + struct cam_sfe_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_SFE, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res || !top_priv || + !top_priv->common_data.soc_info) { + CAM_ERR(CAM_SFE, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = + (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_SFE, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_changebase(); + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_SFE, "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, + SFE_CORE_BASE_IDX); + + if (cdm_args->cdm_id == CAM_CDM_RT) + mem_base -= CAM_SOC_GET_REG_MAP_CAM_BASE( + top_priv->common_data.soc_info, + SFE_RT_CDM_BASE_IDX); + + CAM_DBG(CAM_SFE, "core %d mem_base 0x%x, CDM Id: %d", + top_priv->common_data.soc_info->index, mem_base, + cdm_args->cdm_id); + + 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_sfe_top_clock_update( + struct cam_sfe_top_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_sfe_clock_update_args *clk_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0, i; + + if (arg_size != sizeof(struct cam_sfe_clock_update_args)) { + CAM_ERR(CAM_SFE, "Invalid cmd size"); + return -EINVAL; + } + + clk_update = + (struct cam_sfe_clock_update_args *)cmd_args; + if (!clk_update || !clk_update->node_res || !top_priv || + !top_priv->common_data.soc_info) { + CAM_ERR(CAM_SFE, "Invalid args"); + return -EINVAL; + } + + res = clk_update->node_res; + + if (!res || !res->hw_intf->hw_priv) { + CAM_ERR(CAM_PERF, "Invalid inputs"); + return -EINVAL; + } + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_SFE_IN || + res->res_id >= CAM_ISP_HW_SFE_IN_MAX) { + CAM_ERR(CAM_PERF, + "SFE: %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 < top_priv->num_in_ports; 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_PERF, + "SFE: %d not ready to set clocks yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + rc = -EAGAIN; + } else + rc = cam_sfe_top_set_hw_clk_rate(top_priv); + + return rc; +} + +static int cam_sfe_set_top_debug( + struct cam_sfe_top_priv *top_priv, + void *cmd_args) +{ + uint32_t *sfe_debug; + + sfe_debug = (uint32_t *)cmd_args; + top_priv->sfe_debug_cfg = *sfe_debug; + + return 0; +} + +int cam_sfe_top_process_cmd(void *priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_sfe_top_priv *top_priv; + + if (!priv) { + CAM_ERR(CAM_SFE, "Invalid top_priv"); + return -EINVAL; + } + + top_priv = (struct cam_sfe_top_priv *) priv; + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_CHANGE_BASE: + rc = cam_sfe_top_get_base(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_CLOCK_UPDATE: + rc = cam_sfe_top_clock_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE_V2: + break; + case CAM_ISP_HW_CMD_BW_CONTROL: + break; + case CAM_ISP_HW_CMD_CORE_CONFIG: + rc = cam_sfe_top_core_cfg(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_SET_SFE_DEBUG_CFG: + rc = cam_sfe_set_top_debug(top_priv, cmd_args); + break; + default: + CAM_ERR(CAM_SFE, "Invalid cmd type: %d", cmd_type); + rc = -EINVAL; + break; + } + + return rc; +} + +int cam_sfe_top_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size) +{ + struct cam_sfe_top_priv *top_priv; + struct cam_sfe_acquire_args *args; + struct cam_sfe_hw_sfe_in_acquire_args *acquire_args; + struct cam_sfe_path_data *path_data; + int rc = -EINVAL, i; + + if (!device_priv || !reserve_args) { + CAM_ERR(CAM_SFE, + "Error invalid input arguments"); + return rc; + } + + top_priv = (struct cam_sfe_top_priv *)device_priv; + args = (struct cam_sfe_acquire_args *)reserve_args; + acquire_args = &args->sfe_in; + + for (i = 0; i < CAM_SFE_TOP_IN_PORT_MAX; i++) { + CAM_DBG(CAM_SFE, "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)) { + path_data = (struct cam_sfe_path_data *) + top_priv->in_rsrc[i].res_priv; + path_data->event_cb = args->event_cb; + path_data->priv = args->priv; + CAM_DBG(CAM_SFE, + "SFE [%u] for rsrc: %u acquired", + top_priv->in_rsrc[i].hw_intf->hw_idx, + acquire_args->res_id); + + 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; + acquire_args->rsrc_node = + &top_priv->in_rsrc[i]; + rc = 0; + break; + } + } + + return rc; +} + +int cam_sfe_top_release(void *device_priv, + void *release_args, uint32_t arg_size) +{ + struct cam_sfe_top_priv *top_priv; + struct cam_isp_resource_node *in_res; + + if (!device_priv || !release_args) { + CAM_ERR(CAM_SFE, "Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_sfe_top_priv *)device_priv; + in_res = (struct cam_isp_resource_node *)release_args; + + CAM_DBG(CAM_SFE, + "Release for SFE [%u] resource id: %u 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_SFE, "SFE [%u] 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; + + return 0; +} + +int cam_sfe_top_start( + void *priv, void *start_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_sfe_top_priv *top_priv; + struct cam_isp_resource_node *sfe_res; + struct cam_hw_info *hw_info = NULL; + struct cam_sfe_path_data *path_data; + + if (!priv || !start_args) { + CAM_ERR(CAM_SFE, "Invalid args"); + return -EINVAL; + } + + top_priv = (struct cam_sfe_top_priv *)priv; + sfe_res = (struct cam_isp_resource_node *) start_args; + + hw_info = (struct cam_hw_info *)sfe_res->hw_intf->hw_priv; + if (!hw_info) { + CAM_ERR(CAM_SFE, "Invalid input"); + return rc; + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_SFE, "SFE HW [%u] not powered up", + hw_info->soc_info.index); + rc = -EPERM; + return rc; + } + + path_data = (struct cam_sfe_path_data *)sfe_res->res_priv; + rc = cam_sfe_top_set_hw_clk_rate(top_priv); + if (rc) + return rc; + + /* core cfg updated via CDM */ + CAM_DBG(CAM_SFE, "SFE HW [%u] core_cfg: 0x%x", + hw_info->soc_info.index, + cam_io_r_mb(path_data->mem_base + + path_data->common_reg->core_cfg)); + + /* Enable debug cfg registers */ + cam_io_w_mb(path_data->path_reg_data->top_debug_cfg_en, + path_data->mem_base + + path_data->common_reg->top_debug_cfg); + + /* Enable sensor diag info */ + /* Enable SOF & EOF IRQ based on debug flag */ + /* Enable error IRQ by default */ + + sfe_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return 0; +} + +int cam_sfe_top_stop( + void *priv, void *stop_args, uint32_t arg_size) +{ + int i; + struct cam_sfe_top_priv *top_priv; + struct cam_isp_resource_node *sfe_res; + + if (!priv || !stop_args) { + CAM_ERR(CAM_SFE, "Invalid args"); + return -EINVAL; + } + + top_priv = (struct cam_sfe_top_priv *)priv; + sfe_res = (struct cam_isp_resource_node *) stop_args; + + if (sfe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + sfe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + /* Unsubscribe for IRQs */ + sfe_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + for (i = 0; i < CAM_SFE_TOP_IN_PORT_MAX; i++) { + if (top_priv->in_rsrc[i].res_id == sfe_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_SFE_BW_CONTROL_EXCLUDE; + break; + } + } + + return 0; +} + +int cam_sfe_top_init( + uint32_t hw_version, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + struct cam_sfe_top **sfe_top_ptr) +{ + int i, j, rc = 0; + struct cam_sfe_top_priv *top_priv = NULL; + struct cam_sfe_path_data *path_data = NULL; + struct cam_sfe_top *sfe_top; + struct cam_sfe_top_hw_info *sfe_top_hw_info = + (struct cam_sfe_top_hw_info *)top_hw_info; + + sfe_top = kzalloc(sizeof(struct cam_sfe_top), GFP_KERNEL); + if (!sfe_top) { + CAM_DBG(CAM_SFE, "Error, Failed to alloc for sfe_top"); + rc = -ENOMEM; + goto end; + } + + top_priv = kzalloc(sizeof(struct cam_sfe_top_priv), + GFP_KERNEL); + if (!top_priv) { + rc = -ENOMEM; + goto free_sfe_top; + } + + sfe_top->top_priv = top_priv; + if (sfe_top_hw_info->num_inputs > CAM_SFE_TOP_IN_PORT_MAX) { + CAM_ERR(CAM_SFE, + "Invalid number of input resources: %d max: %d", + sfe_top_hw_info->num_inputs, + CAM_SFE_TOP_IN_PORT_MAX); + rc = -EINVAL; + goto free_top_priv; + } + + top_priv->hw_clk_rate = 0; + top_priv->num_in_ports = sfe_top_hw_info->num_inputs; + memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * + CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES); + memset(&top_priv->core_cfg, 0x0, + sizeof(struct cam_sfe_core_config_args)); + + CAM_DBG(CAM_SFE, + "Initializing SFE [%u] top with hw_version: 0x%x", + hw_intf->hw_idx, hw_version); + for (i = 0, j = 0; i < top_priv->num_in_ports && + j < CAM_SFE_RDI_MAX; i++) { + top_priv->in_rsrc[i].res_type = + CAM_ISP_RESOURCE_SFE_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; + + if (sfe_top_hw_info->input_type[i] == + CAM_SFE_PIX_VER_1_0) { + top_priv->in_rsrc[i].res_id = + CAM_ISP_HW_SFE_IN_PIX; + + path_data = kzalloc(sizeof(struct cam_sfe_path_data), + GFP_KERNEL); + if (!path_data) { + CAM_DBG(CAM_SFE, + "Failed to alloc SFE [%u] pix data", + hw_intf->hw_idx); + goto deinit_resources; + } + top_priv->in_rsrc[i].res_priv = path_data; + path_data->mem_base = + soc_info->reg_map[SFE_CORE_BASE_IDX].mem_base; + path_data->path_reg_data = + sfe_top_hw_info->pix_reg_data; + path_data->common_reg = sfe_top_hw_info->common_reg; + path_data->modules_reg = + sfe_top_hw_info->modules_hw_info; + path_data->hw_intf = hw_intf; + path_data->soc_info = soc_info; + } else if (sfe_top_hw_info->input_type[i] == + CAM_SFE_RDI_VER_1_0) { + top_priv->in_rsrc[i].res_id = + CAM_ISP_HW_SFE_IN_RDI0 + j; + + path_data = kzalloc(sizeof(struct cam_sfe_path_data), + GFP_KERNEL); + if (!path_data) { + CAM_DBG(CAM_SFE, + "Failed to alloc SFE [%u] rdi data res_id: %u", + hw_intf->hw_idx, + (CAM_ISP_HW_SFE_IN_RDI0 + j)); + goto deinit_resources; + } + + top_priv->in_rsrc[i].res_priv = path_data; + + path_data->mem_base = + soc_info->reg_map[SFE_CORE_BASE_IDX].mem_base; + path_data->hw_intf = hw_intf; + path_data->common_reg = sfe_top_hw_info->common_reg; + path_data->modules_reg = + sfe_top_hw_info->modules_hw_info; + path_data->soc_info = soc_info; + path_data->path_reg_data = + sfe_top_hw_info->rdi_reg_data[j++]; + } else { + CAM_WARN(CAM_SFE, "Invalid SFE input type: %u", + sfe_top_hw_info->input_type[i]); + } + } + + top_priv->common_data.soc_info = soc_info; + top_priv->common_data.hw_intf = hw_intf; + top_priv->common_data.common_reg = + sfe_top_hw_info->common_reg; + + sfe_top->hw_ops.process_cmd = cam_sfe_top_process_cmd; + sfe_top->hw_ops.start = cam_sfe_top_start; + sfe_top->hw_ops.stop = cam_sfe_top_stop; + sfe_top->hw_ops.reserve = cam_sfe_top_reserve; + sfe_top->hw_ops.release = cam_sfe_top_release; + *sfe_top_ptr = sfe_top; + + 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_top_priv: + kfree(sfe_top->top_priv); + sfe_top->top_priv = NULL; +free_sfe_top: + kfree(sfe_top); +end: + *sfe_top_ptr = NULL; + return rc; +} + +int cam_sfe_top_deinit( + uint32_t hw_version, + struct cam_sfe_top **sfe_top_ptr) +{ + int i, rc = 0; + struct cam_sfe_top *sfe_top; + struct cam_sfe_top_priv *top_priv; + + if (!sfe_top_ptr) { + CAM_ERR(CAM_SFE, "Error Invalid input"); + return -ENODEV; + } + + sfe_top = *sfe_top_ptr; + if (!sfe_top) { + CAM_ERR(CAM_SFE, "Error sfe top NULL"); + return -ENODEV; + } + + top_priv = sfe_top->top_priv; + if (!top_priv) { + CAM_ERR(CAM_SFE, "Error sfe top priv NULL"); + rc = -ENODEV; + goto free_sfe_top; + } + + CAM_DBG(CAM_SFE, + "Deinit SFE [%u] top with hw_version 0x%x", + top_priv->common_data.hw_intf->hw_idx, + hw_version); + + for (i = 0; i < CAM_SFE_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_SFE, "Error res_priv is NULL"); + continue; + } + + kfree(top_priv->in_rsrc[i].res_priv); + top_priv->in_rsrc[i].res_priv = NULL; + } + + kfree(sfe_top->top_priv); + +free_sfe_top: + kfree(sfe_top); + *sfe_top_ptr = NULL; + + return rc; +} + + diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h new file mode 100644 index 0000000000..c6ad175792 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SFE_TOP_H_ +#define _CAM_SFE_TOP_H_ + +#include "cam_cpas_api.h" + +#define CAM_SFE_PIX_VER_1_0 0x10 +#define CAM_SFE_RDI_VER_1_0 0x1000 +#define CAM_SFE_TOP_VER_1_0 0x10000 + +#define CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES 18 +#define CAM_SFE_TOP_IN_PORT_MAX 6 +#define CAM_SFE_RDI_MAX 5 + +#define CAM_SHIFT_TOP_CORE_CFG_MODE_SEL 2 +#define CAM_SHIFT_TOP_CORE_CFG_OPS_MODE_CFG 1 +#define CAM_SHIFT_TOP_CORE_CFG_FS_MODE_CFG 0 + +struct cam_sfe_top { + void *top_priv; + struct cam_hw_ops hw_ops; +}; + +struct cam_sfe_top_common_reg_offset { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t stats_feature; + uint32_t core_cgc_ctrl; + uint32_t ahb_clk_ovd; + uint32_t core_cfg; + uint32_t violation_status; + uint32_t diag_config; + uint32_t diag_sensor_status_0; + uint32_t diag_sensor_status_1; + uint32_t diag_sensor_frame_cnt_status0; + uint32_t diag_sensor_frame_cnt_status1; + uint32_t top_debug_0; + uint32_t top_debug_1; + uint32_t top_debug_2; + uint32_t top_debug_3; + uint32_t top_debug_4; + uint32_t top_debug_5; + uint32_t top_debug_6; + uint32_t top_debug_7; + uint32_t top_debug_8; + uint32_t top_debug_9; + uint32_t top_debug_10; + uint32_t top_debug_11; + uint32_t top_debug_cfg; + uint32_t stats_ch2_throttle_cfg; + uint32_t stats_ch1_throttle_cfg; + uint32_t stats_ch0_throttle_cfg; + uint32_t lcr_throttle_cfg; + uint32_t hdr_throttle_cfg; + uint32_t sfe_op_throttle_cfg; +}; + +struct cam_sfe_modules_common_reg_offset { + uint32_t demux_module_cfg; + uint32_t demux_qcfa_cfg; + uint32_t demux_hdr_cfg; + uint32_t demux_lcr_sel; + uint32_t hdrc_remo_mod_cfg; + uint32_t hdrc_remo_qcfa_bin_cfg; + uint32_t qcfa_hdrc_remo_out_mux_cfg; +}; + +struct cam_sfe_path_common_reg_data { + uint32_t sof_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask; + uint32_t subscribe_irq_mask; + uint32_t enable_diagnostic_hw; + uint32_t top_debug_cfg_en; +}; + +struct cam_sfe_top_hw_info { + struct cam_sfe_top_common_reg_offset *common_reg; + struct cam_sfe_modules_common_reg_offset *modules_hw_info; + struct cam_sfe_path_common_reg_data *pix_reg_data; + struct cam_sfe_path_common_reg_data *rdi_reg_data[CAM_SFE_RDI_MAX]; + uint32_t num_inputs; + uint32_t input_type[ + CAM_SFE_TOP_IN_PORT_MAX]; +}; + +int cam_sfe_top_init( + uint32_t hw_version, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + struct cam_sfe_top **sfe_top); + +int cam_sfe_top_deinit( + uint32_t hw_version, + struct cam_sfe_top **sfe_top); + +#endif /* _CAM_SFE_TOP_H_ */ diff --git a/drivers/camera_main.c b/drivers/camera_main.c index db91401f13..f59be8dbe1 100644 --- a/drivers/camera_main.c +++ b/drivers/camera_main.c @@ -13,6 +13,7 @@ #include "cam_ife_csid_dev.h" #include "cam_vfe.h" +#include "cam_sfe_dev.h" #include "cam_isp_dev.h" #include "cam_res_mgr_api.h" @@ -91,6 +92,9 @@ static const struct camera_submodule_component camera_isp[] = { {&cam_ife_csid17x_init_module, &cam_ife_csid17x_exit_module}, {&cam_ife_csid_lite_init_module, &cam_ife_csid_lite_exit_module}, {&cam_vfe_init_module, &cam_vfe_exit_module}, +#ifdef CONFIG_SPECTRA_SFE + {&cam_sfe_init_module, &cam_sfe_exit_module}, +#endif {&cam_isp_dev_init_module, &cam_isp_dev_exit_module}, #endif }; diff --git a/drivers/camera_main.h b/drivers/camera_main.h index 255985fc8c..4cc6a6ae3e 100644 --- a/drivers/camera_main.h +++ b/drivers/camera_main.h @@ -19,6 +19,9 @@ extern struct platform_driver cam_top_tpg_driver; extern struct platform_driver cam_ife_csid17x_driver; extern struct platform_driver cam_ife_csid_lite_driver; extern struct platform_driver cam_vfe_driver; +#ifdef CONFIG_SPECTRA_SFE +extern struct platform_driver cam_sfe_driver; +#endif extern struct platform_driver isp_driver; #endif #ifdef CONFIG_SPECTRA_TFE @@ -89,6 +92,9 @@ static struct platform_driver *const cam_component_drivers[] = { &cam_ife_csid17x_driver, &cam_ife_csid_lite_driver, &cam_vfe_driver, +#ifdef CONFIG_SPECTRA_SFE + &cam_sfe_driver, +#endif &isp_driver, #endif #ifdef CONFIG_SPECTRA_SENSOR