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 <kartanan@codeaurora.org>
This commit is contained in:
Karthik Anantha Ram
2020-09-16 10:36:23 -07:00
parent fe2f879a03
commit 1232bfaa25
22 changed files with 5787 additions and 174 deletions

10
config/waipiocamera.conf Normal file
View File

@@ -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
config/waipiocameraconf.h Normal file
View File

@@ -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

View File

@@ -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_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/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/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_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_soc.o \
cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.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_dev.o \
cam_isp/cam_isp_context.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) += \ camera-$(CONFIG_SPECTRA_ICP) += \
cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.o \ cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.o \
cam_icp/icp_hw/ipe_hw/ipe_dev.o \ cam_icp/icp_hw/ipe_hw/ipe_dev.o \

View File

@@ -86,6 +86,9 @@ enum cam_isp_resource_type {
CAM_ISP_RESOURCE_TPG, CAM_ISP_RESOURCE_TPG,
CAM_ISP_RESOURCE_TFE_IN, CAM_ISP_RESOURCE_TFE_IN,
CAM_ISP_RESOURCE_TFE_OUT, CAM_ISP_RESOURCE_TFE_OUT,
CAM_ISP_RESOURCE_SFE_IN,
CAM_ISP_RESOURCE_SFE_RD,
CAM_ISP_RESOURCE_SFE_OUT,
CAM_ISP_RESOURCE_MAX, 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_TPG_CORE_CFG_CMD,
CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE, CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE,
CAM_ISP_HW_CMD_DISABLE_UBWC_COMP, CAM_ISP_HW_CMD_DISABLE_UBWC_COMP,
CAM_ISP_HW_CMD_SET_SFE_DEBUG_CFG,
CAM_ISP_HW_CMD_MAX, 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 * @ num_buf: Number of buffers in the image_buf array
* @ frame_header: frame header iova * @ frame_header: frame header iova
* @ local_id: local id for the wm * @ 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 * @ io_cfg: IO buffer config information sent from UMD
* *
*/ */
@@ -254,6 +262,10 @@ struct cam_isp_hw_get_wm_update {
uint32_t num_buf; uint32_t num_buf;
uint64_t frame_header; uint64_t frame_header;
uint32_t local_id; uint32_t local_id;
uint32_t width;
uint32_t height;
uint32_t stride;
uint32_t slice_height;
struct cam_buf_io_cfg *io_cfg; 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 * @Brief: Get cmd buffer update for different CMD types
* *
* @res: Resource node * @res: Resource node
* @cmd_type: Command type for which to get update * @cmd_type: Command type for which to get update
* @cdm_id : CDM id * @cdm_id: CDM id
* @cmd: Command buffer information * @cmd: Command buffer information
* @use_scratch_cfg: To indicate if it's scratch buffer config
* *
*/ */
struct cam_isp_hw_get_cmd_update { 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_isp_hw_cmd_type cmd_type;
enum cam_cdm_id cdm_id; enum cam_cdm_id cdm_id;
struct cam_isp_hw_cmd_buf_update cmd; struct cam_isp_hw_cmd_buf_update cmd;
bool use_scratch_cfg;
union { union {
void *data; void *data;
struct cam_isp_hw_get_wm_update *wm_update; struct cam_isp_hw_get_wm_update *wm_update;

View File

@@ -8,8 +8,9 @@
#include "cam_isp_hw.h" #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 { enum cam_isp_hw_sfe_in {
CAM_ISP_HW_SFE_IN_PIX, CAM_ISP_HW_SFE_IN_PIX,
@@ -32,6 +33,86 @@ enum cam_sfe_hw_irq_status {
CAM_SFE_IRQ_STATUS_MAX, 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: * struct cam_sfe_hw_get_hw_cap:
* *
@@ -54,18 +135,18 @@ struct cam_sfe_hw_get_hw_cap {
* is successful * is successful
* @res_id: Unique Identity of port to associate with this * @res_id: Unique Identity of port to associate with this
* resource. * resource.
* @is_dual: Flag to indicate dual SFE usecase
* @cdm_ops: CDM operations * @cdm_ops: CDM operations
* @unpacket_fmt: Unpacker format for read engine * @unpacket_fmt: Unpacker format for read engine
* @is_offline: Flag to indicate offline usecase * @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_sfe_hw_sfe_bus_rd_acquire_args {
struct cam_isp_resource_node *rsrc_node; struct cam_isp_resource_node *rsrc_node;
uint32_t res_id; uint32_t res_id;
uint32_t is_dual;
struct cam_cdm_utils_ops *cdm_ops; struct cam_cdm_utils_ops *cdm_ops;
uint32_t unpacker_fmt; uint32_t unpacker_fmt;
bool is_offline; bool is_offline;
bool secure_mode;
}; };
/* /*
@@ -77,9 +158,7 @@ struct cam_sfe_hw_sfe_bus_rd_acquire_args {
* resource. * resource.
* @cdm_ops: CDM operations * @cdm_ops: CDM operations
* @is_dual: Dual mode usecase * @is_dual: Dual mode usecase
* @sync_mode: If in dual mode, indicates master/slave
* @in_port: in port info * @in_port: in port info
* @is_fe_enabled: Flag to indicate if FE is enabled
* @is_offline: Flag to indicate Offline IFE * @is_offline: Flag to indicate Offline IFE
*/ */
struct cam_sfe_hw_sfe_in_acquire_args { struct cam_sfe_hw_sfe_in_acquire_args {
@@ -87,9 +166,7 @@ struct cam_sfe_hw_sfe_in_acquire_args {
uint32_t res_id; uint32_t res_id;
struct cam_cdm_utils_ops *cdm_ops; struct cam_cdm_utils_ops *cdm_ops;
uint32_t is_dual; uint32_t is_dual;
enum cam_isp_hw_sync_mode sync_mode;
struct cam_isp_in_port_generic_info *in_port; struct cam_isp_in_port_generic_info *in_port;
bool is_fe_enabled;
bool is_offline; bool is_offline;
}; };
@@ -126,6 +203,7 @@ struct cam_sfe_hw_sfe_out_acquire_args {
* with this resource. * with this resource.
* @priv: Context data * @priv: Context data
* @event_cb: Callback function to hw mgr in case of hw events * @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_out: Acquire args for SFE_OUT
* @sfe_bus_rd Acquire args for SFE_BUS_READ * @sfe_bus_rd Acquire args for SFE_BUS_READ
* @sfe_in: Acquire args for SFE_IN * @sfe_in: Acquire args for SFE_IN
@@ -135,6 +213,7 @@ struct cam_sfe_acquire_args {
void *tasklet; void *tasklet;
void *priv; void *priv;
cam_hw_mgr_event_cb_func event_cb; cam_hw_mgr_event_cb_func event_cb;
void *buf_done_controller;
union { union {
struct cam_sfe_hw_sfe_out_acquire_args sfe_out; struct cam_sfe_hw_sfe_out_acquire_args sfe_out;
struct cam_sfe_hw_sfe_in_acquire_args sfe_in; struct cam_sfe_hw_sfe_in_acquire_args sfe_in;

View File

@@ -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_ */

View File

@@ -12,12 +12,29 @@
#include "cam_debug_util.h" #include "cam_debug_util.h"
static const char drv_name[] = "sfe"; 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 -EPERM;
return 0; }
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) 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_info *sfe_hw = hw_priv;
struct cam_hw_soc_info *soc_info = NULL; struct cam_hw_soc_info *soc_info = NULL;
struct cam_sfe_hw_core_info *core_info = NULL; struct cam_sfe_hw_core_info *core_info = NULL;
struct cam_isp_resource_node *isp_res = NULL;
int rc = 0; int rc = 0;
CAM_DBG(CAM_SFE, "Enter");
if (!hw_priv) { if (!hw_priv) {
CAM_ERR(CAM_SFE, "Invalid arguments"); CAM_ERR(CAM_SFE, "Invalid arguments");
return -EINVAL; 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++; sfe_hw->open_count++;
if (sfe_hw->open_count > 1) { if (sfe_hw->open_count > 1) {
mutex_unlock(&sfe_hw->hw_mutex); 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); sfe_hw->open_count);
return 0; 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; goto decrement_open_cnt;
} }
isp_res = (struct cam_isp_resource_node *)init_hw_args; CAM_DBG(CAM_SFE, "SFE SOC resource enabled");
if (isp_res && isp_res->init) {
rc = isp_res->init(isp_res, NULL, 0); /* Async Reset as part of power ON */
if (rc) { /* Sync Reset in CSID */
CAM_ERR(CAM_SFE, "init Failed rc=%d", rc);
goto disable_soc; /* INIT SFE BUS WR */
} rc = core_info->sfe_bus_wr->hw_ops.init(
core_info->sfe_bus_wr->bus_priv, NULL, 0);
if (rc) {
CAM_ERR(CAM_SFE,
"SFE bus wr init failed rc: %d", rc);
goto disable_soc;
} }
CAM_DBG(CAM_SFE, "Enable soc done"); /* INIT SFE BUS RD */
rc = core_info->sfe_bus_rd->hw_ops.init(
/* Do HW Reset */ core_info->sfe_bus_rd->bus_priv, NULL, 0);
rc = cam_sfe_reset(hw_priv, NULL, 0);
if (rc) { if (rc) {
CAM_ERR(CAM_SFE, "Reset Failed rc=%d", rc); CAM_ERR(CAM_SFE, "SFE bus rd init failed rc: %d", rc);
goto deinit_sfe_res; goto deinit_bus_wr;
} }
sfe_hw->hw_state = CAM_HW_STATE_POWER_UP; sfe_hw->hw_state = CAM_HW_STATE_POWER_UP;
return rc; return rc;
deinit_sfe_res: deinit_bus_wr:
if (isp_res && isp_res->deinit) core_info->sfe_bus_wr->hw_ops.deinit(
isp_res->deinit(isp_res, NULL, 0); core_info->sfe_bus_wr->bus_priv, NULL, 0);
disable_soc: disable_soc:
cam_sfe_disable_soc_resources(soc_info); cam_sfe_disable_soc_resources(soc_info);
decrement_open_cnt: 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_info *sfe_hw = hw_priv;
struct cam_hw_soc_info *soc_info = NULL; struct cam_hw_soc_info *soc_info = NULL;
struct cam_sfe_hw_core_info *core_info = NULL; struct cam_sfe_hw_core_info *core_info = NULL;
struct cam_isp_resource_node *isp_res = NULL;
int rc = 0; int rc = 0;
CAM_DBG(CAM_SFE, "Enter");
if (!hw_priv) { if (!hw_priv) {
CAM_ERR(CAM_SFE, "Invalid arguments"); CAM_ERR(CAM_SFE, "Invalid arguments");
return -EINVAL; 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); mutex_lock(&sfe_hw->hw_mutex);
if (!sfe_hw->open_count) { if (!sfe_hw->open_count) {
mutex_unlock(&sfe_hw->hw_mutex); mutex_unlock(&sfe_hw->hw_mutex);
CAM_ERR(CAM_SFE, "Error! Unbalanced deinit"); CAM_ERR(CAM_SFE, "Unbalanced deinit");
return -EFAULT; return -EFAULT;
} }
sfe_hw->open_count--; sfe_hw->open_count--;
if (sfe_hw->open_count) { if (sfe_hw->open_count) {
mutex_unlock(&sfe_hw->hw_mutex); 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; return 0;
} }
mutex_unlock(&sfe_hw->hw_mutex); 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; soc_info = &sfe_hw->soc_info;
core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info; core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info;
isp_res = (struct cam_isp_resource_node *)deinit_hw_args; rc = core_info->sfe_bus_wr->hw_ops.deinit(
if (isp_res && isp_res->deinit) { core_info->sfe_bus_wr->bus_priv, NULL, 0);
rc = isp_res->deinit(isp_res, NULL, 0); if (rc)
if (rc) CAM_ERR(CAM_SFE, "SFE bus wr deinit failed rc: %d",
CAM_ERR(CAM_SFE, "deinit failed"); 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 */ /* 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); rc = cam_sfe_disable_soc_resources(soc_info);
if (rc) if (rc)
CAM_ERR(CAM_SFE, "Disable SOC failed"); CAM_ERR(CAM_SFE, "Disable SOC failed");
sfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; 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; 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) int cam_sfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size)
{ {
CAM_DBG(CAM_SFE, "Enter"); struct cam_sfe_hw_core_info *core_info = NULL;
return 0; 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) int cam_sfe_release(void *hw_priv, void *release_args, uint32_t arg_size)
{ {
CAM_DBG(CAM_SFE, "Enter"); struct cam_sfe_hw_core_info *core_info = NULL;
return 0; 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) int cam_sfe_start(void *hw_priv, void *start_args, uint32_t arg_size)
{ {
CAM_DBG(CAM_SFE, "Enter"); struct cam_sfe_hw_core_info *core_info = NULL;
return 0; 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) int cam_sfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size)
{ {
CAM_DBG(CAM_SFE, "Enter"); struct cam_sfe_hw_core_info *core_info = NULL;
return 0; 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) if (!hw_priv || !stop_args ||
{ (arg_size != sizeof(struct cam_isp_resource_node))) {
return -EPERM; CAM_ERR(CAM_SFE, "Invalid input arguments");
} return -EINVAL;
}
int cam_sfe_write(void *hw_priv, void *write_args, uint32_t arg_size) core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info;
{ sfe_res = (struct cam_isp_resource_node *)stop_args;
return -EPERM; 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, 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_hw_soc_info *soc_info = NULL;
struct cam_sfe_hw_core_info *core_info = NULL; struct cam_sfe_hw_core_info *core_info = NULL;
struct cam_sfe_hw_info *hw_info = NULL; struct cam_sfe_hw_info *hw_info = NULL;
int rc; int rc = 0;
if (!hw_priv) { if (!hw_priv) {
CAM_ERR(CAM_SFE, "Invalid arguments"); 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) { switch (cmd_type) {
case CAM_ISP_HW_CMD_GET_CHANGE_BASE: case CAM_ISP_HW_CMD_GET_CHANGE_BASE:
case CAM_ISP_HW_CMD_GET_REG_UPDATE: case CAM_ISP_HW_CMD_CLOCK_UPDATE:
rc = 0; 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; break;
default: default:
CAM_ERR(CAM_SFE, "Invalid cmd type:%d", cmd_type); CAM_ERR(CAM_SFE, "Invalid cmd type: %d", cmd_type);
rc = -EINVAL; rc = -EINVAL;
break; break;
} }
@@ -227,37 +402,85 @@ irqreturn_t cam_sfe_irq(int irq_num, void *data)
} }
int cam_sfe_core_init( int cam_sfe_core_init(
struct cam_sfe_hw_core_info *core_info, struct cam_sfe_hw_core_info *core_info,
struct cam_hw_soc_info *soc_info, struct cam_hw_soc_info *soc_info,
struct cam_hw_intf *hw_intf, struct cam_hw_intf *hw_intf,
struct cam_sfe_hw_info *sfe_hw_info) 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); INIT_LIST_HEAD(&core_info->free_payload_list);
spin_lock_init(&core_info->spin_lock); 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( int cam_sfe_core_deinit(
struct cam_sfe_hw_core_info *core_info, struct cam_sfe_hw_core_info *core_info,
struct cam_sfe_hw_info *sfe_hw_info) struct cam_sfe_hw_info *sfe_hw_info)
{ {
int rc = -EINVAL; int rc = -EINVAL, i;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&core_info->spin_lock, flags); spin_lock_irqsave(&core_info->spin_lock, flags);
INIT_LIST_HEAD(&core_info->free_payload_list); 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) if (rc)
CAM_ERR(CAM_SFE, CAM_ERR(CAM_SFE,
"Error cam_irq_controller_deinit failed rc=%d", rc); "SFE bus rd deinit failed rc: %d", rc);
rc = cam_sfe_bus_deinit(BUS_TYPE_SFE_WR,
sfe_hw_info->bus_wr_version,
&core_info->sfe_bus_wr);
if (rc)
CAM_ERR(CAM_SFE,
"SFE bus wr deinit failed rc: %d", rc);
rc = cam_sfe_top_deinit(sfe_hw_info->top_version,
&core_info->sfe_top);
if (rc)
CAM_ERR(CAM_SFE,
"SFE top deinit failed rc: %d", rc);
spin_unlock_irqrestore(&core_info->spin_lock, flags); spin_unlock_irqrestore(&core_info->spin_lock, flags);
return rc; return rc;
} }

View File

@@ -9,30 +9,48 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include "cam_hw_intf.h" #include "cam_hw_intf.h"
#include "cam_sfe_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_sfe_hw_info {
struct cam_irq_controller_reg_info *irq_reg_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_core_info {
struct cam_sfe_hw_info *sfe_hw_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 *sfe_irq_controller;
void *tasklet_info; void *tasklet_info;
struct cam_sfe_irq_evt_payload evt_payload[CAM_SFE_EVT_MAX];
struct list_head free_payload_list; struct list_head free_payload_list;
spinlock_t spin_lock; spinlock_t spin_lock;
int irq_handle;
}; };
int cam_sfe_get_hw_caps(void *device_priv, int cam_sfe_get_hw_caps(void *device_priv,
void *get_hw_cap_args, uint32_t arg_size); 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, int cam_sfe_init_hw(void *device_priv,
void *init_hw_args, uint32_t arg_size); void *init_hw_args, uint32_t arg_size);
int cam_sfe_deinit_hw(void *hw_priv, int cam_sfe_deinit_hw(void *hw_priv,
void *deinit_hw_args, uint32_t arg_size); 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, int cam_sfe_reserve(void *device_priv,
void *reserve_args, uint32_t arg_size); void *reserve_args, uint32_t arg_size);
int cam_sfe_release(void *device_priv, 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); void *start_args, uint32_t arg_size);
int cam_sfe_stop(void *device_priv, int cam_sfe_stop(void *device_priv,
void *stop_args, uint32_t arg_size); 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, int cam_sfe_process_cmd(void *device_priv, uint32_t cmd_type,
void *cmd_args, uint32_t arg_size); void *cmd_args, uint32_t arg_size);

View File

@@ -6,65 +6,71 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/module.h>
#include "cam_sfe_dev.h" #include "cam_sfe_dev.h"
#include "cam_sfe_core.h" #include "cam_sfe_core.h"
#include "cam_sfe_soc.h" #include "cam_sfe_soc.h"
#include "cam_sfe_hw_intf.h" #include "cam_sfe680.h"
#include "cam_debug_util.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]; 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_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; const struct of_device_id *match_dev = NULL;
struct cam_sfe_hw_core_info *core_info = NULL; struct cam_sfe_hw_core_info *core_info = NULL;
struct cam_sfe_hw_info *hw_info = NULL; struct cam_sfe_hw_info *hw_info = NULL;
struct platform_device *pdev = NULL;
int rc = 0; int rc = 0;
sfe_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); pdev = to_platform_device(dev);
if (!sfe_intf) { sfe_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
if (!sfe_hw_intf) {
rc = -ENOMEM; rc = -ENOMEM;
goto end; goto end;
} }
of_property_read_u32(pdev->dev.of_node, 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); sfe_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
if (!sfe_info) { if (!sfe_info) {
rc = -ENOMEM; rc = -ENOMEM;
goto free_sfe_intf; goto free_sfe_hw_intf;
} }
memset(sfe_dev_name, 0, sizeof(sfe_dev_name)); memset(sfe_dev_name, 0, sizeof(sfe_dev_name));
snprintf(sfe_dev_name, 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.pdev = pdev;
sfe_info->soc_info.dev = &pdev->dev; sfe_info->soc_info.dev = &pdev->dev;
sfe_info->soc_info.dev_name = sfe_dev_name; sfe_info->soc_info.dev_name = sfe_dev_name;
sfe_intf->hw_priv = sfe_info; sfe_hw_intf->hw_priv = sfe_info;
sfe_intf->hw_ops.get_hw_caps = cam_sfe_get_hw_caps; sfe_hw_intf->hw_ops.get_hw_caps = cam_sfe_get_hw_caps;
sfe_intf->hw_ops.init = cam_sfe_init_hw; sfe_hw_intf->hw_ops.init = cam_sfe_init_hw;
sfe_intf->hw_ops.deinit = cam_sfe_deinit_hw; sfe_hw_intf->hw_ops.deinit = cam_sfe_deinit_hw;
sfe_intf->hw_ops.reset = cam_sfe_reset; sfe_hw_intf->hw_ops.reset = cam_sfe_reset;
sfe_intf->hw_ops.reserve = cam_sfe_reserve; sfe_hw_intf->hw_ops.reserve = cam_sfe_reserve;
sfe_intf->hw_ops.release = cam_sfe_release; sfe_hw_intf->hw_ops.release = cam_sfe_release;
sfe_intf->hw_ops.start = cam_sfe_start; sfe_hw_intf->hw_ops.start = cam_sfe_start;
sfe_intf->hw_ops.stop = cam_sfe_stop; sfe_hw_intf->hw_ops.stop = cam_sfe_stop;
sfe_intf->hw_ops.read = cam_sfe_read; sfe_hw_intf->hw_ops.read = cam_sfe_read;
sfe_intf->hw_ops.write = cam_sfe_write; sfe_hw_intf->hw_ops.write = cam_sfe_write;
sfe_intf->hw_ops.process_cmd = cam_sfe_process_cmd; sfe_hw_intf->hw_ops.process_cmd = cam_sfe_process_cmd;
sfe_intf->hw_type = CAM_ISP_HW_TYPE_SFE; sfe_hw_intf->hw_type = CAM_ISP_HW_TYPE_SFE;
CAM_DBG(CAM_SFE, "type %d index %d", CAM_DBG(CAM_SFE, "SFE component bind type %d index %d",
sfe_intf->hw_type, sfe_intf->hw_idx); sfe_hw_intf->hw_type, sfe_hw_intf->hw_idx);
platform_set_drvdata(pdev, sfe_intf); platform_set_drvdata(pdev, sfe_hw_intf);
sfe_info->core_info = kzalloc(sizeof(struct cam_sfe_hw_core_info), sfe_info->core_info = kzalloc(sizeof(struct cam_sfe_hw_core_info),
GFP_KERNEL); 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, rc = cam_sfe_core_init(core_info, &sfe_info->soc_info,
sfe_intf, hw_info); sfe_hw_intf, hw_info);
if (rc < 0) { if (rc < 0) {
CAM_ERR(CAM_SFE, "Failed to init core rc=%d", rc); CAM_ERR(CAM_SFE, "Failed to init core rc=%d", rc);
goto deinit_soc; goto deinit_soc;
@@ -104,9 +110,11 @@ int cam_sfe_probe(struct platform_device *pdev)
spin_lock_init(&sfe_info->hw_lock); spin_lock_init(&sfe_info->hw_lock);
init_completion(&sfe_info->hw_complete); 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; return rc;
@@ -117,40 +125,45 @@ free_core_info:
kfree(sfe_info->core_info); kfree(sfe_info->core_info);
free_sfe_hw: free_sfe_hw:
kfree(sfe_info); kfree(sfe_info);
free_sfe_intf: free_sfe_hw_intf:
kfree(sfe_intf); kfree(sfe_hw_intf);
end: end:
return rc; 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_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 cam_sfe_hw_core_info *core_info = NULL;
struct platform_device *pdev = NULL;
int rc = 0; int rc = 0;
sfe_intf = platform_get_drvdata(pdev); pdev = to_platform_device(dev);
if (!sfe_intf) { sfe_hw_intf = platform_get_drvdata(pdev);
if (!sfe_hw_intf) {
CAM_ERR(CAM_SFE, "Error! No data in pdev"); CAM_ERR(CAM_SFE, "Error! No data in pdev");
return -EINVAL; return;
} }
CAM_DBG(CAM_SFE, "type %d index %d", CAM_DBG(CAM_SFE, "SFE component unbound type %d index %d",
sfe_intf->hw_type, sfe_intf->hw_idx); 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) { if (!sfe_info) {
CAM_ERR(CAM_SFE, "Error! HW data is NULL"); CAM_ERR(CAM_SFE, "HW data is NULL");
rc = -ENODEV; rc = -ENODEV;
goto free_sfe_intf; goto free_sfe_hw_intf;
} }
core_info = (struct cam_sfe_hw_core_info *)sfe_info->core_info; core_info = (struct cam_sfe_hw_core_info *)sfe_info->core_info;
if (!core_info) { if (!core_info) {
CAM_ERR(CAM_SFE, "Error! core data NULL"); CAM_ERR(CAM_SFE, "core data NULL");
rc = -EINVAL; rc = -EINVAL;
goto deinit_soc; goto deinit_soc;
} }
@@ -169,25 +182,80 @@ deinit_soc:
mutex_destroy(&sfe_info->hw_mutex); mutex_destroy(&sfe_info->hw_mutex);
kfree(sfe_info); kfree(sfe_info);
CAM_DBG(CAM_SFE, "SFE%d remove successful", sfe_intf->hw_idx); CAM_DBG(CAM_SFE, "SFE%d remove successful", sfe_hw_intf->hw_idx);
free_sfe_intf: free_sfe_hw_intf:
kfree(sfe_intf); kfree(sfe_hw_intf);
}
const static struct component_ops cam_sfe_component_ops = {
.bind = cam_sfe_component_bind,
.unbind = cam_sfe_component_unbind,
};
int cam_sfe_probe(struct platform_device *pdev)
{
int rc = 0;
CAM_DBG(CAM_SFE, "Adding SFE component");
rc = component_add(&pdev->dev, &cam_sfe_component_ops);
if (rc)
CAM_ERR(CAM_SFE, "failed to add component rc: %d", rc);
return rc; 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; int rc = 0;
if (sfe_instance) { if (cam_sfe_hw_list[hw_idx]) {
*sfe_intf = sfe_instance; *sfe_hw = cam_sfe_hw_list[hw_idx];
rc = 0; rc = 0;
} else { } else {
*sfe_intf = NULL; *sfe_hw = NULL;
rc = -ENODEV; rc = -ENODEV;
} }
return rc; 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");

View File

@@ -6,30 +6,18 @@
#ifndef _CAM_SFE_DEV_H_ #ifndef _CAM_SFE_DEV_H_
#define _CAM_SFE_DEV_H_ #define _CAM_SFE_DEV_H_
#include <linux/platform_device.h> /**
* @brief : API to register SFE hw to platform framework.
/*
* cam_sfe_probe()
*
* @brief: Driver probe function called on Boot
*
* @pdev: Platform Device pointer
*
* @Return: 0: Success * @Return: 0: Success
* Non-zero: Failure * Non-zero: Failure
*/ */
int cam_sfe_probe(struct platform_device *pdev); int cam_sfe_init_module(void);
/* /**
* cam_sfe_remove() * @brief : API to remove SFE Hw from platform framework.
*
* @brief: Driver remove function
*
* @pdev: Platform Device pointer
*
* @Return: 0: Success * @Return: 0: Success
* Non-zero: Failure * Non-zero: Failure
*/ */
int cam_sfe_remove(struct platform_device *pdev); void cam_sfe_exit_module(void);
#endif /* _CAM_SFE_DEV_H_ */ #endif /* _CAM_SFE_DEV_H_ */

View File

@@ -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) irq_handler_t irq_handler_func, void *irq_data)
{ {
int rc = 0; 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); rc = cam_sfe_get_dt_properties(soc_info);
if (rc < 0) { if (rc < 0) {
CAM_ERR(CAM_SFE, "Error Get DT properties failed rc=%d", rc); 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, 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) { if (rc < 0) {
CAM_ERR(CAM_SFE, CAM_ERR(CAM_SFE,
"Error Request platform resources failed rc=%d", rc); "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; return rc;
} }
int cam_sfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info) int cam_sfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info)
{ {
int rc = 0; int rc = 0;
struct cam_sfe_soc_private *soc_private;
if (!soc_info) { if (!soc_info) {
CAM_ERR(CAM_SFE, "Error soc_info NULL"); CAM_ERR(CAM_SFE, "Error soc_info NULL");
return -ENODEV; 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); rc = cam_sfe_release_platform_resource(soc_info);
if (rc < 0) if (rc < 0)
CAM_ERR(CAM_SFE, CAM_ERR(CAM_SFE,
"Error Release platform resources failed rc=%d", rc); "Error Release platform resources failed rc=%d", rc);
kfree(soc_private);
return rc; return rc;
} }
int cam_sfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) 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, if (!soc_info) {
CAM_TURBO_VOTE, true); 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) { 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; 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: end:
return rc; return rc;
} }
@@ -113,14 +191,26 @@ int cam_sfe_soc_disable_clk(struct cam_hw_soc_info *soc_info,
return -EPERM; return -EPERM;
} }
int cam_sfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) int cam_sfe_disable_soc_resources(struct cam_hw_soc_info *soc_info)
{ {
int rc = 0; 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); rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
if (rc) if (rc)
CAM_ERR(CAM_SFE, "Disable platform failed rc=%d", 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; return rc;
} }

View File

@@ -37,7 +37,7 @@ struct cam_sfe_soc_private {
* Non-zero: Failure * Non-zero: Failure
*/ */
int cam_sfe_init_soc_resources(struct cam_hw_soc_info *soc_info, 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() * cam_sfe_deinit_soc_resources()

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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_ */

File diff suppressed because it is too large Load Diff

View File

@@ -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_ */

View File

@@ -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_ */

View File

@@ -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;
}

View File

@@ -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_ */

View File

@@ -13,6 +13,7 @@
#include "cam_ife_csid_dev.h" #include "cam_ife_csid_dev.h"
#include "cam_vfe.h" #include "cam_vfe.h"
#include "cam_sfe_dev.h"
#include "cam_isp_dev.h" #include "cam_isp_dev.h"
#include "cam_res_mgr_api.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_csid17x_init_module, &cam_ife_csid17x_exit_module},
{&cam_ife_csid_lite_init_module, &cam_ife_csid_lite_exit_module}, {&cam_ife_csid_lite_init_module, &cam_ife_csid_lite_exit_module},
{&cam_vfe_init_module, &cam_vfe_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}, {&cam_isp_dev_init_module, &cam_isp_dev_exit_module},
#endif #endif
}; };

View File

@@ -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_csid17x_driver;
extern struct platform_driver cam_ife_csid_lite_driver; extern struct platform_driver cam_ife_csid_lite_driver;
extern struct platform_driver cam_vfe_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; extern struct platform_driver isp_driver;
#endif #endif
#ifdef CONFIG_SPECTRA_TFE #ifdef CONFIG_SPECTRA_TFE
@@ -89,6 +92,9 @@ static struct platform_driver *const cam_component_drivers[] = {
&cam_ife_csid17x_driver, &cam_ife_csid17x_driver,
&cam_ife_csid_lite_driver, &cam_ife_csid_lite_driver,
&cam_vfe_driver, &cam_vfe_driver,
#ifdef CONFIG_SPECTRA_SFE
&cam_sfe_driver,
#endif
&isp_driver, &isp_driver,
#endif #endif
#ifdef CONFIG_SPECTRA_SENSOR #ifdef CONFIG_SPECTRA_SENSOR