msm: camera: ope: Add support to OPE driver

OPE is camera offline engine, support is added
to enable camera OPE hardware.

CRs-Fixed: 2594541
Change-Id: I65c69f5763d05abf265b645b09c95c55fb290182
Signed-off-by: Suresh Vankadara <svankada@codeaurora.org>
Signed-off-by: Ravikishore Pampana <rpampana@codeaurora.org>
Signed-off-by: Trishansh Bhardwaj <tbhardwa@codeaurora.org>
This commit is contained in:
Trishansh Bhardwaj
2019-12-20 14:29:58 +05:30
committed by Karthik Jayakumar
parent b7cfa8b7b0
commit 12d9311463
24 changed files with 8740 additions and 3 deletions

View File

@@ -172,6 +172,17 @@ camera-$(CONFIG_SPECTRA_CUSTOM) += \
cam_cust/cam_custom_dev.o \
cam_cust/cam_custom_context.o
camera-$(CONFIG_SPECTRA_OPE) += \
cam_ope/cam_ope_subdev.o \
cam_ope/cam_ope_context.o \
cam_ope/ope_hw_mgr/cam_ope_hw_mgr.o \
cam_ope/ope_hw_mgr/ope_hw/ope_dev.o \
cam_ope/ope_hw_mgr/ope_hw/ope_soc.o \
cam_ope/ope_hw_mgr/ope_hw/ope_core.o \
cam_ope/ope_hw_mgr/ope_hw/top/ope_top.o \
cam_ope/ope_hw_mgr/ope_hw/bus_rd/ope_bus_rd.o\
cam_ope/ope_hw_mgr/ope_hw/bus_wr/ope_bus_wr.o
camera-y += camera_main.o
obj-$(CONFIG_SPECTRA_CAMERA) += camera.o

View File

@@ -0,0 +1,273 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/debugfs.h>
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <media/cam_sync.h>
#include <media/cam_defs.h>
#include <media/cam_ope.h>
#include "cam_sync_api.h"
#include "cam_node.h"
#include "cam_context.h"
#include "cam_context_utils.h"
#include "cam_ope_context.h"
#include "cam_req_mgr_util.h"
#include "cam_mem_mgr.h"
#include "cam_trace.h"
#include "cam_debug_util.h"
#include "cam_packet_util.h"
static const char ope_dev_name[] = "cam-ope";
static int cam_ope_context_dump_active_request(void *data, unsigned long iova,
uint32_t buf_info)
{
struct cam_context *ctx = (struct cam_context *)data;
struct cam_ctx_request *req = NULL;
struct cam_ctx_request *req_temp = NULL;
struct cam_hw_mgr_dump_pf_data *pf_dbg_entry = NULL;
int rc = 0;
bool b_mem_found = false;
if (!ctx) {
CAM_ERR(CAM_OPE, "Invalid ctx");
return -EINVAL;
}
mutex_lock(&ctx->ctx_mutex);
if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) {
CAM_ERR(CAM_ICP, "Invalid state icp ctx %d state %d",
ctx->ctx_id, ctx->state);
goto end;
}
CAM_INFO(CAM_OPE, "iommu fault for ope ctx %d state %d",
ctx->ctx_id, ctx->state);
list_for_each_entry_safe(req, req_temp,
&ctx->active_req_list, list) {
pf_dbg_entry = &(req->pf_data);
CAM_INFO(CAM_OPE, "req_id : %lld", req->request_id);
rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet,
iova, buf_info, &b_mem_found);
if (rc)
CAM_ERR(CAM_OPE, "Failed to dump pf info");
if (b_mem_found)
CAM_ERR(CAM_OPE, "Found page fault in req %lld %d",
req->request_id, rc);
}
end:
mutex_unlock(&ctx->ctx_mutex);
return rc;
}
static int __cam_ope_acquire_dev_in_available(struct cam_context *ctx,
struct cam_acquire_dev_cmd *cmd)
{
int rc;
rc = cam_context_acquire_dev_to_hw(ctx, cmd);
if (!rc) {
ctx->state = CAM_CTX_ACQUIRED;
trace_cam_context_state("OPE", ctx);
}
return rc;
}
static int __cam_ope_release_dev_in_acquired(struct cam_context *ctx,
struct cam_release_dev_cmd *cmd)
{
int rc;
rc = cam_context_release_dev_to_hw(ctx, cmd);
if (rc)
CAM_ERR(CAM_OPE, "Unable to release device");
ctx->state = CAM_CTX_AVAILABLE;
trace_cam_context_state("OPE", ctx);
return rc;
}
static int __cam_ope_start_dev_in_acquired(struct cam_context *ctx,
struct cam_start_stop_dev_cmd *cmd)
{
int rc;
rc = cam_context_start_dev_to_hw(ctx, cmd);
if (!rc) {
ctx->state = CAM_CTX_READY;
trace_cam_context_state("OPE", ctx);
}
return rc;
}
static int __cam_ope_flush_dev_in_ready(struct cam_context *ctx,
struct cam_flush_dev_cmd *cmd)
{
int rc;
rc = cam_context_flush_dev_to_hw(ctx, cmd);
if (rc)
CAM_ERR(CAM_OPE, "Failed to flush device");
return rc;
}
static int __cam_ope_config_dev_in_ready(struct cam_context *ctx,
struct cam_config_dev_cmd *cmd)
{
int rc;
size_t len;
uintptr_t packet_addr;
rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle,
&packet_addr, &len);
if (rc) {
CAM_ERR(CAM_OPE, "[%s][%d] Can not get packet address",
ctx->dev_name, ctx->ctx_id);
rc = -EINVAL;
return rc;
}
rc = cam_context_prepare_dev_to_hw(ctx, cmd);
if (rc)
CAM_ERR(CAM_OPE, "Failed to prepare device");
return rc;
}
static int __cam_ope_stop_dev_in_ready(struct cam_context *ctx,
struct cam_start_stop_dev_cmd *cmd)
{
int rc;
rc = cam_context_stop_dev_to_hw(ctx);
if (rc)
CAM_ERR(CAM_OPE, "Failed to stop device");
ctx->state = CAM_CTX_ACQUIRED;
trace_cam_context_state("OPE", ctx);
return rc;
}
static int __cam_ope_release_dev_in_ready(struct cam_context *ctx,
struct cam_release_dev_cmd *cmd)
{
int rc;
rc = __cam_ope_stop_dev_in_ready(ctx, NULL);
if (rc)
CAM_ERR(CAM_OPE, "Failed to stop device");
rc = __cam_ope_release_dev_in_acquired(ctx, cmd);
if (rc)
CAM_ERR(CAM_OPE, "Failed to release device");
return rc;
}
static int __cam_ope_handle_buf_done_in_ready(void *ctx,
uint32_t evt_id, void *done)
{
return cam_context_buf_done_from_hw(ctx, done, evt_id);
}
static struct cam_ctx_ops
cam_ope_ctx_state_machine[CAM_CTX_STATE_MAX] = {
/* Uninit */
{
.ioctl_ops = {},
.crm_ops = {},
.irq_ops = NULL,
},
/* Available */
{
.ioctl_ops = {
.acquire_dev = __cam_ope_acquire_dev_in_available,
},
.crm_ops = {},
.irq_ops = NULL,
},
/* Acquired */
{
.ioctl_ops = {
.release_dev = __cam_ope_release_dev_in_acquired,
.start_dev = __cam_ope_start_dev_in_acquired,
.config_dev = __cam_ope_config_dev_in_ready,
.flush_dev = __cam_ope_flush_dev_in_ready,
},
.crm_ops = {},
.irq_ops = __cam_ope_handle_buf_done_in_ready,
.pagefault_ops = cam_ope_context_dump_active_request,
},
/* Ready */
{
.ioctl_ops = {
.stop_dev = __cam_ope_stop_dev_in_ready,
.release_dev = __cam_ope_release_dev_in_ready,
.config_dev = __cam_ope_config_dev_in_ready,
.flush_dev = __cam_ope_flush_dev_in_ready,
},
.crm_ops = {},
.irq_ops = __cam_ope_handle_buf_done_in_ready,
.pagefault_ops = cam_ope_context_dump_active_request,
},
/* Activated */
{
.ioctl_ops = {},
.crm_ops = {},
.irq_ops = NULL,
.pagefault_ops = cam_ope_context_dump_active_request,
},
};
int cam_ope_context_init(struct cam_ope_context *ctx,
struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id)
{
int rc;
if ((!ctx) || (!ctx->base) || (!hw_intf)) {
CAM_ERR(CAM_OPE, "Invalid params: %pK %pK", ctx, hw_intf);
rc = -EINVAL;
goto err;
}
rc = cam_context_init(ctx->base, ope_dev_name, CAM_OPE, ctx_id,
NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX);
if (rc) {
CAM_ERR(CAM_OPE, "Camera Context Base init failed");
goto err;
}
ctx->base->state_machine = cam_ope_ctx_state_machine;
ctx->base->ctx_priv = ctx;
ctx->ctxt_to_hw_map = NULL;
err:
return rc;
}
int cam_ope_context_deinit(struct cam_ope_context *ctx)
{
if ((!ctx) || (!ctx->base)) {
CAM_ERR(CAM_OPE, "Invalid params: %pK", ctx);
return -EINVAL;
}
cam_context_deinit(ctx->base);
memset(ctx, 0, sizeof(*ctx));
return 0;
}

View File

@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_OPE_CONTEXT_H_
#define _CAM_OPE_CONTEXT_H_
#include "cam_context.h"
#define OPE_CTX_MAX 32
/**
* struct cam_ope_context - ope context
* @base: ope context object
* @state_machine: state machine for OPE context
* @req_base: common request structure
* @state: ope context state
* @ctxt_to_hw_map: context to FW handle mapping
*/
struct cam_ope_context {
struct cam_context *base;
struct cam_ctx_ops *state_machine;
struct cam_ctx_request req_base[CAM_CTX_REQ_MAX];
uint32_t state;
void *ctxt_to_hw_map;
};
/**
* cam_ope_context_init() - OPE context init
* @ctx: Pointer to context
* @hw_intf: Pointer to OPE hardware interface
* @ctx_id: ID for this context
*/
int cam_ope_context_init(struct cam_ope_context *ctx,
struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id);
/**
* cam_ope_context_deinit() - OPE context deinit
* @ctx: Pointer to context
*/
int cam_ope_context_deinit(struct cam_ope_context *ctx);
#endif /* _CAM_OPE_CONTEXT_H_ */

View File

