Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 59c745ae authored by Camera Software Integration's avatar Camera Software Integration Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: isp: Add code for SFE HW" into camera-kernel.lnx.4.0

parents 876c0a9b 0934fe01
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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 \
+1 −0
Original line number Diff line number Diff line
@@ -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,
};

+157 −0
Original line number Diff line number Diff line
/* 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_ */
+263 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
 */

#include <linux/slab.h>
#include <linux/list.h>
#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;
}
+61 −0
Original line number Diff line number Diff line
/* 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 <linux/spinlock.h>
#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_ */
Loading