From 0934fe0103b8442d1dbfc9c9491f42b0db388444 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 30 Mar 2020 16:55:19 -0700 Subject: [PATCH] msm: camera: isp: Add code for SFE HW Add initial code drop for SFE HW. CRs-Fixed: 2733230 Change-Id: I44437bbe05d8c60d219c31cb626a4c9845a469e0 Signed-off-by: Jigarkumar Zala --- drivers/Makefile | 5 + .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 1 + .../isp_hw/include/cam_sfe_hw_intf.h | 157 +++++++++++ .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c | 263 ++++++++++++++++++ .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h | 61 ++++ .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c | 193 +++++++++++++ .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.h | 35 +++ .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c | 126 +++++++++ .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.h | 106 +++++++ drivers/cam_utils/cam_debug_util.c | 3 + drivers/cam_utils/cam_debug_util.h | 1 + 11 files changed, 951 insertions(+) create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.h diff --git a/drivers/Makefile b/drivers/Makefile index 154009e600..b4cd9bb273 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -97,6 +97,11 @@ camera-$(CONFIG_SPECTRA_ISP) += \ cam_isp/cam_isp_dev.o \ cam_isp/cam_isp_context.o +camera-$(CONFIG_SPECTRA_SFE) += \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.o \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.o \ + cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.o + camera-$(CONFIG_SPECTRA_ICP) += \ cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.o \ cam_icp/icp_hw/ipe_hw/ipe_dev.o \ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index de5b049960..7bbff8fab2 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -49,6 +49,7 @@ enum cam_isp_hw_type { CAM_ISP_HW_TYPE_TFE, CAM_ISP_HW_TYPE_TFE_CSID, CAM_ISP_HW_TYPE_TPG, + CAM_ISP_HW_TYPE_SFE, CAM_ISP_HW_TYPE_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h new file mode 100644 index 0000000000..8fab99e212 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SFE_HW_INTF_H_ +#define _CAM_SFE_HW_INTF_H_ + +#include "cam_isp_hw.h" + +#define CAM_SFE_HW_NUM_MAX 2 +#define SFE_CORE_BASE_IDX 0 + +enum cam_isp_hw_sfe_in { + CAM_ISP_HW_SFE_IN_PIX, + CAM_ISP_HW_SFE_IN_RD0, + CAM_ISP_HW_SFE_IN_RD1, + CAM_ISP_HW_SFE_IN_RD2, + CAM_ISP_HW_SFE_IN_RDI0, + CAM_ISP_HW_SFE_IN_RDI1, + CAM_ISP_HW_SFE_IN_RDI2, + CAM_ISP_HW_SFE_IN_RDI3, + CAM_ISP_HW_SFE_IN_RDI4, + CAM_ISP_HW_SFE_IN_MAX, +}; + +enum cam_sfe_hw_irq_status { + CAM_SFE_IRQ_STATUS_SUCCESS, + CAM_SFE_IRQ_STATUS_ERR, + CAM_SFE_IRQ_STATUS_OVERFLOW, + CAM_SFE_IRQ_STATUS_VIOLATION, + CAM_SFE_IRQ_STATUS_MAX, +}; + +/* + * struct cam_sfe_hw_get_hw_cap: + * + * @reserved_1: reserved + * @reserved_2: reserved + * @reserved_3: reserved + * @reserved_4: reserved + */ +struct cam_sfe_hw_get_hw_cap { + uint32_t reserved_1; + uint32_t reserved_2; + uint32_t reserved_3; + uint32_t reserved_4; +}; + +/* + * struct cam_sfe_hw_vfe_bus_rd_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @res_id: Unique Identity of port to associate with this + * resource. + * @is_dual: Flag to indicate dual SFE usecase + * @cdm_ops: CDM operations + * @unpacket_fmt: Unpacker format for read engine + * @is_offline: Flag to indicate offline usecase + */ +struct cam_sfe_hw_sfe_bus_rd_acquire_args { + struct cam_isp_resource_node *rsrc_node; + uint32_t res_id; + uint32_t is_dual; + struct cam_cdm_utils_ops *cdm_ops; + uint32_t unpacker_fmt; + bool is_offline; +}; + +/* + * struct cam_sfe_hw_sfe_bus_in_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @res_id: Unique Identity of port to associate with this + * resource. + * @cdm_ops: CDM operations + * @is_dual: Dual mode usecase + * @sync_mode: If in dual mode, indicates master/slave + * @in_port: in port info + * @is_fe_enabled: Flag to indicate if FE is enabled + * @is_offline: Flag to indicate Offline IFE + */ +struct cam_sfe_hw_sfe_in_acquire_args { + struct cam_isp_resource_node *rsrc_node; + uint32_t res_id; + struct cam_cdm_utils_ops *cdm_ops; + uint32_t is_dual; + enum cam_isp_hw_sync_mode sync_mode; + struct cam_isp_in_port_generic_info *in_port; + bool is_fe_enabled; + bool is_offline; +}; + +/* + * struct cam_sfe_hw_sfe_out_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @out_port_info: Output Port details to acquire + * @unique_id: Unique Identity of Context to associate with this + * resource. Used for composite grouping of multiple + * resources in the same context + * @is_dual: Dual SFE or not + * @split_id: In case of Dual SFE, this is Left or Right. + * @is_master: In case of Dual SFE, this is Master or Slave. + * @cdm_ops: CDM operations + */ +struct cam_sfe_hw_sfe_out_acquire_args { + struct cam_isp_resource_node *rsrc_node; + struct cam_isp_out_port_generic_info *out_port_info; + uint32_t unique_id; + uint32_t is_dual; + enum cam_isp_hw_split_id split_id; + uint32_t is_master; + struct cam_cdm_utils_ops *cdm_ops; +}; + +/* + * struct cam_sfe_acquire_args: + * + * @rsrc_type: Type of Resource (OUT/IN) to acquire + * @tasklet: Tasklet to associate with this resource. This is + * used to schedule bottom of IRQ events associated + * with this resource. + * @priv: Context data + * @event_cb: Callback function to hw mgr in case of hw events + * @sfe_out: Acquire args for SFE_OUT + * @sfe_bus_rd Acquire args for SFE_BUS_READ + * @sfe_in: Acquire args for SFE_IN + */ +struct cam_sfe_acquire_args { + enum cam_isp_resource_type rsrc_type; + void *tasklet; + void *priv; + cam_hw_mgr_event_cb_func event_cb; + union { + 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_bus_rd_acquire_args sfe_rd; + }; +}; + +/* + * cam_sfe_hw_init() + * + * @Brief: Initialize SFE HW device + * + * @sfe_hw: sfe_hw interface to fill in and return on + * successful initialization + * @hw_idx: Index of SFE HW + */ +int cam_sfe_hw_init(struct cam_hw_intf **sfe_hw, uint32_t hw_idx); + +#endif /* _CAM_SFE_HW_INTF_H_ */ + diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c new file mode 100644 index 0000000000..73e29bee3c --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_tasklet_util.h" +#include "cam_sfe_hw_intf.h" +#include "cam_sfe_soc.h" +#include "cam_sfe_core.h" +#include "cam_debug_util.h" + +static const char drv_name[] = "sfe"; +#define SFE_CORE_BASE_IDX 0 + +int cam_sfe_get_hw_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size) +{ + CAM_DBG(CAM_SFE, "Enter"); + return 0; +} + +int cam_sfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *sfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_sfe_hw_core_info *core_info = NULL; + struct cam_isp_resource_node *isp_res = NULL; + int rc = 0; + + CAM_DBG(CAM_SFE, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_SFE, "Invalid arguments"); + return -EINVAL; + } + + mutex_lock(&sfe_hw->hw_mutex); + sfe_hw->open_count++; + if (sfe_hw->open_count > 1) { + mutex_unlock(&sfe_hw->hw_mutex); + CAM_DBG(CAM_SFE, "SFE has already been initialized cnt %d", + sfe_hw->open_count); + return 0; + } + mutex_unlock(&sfe_hw->hw_mutex); + + soc_info = &sfe_hw->soc_info; + core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info; + + /* Turn ON Regulators, Clocks and other SOC resources */ + rc = cam_sfe_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_SFE, "Enable SOC failed"); + rc = -EFAULT; + goto decrement_open_cnt; + } + + isp_res = (struct cam_isp_resource_node *)init_hw_args; + if (isp_res && isp_res->init) { + rc = isp_res->init(isp_res, NULL, 0); + if (rc) { + CAM_ERR(CAM_SFE, "init Failed rc=%d", rc); + goto disable_soc; + } + } + + CAM_DBG(CAM_SFE, "Enable soc done"); + + /* Do HW Reset */ + rc = cam_sfe_reset(hw_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_SFE, "Reset Failed rc=%d", rc); + goto deinit_sfe_res; + } + + sfe_hw->hw_state = CAM_HW_STATE_POWER_UP; + return rc; + +deinit_sfe_res: + if (isp_res && isp_res->deinit) + isp_res->deinit(isp_res, NULL, 0); +disable_soc: + cam_sfe_disable_soc_resources(soc_info); +decrement_open_cnt: + mutex_lock(&sfe_hw->hw_mutex); + sfe_hw->open_count--; + mutex_unlock(&sfe_hw->hw_mutex); + return rc; +} + +int cam_sfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *sfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_sfe_hw_core_info *core_info = NULL; + struct cam_isp_resource_node *isp_res = NULL; + int rc = 0; + + CAM_DBG(CAM_SFE, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_SFE, "Invalid arguments"); + return -EINVAL; + } + + mutex_lock(&sfe_hw->hw_mutex); + if (!sfe_hw->open_count) { + mutex_unlock(&sfe_hw->hw_mutex); + CAM_ERR(CAM_SFE, "Error! Unbalanced deinit"); + return -EFAULT; + } + sfe_hw->open_count--; + if (sfe_hw->open_count) { + mutex_unlock(&sfe_hw->hw_mutex); + CAM_DBG(CAM_SFE, "open_cnt non-zero =%d", sfe_hw->open_count); + return 0; + } + mutex_unlock(&sfe_hw->hw_mutex); + + soc_info = &sfe_hw->soc_info; + core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info; + + isp_res = (struct cam_isp_resource_node *)deinit_hw_args; + if (isp_res && isp_res->deinit) { + rc = isp_res->deinit(isp_res, NULL, 0); + if (rc) + CAM_ERR(CAM_SFE, "deinit failed"); + } + + /* Turn OFF Regulators, Clocks and other SOC resources */ + CAM_DBG(CAM_SFE, "Disable SOC resource"); + rc = cam_sfe_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_SFE, "Disable SOC failed"); + + sfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + + CAM_DBG(CAM_SFE, "Exit"); + return rc; +} + +int cam_sfe_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) +{ + CAM_DBG(CAM_SFE, "Enter"); + return 0; +} + +int cam_sfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size) +{ + CAM_DBG(CAM_SFE, "Enter"); + return 0; +} + +int cam_sfe_release(void *hw_priv, void *release_args, uint32_t arg_size) +{ + CAM_DBG(CAM_SFE, "Enter"); + return 0; +} + +int cam_sfe_start(void *hw_priv, void *start_args, uint32_t arg_size) +{ + CAM_DBG(CAM_SFE, "Enter"); + return 0; +} + +int cam_sfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) +{ + CAM_DBG(CAM_SFE, "Enter"); + return 0; +} + +int cam_sfe_read(void *hw_priv, void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_sfe_write(void *hw_priv, void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *sfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_sfe_hw_core_info *core_info = NULL; + struct cam_sfe_hw_info *hw_info = NULL; + int rc; + + if (!hw_priv) { + CAM_ERR(CAM_SFE, "Invalid arguments"); + return -EINVAL; + } + + soc_info = &sfe_hw->soc_info; + core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info; + hw_info = core_info->sfe_hw_info; + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_CHANGE_BASE: + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = 0; + break; + + default: + CAM_ERR(CAM_SFE, "Invalid cmd type:%d", cmd_type); + rc = -EINVAL; + break; + } + + return rc; +} + +irqreturn_t cam_sfe_irq(int irq_num, void *data) +{ + struct cam_hw_info *sfe_hw; + struct cam_sfe_hw_core_info *core_info; + + if (!data) + return IRQ_NONE; + + sfe_hw = (struct cam_hw_info *)data; + core_info = (struct cam_sfe_hw_core_info *)sfe_hw->core_info; + + return cam_irq_controller_handle_irq(irq_num, + core_info->sfe_irq_controller); +} + +int cam_sfe_core_init( + struct cam_sfe_hw_core_info *core_info, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + struct cam_sfe_hw_info *sfe_hw_info) +{ + + CAM_DBG(CAM_SFE, "Enter"); + + INIT_LIST_HEAD(&core_info->free_payload_list); + spin_lock_init(&core_info->spin_lock); + + return 0; +} + +int cam_sfe_core_deinit( + struct cam_sfe_hw_core_info *core_info, + struct cam_sfe_hw_info *sfe_hw_info) +{ + int rc = -EINVAL; + unsigned long flags; + + spin_lock_irqsave(&core_info->spin_lock, flags); + + INIT_LIST_HEAD(&core_info->free_payload_list); + + rc = cam_irq_controller_deinit(&core_info->sfe_irq_controller); + if (rc) + CAM_ERR(CAM_SFE, + "Error cam_irq_controller_deinit failed rc=%d", rc); + + spin_unlock_irqrestore(&core_info->spin_lock, flags); + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h new file mode 100644 index 0000000000..4c25b44584 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SFE_CORE_H_ +#define _CAM_SFE_CORE_H_ + +#include +#include "cam_hw_intf.h" +#include "cam_sfe_hw_intf.h" + +struct cam_sfe_hw_info { + struct cam_irq_controller_reg_info *irq_reg_info; +}; + +#define CAM_SFE_EVT_MAX 256 + +struct cam_sfe_hw_core_info { + struct cam_sfe_hw_info *sfe_hw_info; + void *sfe_irq_controller; + void *tasklet_info; + struct list_head free_payload_list; + spinlock_t spin_lock; + int irq_handle; +}; + +int cam_sfe_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size); +int cam_sfe_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_sfe_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size); +int cam_sfe_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size); +int cam_sfe_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size); +int cam_sfe_release(void *device_priv, + void *reserve_args, uint32_t arg_size); +int cam_sfe_start(void *device_priv, + void *start_args, uint32_t arg_size); +int cam_sfe_stop(void *device_priv, + void *stop_args, uint32_t arg_size); +int cam_sfe_read(void *device_priv, + void *read_args, uint32_t arg_size); +int cam_sfe_write(void *device_priv, + void *write_args, uint32_t arg_size); +int cam_sfe_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +irqreturn_t cam_sfe_irq(int irq_num, void *data); + +int cam_sfe_core_init(struct cam_sfe_hw_core_info *core_info, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + struct cam_sfe_hw_info *sfe_hw_info); + +int cam_sfe_core_deinit(struct cam_sfe_hw_core_info *core_info, + struct cam_sfe_hw_info *sfe_hw_info); + +#endif /* _CAM_SFE_CORE_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c new file mode 100644 index 0000000000..3e41a654cf --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include "cam_sfe_dev.h" +#include "cam_sfe_core.h" +#include "cam_sfe_soc.h" +#include "cam_sfe_hw_intf.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *sfe_instance; + +static char sfe_dev_name[8]; + +int cam_sfe_probe(struct platform_device *pdev) +{ + struct cam_hw_info *sfe_info = NULL; + struct cam_hw_intf *sfe_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_sfe_hw_core_info *core_info = NULL; + struct cam_sfe_hw_info *hw_info = NULL; + int rc = 0; + + sfe_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!sfe_intf) { + rc = -ENOMEM; + goto end; + } + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &sfe_intf->hw_idx); + + sfe_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!sfe_info) { + rc = -ENOMEM; + goto free_sfe_intf; + } + + memset(sfe_dev_name, 0, sizeof(sfe_dev_name)); + snprintf(sfe_dev_name, sizeof(sfe_dev_name), + "sfe%1u", sfe_intf->hw_idx); + + sfe_info->soc_info.pdev = pdev; + sfe_info->soc_info.dev = &pdev->dev; + sfe_info->soc_info.dev_name = sfe_dev_name; + sfe_intf->hw_priv = sfe_info; + sfe_intf->hw_ops.get_hw_caps = cam_sfe_get_hw_caps; + sfe_intf->hw_ops.init = cam_sfe_init_hw; + sfe_intf->hw_ops.deinit = cam_sfe_deinit_hw; + sfe_intf->hw_ops.reset = cam_sfe_reset; + sfe_intf->hw_ops.reserve = cam_sfe_reserve; + sfe_intf->hw_ops.release = cam_sfe_release; + sfe_intf->hw_ops.start = cam_sfe_start; + sfe_intf->hw_ops.stop = cam_sfe_stop; + sfe_intf->hw_ops.read = cam_sfe_read; + sfe_intf->hw_ops.write = cam_sfe_write; + sfe_intf->hw_ops.process_cmd = cam_sfe_process_cmd; + sfe_intf->hw_type = CAM_ISP_HW_TYPE_SFE; + + CAM_DBG(CAM_SFE, "type %d index %d", + sfe_intf->hw_type, sfe_intf->hw_idx); + + platform_set_drvdata(pdev, sfe_intf); + + sfe_info->core_info = kzalloc(sizeof(struct cam_sfe_hw_core_info), + GFP_KERNEL); + if (!sfe_info->core_info) { + CAM_DBG(CAM_SFE, "Failed to alloc for core"); + rc = -ENOMEM; + goto free_sfe_hw; + } + core_info = (struct cam_sfe_hw_core_info *)sfe_info->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_SFE, "Of_match Failed"); + rc = -EINVAL; + goto free_core_info; + } + hw_info = (struct cam_sfe_hw_info *)match_dev->data; + core_info->sfe_hw_info = hw_info; + + rc = cam_sfe_init_soc_resources(&sfe_info->soc_info, cam_sfe_irq, + sfe_info); + if (rc < 0) { + CAM_ERR(CAM_SFE, "Failed to init soc rc=%d", rc); + goto free_core_info; + } + + rc = cam_sfe_core_init(core_info, &sfe_info->soc_info, + sfe_intf, hw_info); + if (rc < 0) { + CAM_ERR(CAM_SFE, "Failed to init core rc=%d", rc); + goto deinit_soc; + } + + sfe_info->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&sfe_info->hw_mutex); + spin_lock_init(&sfe_info->hw_lock); + init_completion(&sfe_info->hw_complete); + + sfe_instance = sfe_intf; + + CAM_DBG(CAM_SFE, "SFE%d probe successful", sfe_intf->hw_idx); + + return rc; + +deinit_soc: + if (cam_sfe_deinit_soc_resources(&sfe_info->soc_info)) + CAM_ERR(CAM_SFE, "Failed to deinit soc"); +free_core_info: + kfree(sfe_info->core_info); +free_sfe_hw: + kfree(sfe_info); +free_sfe_intf: + kfree(sfe_intf); +end: + return rc; +} + +int cam_sfe_remove(struct platform_device *pdev) +{ + struct cam_hw_info *sfe_info = NULL; + struct cam_hw_intf *sfe_intf = NULL; + struct cam_sfe_hw_core_info *core_info = NULL; + int rc = 0; + + sfe_intf = platform_get_drvdata(pdev); + if (!sfe_intf) { + CAM_ERR(CAM_SFE, "Error! No data in pdev"); + return -EINVAL; + } + + CAM_DBG(CAM_SFE, "type %d index %d", + sfe_intf->hw_type, sfe_intf->hw_idx); + + sfe_instance = NULL; + + sfe_info = sfe_intf->hw_priv; + if (!sfe_info) { + CAM_ERR(CAM_SFE, "Error! HW data is NULL"); + rc = -ENODEV; + goto free_sfe_intf; + } + + core_info = (struct cam_sfe_hw_core_info *)sfe_info->core_info; + if (!core_info) { + CAM_ERR(CAM_SFE, "Error! core data NULL"); + rc = -EINVAL; + goto deinit_soc; + } + + rc = cam_sfe_core_deinit(core_info, core_info->sfe_hw_info); + if (rc < 0) + CAM_ERR(CAM_SFE, "Failed to deinit core rc=%d", rc); + + kfree(sfe_info->core_info); + +deinit_soc: + rc = cam_sfe_deinit_soc_resources(&sfe_info->soc_info); + if (rc < 0) + CAM_ERR(CAM_SFE, "Failed to deinit soc rc=%d", rc); + + mutex_destroy(&sfe_info->hw_mutex); + kfree(sfe_info); + + CAM_DBG(CAM_SFE, "SFE%d remove successful", sfe_intf->hw_idx); + +free_sfe_intf: + kfree(sfe_intf); + + return rc; +} + +int cam_sfe_hw_init(struct cam_hw_intf **sfe_intf, uint32_t hw_idx) +{ + int rc = 0; + + if (sfe_instance) { + *sfe_intf = sfe_instance; + rc = 0; + } else { + *sfe_intf = NULL; + rc = -ENODEV; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.h new file mode 100644 index 0000000000..b49ad32178 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_dev.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SFE_DEV_H_ +#define _CAM_SFE_DEV_H_ + +#include + +/* + * cam_sfe_probe() + * + * @brief: Driver probe function called on Boot + * + * @pdev: Platform Device pointer + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_probe(struct platform_device *pdev); + +/* + * cam_sfe_remove() + * + * @brief: Driver remove function + * + * @pdev: Platform Device pointer + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_remove(struct platform_device *pdev); + +#endif /* _CAM_SFE_DEV_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c new file mode 100644 index 0000000000..fb72657a15 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_cpas_api.h" +#include "cam_sfe_soc.h" +#include "cam_debug_util.h" + +static int cam_sfe_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) + CAM_ERR(CAM_SFE, "Error get DT properties failed rc=%d", rc); + + return rc; +} + +static int cam_sfe_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler_func, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, irq_handler_func, + irq_data); + if (rc) + CAM_ERR(CAM_SFE, + "Error Request platform resource failed rc=%d", rc); + + return rc; +} + +static int cam_sfe_release_platform_resource(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_SFE, + "Error Release platform resource failed rc=%d", rc); + + return rc; +} + +int cam_sfe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler_func, void *irq_data) +{ + int rc = 0; + + rc = cam_sfe_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_SFE, "Error Get DT properties failed rc=%d", rc); + goto end; + } + + rc = cam_sfe_request_platform_resource(soc_info, + irq_handler_func, irq_data); + if (rc < 0) { + CAM_ERR(CAM_SFE, + "Error Request platform resources failed rc=%d", rc); + goto end; + } + +end: + return rc; +} + +int cam_sfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + if (!soc_info) { + CAM_ERR(CAM_SFE, "Error soc_info NULL"); + return -ENODEV; + } + + rc = cam_sfe_release_platform_resource(soc_info); + if (rc < 0) + CAM_ERR(CAM_SFE, + "Error Release platform resources failed rc=%d", rc); + + return rc; +} + +int cam_sfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_TURBO_VOTE, true); + if (rc) { + CAM_ERR(CAM_SFE, "Error enable platform failed rc=%d", rc); + goto end; + } + +end: + return rc; +} + +int cam_sfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name) +{ + return -EPERM; +} + +int cam_sfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name) +{ + return -EPERM; +} + + +int cam_sfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_SFE, "Disable platform failed rc=%d", rc); + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.h new file mode 100644 index 0000000000..37bf2918c5 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SFE_SOC_H_ +#define _CAM_SFE_SOC_H_ + +#include "cam_soc_util.h" +#include "cam_isp_hw.h" + +/* + * struct cam_sfe_soc_private: + * + * @Brief: Private SOC data specific to SFE HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver + * This handle is used for all further interface + * with CPAS. + * @cpas_version: CPAS version + */ +struct cam_sfe_soc_private { + uint32_t cpas_handle; + uint32_t cpas_version; +}; + +/* + * cam_sfe_init_soc_resources() + * + * @Brief: Initialize SOC resources including private data + * + * @soc_info: Device soc information + * @handler: Irq handler function pointer + * @irq_data: Irq handler function Callback data + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, void *irq_data); + +/* + * cam_sfe_deinit_soc_resources() + * + * @Brief: Deinitialize SOC resources including private data + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_sfe_enable_soc_resources() + * + * @brief: Enable regulator, irq resources, Clocks + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_sfe_disable_soc_resources() + * + * @brief: Disable regulator, irq resources, Clocks + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_sfe_soc_enable_clk() + * + * @brief: Enable clock wsfe given name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to enable + * + * @Return: 0: Success + * Non-zero: Failure + */ +extern int cam_sfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name); + +/* + * cam_sfe_soc_disable_clk() + * + * @brief: Disable clock wsfe given name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to enable + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_sfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name); + +#endif /* _CAM_SFE_SOC_H_ */ diff --git a/drivers/cam_utils/cam_debug_util.c b/drivers/cam_utils/cam_debug_util.c index 32b9b27444..d4ea078119 100644 --- a/drivers/cam_utils/cam_debug_util.c +++ b/drivers/cam_utils/cam_debug_util.c @@ -215,6 +215,9 @@ const char *cam_get_module_name(unsigned int module_id) case CAM_IO_ACCESS: name = "CAM-IO-ACCESS"; break; + case CAM_SFE: + name = "CAM-SFE"; + break; default: name = "CAM"; break; diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h index 69bdc6d62d..5232501525 100644 --- a/drivers/cam_utils/cam_debug_util.h +++ b/drivers/cam_utils/cam_debug_util.h @@ -39,6 +39,7 @@ #define CAM_PRESIL (1 << 27) #define CAM_OPE (1 << 28) #define CAM_IO_ACCESS (1 << 29) +#define CAM_SFE (1 << 30) /* Log level types */ #define CAM_TYPE_TRACE (1 << 0)