@@ -0,0 +1,277 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/iommu.h>
#include <linux/timer.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-subdev.h>
#include <media/cam_req_mgr.h>
#include <media/cam_defs.h>
#include <media/cam_ope.h>
#include "cam_req_mgr_dev.h"
#include "cam_subdev.h"
#include "cam_node.h"
#include "cam_context.h"
#include "cam_ope_context.h"
#include "cam_ope_hw_mgr_intf.h"
#include "cam_hw_mgr_intf.h"
#include "cam_debug_util.h"
#include "cam_smmu_api.h"
#define OPE_DEV_NAME "cam-ope"
struct cam_ope_subdev {
struct cam_subdev sd;
struct cam_node *node;
struct cam_context ctx[OPE_CTX_MAX];
struct cam_ope_context ctx_ope[OPE_CTX_MAX];
struct mutex ope_lock;
int32_t open_cnt;
int32_t reserved;
};
static struct cam_ope_subdev g_ope_dev;
static void cam_ope_dev_iommu_fault_handler(
struct iommu_domain *domain, struct device *dev, unsigned long iova,
int flags, void *token, uint32_t buf_info)
{
int i = 0;
struct cam_node *node = NULL;
if (!token) {
CAM_ERR(CAM_OPE, "invalid token in page handler cb");
return;
}
node = (struct cam_node *)token;
for (i = 0; i < node->ctx_size; i++)
cam_context_dump_pf_info(&(node->ctx_list[i]), iova,
buf_info);
}
static int cam_ope_subdev_open(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh)
{
struct cam_hw_mgr_intf *hw_mgr_intf = NULL;
struct cam_node *node = v4l2_get_subdevdata(sd);
int rc = 0;
mutex_lock(&g_ope_dev.ope_lock);
if (g_ope_dev.open_cnt >= 1) {
CAM_ERR(CAM_OPE, "OPE subdev is already opened");
rc = -EALREADY;
goto end;
}
if (!node) {
CAM_ERR(CAM_OPE, "Invalid args");
rc = -EINVAL;
goto end;
}
hw_mgr_intf = &node->hw_mgr_intf;
rc = hw_mgr_intf->hw_open(hw_mgr_intf->hw_mgr_priv, NULL);
if (rc < 0) {
CAM_ERR(CAM_OPE, "OPE HW open failed: %d", rc);
goto end;
}
g_ope_dev.open_cnt++;
CAM_DBG(CAM_OPE, "OPE HW open success: %d", rc);
end:
mutex_unlock(&g_ope_dev.ope_lock);
return rc;
}
static int cam_ope_subdev_close(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh)
{
int rc = 0;
struct cam_hw_mgr_intf *hw_mgr_intf = NULL;
struct cam_node *node = v4l2_get_subdevdata(sd);
mutex_lock(&g_ope_dev.ope_lock);
if (g_ope_dev.open_cnt <= 0) {
CAM_DBG(CAM_OPE, "OPE subdev is already closed");
rc = -EINVAL;
goto end;
}
g_ope_dev.open_cnt--;
if (!node) {
CAM_ERR(CAM_OPE, "Invalid args");
rc = -EINVAL;
goto end;
}
hw_mgr_intf = &node->hw_mgr_intf;
if (!hw_mgr_intf) {
CAM_ERR(CAM_OPE, "hw_mgr_intf is not initialized");
rc = -EINVAL;
goto end;
}
rc = cam_node_shutdown(node);
if (rc < 0) {
CAM_ERR(CAM_OPE, "HW close failed");
goto end;
}
CAM_DBG(CAM_OPE, "OPE HW close success: %d", rc);
end:
mutex_unlock(&g_ope_dev.ope_lock);
return rc;
}
const struct v4l2_subdev_internal_ops cam_ope_subdev_internal_ops = {
.open = cam_ope_subdev_open,
.close = cam_ope_subdev_close,
};
static int cam_ope_subdev_probe(struct platform_device *pdev)
{
int rc = 0, i = 0;
struct cam_node *node;
struct cam_hw_mgr_intf *hw_mgr_intf;
int iommu_hdl = -1;
CAM_DBG(CAM_OPE, "OPE subdev probe start");
if (!pdev) {
CAM_ERR(CAM_OPE, "pdev is NULL");
return -EINVAL;
}
g_ope_dev.sd.pdev = pdev;
g_ope_dev.sd.internal_ops = &cam_ope_subdev_internal_ops;
rc = cam_subdev_probe(&g_ope_dev.sd, pdev, OPE_DEV_NAME,
CAM_OPE_DEVICE_TYPE);
if (rc) {
CAM_ERR(CAM_OPE, "OPE cam_subdev_probe failed:%d", rc);
return rc;
}
node = (struct cam_node *) g_ope_dev.sd.token;
hw_mgr_intf = kzalloc(sizeof(*hw_mgr_intf), GFP_KERNEL);
if (!hw_mgr_intf) {
rc = -EINVAL;
goto hw_alloc_fail;
}
rc = cam_ope_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf,
&iommu_hdl);
if (rc) {
CAM_ERR(CAM_OPE, "OPE HW manager init failed: %d", rc);
goto hw_init_fail;
}
for (i = 0; i < OPE_CTX_MAX; i++) {
g_ope_dev.ctx_ope[i].base = &g_ope_dev.ctx[i];
rc = cam_ope_context_init(&g_ope_dev.ctx_ope[i],
hw_mgr_intf, i);
if (rc) {
CAM_ERR(CAM_OPE, "OPE context init failed");
goto ctx_fail;
}
}
rc = cam_node_init(node, hw_mgr_intf, g_ope_dev.ctx,
OPE_CTX_MAX, OPE_DEV_NAME);
if (rc) {
CAM_ERR(CAM_OPE, "OPE node init failed");
goto ctx_fail;
}
cam_smmu_set_client_page_fault_handler(iommu_hdl,
cam_ope_dev_iommu_fault_handler, node);
g_ope_dev.open_cnt = 0;
mutex_init(&g_ope_dev.ope_lock);
CAM_DBG(CAM_OPE, "OPE subdev probe complete");
return rc;
ctx_fail:
for (--i; i >= 0; i--)
cam_ope_context_deinit(&g_ope_dev.ctx_ope[i]);
hw_init_fail:
kfree(hw_mgr_intf);
hw_alloc_fail:
cam_subdev_remove(&g_ope_dev.sd);
return rc;
}
static int cam_ope_subdev_remove(struct platform_device *pdev)
{
int i;
struct v4l2_subdev *sd;
struct cam_subdev *subdev;
if (!pdev) {
CAM_ERR(CAM_OPE, "pdev is NULL");
return -ENODEV;
}
sd = platform_get_drvdata(pdev);
if (!sd) {
CAM_ERR(CAM_OPE, "V4l2 subdev is NULL");
return -ENODEV;
}
subdev = v4l2_get_subdevdata(sd);
if (!subdev) {
CAM_ERR(CAM_OPE, "cam subdev is NULL");
return -ENODEV;
}
for (i = 0; i < OPE_CTX_MAX; i++)
cam_ope_context_deinit(&g_ope_dev.ctx_ope[i]);
cam_node_deinit(g_ope_dev.node);
cam_subdev_remove(&g_ope_dev.sd);
mutex_destroy(&g_ope_dev.ope_lock);
return 0;
}
static const struct of_device_id cam_ope_dt_match[] = {
{.compatible = "qcom,cam-ope"},
{}
};
static struct platform_driver cam_ope_driver = {
.probe = cam_ope_subdev_probe,
.remove = cam_ope_subdev_remove,
.driver = {
.name = "cam_ope",
.of_match_table = cam_ope_dt_match,
.suppress_bind_attrs = true,
},
};
int cam_ope_subdev_init_module(void)
{
return platform_driver_register(&cam_ope_driver);
}
void cam_ope_subdev_exit_module(void)
{
platform_driver_unregister(&cam_ope_driver);
}
MODULE_DESCRIPTION("MSM OPE driver");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,399 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_OPE_HW_MGR_H
#define CAM_OPE_HW_MGR_H
#include <linux/types.h>
#include <linux/completion.h>
#include <media/cam_ope.h>
#include "ope_hw.h"
#include "cam_hw_mgr_intf.h"
#include "cam_hw_intf.h"
#include "cam_req_mgr_workq.h"
#include "cam_mem_mgr.h"
#include "cam_smmu_api.h"
#include "cam_soc_util.h"
#include "cam_req_mgr_timer.h"
#include "cam_context.h"
#include "ope_hw.h"
#include "cam_cdm_intf_api.h"
#include "cam_req_mgr_timer.h"
#define OPE_CTX_MAX 32
#define CAM_FRAME_CMD_MAX 20
#define OPE_WORKQ_NUM_TASK 100
#define OPE_WORKQ_TASK_CMD_TYPE 1
#define OPE_WORKQ_TASK_MSG_TYPE 2
#define OPE_PACKET_SIZE 0
#define OPE_PACKET_TYPE 1
#define OPE_PACKET_OPCODE 2
#define OPE_PACKET_MAX_CMD_BUFS 4
#define OPE_MAX_OUTPUT_SUPPORTED 8
#define OPE_MAX_INPUT_SUPPORTED 3
#define OPE_FRAME_PROCESS_SUCCESS 0
#define OPE_FRAME_PROCESS_FAILURE 1
#define OPE_CTX_STATE_FREE 0
#define OPE_CTX_STATE_IN_USE 1
#define OPE_CTX_STATE_ACQUIRED 2
#define OPE_CTX_STATE_RELEASE 3
#define OPE_CMDS OPE_MAX_CMD_BUFS
#define CAM_MAX_IN_RES 8
#define OPE_MAX_CDM_BLS 16
/**
* struct ope_cmd_work_data
*
* @type: Type of work data
* @data: Private data
* @req_id: Request Id
*/
struct ope_cmd_work_data {
uint32_t type;
void *data;
int64_t req_id;
};
/**
* struct ope_msg_work_data
*
* @type: Type of work data
* @data: Private data
* @irq_status: IRQ status
*/
struct ope_msg_work_data {
uint32_t type;
void *data;
uint32_t irq_status;
};
/**
* struct ope_clk_work_data
*
* @type: Type of work data
* @data: Private data
*/
struct ope_clk_work_data {
uint32_t type;
void *data;
};
/**
* struct cdm_dmi_cmd
*
* @length: Number of bytes in LUT
* @reserved: reserved bits
* @cmd: Command ID (CDMCmd)
* @addr: Address of the LUT in memory
* @DMIAddr: Address of the target DMI config register
* @DMISel: DMI identifier
*/
struct cdm_dmi_cmd {
unsigned int length : 16;
unsigned int reserved : 8;
unsigned int cmd : 8;
unsigned int addr;
unsigned int DMIAddr : 24;
unsigned int DMISel : 8;
} __attribute__((__packed__));
/**
* struct ope_debug_buffer
*
* @cpu_addr: CPU address
* @iova_addr: IOVA address
* @len: Buffer length
* @size: Buffer Size
*/
struct ope_debug_buffer {
uintptr_t cpu_addr;
dma_addr_t iova_addr;
size_t len;
uint32_t size;
};
/**
* struct ope_kmd_buffer
*
* @mem_handle: Memory handle
* @cpu_addr: CPU address
* @iova_addr: IOVA address
* @iova_cdm_addr: CDM IOVA address
* @len: Buffer length
* @size: Buffer Size
*/
struct ope_kmd_buffer {
uint32_t mem_handle;
uintptr_t cpu_addr;
dma_addr_t iova_addr;
dma_addr_t iova_cdm_addr;
size_t len;
uint32_t size;
};
struct ope_stripe_settings {
uintptr_t cpu_addr;
dma_addr_t iova_addr;
size_t len;
uint32_t size;
uint32_t buf_type;
uint32_t type_buffered;
};
/**
* struct ope_pass_settings
*
* @cpu_addr: CPU address
* @iova_addr: IOVA address
* @len: Buffer length
* @size: Buffer Size
* @idx: Pass Index
* @buf_type: Direct/Indirect type
* @type_buffered: SB/DB types
*/
struct ope_pass_settings {
uintptr_t cpu_addr;
dma_addr_t iova_addr;
size_t len;
uint32_t size;
uint32_t idx;
uint32_t buf_type;
uint32_t type_buffered;
};
/**
* struct ope_frame_settings
*
* @cpu_addr: CPU address
* @iova_addr: IOVA address
* @offset: offset
* @len: Buffer length
* @size: Buffer Size
* @buf_type: Direct/Indirect type
* @type_buffered: SB/DB types
* @prefecth_disable: Disable prefetch
*/
struct ope_frame_settings {
uintptr_t cpu_addr;
dma_addr_t iova_addr;
uint32_t offset;
size_t len;
uint32_t size;
uint32_t buf_type;
uint32_t type_buffered;
uint32_t prefecth_disable;
};
/**
* struct ope_stripe_io
*
* @format: Stripe format
* @s_location: Stripe location
* @cpu_addr: Stripe CPU address
* @iova_addr: Stripe IOVA address
* @width: Stripe width
* @height: Stripe height
* @stride: Stripe stride
* @unpack_format: Unpack format
* @pack_format: Packing format
* @alignment: Stripe alignment
* @offset: Stripe offset
* @x_init: X_init
* @subsample_period: Subsample period
* @subsample_pattern: Subsample pattern
* @len: Stripe buffer length
* @disable_bus: disable bus for the stripe
*/
struct ope_stripe_io {
uint32_t format;
uint32_t s_location;
uintptr_t cpu_addr;
dma_addr_t iova_addr;
uint32_t width;
uint32_t height;
uint32_t stride;
uint32_t unpack_format;
uint32_t pack_format;
uint32_t alignment;
uint32_t offset;
uint32_t x_init;
uint32_t subsample_period;
uint32_t subsample_pattern;
size_t len;
uint32_t disable_bus;
};
/**
* struct ope_io_buf
*
* @direction: Direction of a buffer
* @resource_type: Resource type of IO Buffer
* @format: Format
* @fence: Fence
* @num_planes: Number of planes
* @num_stripes: Number of stripes
* @s_io: Stripe info
*/
struct ope_io_buf {
uint32_t direction;
uint32_t resource_type;
uint32_t format;
uint32_t fence;
uint32_t num_planes;
uint32_t num_stripes[OPE_MAX_PLANES];
struct ope_stripe_io s_io[OPE_MAX_PLANES][OPE_MAX_STRIPES];
};
/**
* struct cam_ope_request
*
* @request_id: Request Id
* @req_idx: Index in request list
* @state: Request state
* @num_batch: Number of batches
* @num_cmd_bufs: Number of command buffers
* @num_frame_bufs: Number of frame buffers
* @num_pass_bufs: Number of pass Buffers
* @num_stripes: Number of Stripes
* @num_io_bufs: Number of IO Buffers
* @in_resource: Input resource
* @num_stripe_cmd_bufs: Command buffers per stripe
* @ope_kmd_buf: KMD buffer for OPE programming
* @ope_debug_buf: Debug buffer
* @io_buf: IO config info of a request
* @cdm_cmd: CDM command for OPE CDM
*/
struct cam_ope_request {
uint64_t request_id;
uint32_t req_idx;
uint32_t state;
uint32_t num_batch;
uint32_t num_cmd_bufs;
uint32_t num_frame_bufs;
uint32_t num_pass_bufs;
uint32_t num_stripes[OPE_MAX_BATCH_SIZE];
uint32_t num_io_bufs[OPE_MAX_BATCH_SIZE];
uint32_t in_resource;
uint8_t num_stripe_cmd_bufs[OPE_MAX_BATCH_SIZE][OPE_MAX_STRIPES];
struct ope_kmd_buffer ope_kmd_buf;
struct ope_debug_buffer ope_debug_buf;
struct ope_io_buf io_buf[OPE_MAX_BATCH_SIZE][OPE_MAX_IO_BUFS];
struct cam_cdm_bl_request *cdm_cmd;
};
/**
* struct cam_ope_cdm
*
* @cdm_handle: OPE CDM Handle
* @cdm_ops: OPE CDM Operations
*/
struct cam_ope_cdm {
uint32_t cdm_handle;
struct cam_cdm_utils_ops *cdm_ops;
};
/**
* struct cam_ope_ctx
*
* @context_priv: Private data of context
* @bitmap: Context bit map
* @bitmap_size: Context bit map size
* @bits: Context bit map bits
* @ctx_id: Context ID
* @ctx_state: State of a context
* @req_cnt: Requests count
* @ctx_mutex: Mutex for context
* @acquire_dev_cmd: Cam acquire command
* @ope_acquire: OPE acquire command
* @ctxt_event_cb: Callback of a context
* @req_list: Request List
* @ope_cdm: OPE CDM info
* @req_watch_dog: Watchdog for requests
*/
struct cam_ope_ctx {
void *context_priv;
size_t bitmap_size;
void *bitmap;
size_t bits;
uint32_t ctx_id;
uint32_t ctx_state;
uint32_t req_cnt;
struct mutex ctx_mutex;
struct cam_acquire_dev_cmd acquire_dev_cmd;
struct ope_acquire_dev_info ope_acquire;
cam_hw_event_cb_func ctxt_event_cb;
struct cam_ope_request *req_list[CAM_CTX_REQ_MAX];
struct cam_ope_cdm ope_cdm;
struct cam_req_mgr_timer *req_watch_dog;
};
/**
* struct cam_ope_hw_mgr
*
* @open_cnt: OPE device open count
* @ope_ctx_cnt: Open context count
* @hw_mgr_mutex: Mutex for HW manager
* @hw_mgr_lock: Spinlock for HW manager
* @hfi_en: Flag for HFI
* @iommu_hdl: OPE Handle
* @iommu_sec_hdl: OPE Handle for secure
* @iommu_cdm_hdl: CDM Handle
* @iommu_sec_cdm_hdl: CDM Handle for secure
* @num_ope: Number of OPE
* @secure_mode: Mode of OPE operation
* @ctx_bitmap: Context bit map
* @ctx_bitmap_size: Context bit map size
* @ctx_bits: Context bit map bits
* @ctx: OPE context
* @devices: OPE devices
* @ope_caps: OPE capabilities
* @cmd_work: Command work
* @msg_work: Message work
* @timer_work: Timer work
* @cmd_work_data: Command work data
* @msg_work_data: Message work data
* @timer_work_data: Timer work data
* @ope_dev_intf: OPE device interface
* @cdm_reg_map: OPE CDM register map
*/
struct cam_ope_hw_mgr {
int32_t open_cnt;
uint32_t ope_ctx_cnt;
struct mutex hw_mgr_mutex;
spinlock_t hw_mgr_lock;
bool hfi_en;
int32_t iommu_hdl;
int32_t iommu_sec_hdl;
int32_t iommu_cdm_hdl;
int32_t iommu_sec_cdm_hdl;
uint32_t num_ope;
bool secure_mode;
void *ctx_bitmap;
size_t ctx_bitmap_size;
size_t ctx_bits;
struct cam_ope_ctx ctx[OPE_CTX_MAX];
struct cam_hw_intf **devices[OPE_DEV_MAX];
struct ope_query_cap_cmd ope_caps;
struct cam_req_mgr_core_workq *cmd_work;
struct cam_req_mgr_core_workq *msg_work;
struct cam_req_mgr_core_workq *timer_work;
struct ope_cmd_work_data *cmd_work_data;
struct ope_msg_work_data *msg_work_data;
struct ope_clk_work_data *timer_work_data;
struct cam_hw_intf *ope_dev_intf[OPE_DEV_MAX];
struct cam_soc_reg_map *cdm_reg_map[OPE_DEV_MAX][OPE_BASE_MAX];
};
#endif /* CAM_OPE_HW_MGR_H */

View File

@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_OPE_HW_MGR_INTF_H
#define CAM_OPE_HW_MGR_INTF_H
#include <linux/types.h>
#include <linux/completion.h>
#include <media/cam_ope.h>
int cam_ope_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
int *iommu_hdl);
#endif /* CAM_OPE_HW_MGR_INTF_H */

View File

