Browse Source

msm: camera: isp: Add support for SFE HW layer in ISP driver

Add support for SFE TOP, SFE BUS_WR & SFE BUS_RD in ISP
driver.

CRs-Fixed: 2733230
Change-Id: I85d356d28879b5cf9144a459fcdbd9f57526fa91
Signed-off-by: Karthik Anantha Ram <[email protected]>
Karthik Anantha Ram 4 năm trước cách đây
mục cha
commit
1232bfaa25

+ 10 - 0
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

+ 11 - 0
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

+ 7 - 5
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 \

+ 18 - 4
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;

+ 87 - 8
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;

+ 695 - 0
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_ */

+ 295 - 72
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");
 
-	CAM_DBG(CAM_SFE, "Enable soc done");
+	/* Async Reset as part of power ON */
+	/* Sync Reset in CSID */
 
-	/* Do HW Reset */
-	rc = cam_sfe_reset(hw_priv, NULL, 0);
+	/* 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, "Reset Failed rc=%d", rc);
-		goto deinit_sfe_res;
+		CAM_ERR(CAM_SFE,
+			"SFE bus wr init failed rc: %d", rc);
+		goto disable_soc;
+	}
+
+	/* 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, "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);
 
-	spin_unlock_irqrestore(&core_info->spin_lock, flags);
+	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;
 }

+ 23 - 9
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h

@@ -9,30 +9,48 @@
 #include <linux/spinlock.h>
 #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);
 

+ 119 - 51
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c

@@ -6,65 +6,71 @@
 #include <linux/slab.h>
 #include <linux/mod_devicetable.h>
 #include <linux/of_device.h>
+#include <linux/module.h>
 #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;
-
-	CAM_DBG(CAM_SFE, "type %d index %d",
-		sfe_intf->hw_type, sfe_intf->hw_idx);
-
-	platform_set_drvdata(pdev, sfe_intf);
+	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, "SFE component bind type %d index %d",
+		sfe_hw_intf->hw_type, sfe_hw_intf->hw_idx);
+
+	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_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;
 
-free_sfe_intf:
-	kfree(sfe_intf);
+	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");

+ 6 - 18
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 <linux/platform_device.h>
-
-/*
- * 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_ */

+ 98 - 8
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;
 }

+ 1 - 1
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()

+ 91 - 0
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;
+}
+

+ 1144 - 0
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 <linux/ratelimit.h>
+#include <linux/slab.h>
+
+#include <media/cam_isp.h>
+
+#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;
+}

+ 115 - 0
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_ */

+ 1995 - 0
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 <linux/ratelimit.h>
+#include <linux/slab.h>
+
+#include <media/cam_isp.h>
+
+#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;
+}

+ 181 - 0
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_ */

+ 99 - 0
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_ */

+ 682 - 0
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 <linux/slab.h>
+#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;
+}
+
+

+ 102 - 0
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_ */

+ 4 - 0
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
 };

+ 6 - 0
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