@@ -0,0 +1,693 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/of.h>
#include <linux/debugfs.h>
#include <linux/videodev2.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/iopoll.h>
#include <media/cam_ope.h>
#include "cam_io_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
#include "ope_core.h"
#include "ope_soc.h"
#include "cam_soc_util.h"
#include "cam_io_util.h"
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
#include "cam_cdm_util.h"
#include "ope_hw.h"
#include "ope_dev_intf.h"
#include "ope_bus_rd.h"
static struct ope_bus_rd *bus_rd;
static int cam_ope_bus_rd_in_port_idx(uint32_t input_port_id)
{
int i;
for (i = 0; i < OPE_IN_RES_MAX; i++)
if (bus_rd->in_port_to_rm[i].input_port_id ==
input_port_id)
return i;
return -EINVAL;
}
static int cam_ope_bus_rd_combo_idx(uint32_t format)
{
int rc = -EINVAL;
switch (format) {
case CAM_FORMAT_YUV422:
case CAM_FORMAT_NV21:
case CAM_FORMAT_NV12:
rc = BUS_RD_YUV;
break;
case CAM_FORMAT_MIPI_RAW_6:
case CAM_FORMAT_MIPI_RAW_8:
case CAM_FORMAT_MIPI_RAW_10:
case CAM_FORMAT_MIPI_RAW_12:
case CAM_FORMAT_MIPI_RAW_14:
case CAM_FORMAT_MIPI_RAW_16:
case CAM_FORMAT_MIPI_RAW_20:
case CAM_FORMAT_QTI_RAW_8:
case CAM_FORMAT_QTI_RAW_10:
case CAM_FORMAT_QTI_RAW_12:
case CAM_FORMAT_QTI_RAW_14:
case CAM_FORMAT_PLAIN8:
case CAM_FORMAT_PLAIN16_8:
case CAM_FORMAT_PLAIN16_10:
case CAM_FORMAT_PLAIN16_12:
case CAM_FORMAT_PLAIN16_14:
case CAM_FORMAT_PLAIN16_16:
case CAM_FORMAT_PLAIN32_20:
case CAM_FORMAT_PLAIN64:
case CAM_FORMAT_PLAIN128:
rc = BUS_RD_BAYER;
break;
default:
break;
}
CAM_DBG(CAM_OPE, "Input format = %u rc = %d",
format, rc);
return rc;
}
static uint32_t *cam_ope_bus_rd_update(struct ope_hw *ope_hw_info,
int32_t ctx_id, uint32_t *kmd_buf, int batch_idx,
int io_idx, struct cam_ope_dev_prepare_req *prepare)
{
int k, l, m;
uint32_t idx;
int32_t combo_idx;
uint32_t req_idx, count = 0, temp;
uint32_t temp_reg[128] = {0};
uint32_t rm_id, header_size;
uint32_t rsc_type;
struct cam_hw_prepare_update_args *prepare_args;
struct cam_ope_ctx *ctx_data;
struct cam_ope_request *ope_request;
struct ope_io_buf *io_buf;
struct ope_stripe_io *stripe_io;
struct ope_bus_rd_ctx *bus_rd_ctx;
struct cam_ope_bus_rd_reg *rd_reg;
struct cam_ope_bus_rd_client_reg *rd_reg_client;
struct cam_ope_bus_rd_reg_val *rd_reg_val;
struct cam_ope_bus_rd_client_reg_val *rd_res_val_client;
struct ope_bus_in_port_to_rm *in_port_to_rm;
struct ope_bus_rd_io_port_cdm_info *io_port_cdm;
struct cam_cdm_utils_ops *cdm_ops;
struct ope_bus_rd_io_port_info *io_port_info;
if (ctx_id < 0 || !prepare) {
CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, prepare);
return NULL;
}
if (batch_idx >= OPE_MAX_BATCH_SIZE) {
CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx);
return NULL;
}
if (io_idx >= OPE_MAX_IO_BUFS) {
CAM_ERR(CAM_OPE, "Invalid IO idx: %d", io_idx);
return NULL;
}
prepare_args = prepare->prepare_args;
ctx_data = prepare->ctx_data;
req_idx = prepare->req_idx;
cdm_ops = ctx_data->ope_cdm.cdm_ops;
ope_request = ctx_data->req_list[req_idx];
CAM_DBG(CAM_OPE, "req_idx = %d req_id = %lld KMDbuf %x offset %d",
req_idx, ope_request->request_id,
kmd_buf, prepare->kmd_buf_offset);
bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id];
io_port_info = &bus_rd_ctx->io_port_info;
rd_reg = ope_hw_info->bus_rd_reg;
rd_reg_val = ope_hw_info->bus_rd_reg_val;
io_buf = &ope_request->io_buf[batch_idx][io_idx];
CAM_DBG(CAM_OPE, "batch:%d iobuf:%d direction:%d",
batch_idx, io_idx, io_buf->direction);
io_port_cdm =
&bus_rd_ctx->io_port_cdm_batch.io_port_cdm[batch_idx];
in_port_to_rm =
&bus_rd->in_port_to_rm[io_buf->resource_type - 1];
combo_idx = cam_ope_bus_rd_combo_idx(io_buf->format);
if (combo_idx < 0) {
CAM_ERR(CAM_OPE, "Invalid combo_idx");
return NULL;
}
for (k = 0; k < io_buf->num_planes; k++) {
for (l = 0; l < io_buf->num_stripes[k]; l++) {
stripe_io = &io_buf->s_io[k][l];
rsc_type = io_buf->resource_type - 1;
/* frame level info */
/* stripe level info */
rm_id = in_port_to_rm->rm_port_id[combo_idx][k];
rd_reg_client = &rd_reg->rd_clients[rm_id];
rd_res_val_client = &rd_reg_val->rd_clients[rm_id];
/* security cfg */
temp_reg[count++] = rd_reg->offset +
rd_reg->security_cfg;
temp_reg[count++] =
ctx_data->ope_acquire.secure_mode;
/* enable client */
temp_reg[count++] = rd_reg->offset +
rd_reg_client->core_cfg;
temp_reg[count++] = 1;
/* ccif meta data */
temp_reg[count++] = rd_reg->offset +
rd_reg_client->ccif_meta_data;
temp = 0;
temp |= stripe_io->s_location &
rd_res_val_client->stripe_location_mask;
temp |= (io_port_info->pixel_pattern[rsc_type] &
rd_res_val_client->pix_pattern_mask) <<
rd_res_val_client->pix_pattern_shift;
temp_reg[count++] = temp;
/* Address of the Image */
temp_reg[count++] = rd_reg->offset +
rd_reg_client->img_addr;
temp_reg[count++] = stripe_io->iova_addr;
/* Buffer size */
temp_reg[count++] = rd_reg->offset +
rd_reg_client->img_cfg;
temp = 0;
temp = stripe_io->height;
temp |=
(stripe_io->width &
rd_res_val_client->img_width_mask) <<
rd_res_val_client->img_width_shift;
temp_reg[count++] = temp;
/* stride */
temp_reg[count++] = rd_reg->offset +
rd_reg_client->stride;
temp_reg[count++] = stripe_io->stride;
/* Unpack cfg : Mode and alignment */
temp_reg[count++] = rd_reg->offset +
rd_reg_client->unpack_cfg;
temp = 0;
temp |= (stripe_io->unpack_format &
rd_res_val_client->mode_mask) <<
rd_res_val_client->mode_shift;
temp |= (stripe_io->alignment &
rd_res_val_client->alignment_mask) <<
rd_res_val_client->alignment_shift;
temp_reg[count++] = temp;
/* latency buffer allocation */
temp_reg[count++] = rd_reg->offset +
rd_reg_client->latency_buf_allocation;
temp_reg[count++] = io_port_info->latency_buf_size;
header_size = cdm_ops->cdm_get_cmd_header_size(
CAM_CDM_CMD_REG_RANDOM);
idx = io_port_cdm->num_s_cmd_bufs[l];
io_port_cdm->s_cdm_info[l][idx].len = sizeof(temp) *
(count + header_size);
io_port_cdm->s_cdm_info[l][idx].offset =
prepare->kmd_buf_offset;
io_port_cdm->s_cdm_info[l][idx].addr = kmd_buf;
io_port_cdm->num_s_cmd_bufs[l]++;
kmd_buf = cdm_ops->cdm_write_regrandom(
kmd_buf, count/2, temp_reg);
prepare->kmd_buf_offset += ((count + header_size) *
sizeof(temp));
CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d",
batch_idx, io_idx, k, l);
for (m = 0; m < count; m++)
CAM_DBG(CAM_OPE, "%d:temp:%x",
m, temp_reg[m]);
CAM_DBG(CAM_OPE, "kmd_buf:%x offset:%d",
kmd_buf, prepare->kmd_buf_offset);
CAM_DBG(CAM_OPE, "%x count: %d size:%d",
temp_reg, count, header_size);
CAM_DBG(CAM_OPE, "RD cmdbufs:%d off:%d",
io_port_cdm->num_s_cmd_bufs[l],
io_port_cdm->s_cdm_info[l][idx].offset);
CAM_DBG(CAM_OPE, "len:%d",
io_port_cdm->s_cdm_info[l][idx].len);
CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d",
batch_idx, io_idx, k, l);
count = 0;
}
}
return kmd_buf;
}
static int cam_ope_bus_rd_prepare(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
int i, j;
int32_t combo_idx;
uint32_t req_idx, count = 0, temp;
uint32_t temp_reg[32] = {0};
uint32_t header_size;
uint32_t *kmd_buf;
struct cam_ope_dev_prepare_req *prepare;
struct cam_ope_ctx *ctx_data;
struct cam_ope_request *ope_request;
struct ope_io_buf *io_buf;
struct ope_bus_rd_ctx *bus_rd_ctx;
struct cam_ope_bus_rd_reg *rd_reg;
struct cam_ope_bus_rd_reg_val *rd_reg_val;
struct ope_bus_rd_io_port_cdm_batch *io_port_cdm_batch;
struct ope_bus_rd_io_port_cdm_info *io_port_cdm;
struct cam_cdm_utils_ops *cdm_ops;
if (ctx_id < 0 || !data) {
CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data);
return -EINVAL;
}
prepare = data;
ctx_data = prepare->ctx_data;
req_idx = prepare->req_idx;
cdm_ops = ctx_data->ope_cdm.cdm_ops;
ope_request = ctx_data->req_list[req_idx];
kmd_buf = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr +
prepare->kmd_buf_offset;
CAM_DBG(CAM_OPE, "req_idx = %d req_id = %lld",
req_idx, ope_request->request_id);
CAM_DBG(CAM_OPE, "KMD buf and offset = %x %d",
kmd_buf, prepare->kmd_buf_offset);
bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id];
io_port_cdm_batch =
&bus_rd_ctx->io_port_cdm_batch;
memset(io_port_cdm_batch, 0,
sizeof(struct ope_bus_rd_io_port_cdm_batch));
rd_reg = ope_hw_info->bus_rd_reg;
rd_reg_val = ope_hw_info->bus_rd_reg_val;
for (i = 0; i < ope_request->num_batch; i++) {
for (j = 0; j < ope_request->num_io_bufs[i]; j++) {
io_buf = &ope_request->io_buf[i][j];
if (io_buf->direction != CAM_BUF_INPUT)
continue;
CAM_DBG(CAM_OPE, "batch:%d iobuf:%d direction:%d",
i, j, io_buf->direction);
io_port_cdm =
&bus_rd_ctx->io_port_cdm_batch.io_port_cdm[i];
combo_idx = cam_ope_bus_rd_combo_idx(io_buf->format);
if (combo_idx < 0) {
CAM_ERR(CAM_OPE, "Invalid combo_idx");
return combo_idx;
}
kmd_buf = cam_ope_bus_rd_update(ope_hw_info,
ctx_id, kmd_buf, i, j, prepare);
if (!kmd_buf) {
rc = -EINVAL;
goto end;
}
}
}
if (!io_port_cdm) {
rc = -EINVAL;
goto end;
}
/* Go command */
count = 0;
temp_reg[count++] = rd_reg->offset +
rd_reg->input_if_cmd;
temp = 0;
temp |= rd_reg_val->go_cmd;
temp_reg[count++] = temp;
header_size =
cdm_ops->cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM);
io_port_cdm->go_cmd_addr = kmd_buf;
io_port_cdm->go_cmd_len =
sizeof(temp) * (count + header_size);
io_port_cdm->go_cmd_offset =
prepare->kmd_buf_offset;
kmd_buf = cdm_ops->cdm_write_regrandom(
kmd_buf, count/2, temp_reg);
prepare->kmd_buf_offset +=
((count + header_size) * sizeof(temp));
CAM_DBG(CAM_OPE, "kmd_buf:%x,offset:%d",
kmd_buf, prepare->kmd_buf_offset);
CAM_DBG(CAM_OPE, "t_reg:%xcount: %d size:%d",
temp_reg, count, header_size);
prepare->rd_cdm_batch = &bus_rd_ctx->io_port_cdm_batch;
end:
return rc;
}
static int cam_ope_bus_rd_release(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0, i;
struct ope_acquire_dev_info *in_acquire;
struct ope_bus_rd_ctx *bus_rd_ctx;
if (ctx_id < 0) {
CAM_ERR(CAM_OPE, "Invalid data: %d", ctx_id);
return -EINVAL;
}
in_acquire = bus_rd->bus_rd_ctx[ctx_id].ope_acquire;
bus_rd->bus_rd_ctx[ctx_id].ope_acquire = NULL;
bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id];
bus_rd_ctx->num_in_ports = 0;
for (i = 0; i < bus_rd_ctx->num_in_ports; i++) {
bus_rd_ctx->io_port_info.input_port_id[i] = 0;
bus_rd_ctx->io_port_info.input_format_type[i - 1] = 0;
bus_rd_ctx->io_port_info.pixel_pattern[i - 1] = 0;
}
return rc;
}
static int cam_ope_bus_rd_acquire(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0, i;
struct ope_acquire_dev_info *in_acquire;
struct ope_bus_rd_ctx *bus_rd_ctx;
struct ope_bus_in_port_to_rm *in_port_to_rm;
struct cam_ope_bus_rd_reg_val *bus_rd_reg_val;
int combo_idx;
int in_port_idx;
if (ctx_id < 0 || !data || !ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid data: %d %x %x",
ctx_id, data, ope_hw_info);
return -EINVAL;
}
bus_rd->bus_rd_ctx[ctx_id].ope_acquire = data;
in_acquire = data;
bus_rd_ctx = &bus_rd->bus_rd_ctx[ctx_id];
bus_rd_ctx->num_in_ports = in_acquire->num_in_res;
bus_rd_ctx->security_flag = in_acquire->secure_mode;
bus_rd_reg_val = ope_hw_info->bus_rd_reg_val;
for (i = 0; i < in_acquire->num_in_res; i++) {
if (!in_acquire->in_res[i].width)
continue;
CAM_DBG(CAM_OPE, "i = %d format = %u width = %x height = %x",
i, in_acquire->in_res[i].format,
in_acquire->in_res[i].width,
in_acquire->in_res[i].height);
CAM_DBG(CAM_OPE, "pix_pattern:%u alignment:%u unpack_format:%u",
in_acquire->in_res[i].pixel_pattern,
in_acquire->in_res[i].alignment,
in_acquire->in_res[i].unpacker_format);
CAM_DBG(CAM_OPE, "max_stripe = %u fps = %u",
in_acquire->in_res[i].max_stripe_size,
in_acquire->in_res[i].fps);
in_port_idx = cam_ope_bus_rd_in_port_idx(i + 1);
if (in_port_idx < 0) {
CAM_ERR(CAM_OPE, "Invalid in_port_idx: %d", i + 1);
rc = -EINVAL;
goto end;
}
in_port_to_rm = &bus_rd->in_port_to_rm[in_port_idx];
combo_idx = cam_ope_bus_rd_combo_idx(
in_acquire->in_res[i].format);
if (combo_idx < 0) {
CAM_ERR(CAM_OPE, "Invalid format: %d",
in_acquire->in_res[i].format);
rc = -EINVAL;
goto end;
}
if (!in_port_to_rm->num_rm[combo_idx]) {
CAM_ERR(CAM_OPE, "Invalid format for Input port");
rc = -EINVAL;
goto end;
}
bus_rd_ctx->io_port_info.input_port_id[i] =
in_acquire->in_res[i].res_id;
bus_rd_ctx->io_port_info.input_format_type[i] =
in_acquire->in_res[i].format;
if (in_acquire->in_res[i].pixel_pattern >
PIXEL_PATTERN_CRYCBY) {
CAM_ERR(CAM_OPE, "Invalid pix pattern = %u",
in_acquire->in_res[i].pixel_pattern);
rc = -EINVAL;
goto end;
}
bus_rd_ctx->io_port_info.pixel_pattern[i] =
in_acquire->in_res[i].pixel_pattern;
bus_rd_ctx->io_port_info.latency_buf_size =
bus_rd_reg_val->latency_buf_size;
CAM_DBG(CAM_OPE, "i:%d port_id = %u format %u pix_pattern = %u",
i, bus_rd_ctx->io_port_info.input_port_id[i],
bus_rd_ctx->io_port_info.input_format_type[i],
bus_rd_ctx->io_port_info.pixel_pattern[i]);
CAM_DBG(CAM_OPE, "latency_buf_size = %u",
bus_rd_ctx->io_port_info.latency_buf_size);
}
end:
return rc;
}
static int cam_ope_bus_rd_init(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
struct cam_ope_bus_rd_reg_val *bus_rd_reg_val;
struct cam_ope_bus_rd_reg *bus_rd_reg;
struct cam_ope_dev_init *dev_init = data;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
bus_rd_reg_val = ope_hw_info->bus_rd_reg_val;
bus_rd_reg = ope_hw_info->bus_rd_reg;
bus_rd_reg->base = dev_init->core_info->ope_hw_info->ope_bus_rd_base;
/* OPE SW RESET */
init_completion(&bus_rd->reset_complete);
/* enable interrupt mask */
cam_io_w_mb(bus_rd_reg_val->irq_mask,
ope_hw_info->bus_rd_reg->base + bus_rd_reg->irq_mask);
cam_io_w_mb(bus_rd_reg_val->sw_reset,
ope_hw_info->bus_rd_reg->base + bus_rd_reg->sw_reset);
rc = wait_for_completion_timeout(
&bus_rd->reset_complete, msecs_to_jiffies(30000));
if (!rc || rc < 0) {
CAM_ERR(CAM_OPE, "reset error result = %d", rc);
if (!rc)
rc = -ETIMEDOUT;
} else {
rc = 0;
}
cam_io_w_mb(bus_rd_reg_val->irq_mask,
ope_hw_info->bus_rd_reg->base + bus_rd_reg->irq_mask);
return rc;
}
static int cam_ope_bus_rd_probe(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0, i, j, combo_idx, k;
struct cam_ope_bus_rd_reg_val *bus_rd_reg_val;
struct cam_ope_bus_rd_reg *bus_rd_reg;
struct ope_bus_in_port_to_rm *in_port_to_rm;
uint32_t input_port_idx;
uint32_t rm_idx;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
bus_rd = kzalloc(sizeof(struct ope_bus_rd), GFP_KERNEL);
if (!bus_rd) {
CAM_ERR(CAM_OPE, "Out of memory");
return -ENOMEM;
}
bus_rd->ope_hw_info = ope_hw_info;
bus_rd_reg_val = ope_hw_info->bus_rd_reg_val;
bus_rd_reg = ope_hw_info->bus_rd_reg;
for (i = 0; i < bus_rd_reg_val->num_clients; i++) {
input_port_idx =
bus_rd_reg_val->rd_clients[i].input_port_id - 1;
in_port_to_rm = &bus_rd->in_port_to_rm[input_port_idx];
if (bus_rd_reg_val->rd_clients[i].format_type &
BUS_RD_COMBO_BAYER_MASK) {
combo_idx = BUS_RD_BAYER;
rm_idx = in_port_to_rm->num_rm[combo_idx];
in_port_to_rm->input_port_id =
bus_rd_reg_val->rd_clients[i].input_port_id;
in_port_to_rm->rm_port_id[combo_idx][rm_idx] =
bus_rd_reg_val->rd_clients[i].rm_port_id;
if (!in_port_to_rm->num_rm[combo_idx])
in_port_to_rm->num_combos++;
in_port_to_rm->num_rm[combo_idx]++;
}
if (bus_rd_reg_val->rd_clients[i].format_type &
BUS_RD_COMBO_YUV_MASK) {
combo_idx = BUS_RD_YUV;
rm_idx = in_port_to_rm->num_rm[combo_idx];
in_port_to_rm->input_port_id =
bus_rd_reg_val->rd_clients[i].input_port_id;
in_port_to_rm->rm_port_id[combo_idx][rm_idx] =
bus_rd_reg_val->rd_clients[i].rm_port_id;
if (!in_port_to_rm->num_rm[combo_idx])
in_port_to_rm->num_combos++;
in_port_to_rm->num_rm[combo_idx]++;
}
}
for (i = 0; i < OPE_IN_RES_MAX; i++) {
in_port_to_rm = &bus_rd->in_port_to_rm[i];
CAM_DBG(CAM_OPE, "input port id = %d num_combos = %d",
in_port_to_rm->input_port_id,
in_port_to_rm->num_combos);
for (j = 0; j < in_port_to_rm->num_combos; j++) {
CAM_DBG(CAM_OPE, "combo idx = %d num_rms = %d",
j, in_port_to_rm->num_rm[j]);
for (k = 0; k < in_port_to_rm->num_rm[j]; k++) {
CAM_DBG(CAM_OPE, "rm port id = %d",
in_port_to_rm->rm_port_id[j][k]);
}
}
}
return rc;
}
static int cam_ope_bus_rd_isr(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
uint32_t irq_status;
struct cam_ope_bus_rd_reg *bus_rd_reg;
struct cam_ope_bus_rd_reg_val *bus_rd_reg_val;
struct cam_ope_irq_data *irq_data = data;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
bus_rd_reg = ope_hw_info->bus_rd_reg;
bus_rd_reg_val = ope_hw_info->bus_rd_reg_val;
/* Read and Clear Top Interrupt status */
irq_status = cam_io_r_mb(bus_rd_reg->base + bus_rd_reg->irq_status);
cam_io_w_mb(irq_status,
bus_rd_reg->base + bus_rd_reg->irq_clear);
cam_io_w_mb(bus_rd_reg_val->irq_set_clear,
bus_rd_reg->base + bus_rd_reg->irq_cmd);
if (irq_status & bus_rd_reg_val->rst_done) {
complete(&bus_rd->reset_complete);
CAM_ERR(CAM_OPE, "ope bus rd reset done");
}
if ((irq_status & bus_rd_reg_val->violation) ==
bus_rd_reg_val->violation) {
irq_data->error = 1;
CAM_ERR(CAM_OPE, "ope bus rd CCIF vioalation");
}
return rc;
}
int cam_ope_bus_rd_process(struct ope_hw *ope_hw_info,
int32_t ctx_id, uint32_t cmd_id, void *data)
{
int rc = -EINVAL;
switch (cmd_id) {
case OPE_HW_PROBE:
CAM_DBG(CAM_OPE, "OPE_HW_PROBE: E");
rc = cam_ope_bus_rd_probe(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_PROBE: X");
break;
case OPE_HW_INIT:
CAM_DBG(CAM_OPE, "OPE_HW_INIT: E");
rc = cam_ope_bus_rd_init(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_INIT: X");
break;
case OPE_HW_ACQUIRE:
CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: E");
rc = cam_ope_bus_rd_acquire(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: X");
break;
case OPE_HW_RELEASE:
CAM_DBG(CAM_OPE, "OPE_HW_RELEASE: E");
rc = cam_ope_bus_rd_release(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_RELEASE: X");
break;
case OPE_HW_PREPARE:
CAM_DBG(CAM_OPE, "OPE_HW_PREPARE: E");
rc = cam_ope_bus_rd_prepare(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_PREPARE: X");
break;
case OPE_HW_ISR:
rc = cam_ope_bus_rd_isr(ope_hw_info, 0, data);
break;
case OPE_HW_DEINIT:
case OPE_HW_START:
case OPE_HW_STOP:
case OPE_HW_FLUSH:
case OPE_HW_CLK_UPDATE:
case OPE_HW_BW_UPDATE:
case OPE_HW_RESET:
case OPE_HW_SET_IRQ_CB:
rc = 0;
CAM_DBG(CAM_OPE, "Unhandled cmds: %d", cmd_id);
break;
default:
CAM_ERR(CAM_OPE, "Unsupported cmd: %d", cmd_id);
break;
}
return rc;
}

View File

@@ -0,0 +1,139 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef OPE_BUS_RD_H
#define OPE_BUS_RD_H
#include <linux/types.h>
#include <linux/completion.h>
#include <media/cam_ope.h>
#include "ope_hw.h"
#include "cam_hw_mgr_intf.h"
#include "cam_hw_intf.h"
#include "cam_soc_util.h"
#include "cam_context.h"
#include "cam_ope_context.h"
#include "cam_ope_hw_mgr.h"
/**
* struct ope_bus_rd_cdm_info
*
* @offset: Offset
* @addr: Address
* @len: Length
*/
struct ope_bus_rd_cdm_info {
uint32_t offset;
uint32_t *addr;
uint32_t len;
};
/**
* struct ope_bus_rd_io_port_cdm_info
*
* @num_frames_cmds: Number of frame commands
* @f_cdm_info: Frame cdm info
* @num_stripes: Number of stripes
* @num_s_cmd_bufs: Number of stripe commands
* @s_cdm_info: Stripe cdm info
* @go_cmd_addr: GO command address
* @go_cmd_len: GO command length
*/
struct ope_bus_rd_io_port_cdm_info {
uint32_t num_frames_cmds;
struct ope_bus_rd_cdm_info f_cdm_info[MAX_RD_CLIENTS];
uint32_t num_stripes;
uint32_t num_s_cmd_bufs[OPE_MAX_STRIPES];
struct ope_bus_rd_cdm_info s_cdm_info[OPE_MAX_STRIPES][MAX_RD_CLIENTS];
uint32_t go_cmd_offset;
uint32_t *go_cmd_addr;
uint32_t go_cmd_len;
};
/**
* struct ope_bus_rd_io_port_cdm_batch
*
* num_batch: Number of batches
* io_port_cdm: CDM IO Port Info
*/
struct ope_bus_rd_io_port_cdm_batch {
uint32_t num_batch;
struct ope_bus_rd_io_port_cdm_info io_port_cdm[OPE_MAX_BATCH_SIZE];
};
/**
* struct ope_bus_rd_rm
*
* @rm_port_id: RM port ID
* @format_type: Format type
*/
struct ope_bus_rd_rm {
uint32_t rm_port_id;
uint32_t format_type;
};
/**
* struct ope_bus_in_port_to_rm
*
* @input_port_id: Intput port ID
* @num_combos: Number of combos
* @num_rm: Number of RMs
* @rm_port_id: RM port Id
*/
struct ope_bus_in_port_to_rm {
uint32_t input_port_id;
uint32_t num_combos;
uint32_t num_rm[BUS_RD_COMBO_MAX];
uint32_t rm_port_id[BUS_RD_COMBO_MAX][MAX_RD_CLIENTS];
};
/**
* struct ope_bus_rd_io_port_info
*
* @pixel_pattern: Pixel pattern
* @input_port_id: Port Id
* @input_format_type: Format type
* @latency_buf_size: Latency buffer size
*/
struct ope_bus_rd_io_port_info {
uint32_t pixel_pattern[OPE_IN_RES_MAX];
uint32_t input_port_id[OPE_IN_RES_MAX];
uint32_t input_format_type[OPE_IN_RES_MAX];
uint32_t latency_buf_size;
};
/**
* struct ope_bus_rd_ctx
*
* @ope_acquire: OPE acquire structure
* @security_flag: security flag
* @num_in_ports: Number of in ports
* @io_port_info: IO port info
* @io_port_cdm_batch: IO port cdm info
*/
struct ope_bus_rd_ctx {
struct ope_acquire_dev_info *ope_acquire;
bool security_flag;
uint32_t num_in_ports;
struct ope_bus_rd_io_port_info io_port_info;
struct ope_bus_rd_io_port_cdm_batch io_port_cdm_batch;
};
/**
* struct ope_bus_rd
*
* @ope_hw_info: OPE hardware info
* @in_port_to_rm: IO port to RM mapping
* @bus_rd_ctx: RM context
*/
struct ope_bus_rd {
struct ope_hw *ope_hw_info;
struct ope_bus_in_port_to_rm in_port_to_rm[OPE_IN_RES_MAX];
struct ope_bus_rd_ctx bus_rd_ctx[OPE_CTX_MAX];
struct completion reset_complete;
};
#endif /* OPE_BUS_RD_H */

View File

@@ -0,0 +1,785 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/of.h>
#include <linux/debugfs.h>
#include <linux/videodev2.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/iopoll.h>
#include <media/cam_ope.h>
#include "cam_io_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
#include "ope_core.h"
#include "ope_soc.h"
#include "cam_soc_util.h"
#include "cam_io_util.h"
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
#include "ope_hw.h"
#include "ope_dev_intf.h"
#include "ope_bus_wr.h"
#include "cam_cdm_util.h"
static struct ope_bus_wr *wr_info;
static int cam_ope_bus_en_port_idx(
struct cam_ope_request *ope_request,
uint32_t batch_idx,
uint32_t output_port_id)
{
int i;
struct ope_io_buf *io_buf;
if (batch_idx >= OPE_MAX_BATCH_SIZE) {
CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx);
return -EINVAL;
}
for (i = 0; i < ope_request->num_io_bufs[batch_idx]; i++) {
io_buf = &ope_request->io_buf[batch_idx][i];
if (io_buf->direction != CAM_BUF_OUTPUT)
continue;
if (io_buf->resource_type == output_port_id)
return i;
}
return -EINVAL;
}
static int cam_ope_bus_wr_out_port_idx(uint32_t output_port_id)
{
int i;
for (i = 0; i < OPE_OUT_RES_MAX; i++)
if (wr_info->out_port_to_wm[i].output_port_id == output_port_id)
return i;
return -EINVAL;
}
static int cam_ope_bus_wr_subsample(
struct cam_ope_ctx *ctx_data,
struct ope_hw *ope_hw_info,
struct cam_ope_bus_wr_client_reg *wr_reg_client,
struct ope_io_buf *io_buf,
uint32_t *temp_reg, uint32_t count,
int plane_idx, int stripe_idx)
{
int k, l;
struct cam_ope_bus_wr_reg *wr_reg;
struct cam_ope_bus_wr_reg_val *wr_reg_val;
wr_reg = ope_hw_info->bus_wr_reg;
wr_reg_val = ope_hw_info->bus_wr_reg_val;
if (plane_idx >= OPE_MAX_PLANES) {
CAM_ERR(CAM_OPE, "Invalid plane idx: %d", plane_idx);
return count;
}
k = plane_idx;
l = stripe_idx;
/* subsample period and pattern */
if ((ctx_data->ope_acquire.dev_type ==
OPE_DEV_TYPE_OPE_RT) && l == 0) {
temp_reg[count++] = wr_reg->offset +
wr_reg_client->subsample_period;
temp_reg[count++] = io_buf->num_stripes[k];
temp_reg[count++] = wr_reg->offset +
wr_reg_client->subsample_pattern;
temp_reg[count++] = 1 <<
(io_buf->num_stripes[k] - 1);
} else if ((ctx_data->ope_acquire.dev_type ==
OPE_DEV_TYPE_OPE_NRT) &&
((l %
ctx_data->ope_acquire.nrt_stripes_for_arb) ==
0)) {
if (io_buf->num_stripes[k] >=
(l +
ctx_data->ope_acquire.nrt_stripes_for_arb)){
temp_reg[count++] = wr_reg->offset +
wr_reg_client->subsample_period;
temp_reg[count++] =
ctx_data->ope_acquire.nrt_stripes_for_arb;
temp_reg[count++] = wr_reg->offset +
wr_reg_client->subsample_pattern;
temp_reg[count++] = 1 <<
(ctx_data->ope_acquire.nrt_stripes_for_arb -
1);
} else {
temp_reg[count++] = wr_reg->offset +
wr_reg_client->subsample_period;
temp_reg[count++] = io_buf->num_stripes[k] - l;
/* subsample pattern */
temp_reg[count++] = wr_reg->offset +
wr_reg_client->subsample_pattern;
temp_reg[count++] = 1 << (io_buf->num_stripes[k] -
l - 1);
}
}
return count;
}
static int cam_ope_bus_wr_release(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0, i;
struct ope_acquire_dev_info *in_acquire;
struct ope_bus_wr_ctx *bus_wr_ctx;
if (ctx_id < 0) {
CAM_ERR(CAM_OPE, "Invalid data: %d", ctx_id);
return -EINVAL;
}
in_acquire = wr_info->bus_wr_ctx[ctx_id].ope_acquire;
wr_info->bus_wr_ctx[ctx_id].ope_acquire = NULL;
bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id];
bus_wr_ctx->num_out_ports = 0;
for (i = 0; i < bus_wr_ctx->num_out_ports; i++) {
bus_wr_ctx->io_port_info.output_port_id[i] = 0;
bus_wr_ctx->io_port_info.output_format_type[i - 1] = 0;
bus_wr_ctx->io_port_info.pixel_pattern[i - 1] = 0;
}
return rc;
}
static uint32_t *cam_ope_bus_wr_update(struct ope_hw *ope_hw_info,
int32_t ctx_id, struct cam_ope_dev_prepare_req *prepare,
int batch_idx, int io_idx,
uint32_t *kmd_buf, uint32_t *num_stripes)
{
int k, l, out_port_idx;
uint32_t idx;
uint32_t num_wm_ports;
uint32_t comb_idx;
uint32_t req_idx;
uint32_t temp_reg[128];
uint32_t count = 0;
uint32_t temp = 0;
uint32_t wm_port_id;
uint32_t header_size;
struct cam_hw_prepare_update_args *prepare_args;
struct cam_ope_ctx *ctx_data;
struct cam_ope_request *ope_request;
struct ope_io_buf *io_buf;
struct ope_stripe_io *stripe_io;
struct ope_bus_wr_ctx *bus_wr_ctx;
struct cam_ope_bus_wr_reg *wr_reg;
struct cam_ope_bus_wr_client_reg *wr_reg_client;
struct cam_ope_bus_wr_reg_val *wr_reg_val;
struct cam_ope_bus_wr_client_reg_val *wr_res_val_client;
struct ope_bus_out_port_to_wm *out_port_to_wm;
struct ope_bus_wr_io_port_cdm_batch *io_port_cdm_batch;
struct ope_bus_wr_io_port_cdm_info *io_port_cdm;
struct cam_cdm_utils_ops *cdm_ops;
if (ctx_id < 0 || !prepare) {
CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, prepare);
return NULL;
}
if (batch_idx >= OPE_MAX_BATCH_SIZE) {
CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx);
return NULL;
}
if (io_idx >= OPE_MAX_IO_BUFS) {
CAM_ERR(CAM_OPE, "Invalid IO idx: %d", io_idx);
return NULL;
}
prepare_args = prepare->prepare_args;
ctx_data = prepare->ctx_data;
req_idx = prepare->req_idx;
cdm_ops = ctx_data->ope_cdm.cdm_ops;
ope_request = ctx_data->req_list[req_idx];
bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id];
io_port_cdm_batch = &bus_wr_ctx->io_port_cdm_batch;
wr_reg = ope_hw_info->bus_wr_reg;
wr_reg_val = ope_hw_info->bus_wr_reg_val;
CAM_DBG(CAM_OPE, "kmd_buf = %x req_idx = %d req_id = %lld offset = %d",
kmd_buf, req_idx, ope_request->request_id,
prepare->kmd_buf_offset);
io_buf = &ope_request->io_buf[batch_idx][io_idx];
CAM_DBG(CAM_OPE, "batch = %d io buf num = %d dir = %d",
batch_idx, io_idx, io_buf->direction);
io_port_cdm =
&bus_wr_ctx->io_port_cdm_batch.io_port_cdm[batch_idx];
out_port_idx =
cam_ope_bus_wr_out_port_idx(io_buf->resource_type);
if (out_port_idx < 0) {
CAM_ERR(CAM_OPE, "Invalid idx for rsc type: %d",
io_buf->resource_type);
return NULL;
}
out_port_to_wm = &wr_info->out_port_to_wm[out_port_idx];
comb_idx = BUS_WR_YUV;
num_wm_ports = out_port_to_wm->num_wm[comb_idx];
for (k = 0; k < io_buf->num_planes; k++) {
*num_stripes = io_buf->num_stripes[k];
for (l = 0; l < io_buf->num_stripes[k]; l++) {
stripe_io = &io_buf->s_io[k][l];
CAM_DBG(CAM_OPE, "comb_idx = %d p_idx = %d s_idx = %d",
comb_idx, k, l);
/* frame level info */
/* stripe level info */
wm_port_id = out_port_to_wm->wm_port_id[comb_idx][k];
wr_reg_client = &wr_reg->wr_clients[wm_port_id];
wr_res_val_client = &wr_reg_val->wr_clients[wm_port_id];
/* Core cfg: enable, Mode */
temp_reg[count++] = wr_reg->offset +
wr_reg_client->core_cfg;
temp = 0;
if (!stripe_io->disable_bus)
temp = wr_res_val_client->core_cfg_en;
temp |= ((wr_res_val_client->mode &
wr_res_val_client->mode_mask) <<
wr_res_val_client->mode_shift);
temp_reg[count++] = temp;
/* Address of the Image */
temp_reg[count++] = wr_reg->offset +
wr_reg_client->img_addr;
temp_reg[count++] = stripe_io->iova_addr;
/* Buffer size */
temp_reg[count++] = wr_reg->offset +
wr_reg_client->img_cfg;
temp = 0;
temp = stripe_io->width;
temp |= (stripe_io->height &
wr_res_val_client->height_mask) <<
wr_res_val_client->height_shift;
temp_reg[count++] = temp;
/* x_init */
temp_reg[count++] = wr_reg->offset +
wr_reg_client->x_init;
temp_reg[count++] = stripe_io->x_init;
/* stride */
temp_reg[count++] = wr_reg->offset +
wr_reg_client->stride;
temp_reg[count++] = stripe_io->stride;
/* pack cfg : Format and alignment */
temp_reg[count++] = wr_reg->offset +
wr_reg_client->pack_cfg;
temp = 0;
temp |= ((stripe_io->pack_format &
wr_res_val_client->format_mask) <<
wr_res_val_client->format_shift);
temp |= ((stripe_io->alignment &
wr_res_val_client->alignment_mask) <<
wr_res_val_client->alignment_shift);
temp_reg[count++] = temp;
/* subsample period and pattern */
count = cam_ope_bus_wr_subsample(
ctx_data, ope_hw_info,
wr_reg_client, io_buf,
temp_reg, count, k, l);
header_size = cdm_ops->cdm_get_cmd_header_size(
CAM_CDM_CMD_REG_RANDOM);
idx = io_port_cdm->num_s_cmd_bufs[l];
io_port_cdm->s_cdm_info[l][idx].len =
sizeof(temp) * (count + header_size);
io_port_cdm->s_cdm_info[l][idx].offset =
prepare->kmd_buf_offset;
io_port_cdm->s_cdm_info[l][idx].addr = kmd_buf;
io_port_cdm->num_s_cmd_bufs[l]++;
kmd_buf = cdm_ops->cdm_write_regrandom(
kmd_buf, count/2, temp_reg);
prepare->kmd_buf_offset += ((count + header_size) *
sizeof(temp));
CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d",
batch_idx, io_idx, k, l);
CAM_DBG(CAM_OPE, "kmdbuf:%x, offset:%d",
kmd_buf, prepare->kmd_buf_offset);
CAM_DBG(CAM_OPE, "count:%d temp_reg:%x",
count, temp_reg, header_size);
CAM_DBG(CAM_OPE, "header_size:%d", header_size);
CAM_DBG(CAM_OPE, "WR cmd bufs = %d",
io_port_cdm->num_s_cmd_bufs[l]);
CAM_DBG(CAM_OPE, "off:%d len:%d",
io_port_cdm->s_cdm_info[l][idx].offset,
io_port_cdm->s_cdm_info[l][idx].len);
CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d",
batch_idx, io_idx, k, l);
count = 0;
}
}
return kmd_buf;
}
static uint32_t *cam_ope_bus_wm_disable(struct ope_hw *ope_hw_info,
int32_t ctx_id, struct cam_ope_dev_prepare_req *prepare,
int batch_idx, int io_idx,
uint32_t *kmd_buf, uint32_t num_stripes)
{
int k, l;
uint32_t idx;
uint32_t num_wm_ports;
uint32_t comb_idx;
uint32_t req_idx;
uint32_t temp_reg[128];
uint32_t count = 0;
uint32_t temp = 0;
uint32_t wm_port_id;
uint32_t header_size;
struct cam_ope_ctx *ctx_data;
struct ope_bus_wr_ctx *bus_wr_ctx;
struct cam_ope_bus_wr_reg *wr_reg;
struct cam_ope_bus_wr_client_reg *wr_reg_client;
struct ope_bus_out_port_to_wm *out_port_to_wm;
struct ope_bus_wr_io_port_cdm_batch *io_port_cdm_batch;
struct ope_bus_wr_io_port_cdm_info *io_port_cdm;
struct cam_cdm_utils_ops *cdm_ops;
if (ctx_id < 0 || !prepare) {
CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, prepare);
return NULL;
}
if (batch_idx >= OPE_MAX_BATCH_SIZE) {
CAM_ERR(CAM_OPE, "Invalid batch idx: %d", batch_idx);
return NULL;
}
ctx_data = prepare->ctx_data;
req_idx = prepare->req_idx;
cdm_ops = ctx_data->ope_cdm.cdm_ops;
bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id];
io_port_cdm_batch = &bus_wr_ctx->io_port_cdm_batch;
wr_reg = ope_hw_info->bus_wr_reg;
CAM_DBG(CAM_OPE, "kmd_buf = %x req_idx = %d offset = %d",
kmd_buf, req_idx, prepare->kmd_buf_offset);
io_port_cdm =
&bus_wr_ctx->io_port_cdm_batch.io_port_cdm[batch_idx];
out_port_to_wm = &wr_info->out_port_to_wm[io_idx];
comb_idx = BUS_WR_YUV;
num_wm_ports = out_port_to_wm->num_wm[comb_idx];
for (k = 0; k < num_wm_ports; k++) {
for (l = 0; l < num_stripes; l++) {
CAM_DBG(CAM_OPE, "comb_idx = %d p_idx = %d s_idx = %d",
comb_idx, k, l);
/* frame level info */
/* stripe level info */
wm_port_id = out_port_to_wm->wm_port_id[comb_idx][k];
wr_reg_client = &wr_reg->wr_clients[wm_port_id];
/* Core cfg: enable, Mode */
temp_reg[count++] = wr_reg->offset +
wr_reg_client->core_cfg;
temp_reg[count++] = 0;
header_size = cdm_ops->cdm_get_cmd_header_size(
CAM_CDM_CMD_REG_RANDOM);
idx = io_port_cdm->num_s_cmd_bufs[l];
io_port_cdm->s_cdm_info[l][idx].len =
sizeof(temp) * (count + header_size);
io_port_cdm->s_cdm_info[l][idx].offset =
prepare->kmd_buf_offset;
io_port_cdm->s_cdm_info[l][idx].addr = kmd_buf;
io_port_cdm->num_s_cmd_bufs[l]++;
kmd_buf = cdm_ops->cdm_write_regrandom(
kmd_buf, count/2, temp_reg);
prepare->kmd_buf_offset += ((count + header_size) *
sizeof(temp));
CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d",
batch_idx, io_idx, k, l);
CAM_DBG(CAM_OPE, "kmdbuf:%x, offset:%d",
kmd_buf, prepare->kmd_buf_offset);
CAM_DBG(CAM_OPE, "count:%d temp_reg:%x",
count, temp_reg, header_size);
CAM_DBG(CAM_OPE, "header_size:%d", header_size);
CAM_DBG(CAM_OPE, "WR cmd bufs = %d",
io_port_cdm->num_s_cmd_bufs[l]);
CAM_DBG(CAM_OPE, "off:%d len:%d",
io_port_cdm->s_cdm_info[l][idx].offset,
io_port_cdm->s_cdm_info[l][idx].len);
CAM_DBG(CAM_OPE, "b:%d io:%d p:%d s:%d",
batch_idx, io_idx, k, l);
count = 0;
}
}
prepare->wr_cdm_batch = &bus_wr_ctx->io_port_cdm_batch;
return kmd_buf;
}
static int cam_ope_bus_wr_prepare(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
int i, j = 0;
uint32_t req_idx;
uint32_t *kmd_buf;
struct cam_ope_dev_prepare_req *prepare;
struct cam_ope_ctx *ctx_data;
struct cam_ope_request *ope_request;
struct ope_io_buf *io_buf;
uint32_t temp;
int io_buf_idx;
uint32_t num_stripes = 0;
struct ope_bus_wr_io_port_cdm_batch *io_port_cdm_batch;
struct ope_bus_wr_ctx *bus_wr_ctx;
if (ctx_id < 0 || !data) {
CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data);
return -EINVAL;
}
prepare = data;
ctx_data = prepare->ctx_data;
req_idx = prepare->req_idx;
bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id];
ope_request = ctx_data->req_list[req_idx];
kmd_buf = (uint32_t *)ope_request->ope_kmd_buf.cpu_addr +
(prepare->kmd_buf_offset / sizeof(temp));
CAM_DBG(CAM_OPE, "kmd_buf = %x req_idx = %d req_id = %lld offset = %d",
kmd_buf, req_idx, ope_request->request_id,
prepare->kmd_buf_offset);
io_port_cdm_batch = &wr_info->bus_wr_ctx[ctx_id].io_port_cdm_batch;
memset(io_port_cdm_batch, 0,
sizeof(struct ope_bus_wr_io_port_cdm_batch));
for (i = 0; i < ope_request->num_batch; i++) {
for (j = 0; j < ope_request->num_io_bufs[i]; j++) {
io_buf = &ope_request->io_buf[i][j];
CAM_DBG(CAM_OPE, "batch = %d io buf num = %d dir = %d",
i, j, io_buf->direction);
if (io_buf->direction != CAM_BUF_OUTPUT)
continue;
kmd_buf = cam_ope_bus_wr_update(ope_hw_info,
ctx_id, prepare, i, j,
kmd_buf, &num_stripes);
if (!kmd_buf) {
rc = -EINVAL;
goto end;
}
}
}
/* Disable WMs which are not enabled */
for (i = 0; i < ope_request->num_batch; i++) {
for (j = OPE_OUT_RES_VIDEO; j <= OPE_OUT_RES_MAX; j++) {
io_buf_idx = cam_ope_bus_en_port_idx(ope_request, i, j);
if (io_buf_idx >= 0)
continue;
io_buf_idx = cam_ope_bus_wr_out_port_idx(j);
if (io_buf_idx < 0) {
CAM_ERR(CAM_OPE, "Invalid idx for rsc type:%d",
j);
return io_buf_idx;
}
kmd_buf = cam_ope_bus_wm_disable(ope_hw_info,
ctx_id, prepare, i, io_buf_idx,
kmd_buf, num_stripes);
}
}
prepare->wr_cdm_batch = &bus_wr_ctx->io_port_cdm_batch;
end:
return rc;
}
static int cam_ope_bus_wr_acquire(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0, i;
struct ope_acquire_dev_info *in_acquire;
struct ope_bus_wr_ctx *bus_wr_ctx;
struct ope_bus_out_port_to_wm *out_port_to_wr;
int combo_idx;
int out_port_idx;
if (ctx_id < 0 || !data) {
CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data);
return -EINVAL;
}
wr_info->bus_wr_ctx[ctx_id].ope_acquire = data;
in_acquire = data;
bus_wr_ctx = &wr_info->bus_wr_ctx[ctx_id];
bus_wr_ctx->num_out_ports = in_acquire->num_out_res;
bus_wr_ctx->security_flag = in_acquire->secure_mode;
for (i = 0; i < in_acquire->num_out_res; i++) {
if (!in_acquire->out_res[i].width)
continue;
CAM_DBG(CAM_OPE, "i = %d format = %u width = %x height = %x",
i, in_acquire->out_res[i].format,
in_acquire->out_res[i].width,
in_acquire->out_res[i].height);
CAM_DBG(CAM_OPE, "pix_pattern:%u alignment:%u packer_format:%u",
in_acquire->out_res[i].pixel_pattern,
in_acquire->out_res[i].alignment,
in_acquire->out_res[i].packer_format);
CAM_DBG(CAM_OPE, "subsample_period = %u subsample_pattern = %u",
in_acquire->out_res[i].subsample_period,
in_acquire->out_res[i].subsample_pattern);
out_port_idx =
cam_ope_bus_wr_out_port_idx(in_acquire->out_res[i].res_id);
if (out_port_idx < 0) {
CAM_DBG(CAM_OPE, "Invalid in_port_idx: %d",
in_acquire->out_res[i].res_id);
rc = -EINVAL;
goto end;
}
out_port_to_wr = &wr_info->out_port_to_wm[out_port_idx];
combo_idx = BUS_WR_YUV;
if (!out_port_to_wr->num_wm[combo_idx]) {
CAM_DBG(CAM_OPE, "Invalid format for Input port");
rc = -EINVAL;
goto end;
}
bus_wr_ctx->io_port_info.output_port_id[i] =
in_acquire->out_res[i].res_id;
bus_wr_ctx->io_port_info.output_format_type[i] =
in_acquire->out_res[i].format;
if (in_acquire->out_res[i].pixel_pattern >
PIXEL_PATTERN_CRYCBY) {
CAM_DBG(CAM_OPE, "Invalid pix pattern = %u",
in_acquire->out_res[i].pixel_pattern);
rc = -EINVAL;
goto end;
}
bus_wr_ctx->io_port_info.pixel_pattern[i] =
in_acquire->out_res[i].pixel_pattern;
bus_wr_ctx->io_port_info.latency_buf_size = 4096;
CAM_DBG(CAM_OPE, "i:%d port_id = %u format %u pix_pattern = %u",
i, bus_wr_ctx->io_port_info.output_port_id[i],
bus_wr_ctx->io_port_info.output_format_type[i],
bus_wr_ctx->io_port_info.pixel_pattern[i]);
CAM_DBG(CAM_OPE, "latency_buf_size = %u",
bus_wr_ctx->io_port_info.latency_buf_size);
}
end:
return rc;
}
static int cam_ope_bus_wr_init(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
struct cam_ope_bus_wr_reg_val *bus_wr_reg_val;
struct cam_ope_bus_wr_reg *bus_wr_reg;
struct cam_ope_dev_init *dev_init = data;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
wr_info->ope_hw_info = ope_hw_info;
bus_wr_reg_val = ope_hw_info->bus_wr_reg_val;
bus_wr_reg = ope_hw_info->bus_wr_reg;
bus_wr_reg->base = dev_init->core_info->ope_hw_info->ope_bus_wr_base;
cam_io_w_mb(bus_wr_reg_val->irq_mask_0,
ope_hw_info->bus_wr_reg->base + bus_wr_reg->irq_mask_0);
cam_io_w_mb(bus_wr_reg_val->irq_mask_1,
ope_hw_info->bus_wr_reg->base + bus_wr_reg->irq_mask_1);
return rc;
}
static int cam_ope_bus_wr_probe(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0, i, j, combo_idx, k;
struct cam_ope_bus_wr_reg_val *bus_wr_reg_val;
struct ope_bus_out_port_to_wm *out_port_to_wm;
uint32_t output_port_idx;
uint32_t wm_idx;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
wr_info = kzalloc(sizeof(struct ope_bus_wr), GFP_KERNEL);
if (!wr_info) {
CAM_ERR(CAM_OPE, "Out of memory");
return -ENOMEM;
}
wr_info->ope_hw_info = ope_hw_info;
bus_wr_reg_val = ope_hw_info->bus_wr_reg_val;
for (i = 0; i < bus_wr_reg_val->num_clients; i++) {
output_port_idx =
bus_wr_reg_val->wr_clients[i].output_port_id - 1;
out_port_to_wm = &wr_info->out_port_to_wm[output_port_idx];
combo_idx = BUS_WR_YUV;
wm_idx = out_port_to_wm->num_wm[combo_idx];
out_port_to_wm->output_port_id =
bus_wr_reg_val->wr_clients[i].output_port_id;
out_port_to_wm->wm_port_id[combo_idx][wm_idx] =
bus_wr_reg_val->wr_clients[i].wm_port_id;
if (!out_port_to_wm->num_wm[combo_idx])
out_port_to_wm->num_combos++;
out_port_to_wm->num_wm[combo_idx]++;
}
for (i = 0; i < OPE_OUT_RES_MAX; i++) {
out_port_to_wm = &wr_info->out_port_to_wm[i];
CAM_DBG(CAM_OPE, "output port id = %d num_combos = %d",
out_port_to_wm->output_port_id,
out_port_to_wm->num_combos);
for (j = 0; j < out_port_to_wm->num_combos; j++) {
CAM_DBG(CAM_OPE, "combo idx = %d num_wms = %d",
j, out_port_to_wm->num_wm[j]);
for (k = 0; k < out_port_to_wm->num_wm[j]; k++) {
CAM_DBG(CAM_OPE, "wm port id = %d",
out_port_to_wm->wm_port_id[j][k]);
}
}
}
return rc;
}
static int cam_ope_bus_wr_isr(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
uint32_t irq_status_0, irq_status_1;
struct cam_ope_bus_wr_reg *bus_wr_reg;
struct cam_ope_bus_wr_reg_val *bus_wr_reg_val;
struct cam_ope_irq_data *irq_data = data;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
bus_wr_reg = ope_hw_info->bus_wr_reg;
bus_wr_reg_val = ope_hw_info->bus_wr_reg_val;
/* Read and Clear Top Interrupt status */
irq_status_0 = cam_io_r_mb(bus_wr_reg->base + bus_wr_reg->irq_status_0);
irq_status_1 = cam_io_r_mb(bus_wr_reg->base + bus_wr_reg->irq_status_1);
cam_io_w_mb(irq_status_0,
bus_wr_reg->base + bus_wr_reg->irq_clear_0);
cam_io_w_mb(irq_status_1,
bus_wr_reg->base + bus_wr_reg->irq_clear_1);
cam_io_w_mb(bus_wr_reg_val->irq_set_clear,
bus_wr_reg->base + bus_wr_reg->irq_cmd);
if (irq_status_0 & bus_wr_reg_val->cons_violation) {
irq_data->error = 1;
CAM_ERR(CAM_OPE, "ope bus wr cons_violation");
}
if (irq_status_0 & bus_wr_reg_val->violation) {
irq_data->error = 1;
CAM_ERR(CAM_OPE, "ope bus wr vioalation");
}
if (irq_status_0 & bus_wr_reg_val->img_size_violation) {
irq_data->error = 1;
CAM_ERR(CAM_OPE, "ope bus wr img_size_violation");
}
return rc;
}
int cam_ope_bus_wr_process(struct ope_hw *ope_hw_info,
int32_t ctx_id, uint32_t cmd_id, void *data)
{
int rc = 0;
switch (cmd_id) {
case OPE_HW_PROBE:
CAM_DBG(CAM_OPE, "OPE_HW_PROBE: E");
rc = cam_ope_bus_wr_probe(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_PROBE: X");
break;
case OPE_HW_INIT:
CAM_DBG(CAM_OPE, "OPE_HW_INIT: E");
rc = cam_ope_bus_wr_init(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_INIT: X");
break;
case OPE_HW_ACQUIRE:
CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: E");
rc = cam_ope_bus_wr_acquire(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: X");
break;
case OPE_HW_RELEASE:
CAM_DBG(CAM_OPE, "OPE_HW_RELEASE: E");
rc = cam_ope_bus_wr_release(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_RELEASE: X");
break;
case OPE_HW_PREPARE:
CAM_DBG(CAM_OPE, "OPE_HW_PREPARE: E");
rc = cam_ope_bus_wr_prepare(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_PREPARE: X");
break;
case OPE_HW_DEINIT:
case OPE_HW_START:
case OPE_HW_STOP:
case OPE_HW_FLUSH:
case OPE_HW_CLK_UPDATE:
case OPE_HW_BW_UPDATE:
case OPE_HW_RESET:
case OPE_HW_SET_IRQ_CB:
rc = 0;
CAM_DBG(CAM_OPE, "Unhandled cmds: %d", cmd_id);
break;
case OPE_HW_ISR:
rc = cam_ope_bus_wr_isr(ope_hw_info, 0, NULL);
break;
default:
CAM_ERR(CAM_OPE, "Unsupported cmd: %d", cmd_id);
break;
}
return rc;
}

View File

@@ -0,0 +1,137 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef OPE_BUS_WR_H
#define OPE_BUS_WR_H
#include <linux/types.h>
#include <linux/completion.h>
#include <media/cam_ope.h>
#include "ope_hw.h"
#include "cam_hw_mgr_intf.h"
#include "cam_hw_intf.h"
#include "cam_soc_util.h"
#include "cam_context.h"
#include "cam_ope_context.h"
#include "cam_ope_hw_mgr.h"
/**
* struct ope_bus_wr_cdm_info
*
* @offset: Offset
* @addr: Address
* @len: Length
*/
struct ope_bus_wr_cdm_info {
uint32_t offset;
uint32_t *addr;
uint32_t len;
};
/**
* struct ope_bus_wr_io_port_cdm_info
*
* @num_frames_cmds: Number of frame commands
* @f_cdm_info: Frame cdm info
* @num_stripes: Number of stripes
* @num_s_cmd_bufs: Number of stripe commands
* @s_cdm_info: Stripe cdm info
* @go_cmd_addr: GO command address
* @go_cmd_len: GO command length
*/
struct ope_bus_wr_io_port_cdm_info {
uint32_t num_frames_cmds;
struct ope_bus_wr_cdm_info f_cdm_info[MAX_WR_CLIENTS];
uint32_t num_stripes;
uint32_t num_s_cmd_bufs[OPE_MAX_STRIPES];
struct ope_bus_wr_cdm_info s_cdm_info[OPE_MAX_STRIPES][MAX_WR_CLIENTS];
uint32_t *go_cmd_addr;
uint32_t go_cmd_len;
};
/**
* struct ope_bus_wr_io_port_cdm_batch
*
* num_batch: Number of batches
* io_port_cdm: CDM IO Port Info
*/
struct ope_bus_wr_io_port_cdm_batch {
uint32_t num_batch;
struct ope_bus_wr_io_port_cdm_info io_port_cdm[OPE_MAX_BATCH_SIZE];
};
/**
* struct ope_bus_wr_wm
*
* @wm_port_id: WM port ID
* @format_type: Format type
*/
struct ope_bus_wr_wm {
uint32_t wm_port_id;
uint32_t format_type;
};
/**
* struct ope_bus_out_port_to_wm
*
* @output_port_id: Output port ID
* @num_combos: Number of combos
* @num_wm: Number of WMs
* @wm_port_id: WM port Id
*/
struct ope_bus_out_port_to_wm {
uint32_t output_port_id;
uint32_t num_combos;
uint32_t num_wm[BUS_WR_COMBO_MAX];
uint32_t wm_port_id[BUS_WR_COMBO_MAX][MAX_WR_CLIENTS];
};
/**
* struct ope_bus_wr_io_port_info
*
* @pixel_pattern: Pixel pattern
* @output_port_id: Port Id
* @output_format_type: Format type
* @latency_buf_size: Latency buffer size
*/
struct ope_bus_wr_io_port_info {
uint32_t pixel_pattern[OPE_OUT_RES_MAX];
uint32_t output_port_id[OPE_OUT_RES_MAX];
uint32_t output_format_type[OPE_OUT_RES_MAX];
uint32_t latency_buf_size;
};
/**
* struct ope_bus_wr_ctx
*
* @ope_acquire: OPE acquire structure
* @security_flag: security flag
* @num_out_ports: Number of out ports
* @io_port_info: IO port info
* @io_port_cdm_batch: IO port cdm info
*/
struct ope_bus_wr_ctx {
struct ope_acquire_dev_info *ope_acquire;
bool security_flag;
uint32_t num_out_ports;
struct ope_bus_wr_io_port_info io_port_info;
struct ope_bus_wr_io_port_cdm_batch io_port_cdm_batch;
};
/**
* struct ope_bus_wr
*
* @ope_hw_info: OPE hardware info
* @out_port_to_wm: IO port to WM mapping
* @bus_wr_ctx: WM context
*/
struct ope_bus_wr {
struct ope_hw *ope_hw_info;
struct ope_bus_out_port_to_wm out_port_to_wm[OPE_OUT_RES_MAX];
struct ope_bus_wr_ctx bus_wr_ctx[OPE_CTX_MAX];
};
#endif /* OPE_BUS_WR_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,99 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_OPE_CORE_H
#define CAM_OPE_CORE_H
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/dma-buf.h>
#include <media/cam_ope.h>
#include "cam_cpas_api.h"
#include "ope_hw.h"
#include "ope_dev_intf.h"
/**
* struct cam_ope_cpas_vote
* @ahb_vote: AHB vote info
* @axi_vote: AXI vote info
* @ahb_vote_valid: Flag for ahb vote data
* @axi_vote_valid: flag for axi vote data
*/
struct cam_ope_cpas_vote {
struct cam_ahb_vote ahb_vote;
struct cam_axi_vote axi_vote;
uint32_t ahb_vote_valid;
uint32_t axi_vote_valid;
};
/**
* struct cam_ope_device_hw_info
*
* @ope_hw: OPE hardware
* @hw_idx: Hardware index
* @ope_cdm_base: Base address of CDM
* @ope_top_base: Base address of top
* @ope_qos_base: Base address of QOS
* @ope_pp_base: Base address of PP
* @ope_bus_rd_base: Base address of RD
* @ope_bus_wr_base: Base address of WM
* @hfi_en: HFI flag enable
* @reserved: Reserved
*/
struct cam_ope_device_hw_info {
struct ope_hw *ope_hw;
uint32_t hw_idx;
void *ope_cdm_base;
void *ope_top_base;
void *ope_qos_base;
void *ope_pp_base;
void *ope_bus_rd_base;
void *ope_bus_wr_base;
bool hfi_en;
uint32_t reserved;
};
/**
* struct cam_ope_device_core_info
*
* @ope_hw_info: OPE hardware info
* @hw_version: Hardware version
* @hw_idx: Hardware Index
* @hw_type: Hardware Type
* @cpas_handle: CPAS Handle
* @cpas_start: CPAS start flag
* @clk_enable: Clock enable flag
* @irq_cb: IRQ Callback
*/
struct cam_ope_device_core_info {
struct cam_ope_device_hw_info *ope_hw_info;
uint32_t hw_version;
uint32_t hw_idx;
uint32_t hw_type;
uint32_t cpas_handle;
bool cpas_start;
bool clk_enable;
struct cam_ope_set_irq_cb irq_cb;
};
int cam_ope_init_hw(void *device_priv,
void *init_hw_args, uint32_t arg_size);
int cam_ope_deinit_hw(void *device_priv,
void *init_hw_args, uint32_t arg_size);
int cam_ope_start(void *device_priv,
void *start_args, uint32_t arg_size);
int cam_ope_stop(void *device_priv,
void *stop_args, uint32_t arg_size);
int cam_ope_flush(void *device_priv,
void *flush_args, uint32_t arg_size);
int cam_ope_get_hw_caps(void *device_priv,
void *get_hw_cap_args, uint32_t arg_size);
int cam_ope_process_cmd(void *device_priv, uint32_t cmd_type,
void *cmd_args, uint32_t arg_size);
irqreturn_t cam_ope_irq(int irq_num, void *data);
#endif /* CAM_OPE_CORE_H */

View File

@@ -0,0 +1,253 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mod_devicetable.h>
#include <linux/of_device.h>
#include <linux/timer.h>
#include "ope_core.h"
#include "ope_soc.h"
#include "cam_hw.h"
#include "ope_hw.h"
#include "cam_hw_intf.h"
#include "cam_io_util.h"
#include "cam_ope_hw_mgr_intf.h"
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
#include "ope_hw_100.h"
#include "ope_dev_intf.h"
static struct cam_ope_device_hw_info ope_hw_info;
static struct ope_dev_soc ope_soc_info;
EXPORT_SYMBOL(ope_soc_info);
static struct hw_version_reg ope_hw_version_reg = {
.hw_ver = 0x0,
};
static char ope_dev_name[8];
static int cam_ope_init_hw_version(struct cam_hw_soc_info *soc_info,
struct cam_ope_device_core_info *core_info)
{
int rc = 0;
CAM_DBG(CAM_OPE, "soc_info = %x core_info = %x",
soc_info, core_info);
CAM_DBG(CAM_OPE, "CDM:%x TOP: %x QOS: %x PP: %x RD: %x WR: %x",
soc_info->reg_map[OPE_CDM_BASE].mem_base,
soc_info->reg_map[OPE_TOP_BASE].mem_base,
soc_info->reg_map[OPE_QOS_BASE].mem_base,
soc_info->reg_map[OPE_PP_BASE].mem_base,
soc_info->reg_map[OPE_BUS_RD].mem_base,
soc_info->reg_map[OPE_BUS_WR].mem_base);
CAM_DBG(CAM_OPE, "core: %x",
core_info->ope_hw_info->ope_cdm_base);
core_info->ope_hw_info->ope_cdm_base =
soc_info->reg_map[OPE_CDM_BASE].mem_base;
core_info->ope_hw_info->ope_top_base =
soc_info->reg_map[OPE_TOP_BASE].mem_base;
core_info->ope_hw_info->ope_qos_base =
soc_info->reg_map[OPE_QOS_BASE].mem_base;
core_info->ope_hw_info->ope_pp_base =
soc_info->reg_map[OPE_PP_BASE].mem_base;
core_info->ope_hw_info->ope_bus_rd_base =
soc_info->reg_map[OPE_BUS_RD].mem_base;
core_info->ope_hw_info->ope_bus_wr_base =
soc_info->reg_map[OPE_BUS_WR].mem_base;
core_info->hw_version = cam_io_r_mb(
core_info->ope_hw_info->ope_top_base +
ope_hw_version_reg.hw_ver);
switch (core_info->hw_version) {
case OPE_HW_VER_1_0_0:
core_info->ope_hw_info->ope_hw = &ope_hw_100;
break;
default:
CAM_ERR(CAM_OPE, "Unsupported version : %u",
core_info->hw_version);
rc = -EINVAL;
break;
}
ope_hw_100.top_reg->base = core_info->ope_hw_info->ope_top_base;
ope_hw_100.bus_rd_reg->base = core_info->ope_hw_info->ope_bus_rd_base;
ope_hw_100.bus_wr_reg->base = core_info->ope_hw_info->ope_bus_wr_base;
return rc;
}
int cam_ope_register_cpas(struct cam_hw_soc_info *soc_info,
struct cam_ope_device_core_info *core_info,
uint32_t hw_idx)
{
struct cam_cpas_register_params cpas_register_params;
int rc;
cpas_register_params.dev = &soc_info->pdev->dev;
memcpy(cpas_register_params.identifier, "ope", sizeof("ope"));
cpas_register_params.cam_cpas_client_cb = NULL;
cpas_register_params.cell_index = hw_idx;
cpas_register_params.userdata = NULL;
rc = cam_cpas_register_client(&cpas_register_params);
if (rc < 0) {
CAM_ERR(CAM_OPE, "failed: %d", rc);
return rc;
}
core_info->cpas_handle = cpas_register_params.client_handle;
return rc;
}
int cam_ope_probe(struct platform_device *pdev)
{
struct cam_hw_intf *ope_dev_intf = NULL;
struct cam_hw_info *ope_dev = NULL;
const struct of_device_id *match_dev = NULL;
struct cam_ope_device_core_info *core_info = NULL;
int rc = 0;
uint32_t hw_idx;
struct cam_ope_dev_probe ope_probe;
of_property_read_u32(pdev->dev.of_node,
"cell-index", &hw_idx);
ope_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
if (!ope_dev_intf)
return -ENOMEM;
ope_dev_intf->hw_idx = hw_idx;
ope_dev_intf->hw_type = OPE_DEV_OPE;
ope_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
if (!ope_dev) {
rc = -ENOMEM;
goto ope_dev_alloc_failed;
}
memset(ope_dev_name, 0, sizeof(ope_dev_name));
snprintf(ope_dev_name, sizeof(ope_dev_name),
"ope%1u", ope_dev_intf->hw_idx);
ope_dev->soc_info.pdev = pdev;
ope_dev->soc_info.dev = &pdev->dev;
ope_dev->soc_info.dev_name = ope_dev_name;
ope_dev_intf->hw_priv = ope_dev;
ope_dev_intf->hw_ops.init = cam_ope_init_hw;
ope_dev_intf->hw_ops.deinit = cam_ope_deinit_hw;
ope_dev_intf->hw_ops.get_hw_caps = cam_ope_get_hw_caps;
ope_dev_intf->hw_ops.start = cam_ope_start;
ope_dev_intf->hw_ops.stop = cam_ope_stop;
ope_dev_intf->hw_ops.flush = cam_ope_flush;
ope_dev_intf->hw_ops.process_cmd = cam_ope_process_cmd;
CAM_DBG(CAM_OPE, "type %d index %d",
ope_dev_intf->hw_type,
ope_dev_intf->hw_idx);
platform_set_drvdata(pdev, ope_dev_intf);
ope_dev->core_info = kzalloc(sizeof(struct cam_ope_device_core_info),
GFP_KERNEL);
if (!ope_dev->core_info) {
rc = -ENOMEM;
goto ope_core_alloc_failed;
}
core_info = (struct cam_ope_device_core_info *)ope_dev->core_info;
core_info->ope_hw_info = &ope_hw_info;
ope_dev->soc_info.soc_private = &ope_soc_info;
match_dev = of_match_device(pdev->dev.driver->of_match_table,
&pdev->dev);
if (!match_dev) {
rc = -EINVAL;
CAM_DBG(CAM_OPE, "No ope hardware info");
goto ope_match_dev_failed;
}
rc = cam_ope_init_soc_resources(&ope_dev->soc_info, cam_ope_irq,
ope_dev);
if (rc < 0) {
CAM_ERR(CAM_OPE, "failed to init_soc");
goto init_soc_failed;
}
rc = cam_ope_enable_soc_resources(&ope_dev->soc_info);
if (rc < 0) {
CAM_ERR(CAM_OPE, "enable soc resorce failed: %d", rc);
goto enable_soc_failed;
}
rc = cam_ope_init_hw_version(&ope_dev->soc_info, ope_dev->core_info);
if (rc)
goto init_hw_failure;
core_info->hw_type = OPE_DEV_OPE;
core_info->hw_idx = hw_idx;
rc = cam_ope_register_cpas(&ope_dev->soc_info,
core_info, ope_dev_intf->hw_idx);
if (rc < 0)
goto register_cpas_failed;
cam_ope_disable_soc_resources(&ope_dev->soc_info, true);
ope_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
ope_probe.hfi_en = ope_soc_info.hfi_en;
cam_ope_process_cmd(ope_dev, OPE_HW_PROBE,
&ope_probe, sizeof(ope_probe));
mutex_init(&ope_dev->hw_mutex);
spin_lock_init(&ope_dev->hw_lock);
init_completion(&ope_dev->hw_complete);
CAM_DBG(CAM_OPE, "OPE%d probe successful",
ope_dev_intf->hw_idx);
return rc;
init_hw_failure:
enable_soc_failed:
register_cpas_failed:
init_soc_failed:
ope_match_dev_failed:
kfree(ope_dev->core_info);
ope_core_alloc_failed:
kfree(ope_dev);
ope_dev_alloc_failed:
kfree(ope_dev_intf);
return rc;
}
static const struct of_device_id cam_ope_dt_match[] = {
{
.compatible = "qcom,ope",
.data = &ope_hw_version_reg,
},
{}
};
MODULE_DEVICE_TABLE(of, cam_ope_dt_match);
static struct platform_driver cam_ope_driver = {
.probe = cam_ope_probe,
.driver = {
.name = "ope",
.of_match_table = cam_ope_dt_match,
.suppress_bind_attrs = true,
},
};
int cam_ope_init_module(void)
{
return platform_driver_register(&cam_ope_driver);
}
void cam_ope_exit_module(void)
{
platform_driver_unregister(&cam_ope_driver);
}
MODULE_DESCRIPTION("CAM OPE driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,174 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_OPE_DEV_INTF_H
#define CAM_OPE_DEV_INTF_H
#include <media/cam_ope.h>
#include "cam_ope_hw_mgr.h"
#include "cam_cdm_intf_api.h"
#include "cam_cpas_api.h"
#define OPE_HW_INIT 0x1
#define OPE_HW_DEINIT 0x2
#define OPE_HW_ACQUIRE 0x3
#define OPE_HW_RELEASE 0x4
#define OPE_HW_START 0x5
#define OPE_HW_STOP 0x6
#define OPE_HW_FLUSH 0x7
#define OPE_HW_PREPARE 0x8
#define OPE_HW_ISR 0x9
#define OPE_HW_PROBE 0xA
#define OPE_HW_CLK_UPDATE 0xB
#define OPE_HW_BW_UPDATE 0xC
#define OPE_HW_RESET 0xD
#define OPE_HW_SET_IRQ_CB 0xE
/**
* struct cam_ope_dev_probe
*
* @hfi_en: HFI enable flag
*/
struct cam_ope_dev_probe {
bool hfi_en;
};
/**
* struct cam_ope_dev_init
*
* @hfi_en: HFI enable flag
* @core_info: OPE core info
*/
struct cam_ope_dev_init {
bool hfi_en;
struct cam_ope_device_core_info *core_info;
};
/**
* struct cam_ope_dev_clk_update
*
* @clk_rate: Clock rate
*/
struct cam_ope_dev_clk_update {
uint32_t clk_rate;
};
/**
* struct cam_ope_dev_bw_update
*
* @ahb_vote: AHB vote info
* @axi_vote: AXI vote info
* @ahb_vote_valid: Flag for ahb vote
* @axi_vote_valid: Flag for axi vote
*/
struct cam_ope_dev_bw_update {
struct cam_ahb_vote ahb_vote;
struct cam_axi_vote axi_vote;
uint32_t ahb_vote_valid;
uint32_t axi_vote_valid;
};
/**
* struct cam_ope_dev_caps
*
* @hw_idx: Hardware index
* @hw_ver: Hardware version info
*/
struct cam_ope_dev_caps {
uint32_t hw_idx;
struct ope_hw_ver hw_ver;
};
/**
* struct cam_ope_dev_acquire
*
* @ctx_id: Context id
* @ope_acquire: OPE acquire info
* @bus_wr_ctx: Bus Write context
* @bus_rd_ctx: Bus Read context
*/
struct cam_ope_dev_acquire {
uint32_t ctx_id;
struct ope_acquire_dev_info *ope_acquire;
struct ope_bus_wr_ctx *bus_wr_ctx;
struct ope_bus_rd_ctx *bus_rd_ctx;
};
/**
* struct cam_ope_dev_release
*
* @ctx_id: Context id
* @bus_wr_ctx: Bus Write context
* @bus_rd_ctx: Bus Read context
*/
struct cam_ope_dev_release {
uint32_t ctx_id;
struct ope_bus_wr_ctx *bus_wr_ctx;
struct ope_bus_rd_ctx *bus_rd_ctx;
};
/**
* struct cam_ope_set_irq_cb
*
* @ope_hw_mgr_cb: Callback to hardware manager
* @data: Private data
*/
struct cam_ope_set_irq_cb {
int32_t (*ope_hw_mgr_cb)(uint32_t irq_status, void *data);
void *data;
};
/**
* struct cam_ope_irq_data
*
* @error: IRQ error
*/
struct cam_ope_irq_data {
uint32_t error;
};
/**
* struct cam_ope_dev_prepare_req
*
* @hw_mgr: OPE hardware manager
* @packet: Packet
* @prepare_args: Prepare request args
* @ctx_data: Context data
* @wr_cdm_batch: WM request
* @rd_cdm_batch: RD master request
* @frame_process: Frame process command
* @req_idx: Request Index
* @kmd_buf_offset: KMD buffer offset
*/
struct cam_ope_dev_prepare_req {
struct cam_ope_hw_mgr *hw_mgr;
struct cam_packet *packet;
struct cam_hw_prepare_update_args *prepare_args;
struct cam_ope_ctx *ctx_data;
struct ope_bus_wr_io_port_cdm_batch *wr_cdm_batch;
struct ope_bus_rd_io_port_cdm_batch *rd_cdm_batch;
struct ope_frame_process *frame_process;
uint32_t req_idx;
uint32_t kmd_buf_offset;
};
int cam_ope_top_process(struct ope_hw *ope_hw_info,
int32_t ctx_id, uint32_t cmd_id, void *data);
int cam_ope_bus_rd_process(struct ope_hw *ope_hw_info,
int32_t ctx_id, uint32_t cmd_id, void *data);
int cam_ope_bus_wr_process(struct ope_hw *ope_hw_info,
int32_t ctx_id, uint32_t cmd_id, void *data);
int cam_ope_init_module(void);
void cam_ope_exit_module(void);
int cam_ope_subdev_init_module(void);
void cam_ope_subdev_exit_module(void);
#endif /* CAM_OPE_DEV_INTF_H */

View File

@@ -0,0 +1,399 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_OPE_HW_H
#define CAM_OPE_HW_H
#define OPE_HW_VER_1_0_0 0x10000000
#define OPE_DEV_OPE 0
#define OPE_DEV_MAX 1
#define MAX_RD_CLIENTS 2
#define MAX_WR_CLIENTS 8
#define OPE_CDM_BASE 0x0
#define OPE_TOP_BASE 0x1
#define OPE_QOS_BASE 0x2
#define OPE_PP_BASE 0x3
#define OPE_BUS_RD 0x4
#define OPE_BUS_WR 0x5
#define OPE_BASE_MAX 0x6
#define BUS_RD_COMBO_BAYER_MASK 0x1
#define BUS_RD_COMBO_YUV_MASK 0x2
#define BUS_RD_COMBO_MAX 0x2
#define BUS_RD_BAYER 0x0
#define BUS_RD_YUV 0x1
#define BUS_WR_COMBO_YUV_MASK 0x1
#define BUS_WR_COMBO_MAX 0x1
#define BUS_WR_YUV 0x0
#define BUS_WR_VIDEO_Y 0x0
#define BUS_WR_VIDEO_C 0x1
#define BUS_WR_DISP_Y 0x2
#define BUS_WR_DISP_C 0x3
#define BUS_WR_ARGB 0x4
#define BUS_WR_STATS_RS 0x5
#define BUS_WR_STATS_IHIST 0x6
#define BUS_WR_STATS_LTM 0x7
#define OPE_WAIT_COMP_RUP 0x1
#define OPE_WAIT_COMP_WR_DONE 0x2
#define OPE_WAIT_COMP_IDLE 0x4
#define OPE_WAIT_COMP_GEN_IRQ 0x8
struct cam_ope_common {
uint32_t mode[CAM_FORMAT_MAX];
};
struct cam_ope_top_reg {
void *base;
uint32_t offset;
uint32_t hw_version;
uint32_t reset_cmd;
uint32_t core_clk_cfg_ctrl_0;
uint32_t ahb_clk_cgc_ctrl;
uint32_t core_cfg;
uint32_t irq_status;
uint32_t irq_mask;
uint32_t irq_clear;
uint32_t irq_set;
uint32_t irq_cmd;
uint32_t violation_status;
uint32_t throttle_cnt_cfg;
};
struct cam_ope_top_reg_val {
uint32_t hw_version;
uint32_t major_mask;
uint32_t major_shift;
uint32_t minor_mask;
uint32_t minor_shift;
uint32_t incr_mask;
uint32_t incr_shift;
uint32_t irq_mask;
uint32_t irq_set_clear;
uint32_t sw_reset_cmd;
uint32_t hw_reset_cmd;
uint32_t core_clk_cfg_ctrl_0;
uint32_t ahb_clk_cgc_ctrl;
uint32_t input_format;
uint32_t input_format_mask;
uint32_t color_correct_src_sel;
uint32_t color_correct_src_sel_mask;
uint32_t stats_ihist_src_sel;
uint32_t stats_ihist_src_sel_mask;
uint32_t chroma_up_src_sel;
uint32_t chroma_up_src_sel_mask;
uint32_t argb_alpha;
uint32_t argb_alpha_mask;
uint32_t rs_throttle_cnt;
uint32_t rs_throttle_cnt_mask;
uint32_t ihist_throttle_cnt;
uint32_t ihist_throttle_cnt_mask;
uint32_t rst_done;
uint32_t we_done;
uint32_t fe_done;
uint32_t ope_violation;
uint32_t idle;
};
struct cam_ope_qos_reg {
void *base;
uint32_t offset;
uint32_t hw_version;
uint32_t hw_status;
uint32_t module_cfg;
uint32_t curve_cfg_0;
uint32_t curve_cfg_1;
uint32_t window_cfg;
uint32_t eos_status_0;
uint32_t eos_status_1;
uint32_t eos_status_2;
};
struct cam_ope_qos_reg_val {
uint32_t hw_version;
uint32_t proc_interval;
uint32_t proc_interval_mask;
uint32_t static_health;
uint32_t static_health_mask;
uint32_t module_cfg_en;
uint32_t module_cfg_en_mask;
uint32_t yexp_ymin_dec;
uint32_t yexp_ymin_dec_mask;
uint32_t ymin_inc;
uint32_t ymin_inc_mask;
uint32_t initial_delta;
uint32_t initial_delta_mask;
uint32_t window_cfg;
};
struct cam_ope_bus_rd_client_reg {
uint32_t core_cfg;
uint32_t ccif_meta_data;
uint32_t img_addr;
uint32_t img_cfg;
uint32_t stride;
uint32_t unpack_cfg;
uint32_t latency_buf_allocation;
uint32_t misr_cfg_0;
uint32_t misr_cfg_1;
uint32_t misr_rd_val;
};
struct cam_ope_bus_rd_reg {
void *base;
uint32_t offset;
uint32_t hw_version;
uint32_t sw_reset;
uint32_t cgc_override;
uint32_t irq_mask;
uint32_t irq_clear;
uint32_t irq_cmd;
uint32_t irq_status;
uint32_t input_if_cmd;
uint32_t irq_set;
uint32_t misr_reset;
uint32_t security_cfg;
uint32_t iso_cfg;
uint32_t iso_seed;
uint32_t num_clients;
struct cam_ope_bus_rd_client_reg rd_clients[MAX_RD_CLIENTS];
};
struct cam_ope_bus_rd_client_reg_val {
uint32_t core_cfg;
uint32_t stripe_location;
uint32_t stripe_location_mask;
uint32_t stripe_location_shift;
uint32_t pix_pattern;
uint32_t pix_pattern_mask;
uint32_t pix_pattern_shift;
uint32_t img_addr;
uint32_t img_width;
uint32_t img_width_mask;
uint32_t img_width_shift;
uint32_t img_height;
uint32_t img_height_mask;
uint32_t img_height_shift;
uint32_t stride;
uint32_t mode;
uint32_t mode_mask;
uint32_t mode_shift;
uint32_t alignment;
uint32_t alignment_mask;
uint32_t alignment_shift;
uint32_t latency_buf_allocation;
uint32_t misr_cfg_samp_mode;
uint32_t misr_cfg_samp_mode_mask;
uint32_t misr_cfg_en;
uint32_t misr_cfg_en_mask;
uint32_t misr_cfg_1;
uint32_t misr_rd_val;
uint32_t input_port_id;
uint32_t rm_port_id;
uint32_t format_type;
uint32_t num_combos_supported;
};
struct cam_ope_bus_rd_reg_val {
uint32_t hw_version;
uint32_t sw_reset;
uint32_t cgc_override;
uint32_t irq_mask;
uint32_t go_cmd;
uint32_t go_cmd_mask;
uint32_t ica_en;
uint32_t ica_en_mask;
uint32_t static_prg;
uint32_t static_prg_mask;
uint32_t go_cmd_sel;
uint32_t go_cmd_sel_mask;
uint32_t fs_sync_en;
uint32_t fs_sync_en_mask;
uint32_t misr_reset;
uint32_t security_cfg;
uint32_t iso_bpp_select;
uint32_t iso_bpp_select_mask;
uint32_t iso_pattern_select;
uint32_t iso_pattern_select_mask;
uint32_t iso_en;
uint32_t iso_en_mask;
uint32_t iso_seed;
uint32_t irq_set_clear;
uint32_t rst_done;
uint32_t rup_done;
uint32_t rd_buf_done;
uint32_t violation;
uint32_t latency_buf_size;
uint32_t num_clients;
struct cam_ope_bus_rd_client_reg_val rd_clients[MAX_RD_CLIENTS];
};
struct cam_ope_bus_wr_client_reg {
uint32_t core_cfg;
uint32_t img_addr;
uint32_t img_cfg;
uint32_t x_init;
uint32_t stride;
uint32_t pack_cfg;
uint32_t bw_limit;
uint32_t frame_header_addr;
uint32_t subsample_period;
uint32_t subsample_pattern;
};
struct cam_ope_bus_wr_reg {
void *base;
uint32_t offset;
uint32_t hw_version;
uint32_t cgc_override;
uint32_t irq_mask_0;
uint32_t irq_mask_1;
uint32_t irq_clear_0;
uint32_t irq_clear_1;
uint32_t irq_status_0;
uint32_t irq_status_1;
uint32_t irq_cmd;
uint32_t frame_header_cfg_0;
uint32_t local_frame_header_cfg_0;
uint32_t irq_set_0;
uint32_t irq_set_1;
uint32_t iso_cfg;
uint32_t violation_status;
uint32_t image_size_violation_status;
uint32_t misr_cfg_0;
uint32_t misr_cfg_1;
uint32_t misr_rd_sel;
uint32_t misr_reset;
uint32_t misr_val;
uint32_t num_clients;
struct cam_ope_bus_wr_client_reg wr_clients[MAX_WR_CLIENTS];
};
struct cam_ope_bus_wr_client_reg_val {
uint32_t core_cfg_en;
uint32_t core_cfg_en_mask;
uint32_t core_cfg_en_shift;
uint32_t virtual_frame_en;
uint32_t virtual_frame_en_mask;
uint32_t virtual_frame_en_shift;
uint32_t frame_header_en;
uint32_t frame_header_en_mask;
uint32_t frame_header_en_shift;
uint32_t auto_recovery_en;
uint32_t auto_recovery_en_mask;
uint32_t auto_recovery_en_shift;
uint32_t mode;
uint32_t mode_mask;
uint32_t mode_shift;
uint32_t img_addr;
uint32_t width;
uint32_t width_mask;
uint32_t width_shift;
uint32_t height;
uint32_t height_mask;
uint32_t height_shift;
uint32_t x_init;
uint32_t stride;
uint32_t format;
uint32_t format_mask;
uint32_t format_shift;
uint32_t alignment;
uint32_t alignment_mask;
uint32_t alignment_shift;
uint32_t bw_limit_en;
uint32_t bw_limit_en_mask;
uint32_t bw_limit_counter;
uint32_t bw_limit_counter_mask;
uint32_t frame_header_addr;
uint32_t subsample_period;
uint32_t subsample_pattern;
uint32_t output_port_id;
uint32_t wm_port_id;
uint32_t format_type;
uint32_t num_combos_supported;
};
struct cam_ope_bus_wr_reg_val {
uint32_t hw_version;
uint32_t cgc_override;
uint32_t irq_mask_0;
uint32_t irq_mask_1;
uint32_t irq_set_clear;
uint32_t comp_rup_done;
uint32_t comp_buf_done;
uint32_t cons_violation;
uint32_t violation;
uint32_t img_size_violation;
uint32_t frame_header_cfg_0;
uint32_t local_frame_header_cfg_0;
uint32_t iso_cfg;
uint32_t misr_0_en;
uint32_t misr_0_en_mask;
uint32_t misr_1_en;
uint32_t misr_1_en_mask;
uint32_t misr_2_en;
uint32_t misr_2_en_mask;
uint32_t misr_3_en;
uint32_t misr_3_en_mask;
uint32_t misr_0_samp_mode;
uint32_t misr_0_samp_mode_mask;
uint32_t misr_1_samp_mode;
uint32_t misr_1_samp_mode_mask;
uint32_t misr_2_samp_mode;
uint32_t misr_2_samp_mode_mask;
uint32_t misr_3_samp_mode;
uint32_t misr_3_samp_mode_mask;
uint32_t misr_0_id;
uint32_t misr_0_id_mask;
uint32_t misr_1_id;
uint32_t misr_1_id_mask;
uint32_t misr_2_id;
uint32_t misr_2_id_mask;
uint32_t misr_3_id;
uint32_t misr_3_id_mask;
uint32_t misr_rd_misr_sel;
uint32_t misr_rd_misr_sel_mask;
uint32_t misr_rd_word_sel;
uint32_t misr_rd_word_sel_mask;
uint32_t misr_reset;
uint32_t misr_val;
uint32_t num_clients;
struct cam_ope_bus_wr_client_reg_val wr_clients[MAX_WR_CLIENTS];
};
struct ope_hw {
struct cam_ope_top_reg *top_reg;
struct cam_ope_top_reg_val *top_reg_val;
struct cam_ope_bus_rd_reg *bus_rd_reg;
struct cam_ope_bus_rd_reg_val *bus_rd_reg_val;
struct cam_ope_bus_wr_reg *bus_wr_reg;
struct cam_ope_bus_wr_reg_val *bus_wr_reg_val;
struct cam_ope_qos_reg *qos_reg;
struct cam_ope_qos_reg_val *qos_reg_val;
struct cam_ope_common *common;
};
struct hw_version_reg {
uint32_t hw_ver;
uint32_t reserved;
};
#endif /* CAM_OPE_HW_H */

View File

@@ -0,0 +1,532 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_OPE_HW_100_H
#define CAM_OPE_HW_100_H
#define OPE_BUS_RD_TYPE_BAYER 0x0
#define OPE_BUS_RD_TYPE_YUV_Y 0x0
#define OPE_BUS_RD_TYPE_YUC_C 0x1
#define OPE_BUS_WR_TYPE_VID_Y 0x0
#define OPE_BUS_WR_TYPE_VID_C 0x1
#define OPE_BUS_WR_TYPE_DISP_Y 0x2
#define OPE_BUS_WR_TYPE_DISP_C 0x3
#define OPE_BUS_WR_TYPE_ARGB 0x4
#define OPE_BUS_WR_TYPE_RS 0x5
#define OPE_BUS_WR_TYPE_IHIST 0x6
#define OPE_BUS_WR_TYPE_LTM 0x7
enum cam_ope_bus_rd_unpacker_format {
BUS_RD_VER1_PACKER_FMT_PLAIN_128_BYPASS = 0x0,
BUS_RD_VER1_PACKER_FMT_PLAIN_8 = 0x1,
BUS_RD_VER1_PACKER_FMT_PLAIN_16_10BPP = 0x2,
BUS_RD_VER1_PACKER_FMT_PLAIN_16_12BPP = 0x3,
BUS_RD_VER1_PACKER_FMT_PLAIN_16_14BPP = 0x4,
BUS_RD_VER1_PACKER_FMT_PLAIN_32_20BPP = 0x5,
BUS_RD_VER1_PACKER_FMT_ARGB16_10 = 0x6,
BUS_RD_VER1_PACKER_FMT_ARGB16_12 = 0x7,
BUS_RD_VER1_PACKER_FMT_ARGB16_14 = 0x8,
BUS_RD_VER1_PACKER_FMT_PLAIN_32 = 0x9,
BUS_RD_VER1_PACKER_FMT_PLAIN_64 = 0xA,
BUS_RD_VER1_PACKER_FMT_TP_10 = 0xB,
BUS_RD_VER1_PACKER_FMT_MIPI_8 = 0xC,
BUS_RD_VER1_PACKER_FMT_MIPI_10 = 0xD,
BUS_RD_VER1_PACKER_FMT_MIPI_12 = 0xE,
BUS_RD_VER1_PACKER_FMT_MIPI_14 = 0xF,
BUS_RD_VER1_PACKER_FMT_PLAIN_16_16BPP = 0x10,
BUS_RD_VER1_PACKER_FMT_BYPASS_SWAP = 0x11,
BUS_RD_VER1_PACKER_FMT_PLAIN_8_SWAP = 0x12,
BUS_RD_VER1_PACKER_FMT_MAX = 0x13,
};
static struct cam_ope_top_reg ope_top_reg = {
.offset = 0x400,
.hw_version = 0x0,
.reset_cmd = 0x4,
.core_clk_cfg_ctrl_0 = 0x8,
.ahb_clk_cgc_ctrl = 0xC,
.core_cfg = 0x10,
.irq_status = 0x14,
.irq_mask = 0x18,
.irq_clear = 0x1C,
.irq_set = 0x20,
.irq_cmd = 0x24,
.violation_status = 0x28,
.throttle_cnt_cfg = 0x2C,
};
static struct cam_ope_top_reg_val ope_top_reg_val = {
.hw_version = 0x10000000,
.major_mask = 0xFFFF,
.major_shift = 0x0,
.minor_mask = 0x0FFF0000,
.minor_shift = 0xF,
.incr_mask = 0xF0000000,
.incr_shift = 0x1B,
.irq_mask = 0x0000000F,
.sw_reset_cmd = 0x2,
.hw_reset_cmd = 0x1,
.irq_set_clear = 0x1,
.rst_done = 0x1,
.we_done = 0x2,
.fe_done = 0x4,
.ope_violation = 0x8,
.idle = 0x10,
};
static struct cam_ope_bus_rd_reg_val ope_bus_rd_reg_val = {
.hw_version = 0x00050000,
.sw_reset = 0x1,
.cgc_override = 0x0,
.irq_mask = 0x30001,
.irq_set_clear = 0x1,
.rst_done = 0x1,
.rup_done = 0x2,
.rd_buf_done = 0xC,
.violation = 0x3000,
.go_cmd = 0x1,
.security_cfg = 0x0,
.latency_buf_size = 4096,
.num_clients = 0x2,
.rd_clients = {
{
.core_cfg = 0x1,
.stripe_location_mask = 0x3,
.stripe_location_shift = 0x0,
.pix_pattern_mask = 0x3F,
.pix_pattern_shift = 0x2,
.img_width_mask = 0xFFFF,
.img_width_shift = 0x10,
.img_height_mask = 0xFFFF,
.img_height_shift = 0x0,
.mode_mask = 0x1F,
.mode_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x5,
.latency_buf_allocation = 4096,
.input_port_id = OPE_IN_RES_FULL,
.rm_port_id = 0,
.format_type = BUS_RD_COMBO_BAYER_MASK |
BUS_RD_COMBO_YUV_MASK,
.num_combos_supported = 2,
},
{
.core_cfg = 0x1,
.stripe_location_mask = 0x3,
.stripe_location_shift = 0x0,
.pix_pattern_mask = 0x3F,
.pix_pattern_shift = 0x2,
.img_width_mask = 0xFFFF,
.img_width_shift = 0x10,
.img_height_mask = 0xFFFF,
.img_height_shift = 0x0,
.mode_mask = 0x1F,
.mode_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x5,
.latency_buf_allocation = 4096,
.input_port_id = OPE_IN_RES_FULL,
.rm_port_id = 1,
.format_type = BUS_RD_COMBO_YUV_MASK,
.num_combos_supported = 1,
},
},
};
static struct cam_ope_bus_rd_reg ope_bus_rd_reg = {
.offset = 0x4C00,
.hw_version = 0x0,
.sw_reset = 0x4,
.cgc_override = 0x8,
.irq_mask = 0xC,
.irq_clear = 0x10,
.irq_cmd = 0x14,
.irq_status = 0x18,
.input_if_cmd = 0x1C,
.irq_set = 0x20,
.misr_reset = 0x24,
.security_cfg = 0x28,
.iso_cfg = 0x2C,
.iso_seed = 0x30,
.num_clients = 0x2,
.rd_clients = {
{
.core_cfg = 0x50,
.ccif_meta_data = 0x54,
.img_addr = 0x58,
.img_cfg = 0x5C,
.stride = 0x60,
.unpack_cfg = 0x64,
.latency_buf_allocation = 0x78,
.misr_cfg_0 = 0x80,
.misr_cfg_1 = 0x84,
.misr_rd_val = 0x88,
},
{
.core_cfg = 0xF0,
.ccif_meta_data = 0xF4,
.img_addr = 0xF8,
.img_cfg = 0xFC,
.stride = 0x100,
.unpack_cfg = 0x104,
.latency_buf_allocation = 0x118,
.misr_cfg_0 = 0x120,
.misr_cfg_1 = 0x124,
.misr_rd_val = 0x128,
},
},
};
static struct cam_ope_bus_wr_reg ope_bus_wr_reg = {
.offset = 0x4D90,
.hw_version = 0x0,
.cgc_override = 0x8,
.irq_mask_0 = 0x18,
.irq_mask_1 = 0x1C,
.irq_clear_0 = 0x20,
.irq_clear_1 = 0x24,
.irq_status_0 = 0x28,
.irq_status_1 = 0x2C,
.irq_cmd = 0x30,
.frame_header_cfg_0 = 0x34,
.local_frame_header_cfg_0 = 0x4C,
.irq_set_0 = 0x50,
.irq_set_1 = 0x54,
.iso_cfg = 0x5C,
.violation_status = 0x64,
.image_size_violation_status = 0x70,
.misr_cfg_0 = 0xB8,
.misr_cfg_1 = 0xBC,
.misr_rd_sel = 0xC8,
.misr_reset = 0xCC,
.misr_val = 0xD0,
.num_clients = 0x8,
.wr_clients = {
{
.core_cfg = 0x200,
.img_addr = 0x204,
.img_cfg = 0x20C,
.x_init = 0x210,
.stride = 0x214,
.pack_cfg = 0x218,
.bw_limit = 0x21C,
.frame_header_addr = 0x220,
.subsample_period = 0x230,
.subsample_pattern = 0x234,
},
{
.core_cfg = 0x300,
.img_addr = 0x304,
.img_cfg = 0x30C,
.x_init = 0x310,
.stride = 0x314,
.pack_cfg = 0x318,
.bw_limit = 0x31C,
.frame_header_addr = 0x320,
.subsample_period = 0x330,
.subsample_pattern = 0x334,
},
{
.core_cfg = 0x400,
.img_addr = 0x404,
.img_cfg = 0x40C,
.x_init = 0x410,
.stride = 0x414,
.pack_cfg = 0x418,
.bw_limit = 0x41C,
.frame_header_addr = 0x420,
.subsample_period = 0x430,
.subsample_pattern = 0x434,
},
{
.core_cfg = 0x500,
.img_addr = 0x504,
.img_cfg = 0x50C,
.x_init = 0x510,
.stride = 0x514,
.pack_cfg = 0x518,
.bw_limit = 0x51C,
.frame_header_addr = 0x520,
.subsample_period = 0x530,
.subsample_pattern = 0x534,
},
{
.core_cfg = 0x600,
.img_addr = 0x604,
.img_cfg = 0x60C,
.x_init = 0x610,
.stride = 0x614,
.pack_cfg = 0x618,
.bw_limit = 0x61C,
.frame_header_addr = 0x620,
.subsample_period = 0x630,
.subsample_pattern = 0x634,
},
{
.core_cfg = 0x700,
.img_addr = 0x704,
.img_cfg = 0x70C,
.x_init = 0x710,
.stride = 0x714,
.pack_cfg = 0x718,
.bw_limit = 0x71C,
.frame_header_addr = 0x720,
.subsample_period = 0x730,
.subsample_pattern = 0x734,
},
{
.core_cfg = 0x800,
.img_addr = 0x804,
.img_cfg = 0x80C,
.x_init = 0x810,
.stride = 0x814,
.pack_cfg = 0x818,
.bw_limit = 0x81C,
.frame_header_addr = 0x820,
.subsample_period = 0x830,
.subsample_pattern = 0x834,
},
{
.core_cfg = 0x900,
.img_addr = 0x904,
.img_cfg = 0x90C,
.x_init = 0x910,
.stride = 0x914,
.pack_cfg = 0x918,
.bw_limit = 0x91C,
.frame_header_addr = 0x920,
.subsample_period = 0x930,
.subsample_pattern = 0x934,
},
},
};
static struct cam_ope_bus_wr_reg_val ope_bus_wr_reg_val = {
.hw_version = 0x20010000,
.irq_mask_0 = 0xD0000000,
.irq_mask_1 = 0x0,
.irq_set_clear = 0x1,
.comp_rup_done = 0x1,
.comp_buf_done = 0x100,
.cons_violation = 0x10000000,
.violation = 0x40000000,
.img_size_violation = 0x80000000,
.num_clients = 0x8,
.wr_clients = {
{
.core_cfg_en = 0x1,
.core_cfg_en_mask = 0x1,
.core_cfg_en_shift = 0x0,
.virtual_frame_en_mask = 0x1,
.virtual_frame_en_shift = 0x1,
.frame_header_en_mask = 0x1,
.frame_header_en_shift = 0x2,
.auto_recovery_en_mask = 0x1,
.auto_recovery_en_shift = 0x4,
.mode_mask = 0x3,
.mode_shift = 0x10,
.width_mask = 0xFFFF,
.width_shift = 0x0,
.height_mask = 0xFFFF,
.height_shift = 0x10,
.format_mask = 0xF,
.format_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x4,
.output_port_id = OPE_OUT_RES_VIDEO,
.wm_port_id = BUS_WR_VIDEO_Y,
.format_type = BUS_WR_COMBO_YUV_MASK,
.num_combos_supported = 1,
},
{
.core_cfg_en = 0x1,
.core_cfg_en_mask = 0x1,
.core_cfg_en_shift = 0x0,
.virtual_frame_en_mask = 0x1,
.virtual_frame_en_shift = 0x1,
.frame_header_en_mask = 0x1,
.frame_header_en_shift = 0x2,
.auto_recovery_en_mask = 0x1,
.auto_recovery_en_shift = 0x4,
.mode_mask = 0x3,
.mode_shift = 0x10,
.width_mask = 0xFFFF,
.width_shift = 0x0,
.height_mask = 0xFFFF,
.height_shift = 0x10,
.format_mask = 0xF,
.format_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x4,
.output_port_id = OPE_OUT_RES_VIDEO,
.wm_port_id = BUS_WR_VIDEO_C,
.format_type = BUS_WR_COMBO_YUV_MASK,
.num_combos_supported = 1,
},
{
.core_cfg_en = 0x1,
.core_cfg_en_mask = 0x1,
.core_cfg_en_shift = 0x0,
.virtual_frame_en_mask = 0x1,
.virtual_frame_en_shift = 0x1,
.frame_header_en_mask = 0x1,
.frame_header_en_shift = 0x2,
.auto_recovery_en_mask = 0x1,
.auto_recovery_en_shift = 0x4,
.mode_mask = 0x3,
.mode_shift = 0x10,
.width_mask = 0xFFFF,
.width_shift = 0x0,
.height_mask = 0xFFFF,
.height_shift = 0x10,
.format_mask = 0xF,
.format_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x4,
.output_port_id = OPE_OUT_RES_DISP,
.wm_port_id = BUS_WR_DISP_Y,
.format_type = BUS_WR_COMBO_YUV_MASK,
.num_combos_supported = 1,
},
{
.core_cfg_en = 0x1,
.core_cfg_en_mask = 0x1,
.core_cfg_en_shift = 0x0,
.virtual_frame_en_mask = 0x1,
.virtual_frame_en_shift = 0x1,
.frame_header_en_mask = 0x1,
.frame_header_en_shift = 0x2,
.auto_recovery_en_mask = 0x1,
.auto_recovery_en_shift = 0x4,
.mode_mask = 0x3,
.mode_shift = 0x10,
.width_mask = 0xFFFF,
.width_shift = 0x0,
.height_mask = 0xFFFF,
.height_shift = 0x10,
.format_mask = 0xF,
.format_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x4,
.output_port_id = OPE_OUT_RES_DISP,
.wm_port_id = BUS_WR_DISP_C,
.format_type = BUS_WR_COMBO_YUV_MASK,
.num_combos_supported = 1,
},
{
.core_cfg_en = 0x1,
.core_cfg_en_mask = 0x1,
.core_cfg_en_shift = 0x0,
.virtual_frame_en_mask = 0x1,
.virtual_frame_en_shift = 0x1,
.frame_header_en_mask = 0x1,
.frame_header_en_shift = 0x2,
.auto_recovery_en_mask = 0x1,
.auto_recovery_en_shift = 0x4,
.mode_mask = 0x3,
.mode_shift = 0x10,
.width_mask = 0xFFFF,
.width_shift = 0x0,
.height_mask = 0xFFFF,
.height_shift = 0x10,
.format_mask = 0xF,
.format_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x4,
.output_port_id = OPE_OUT_RES_ARGB,
.wm_port_id = BUS_WR_ARGB,
.format_type = BUS_WR_COMBO_YUV_MASK,
.num_combos_supported = 1,
},
{
.core_cfg_en = 0x1,
.core_cfg_en_mask = 0x1,
.core_cfg_en_shift = 0x0,
.virtual_frame_en_mask = 0x1,
.virtual_frame_en_shift = 0x1,
.frame_header_en_mask = 0x1,
.frame_header_en_shift = 0x2,
.auto_recovery_en_mask = 0x1,
.auto_recovery_en_shift = 0x4,
.mode_mask = 0x3,
.mode_shift = 0x10,
.width_mask = 0xFFFF,
.width_shift = 0x0,
.height_mask = 0xFFFF,
.height_shift = 0x10,
.format_mask = 0xF,
.format_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x4,
.output_port_id = OPE_OUT_RES_STATS_RS,
.wm_port_id = BUS_WR_STATS_RS,
.format_type = BUS_WR_COMBO_YUV_MASK,
.num_combos_supported = 1,
},
{
.core_cfg_en = 0x1,
.core_cfg_en_mask = 0x1,
.core_cfg_en_shift = 0x0,
.virtual_frame_en_mask = 0x1,
.virtual_frame_en_shift = 0x1,
.frame_header_en_mask = 0x1,
.frame_header_en_shift = 0x2,
.auto_recovery_en_mask = 0x1,
.auto_recovery_en_shift = 0x4,
.mode_mask = 0x3,
.mode_shift = 0x10,
.width_mask = 0xFFFF,
.width_shift = 0x0,
.height_mask = 0xFFFF,
.height_shift = 0x10,
.format_mask = 0xF,
.format_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x4,
.output_port_id = OPE_OUT_RES_STATS_IHIST,
.wm_port_id = BUS_WR_STATS_IHIST,
.format_type = BUS_WR_COMBO_YUV_MASK,
.num_combos_supported = 1,
},
{
.core_cfg_en = 0x1,
.core_cfg_en_mask = 0x1,
.core_cfg_en_shift = 0x0,
.virtual_frame_en_mask = 0x1,
.virtual_frame_en_shift = 0x1,
.frame_header_en_mask = 0x1,
.frame_header_en_shift = 0x2,
.auto_recovery_en_mask = 0x1,
.auto_recovery_en_shift = 0x4,
.mode_mask = 0x3,
.mode_shift = 0x10,
.width_mask = 0xFFFF,
.width_shift = 0x0,
.height_mask = 0xFFFF,
.height_shift = 0x10,
.format_mask = 0xF,
.format_shift = 0x0,
.alignment_mask = 0x1,
.alignment_shift = 0x4,
.output_port_id = OPE_OUT_RES_STATS_LTM,
.wm_port_id = BUS_WR_STATS_LTM,
.format_type = BUS_WR_COMBO_YUV_MASK,
.num_combos_supported = 1,
},
},
};
static struct ope_hw ope_hw_100 = {
.top_reg = &ope_top_reg,
.top_reg_val = &ope_top_reg_val,
.bus_rd_reg = &ope_bus_rd_reg,
.bus_rd_reg_val = &ope_bus_rd_reg_val,
.bus_wr_reg = &ope_bus_wr_reg,
.bus_wr_reg_val = &ope_bus_wr_reg_val,
};
#endif /* CAM_OPE_HW_100_H */

View File

@@ -0,0 +1,136 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/dma-buf.h>
#include <media/cam_defs.h>
#include <media/cam_icp.h>
#include "ope_soc.h"
#include "cam_soc_util.h"
#include "cam_debug_util.h"
static int cam_ope_get_dt_properties(struct cam_hw_soc_info *soc_info)
{
int rc = 0;
struct platform_device *pdev = NULL;
struct device_node *of_node = NULL;
struct ope_dev_soc *ope_soc_info;
if (!soc_info) {
CAM_ERR(CAM_OPE, "soc_info is NULL");
return -EINVAL;
}
pdev = soc_info->pdev;
of_node = pdev->dev.of_node;
ope_soc_info = soc_info->soc_private;
rc = cam_soc_util_get_dt_properties(soc_info);
if (rc < 0)
CAM_ERR(CAM_OPE, "get ope dt prop is failed: %d", rc);
ope_soc_info->hfi_en = of_property_read_bool(of_node, "hfi_en");
return rc;
}
static int cam_ope_request_platform_resource(
struct cam_hw_soc_info *soc_info,
irq_handler_t ope_irq_handler, void *irq_data)
{
int rc = 0;
rc = cam_soc_util_request_platform_resource(soc_info, ope_irq_handler,
irq_data);
return rc;
}
int cam_ope_init_soc_resources(struct cam_hw_soc_info *soc_info,
irq_handler_t ope_irq_handler, void *irq_data)
{
int rc = 0;
rc = cam_ope_get_dt_properties(soc_info);
if (rc < 0)
return rc;
rc = cam_ope_request_platform_resource(soc_info, ope_irq_handler,
irq_data);
if (rc < 0)
return rc;
return rc;
}
int cam_ope_enable_soc_resources(struct cam_hw_soc_info *soc_info)
{
int rc = 0;
rc = cam_soc_util_enable_platform_resource(soc_info, true,
CAM_SVS_VOTE, true);
if (rc) {
CAM_ERR(CAM_OPE, "enable platform failed");
return rc;
}
return rc;
}
int cam_ope_disable_soc_resources(struct cam_hw_soc_info *soc_info,
bool disable_clk)
{
int rc = 0;
rc = cam_soc_util_disable_platform_resource(soc_info, disable_clk,
true);
if (rc)
CAM_ERR(CAM_OPE, "enable platform failed");
return rc;
}
int cam_ope_update_clk_rate(struct cam_hw_soc_info *soc_info,
uint32_t clk_rate)
{
int32_t src_clk_idx;
if (!soc_info) {
CAM_ERR(CAM_OPE, "Invalid soc info");
return -EINVAL;
}
src_clk_idx = soc_info->src_clk_idx;
CAM_DBG(CAM_OPE, "clk_rate = %u src_clk_index = %d",
clk_rate, src_clk_idx);
if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) &&
(soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) &&
(clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) {
CAM_DBG(CAM_OPE, "clk_rate %d greater than max, reset to %d",
clk_rate,
soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]);
clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx];
}
CAM_DBG(CAM_OPE, "clk_rate = %u src_clk_index = %d",
clk_rate, src_clk_idx);
return cam_soc_util_set_src_clk_rate(soc_info, clk_rate);
}
int cam_ope_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable)
{
int rc = 0;
if (clk_enable)
rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE);
else
cam_soc_util_clk_disable_default(soc_info);
return rc;
}

View File

@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_OPE_SOC_H
#define CAM_OPE_SOC_H
#include "cam_soc_util.h"
/**
* struct ope_dev_soc
*
* @hfi_en: HFI enable flag
*/
struct ope_dev_soc {
uint32_t hfi_en;
};
int cam_ope_init_soc_resources(struct cam_hw_soc_info *soc_info,
irq_handler_t ope_irq_handler, void *irq_data);
int cam_ope_enable_soc_resources(struct cam_hw_soc_info *soc_info);
int cam_ope_disable_soc_resources(struct cam_hw_soc_info *soc_info,
bool disable_clk);
int cam_ope_update_clk_rate(struct cam_hw_soc_info *soc_info,
uint32_t clk_rate);
int cam_ope_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable);
#endif /* CAM_OPE_SOC_H */

View File

@@ -0,0 +1,246 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/of.h>
#include <linux/debugfs.h>
#include <linux/videodev2.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/iopoll.h>
#include <linux/completion.h>
#include <media/cam_ope.h>
#include "cam_io_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
#include "ope_core.h"
#include "ope_soc.h"
#include "cam_soc_util.h"
#include "cam_io_util.h"
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
#include "ope_hw.h"
#include "ope_dev_intf.h"
#include "ope_top.h"
static struct ope_top ope_top_info;
static int cam_ope_top_reset(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
struct cam_ope_top_reg *top_reg;
struct cam_ope_top_reg_val *top_reg_val;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
top_reg = ope_hw_info->top_reg;
top_reg_val = ope_hw_info->top_reg_val;
init_completion(&ope_top_info.reset_complete);
/* enable interrupt mask */
cam_io_w_mb(top_reg_val->irq_mask,
ope_hw_info->top_reg->base + top_reg->irq_mask);
/* OPE SW RESET */
cam_io_w_mb(top_reg_val->sw_reset_cmd,
ope_hw_info->top_reg->base + top_reg->reset_cmd);
rc = wait_for_completion_timeout(
&ope_top_info.reset_complete,
msecs_to_jiffies(30));
if (!rc || rc < 0) {
CAM_ERR(CAM_OPE, "reset error result = %d", rc);
if (!rc)
rc = -ETIMEDOUT;
} else {
rc = 0;
}
return rc;
}
static int cam_ope_top_release(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
if (ctx_id < 0) {
CAM_ERR(CAM_OPE, "Invalid data: %d", ctx_id);
return -EINVAL;
}
ope_top_info.top_ctx[ctx_id].ope_acquire = NULL;
return rc;
}
static int cam_ope_top_acquire(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
if (ctx_id < 0 || !data) {
CAM_ERR(CAM_OPE, "Invalid data: %d %x", ctx_id, data);
return -EINVAL;
}
ope_top_info.top_ctx[ctx_id].ope_acquire = data;
return rc;
}
static int cam_ope_top_init(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
struct cam_ope_top_reg *top_reg;
struct cam_ope_top_reg_val *top_reg_val;
struct cam_ope_dev_init *dev_init = data;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
top_reg = ope_hw_info->top_reg;
top_reg_val = ope_hw_info->top_reg_val;
top_reg->base = dev_init->core_info->ope_hw_info->ope_top_base;
/* OPE SW RESET */
init_completion(&ope_top_info.reset_complete);
/* enable interrupt mask */
cam_io_w_mb(top_reg_val->irq_mask,
ope_hw_info->top_reg->base + top_reg->irq_mask);
cam_io_w_mb(top_reg_val->sw_reset_cmd,
ope_hw_info->top_reg->base + top_reg->reset_cmd);
rc = wait_for_completion_timeout(
&ope_top_info.reset_complete,
msecs_to_jiffies(30));
if (!rc || rc < 0) {
CAM_ERR(CAM_OPE, "reset error result = %d", rc);
if (!rc)
rc = -ETIMEDOUT;
} else {
rc = 0;
}
return rc;
}
static int cam_ope_top_probe(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
ope_top_info.ope_hw_info = ope_hw_info;
return rc;
}
static int cam_ope_top_isr(struct ope_hw *ope_hw_info,
int32_t ctx_id, void *data)
{
int rc = 0;
uint32_t irq_status;
uint32_t violation_status;
struct cam_ope_top_reg *top_reg;
struct cam_ope_top_reg_val *top_reg_val;
struct cam_ope_irq_data *irq_data = data;
if (!ope_hw_info) {
CAM_ERR(CAM_OPE, "Invalid ope_hw_info");
return -EINVAL;
}
top_reg = ope_hw_info->top_reg;
top_reg_val = ope_hw_info->top_reg_val;
/* Read and Clear Top Interrupt status */
irq_status = cam_io_r_mb(top_reg->base + top_reg->irq_status);
cam_io_w_mb(irq_status,
top_reg->base + top_reg->irq_clear);
cam_io_w_mb(top_reg_val->irq_set_clear,
top_reg->base + top_reg->irq_cmd);
if (irq_status & top_reg_val->rst_done) {
CAM_DBG(CAM_OPE, "ope reset done");
complete(&ope_top_info.reset_complete);
}
if (irq_status & top_reg_val->ope_violation) {
violation_status = cam_io_r_mb(top_reg->base +
top_reg->violation_status);
irq_data->error = 1;
CAM_ERR(CAM_OPE, "ope violation: %x", violation_status);
}
return rc;
}
int cam_ope_top_process(struct ope_hw *ope_hw_info,
int32_t ctx_id, uint32_t cmd_id, void *data)
{
int rc = 0;
switch (cmd_id) {
case OPE_HW_PROBE:
CAM_DBG(CAM_OPE, "OPE_HW_PROBE: E");
rc = cam_ope_top_probe(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_PROBE: X");
break;
case OPE_HW_INIT:
CAM_DBG(CAM_OPE, "OPE_HW_INIT: E");
rc = cam_ope_top_init(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_INIT: X");
break;
case OPE_HW_DEINIT:
break;
case OPE_HW_ACQUIRE:
CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: E");
rc = cam_ope_top_acquire(ope_hw_info, ctx_id, data);
CAM_DBG(CAM_OPE, "OPE_HW_ACQUIRE: X");
break;
case OPE_HW_PREPARE:
break;
case OPE_HW_RELEASE:
rc = cam_ope_top_release(ope_hw_info, ctx_id, data);
break;
case OPE_HW_START:
break;
case OPE_HW_STOP:
break;
case OPE_HW_FLUSH:
break;
case OPE_HW_ISR:
rc = cam_ope_top_isr(ope_hw_info, 0, data);
break;
case OPE_HW_RESET:
rc = cam_ope_top_reset(ope_hw_info, 0, 0);
break;
default:
break;
}
return rc;
}

View File

@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef OPE_TOP_H
#define OPE_TOP_H
#include <linux/types.h>
#include <linux/completion.h>
#include <media/cam_ope.h>
#include "ope_hw.h"
#include "cam_hw_mgr_intf.h"
#include "cam_hw_intf.h"
#include "cam_soc_util.h"
#include "cam_context.h"
#include "cam_ope_context.h"
#include "cam_ope_hw_mgr.h"
/**
* struct ope_top_ctx
*
* @ope_acquire: OPE acquire info
*/
struct ope_top_ctx {
struct ope_acquire_dev_info *ope_acquire;
};
/**
* struct ope_top
*
* @ope_hw_info: OPE hardware info
* @top_ctx: OPE top context
* @reset_complete: Reset complete flag
*/
struct ope_top {
struct ope_hw *ope_hw_info;
struct ope_top_ctx top_ctx[OPE_CTX_MAX];
struct completion reset_complete;
};
#endif /* OPE_TOP_H */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundataion. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundataion. All rights reserved.
*/
#include <linux/io.h>
@@ -93,6 +93,11 @@ const char *cam_get_module_name(unsigned int module_id)
break;
case CAM_CUSTOM:
name = "CAM-CUSTOM";
case CAM_OPE:
name = "CAM-OPE";
break;
case CAM_PRESIL:
name = "CAM-PRESIL";
break;
default:
name = "CAM";

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_DEBUG_UTIL_H_
@@ -39,6 +39,8 @@
/* CAM_PERF: Used for performance (clock, BW etc) logs */
#define CAM_PERF (1 << 25)
#define CAM_CUSTOM (1 << 26)
#define CAM_OPE (1 << 28)
#define CAM_PRESIL (1 << 27)
#define STR_BUFFER_MAX_LENGTH 1024

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
#include <linux/build_bug.h>
@@ -48,6 +48,8 @@
#include "cam_debug_util.h"
#include "ope_dev_intf.h"
struct camera_submodule_component {
int (*init)(void);
void (*exit)(void);
@@ -101,6 +103,13 @@ static const struct camera_submodule_component camera_icp[] = {
#endif
};
static const struct camera_submodule_component camera_ope[] = {
#ifdef CONFIG_SPECTRA_OPE
{&cam_ope_init_module, &cam_ope_exit_module},
{&cam_ope_subdev_init_module, &cam_ope_subdev_exit_module},
#endif
};
static const struct camera_submodule_component camera_jpeg[] = {
#ifdef CONFIG_SPECTRA_JPEG
{&cam_jpeg_enc_init_module, &cam_jpeg_enc_exit_module},
@@ -152,6 +161,11 @@ static const struct camera_submodule submodule_table[] = {
.num_component = ARRAY_SIZE(camera_icp),
.component = camera_icp,
},
{
.name = "Camera OPE",
.num_component = ARRAY_SIZE(camera_ope),
.component = camera_ope,
},
{
.name = "Camera JPEG",
.num_component = ARRAY_SIZE(camera_jpeg),