msm: camera: icp: Rename A5 and LX7

Rename all instances of a5 and lx7 to icp_v1 and icp_v2
respectively. Remove all mentions of lx7 or a5 in icp_hw_mgr.
Relocate lx7_hw and a5_hw directories to a new directory -
icp_proc which contains a new file to provide related a5 or lx7
interfaces to icp_hw_mgr. Thus, icp_hw_mgr is agnostic to icp proc.
Place common functions and common global constant into icp_proc_common
file. Remove a5/lx7 soc files and create a common soc file for both.
Modify kbuild file to account for directory or file changes.

CRs-Fixed: 3162183
Change-Id: I7e0cfd2a2917f129097a517af3bd39578f85293d
Signed-off-by: sokchetra eung <quic_eung@quicinc.com>
This commit is contained in:
sokchetra eung
2022-04-13 21:14:57 -07:00
committed by Camera Software Integration
parent b2d3d9c6ac
commit 9c730e3b84
36 changed files with 1676 additions and 1780 deletions

16
Kbuild
View File

@@ -162,19 +162,19 @@ camera-$(CONFIG_SPECTRA_ICP) += \
drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.o \
drivers/cam_icp/icp_hw/ipe_hw/ipe_core.o \
drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.o \
drivers/cam_icp/icp_hw/a5_hw/a5_dev.o \
drivers/cam_icp/icp_hw/a5_hw/a5_core.o \
drivers/cam_icp/icp_hw/a5_hw/a5_soc.o \
drivers/cam_icp/icp_hw/lx7_hw/lx7_dev.o \
drivers/cam_icp/icp_hw/lx7_hw/lx7_core.o \
drivers/cam_icp/icp_hw/lx7_hw/lx7_soc.o \
drivers/cam_icp/icp_hw/icp_proc/icp_v1_hw/cam_icp_v1_dev.o \
drivers/cam_icp/icp_hw/icp_proc/icp_v1_hw/cam_icp_v1_core.o \
drivers/cam_icp/icp_hw/icp_proc/icp_v2_hw/cam_icp_v2_dev.o \
drivers/cam_icp/icp_hw/icp_proc/icp_v2_hw/cam_icp_v2_core.o \
drivers/cam_icp/icp_hw/icp_proc/icp_common/cam_icp_proc_common.o \
drivers/cam_icp/icp_hw/icp_proc/icp_common/cam_icp_soc_common.o \
drivers/cam_icp/icp_hw/icp_proc/cam_icp_proc.o \
drivers/cam_icp/icp_hw/bps_hw/bps_dev.o \
drivers/cam_icp/icp_hw/bps_hw/bps_core.o \
drivers/cam_icp/icp_hw/bps_hw/bps_soc.o \
drivers/cam_icp/cam_icp_subdev.o \
drivers/cam_icp/cam_icp_context.o \
drivers/cam_icp/hfi.o \
drivers/cam_icp/utils/cam_icp_utils.o
drivers/cam_icp/hfi.o
camera-$(CONFIG_SPECTRA_JPEG) += \
drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.o \

View File

@@ -1052,7 +1052,7 @@ static int cam_hfi_presil_setup(struct hfi_mem_info *hfi_mem)
static int cam_hfi_presil_set_init_request(void)
{
CAM_DBG(CAM_PRESIL, "notifying pchost to start HFI init...");
cam_presil_send_event(CAM_PRESIL_EVENT_HFI_REG_A5_HW_VERSION_TO_START_HFI_INIT, 0xFF);
cam_presil_send_event(CAM_PRESIL_EVENT_HFI_REG_ICP_V1_HW_VERSION_TO_START_HFI_INIT, 0xFF);
CAM_DBG(CAM_PRESIL, "got done with PCHOST HFI init...");
return 0;

View File

@@ -1,98 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_A5_CORE_H
#define CAM_A5_CORE_H
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include "cam_a5_hw_intf.h"
#define A5_QGIC_BASE 0
#define A5_SIERRA_BASE 1
#define A5_CSR_BASE 2
#define A5_HOST_INT 0x1
#define A5_WDT_0 0x2
#define A5_WDT_1 0x4
#define ICP_SIERRA_A5_CSR_ACCESS 0x3C
#define ELF_GUARD_PAGE (2 * 1024 * 1024)
struct cam_a5_device_hw_info {
uint32_t hw_ver;
uint32_t nsec_reset;
uint32_t a5_control;
uint32_t a5_host_int_en;
uint32_t a5_host_int;
uint32_t a5_host_int_clr;
uint32_t a5_host_int_status;
uint32_t a5_host_int_set;
uint32_t host_a5_int;
uint32_t fw_version;
uint32_t init_req;
uint32_t init_response;
uint32_t shared_mem_ptr;
uint32_t shared_mem_size;
uint32_t qtbl_ptr;
uint32_t uncached_heap_ptr;
uint32_t uncached_heap_size;
uint32_t a5_status;
};
/**
* struct cam_a5_device_hw_info
* @a5_hw_info: A5 hardware info
* @fw_elf: start address of fw start with elf header
* @fw: start address of fw blob
* @fw_buf: smmu alloc/mapped fw buffer
* @fw_buf_len: fw buffer length
* @query_cap: A5 query info from firmware
* @a5_acquire: Acquire information of A5
* @irq_cb: IRQ callback
* @cpas_handle: CPAS handle for A5
* @cpast_start: state variable for cpas
*/
struct cam_a5_device_core_info {
struct cam_a5_device_hw_info *a5_hw_info;
const struct firmware *fw_elf;
void *fw;
uint32_t fw_buf;
uintptr_t fw_kva_addr;
uint64_t fw_buf_len;
struct cam_icp_a5_query_cap query_cap;
struct cam_icp_a5_acquire_dev a5_acquire[8];
struct cam_icp_irq_cb irq_cb;
uint32_t cpas_handle;
bool cpas_start;
};
int cam_a5_init_hw(void *device_priv,
void *init_hw_args, uint32_t arg_size);
int cam_a5_deinit_hw(void *device_priv,
void *init_hw_args, uint32_t arg_size);
int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
void *cmd_args, uint32_t arg_size);
irqreturn_t cam_a5_irq(int irq_num, void *data);
void cam_a5_irq_raise(void *priv);
void cam_a5_irq_enable(void *priv);
void __iomem *cam_a5_iface_addr(void *priv);
/**
* @brief : API to register a5 hw to platform framework.
* @return struct platform_device pointer on on success, or ERR_PTR() on error.
*/
int cam_a5_init_module(void);
/**
* @brief : API to remove a5 hw from platform framework.
*/
void cam_a5_exit_module(void);
#endif /* CAM_A5_CORE_H */

View File

@@ -1,275 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-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 "a5_core.h"
#include "a5_soc.h"
#include "cam_io_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
#include "cam_a5_hw_intf.h"
#include "cam_icp_hw_mgr_intf.h"
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
#include "camera_main.h"
struct a5_soc_info cam_a5_soc_info;
EXPORT_SYMBOL(cam_a5_soc_info);
struct cam_a5_device_hw_info cam_a5_hw_info = {
.hw_ver = 0x0,
.nsec_reset = 0x4,
.a5_control = 0x8,
.a5_host_int_en = 0x10,
.a5_host_int = 0x14,
.a5_host_int_clr = 0x18,
.a5_host_int_status = 0x1c,
.a5_host_int_set = 0x20,
.host_a5_int = 0x30,
.fw_version = 0x44,
.init_req = 0x48,
.init_response = 0x4c,
.shared_mem_ptr = 0x50,
.shared_mem_size = 0x54,
.qtbl_ptr = 0x58,
.uncached_heap_ptr = 0x5c,
.uncached_heap_size = 0x60,
.a5_status = 0x200,
};
EXPORT_SYMBOL(cam_a5_hw_info);
static bool cam_a5_cpas_cb(uint32_t client_handle, void *userdata,
struct cam_cpas_irq_data *irq_data)
{
bool error_handled = false;
if (!irq_data)
return error_handled;
switch (irq_data->irq_type) {
case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR:
CAM_ERR_RATE_LIMIT(CAM_ICP,
"IPE/BPS UBWC Decode error type=%d status=%x thr_err=%d, fcl_err=%d, len_md_err=%d, format_err=%d",
irq_data->irq_type,
irq_data->u.dec_err.decerr_status.value,
irq_data->u.dec_err.decerr_status.thr_err,
irq_data->u.dec_err.decerr_status.fcl_err,
irq_data->u.dec_err.decerr_status.len_md_err,
irq_data->u.dec_err.decerr_status.format_err);
error_handled = true;
break;
case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR:
CAM_ERR_RATE_LIMIT(CAM_ICP,
"IPE/BPS UBWC Encode error type=%d status=%x",
irq_data->irq_type,
irq_data->u.enc_err.encerr_status.value);
error_handled = true;
break;
default:
break;
}
return error_handled;
}
int cam_a5_register_cpas(struct cam_hw_soc_info *soc_info,
struct cam_a5_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, "icp", sizeof("icp"));
cpas_register_params.cam_cpas_client_cb = cam_a5_cpas_cb;
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_ICP, "failed: %d", rc);
return rc;
}
core_info->cpas_handle = cpas_register_params.client_handle;
return rc;
}
static int cam_a5_component_bind(struct device *dev,
struct device *master_dev, void *data)
{
int rc = 0;
struct cam_hw_info *a5_dev = NULL;
struct cam_hw_intf *a5_dev_intf = NULL;
const struct of_device_id *match_dev = NULL;
struct cam_a5_device_core_info *core_info = NULL;
struct cam_a5_device_hw_info *hw_info = NULL;
struct platform_device *pdev = to_platform_device(dev);
a5_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
if (!a5_dev_intf)
return -ENOMEM;
of_property_read_u32(pdev->dev.of_node,
"cell-index", &a5_dev_intf->hw_idx);
a5_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
if (!a5_dev) {
rc = -ENOMEM;
goto a5_dev_alloc_failure;
}
a5_dev->soc_info.pdev = pdev;
a5_dev->soc_info.dev = &pdev->dev;
a5_dev->soc_info.dev_name = pdev->name;
a5_dev_intf->hw_priv = a5_dev;
a5_dev_intf->hw_ops.init = cam_a5_init_hw;
a5_dev_intf->hw_ops.deinit = cam_a5_deinit_hw;
a5_dev_intf->hw_ops.process_cmd = cam_a5_process_cmd;
a5_dev_intf->hw_type = CAM_ICP_DEV_A5;
CAM_DBG(CAM_ICP, "type %d index %d",
a5_dev_intf->hw_type,
a5_dev_intf->hw_idx);
platform_set_drvdata(pdev, a5_dev_intf);
a5_dev->core_info = kzalloc(sizeof(struct cam_a5_device_core_info),
GFP_KERNEL);
if (!a5_dev->core_info) {
rc = -ENOMEM;
goto core_info_alloc_failure;
}
core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
match_dev = of_match_device(pdev->dev.driver->of_match_table,
&pdev->dev);
if (!match_dev) {
CAM_ERR(CAM_ICP, "No a5 hardware info");
rc = -EINVAL;
goto match_err;
}
hw_info = (struct cam_a5_device_hw_info *)match_dev->data;
core_info->a5_hw_info = hw_info;
a5_dev->soc_info.soc_private = &cam_a5_soc_info;
rc = cam_a5_init_soc_resources(&a5_dev->soc_info, cam_a5_irq,
a5_dev);
if (rc < 0) {
CAM_ERR(CAM_ICP, "failed to init_soc");
goto init_soc_failure;
}
CAM_DBG(CAM_ICP, "soc info : %pK",
(void *)&a5_dev->soc_info);
rc = cam_a5_register_cpas(&a5_dev->soc_info,
core_info, a5_dev_intf->hw_idx);
if (rc < 0) {
CAM_ERR(CAM_ICP, "a5 cpas registration failed");
goto cpas_reg_failed;
}
a5_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
mutex_init(&a5_dev->hw_mutex);
spin_lock_init(&a5_dev->hw_lock);
init_completion(&a5_dev->hw_complete);
CAM_DBG(CAM_ICP, "A5:%d component bound successfully",
a5_dev_intf->hw_idx);
return 0;
cpas_reg_failed:
cam_a5_deinit_soc_resources(&a5_dev->soc_info);
init_soc_failure:
match_err:
kfree(a5_dev->core_info);
core_info_alloc_failure:
kfree(a5_dev);
a5_dev_alloc_failure:
kfree(a5_dev_intf);
return rc;
}
static void cam_a5_component_unbind(struct device *dev,
struct device *master_dev, void *data)
{
struct cam_hw_info *a5_dev = NULL;
struct cam_hw_intf *a5_dev_intf = NULL;
struct cam_a5_device_core_info *core_info = NULL;
struct platform_device *pdev = to_platform_device(dev);
a5_dev_intf = platform_get_drvdata(pdev);
a5_dev = a5_dev_intf->hw_priv;
core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
cam_cpas_unregister_client(core_info->cpas_handle);
cam_a5_deinit_soc_resources(&a5_dev->soc_info);
memset(&cam_a5_soc_info, 0, sizeof(struct a5_soc_info));
kfree(a5_dev->core_info);
a5_dev->core_info = NULL;
kfree(a5_dev);
kfree(a5_dev_intf);
}
const static struct component_ops cam_a5_component_ops = {
.bind = cam_a5_component_bind,
.unbind = cam_a5_component_unbind,
};
int cam_a5_probe(struct platform_device *pdev)
{
int rc = 0;
CAM_DBG(CAM_ICP, "Adding A5 component");
rc = component_add(&pdev->dev, &cam_a5_component_ops);
if (rc)
CAM_ERR(CAM_ICP, "failed to add component rc: %d", rc);
return rc;
}
static int cam_a5_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &cam_a5_component_ops);
return 0;
}
static const struct of_device_id cam_a5_dt_match[] = {
{
.compatible = "qcom,cam-a5",
.data = &cam_a5_hw_info,
},
{}
};
MODULE_DEVICE_TABLE(of, cam_a5_dt_match);
struct platform_driver cam_a5_driver = {
.probe = cam_a5_probe,
.remove = cam_a5_remove,
.driver = {
.name = "cam-a5",
.owner = THIS_MODULE,
.of_match_table = cam_a5_dt_match,
.suppress_bind_attrs = true,
},
};
int cam_a5_init_module(void)
{
return platform_driver_register(&cam_a5_driver);
}
void cam_a5_exit_module(void)
{
platform_driver_unregister(&cam_a5_driver);
}
MODULE_DESCRIPTION("CAM A5 driver");
MODULE_LICENSE("GPL v2");

View File

@@ -1,37 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_A5_REG_H_
#define _CAM_A5_REG_H_
#define ICP_SIERRA_A5_CSR_NSEC_RESET 0x4
#define A5_CSR_FUNC_RESET (1 << 4)
#define A5_CSR_DBG_RESET (1 << 3)
#define A5_CSR_CPU_RESET (1 << 2)
#define ICP_SIERRA_A5_CSR_A5_CONTROL 0x8
#define A5_CSR_DBGSWENABLE (1 << 22)
#define A5_CSR_EDBGRQ (1 << 14)
#define A5_CSR_EN_CLKGATE_WFI (1 << 12)
#define A5_CSR_A5_CPU_EN (1 << 9)
#define A5_CSR_WAKE_UP_EN (1 << 4)
#define A5_CSR_FULL_DBG_EN (A5_CSR_DBGSWENABLE | A5_CSR_EDBGRQ)
#define A5_CSR_FULL_CPU_EN (A5_CSR_A5_CPU_EN | \
A5_CSR_WAKE_UP_EN | \
A5_CSR_EN_CLKGATE_WFI)
#define ICP_SIERRA_A5_CSR_A2HOSTINTEN 0x10
#define A5_WDT_WS1EN (1 << 2)
#define A5_WDT_WS0EN (1 << 1)
#define A5_A2HOSTINTEN (1 << 0)
#define ICP_SIERRA_A5_CSR_HOST2ICPINT 0x30
#define A5_HOSTINT (1 << 0)
#define ICP_SIERRA_A5_CSR_A5_STATUS 0x200
#define A5_CSR_A5_STANDBYWFI (1 << 7)
#endif /* _CAM_A5_REG_H_ */

View File

@@ -1,260 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <media/cam_defs.h>
#include <media/cam_icp.h>
#include "a5_soc.h"
#include "cam_soc_util.h"
#include "cam_debug_util.h"
#include "hfi_intf.h"
static int cam_a5_get_dt_properties(struct cam_hw_soc_info *soc_info)
{
int rc = 0, i;
const char *fw_name;
struct a5_soc_info *a5_soc_info;
struct device_node *of_node = NULL;
struct platform_device *pdev = NULL;
struct a5_ubwc_cfg_ext *ubwc_cfg_ext = NULL;
int num_ubwc_cfg;
pdev = soc_info->pdev;
of_node = pdev->dev.of_node;
rc = cam_soc_util_get_dt_properties(soc_info);
if (rc < 0) {
CAM_ERR(CAM_ICP, "get a5 dt prop is failed");
return rc;
}
a5_soc_info = soc_info->soc_private;
rc = of_property_read_string(of_node, "fw_name", &fw_name);
if (rc < 0) {
CAM_ERR(CAM_ICP, "fw_name read failed");
goto end;
}
a5_soc_info->fw_name = fw_name;
rc = of_property_read_u32(of_node, "qos-val",
&a5_soc_info->a5_qos_val);
if (rc < 0) {
CAM_WARN(CAM_ICP, "QoS need not be set");
a5_soc_info->a5_qos_val = 0;
}
ubwc_cfg_ext = &a5_soc_info->uconfig.ubwc_cfg_ext;
num_ubwc_cfg = of_property_count_u32_elems(of_node,
"ubwc-ipe-fetch-cfg");
if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) {
CAM_DBG(CAM_ICP, "wrong ubwc_ipe_fetch_cfg: %d", num_ubwc_cfg);
rc = num_ubwc_cfg;
goto ubwc_ex_cfg;
}
for (i = 0; i < num_ubwc_cfg; i++) {
rc = of_property_read_u32_index(of_node, "ubwc-ipe-fetch-cfg",
i, &ubwc_cfg_ext->ubwc_ipe_fetch_cfg[i]);
if (rc < 0) {
CAM_ERR(CAM_ICP,
"unable to read ubwc_ipe_fetch_cfg values");
goto end;
}
}
num_ubwc_cfg = of_property_count_u32_elems(of_node,
"ubwc-ipe-write-cfg");
if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) {
CAM_ERR(CAM_ICP, "wrong ubwc_ipe_write_cfg: %d", num_ubwc_cfg);
rc = num_ubwc_cfg;
goto end;
}
for (i = 0; i < num_ubwc_cfg; i++) {
rc = of_property_read_u32_index(of_node, "ubwc-ipe-write-cfg",
i, &ubwc_cfg_ext->ubwc_ipe_write_cfg[i]);
if (rc < 0) {
CAM_ERR(CAM_ICP,
"unable to read ubwc_ipe_write_cfg values");
goto end;
}
}
num_ubwc_cfg = of_property_count_u32_elems(of_node,
"ubwc-bps-fetch-cfg");
if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) {
CAM_ERR(CAM_ICP, "wrong ubwc_bps_fetch_cfg: %d", num_ubwc_cfg);
rc = num_ubwc_cfg;
goto end;
}
for (i = 0; i < num_ubwc_cfg; i++) {
rc = of_property_read_u32_index(of_node, "ubwc-bps-fetch-cfg",
i, &ubwc_cfg_ext->ubwc_bps_fetch_cfg[i]);
if (rc < 0) {
CAM_ERR(CAM_ICP,
"unable to read ubwc_bps_fetch_cfg values");
goto end;
}
}
num_ubwc_cfg = of_property_count_u32_elems(of_node,
"ubwc-bps-write-cfg");
if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) {
CAM_ERR(CAM_ICP, "wrong ubwc_bps_write_cfg: %d", num_ubwc_cfg);
rc = num_ubwc_cfg;
goto end;
}
for (i = 0; i < num_ubwc_cfg; i++) {
rc = of_property_read_u32_index(of_node, "ubwc-bps-write-cfg",
i, &ubwc_cfg_ext->ubwc_bps_write_cfg[i]);
if (rc < 0) {
CAM_ERR(CAM_ICP,
"unable to read ubwc_bps_write_cfg values");
goto end;
}
}
a5_soc_info->ubwc_config_ext = true;
CAM_DBG(CAM_ICP, "read ubwc_cfg_ext for ipe/bps");
return rc;
ubwc_ex_cfg:
num_ubwc_cfg = of_property_count_u32_elems(of_node, "ubwc-cfg");
if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) {
CAM_ERR(CAM_ICP, "wrong ubwc_cfg: %d", num_ubwc_cfg);
rc = num_ubwc_cfg;
goto end;
}
for (i = 0; i < num_ubwc_cfg; i++) {
rc = of_property_read_u32_index(of_node, "ubwc-cfg",
i, &a5_soc_info->uconfig.ubwc_cfg[i]);
if (rc < 0) {
CAM_ERR(CAM_ICP, "unable to read ubwc_cfg values");
break;
}
}
end:
return rc;
}
static int cam_a5_request_platform_resource(
struct cam_hw_soc_info *soc_info,
irq_handler_t a5_irq_handler, void *irq_data)
{
int rc = 0;
rc = cam_soc_util_request_platform_resource(soc_info, a5_irq_handler,
irq_data);
return rc;
}
int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info,
irq_handler_t a5_irq_handler, void *irq_data)
{
int rc = 0;
rc = cam_a5_get_dt_properties(soc_info);
if (rc < 0)
return rc;
rc = cam_a5_request_platform_resource(soc_info, a5_irq_handler,
irq_data);
if (rc < 0)
return rc;
return rc;
}
void cam_a5_deinit_soc_resources(struct cam_hw_soc_info *soc_info)
{
int rc = 0;
rc = cam_soc_util_release_platform_resource(soc_info);
if (rc)
CAM_WARN(CAM_ICP, "release platform resources fail");
}
int cam_a5_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_ICP, "enable platform failed");
return rc;
}
int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info)
{
int rc = 0;
rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
if (rc)
CAM_ERR(CAM_ICP, "disable platform failed");
return rc;
}
int cam_a5_update_clk_rate(struct cam_hw_soc_info *soc_info,
int32_t clk_level)
{
int32_t src_clk_idx = 0;
int32_t clk_rate = 0;
int rc = 0;
if (!soc_info) {
CAM_ERR(CAM_ICP, "Invalid args");
return -EINVAL;
}
if ((clk_level < 0) || (clk_level >= CAM_MAX_VOTE)) {
CAM_ERR(CAM_ICP, "clock level %d is not valid",
clk_level);
return -EINVAL;
}
if (!soc_info->clk_level_valid[clk_level]) {
CAM_ERR(CAM_ICP,
"Clock level %d not supported",
clk_level);
return -EINVAL;
}
src_clk_idx = soc_info->src_clk_idx;
if ((src_clk_idx < 0) || (src_clk_idx >= CAM_SOC_MAX_CLK)) {
CAM_WARN(CAM_ICP, "src_clk not defined for %s",
soc_info->dev_name);
return -EINVAL;
}
clk_rate = soc_info->clk_rate[clk_level][src_clk_idx];
if ((soc_info->clk_level_valid[CAM_TURBO_VOTE]) &&
(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_ICP, "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];
}
rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate);
if (rc)
return rc;
hfi_send_freq_info(clk_rate);
return 0;
}

View File

@@ -1,41 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_A5_SOC_H
#define CAM_A5_SOC_H
#include "cam_soc_util.h"
#define ICP_UBWC_MAX 2
struct a5_ubwc_cfg_ext {
uint32_t ubwc_ipe_fetch_cfg[ICP_UBWC_MAX];
uint32_t ubwc_ipe_write_cfg[ICP_UBWC_MAX];
uint32_t ubwc_bps_fetch_cfg[ICP_UBWC_MAX];
uint32_t ubwc_bps_write_cfg[ICP_UBWC_MAX];
};
struct a5_soc_info {
const char *fw_name;
bool ubwc_config_ext;
uint32_t a5_qos_val;
union {
uint32_t ubwc_cfg[ICP_UBWC_MAX];
struct a5_ubwc_cfg_ext ubwc_cfg_ext;
} uconfig;
};
int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info,
irq_handler_t a5_irq_handler, void *irq_data);
void cam_a5_deinit_soc_resources(struct cam_hw_soc_info *soc_info);
int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info);
int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info);
int cam_a5_update_clk_rate(struct cam_hw_soc_info *soc_info,
int32_t clk_level);
#endif

View File

@@ -27,7 +27,6 @@
#include "cam_hw_mgr_intf.h"
#include "cam_icp_hw_mgr_intf.h"
#include "cam_icp_hw_mgr.h"
#include "cam_a5_hw_intf.h"
#include "cam_bps_hw_intf.h"
#include "cam_ipe_hw_intf.h"
#include "cam_smmu_api.h"
@@ -37,8 +36,6 @@
#include "hfi_session_defs.h"
#include "hfi_sys_defs.h"
#include "cam_req_mgr_workq.h"
#include "a5_core.h"
#include "lx7_core.h"
#include "hfi_sys_defs.h"
#include "cam_debug_util.h"
#include "cam_soc_util.h"
@@ -47,6 +44,7 @@
#include "cam_common_util.h"
#include "cam_mem_mgr_api.h"
#include "cam_presil_hw_access.h"
#include "cam_icp_proc.h"
#define ICP_WORKQ_TASK_CMD_TYPE 1
#define ICP_WORKQ_TASK_MSG_TYPE 2
@@ -56,18 +54,6 @@
#define ICP_DEVICE_IDLE_TIMEOUT 400
static const struct hfi_ops hfi_a5_ops = {
.irq_raise = cam_a5_irq_raise,
.irq_enable = cam_a5_irq_enable,
.iface_addr = cam_a5_iface_addr,
};
static const struct hfi_ops hfi_lx7_ops = {
.irq_raise = cam_lx7_irq_raise,
.irq_enable = cam_lx7_irq_enable,
.iface_addr = cam_lx7_iface_addr,
};
static struct cam_icp_hw_mgr icp_hw_mgr;
static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl);
@@ -1525,7 +1511,7 @@ static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr,
&clk_upd_cmd, sizeof(clk_upd_cmd));
}
/* update a5 clock */
/* update ICP Proc clock */
CAM_DBG(CAM_PERF, "Update ICP clk to level [%d]",
clk_upd_cmd.clk_level);
icp_dev_intf->hw_ops.process_cmd(icp_dev_intf->hw_priv,
@@ -4232,6 +4218,7 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr)
struct cam_hw_info *icp_dev = NULL;
struct hfi_mem_info hfi_mem;
const struct hfi_ops *hfi_ops;
int rc;
icp_dev_intf = hw_mgr->icp_dev_intf;
if (!icp_dev_intf) {
@@ -4299,10 +4286,11 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr)
hfi_mem.fw_uncached.iova = icp_hw_mgr.hfi_mem.fw_uncached.iova;
hfi_mem.fw_uncached.len = icp_hw_mgr.hfi_mem.fw_uncached.len;
if (icp_dev_intf->hw_type == CAM_ICP_DEV_LX7)
hfi_ops = &hfi_lx7_ops;
else
hfi_ops = &hfi_a5_ops;
rc = cam_icp_get_hfi_device_ops(icp_dev_intf->hw_type, &hfi_ops);
if (rc) {
CAM_ERR(CAM_ICP, "Fail to get HFI device ops rc: %d", rc);
return rc;
}
return cam_hfi_init(&hfi_mem, hfi_ops, icp_dev, 0);
}
@@ -6591,29 +6579,18 @@ end:
static int cam_icp_mgr_alloc_devs(struct device_node *np)
{
struct cam_hw_intf **devices;
struct cam_hw_intf **devices = NULL;
int rc, icp_hw_type;
uint32_t num;
memset(icp_hw_mgr.devices, 0, sizeof(icp_hw_mgr.devices));
if (!of_property_read_u32(np, "num-a5", &num)) {
icp_hw_type = CAM_ICP_DEV_A5;
} else if (!of_property_read_u32(np, "num-lx7", &num)) {
icp_hw_type = CAM_ICP_DEV_LX7;
} else {
CAM_ERR(CAM_ICP, "missing processor device num prop");
return -ENODEV;
}
rc = cam_icp_alloc_processor_devs(np, &icp_hw_type, &devices);
devices = kcalloc(num, sizeof(*devices), GFP_KERNEL);
if (!devices) {
CAM_ERR(CAM_ICP, "icp device allocation failed");
return -ENOMEM;
if (rc) {
CAM_ERR(CAM_ICP, "ICP proc devices allocation failed rc=%d", rc);
return rc;
}
CAM_DBG(CAM_ICP, "allocated device iface for %s",
icp_hw_type == CAM_ICP_DEV_A5 ? "A5" : "LX7");
icp_hw_mgr.devices[icp_hw_type] = devices;
rc = of_property_read_u32(np, "num-ipe", &num);
@@ -6730,13 +6707,10 @@ static int cam_icp_mgr_init_devs(struct device_node *np)
rc = -EINVAL;
goto free_devices;
}
icp_hw_mgr.devices[iface->hw_type][iface->hw_idx] = iface;
}
icp_hw_mgr.icp_dev_intf = icp_hw_mgr.devices[CAM_ICP_DEV_A5] ?
icp_hw_mgr.devices[CAM_ICP_DEV_A5][0] :
icp_hw_mgr.devices[CAM_ICP_DEV_LX7][0];
icp_hw_mgr.icp_dev_intf = CAM_ICP_GET_PROC_DEV_INTF(icp_hw_mgr.devices);
icp_hw_mgr.bps_dev_intf = icp_hw_mgr.devices[CAM_ICP_DEV_BPS][0];
icp_hw_mgr.ipe0_dev_intf = icp_hw_mgr.devices[CAM_ICP_DEV_IPE][0];

View File

@@ -13,7 +13,6 @@
#include "cam_icp_hw_intf.h"
#include "cam_hw_mgr_intf.h"
#include "cam_hw_intf.h"
#include "cam_a5_hw_intf.h"
#include "hfi_session_defs.h"
#include "hfi_intf.h"
#include "cam_req_mgr_workq.h"

View File

@@ -1,46 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_A5_HW_INTF_H
#define CAM_A5_HW_INTF_H
#include <linux/timer.h>
#include <media/cam_defs.h>
#include <media/cam_icp.h>
#include "cam_hw_mgr_intf.h"
#include "cam_icp_hw_intf.h"
/**
* struct cam_icp_a5_query_cap - ICP query device capability payload
* @fw_version: firmware version info
* @api_version: api version info
* @num_ipe: number of ipes
* @num_bps: number of bps
* @num_dev: number of device capabilities in dev_caps
* @reserved: reserved
* @dev_ver: returned device capability array
* @CAM_QUERY_CAP IOCTL
*/
struct cam_icp_a5_query_cap {
struct cam_icp_ver fw_version;
struct cam_icp_ver api_version;
uint32_t num_ipe;
uint32_t num_bps;
uint32_t num_dev;
uint32_t reserved;
struct cam_icp_dev_ver dev_ver[CAM_ICP_DEV_TYPE_MAX];
};
struct cam_icp_a5_acquire_dev {
uint32_t ctx_id;
struct cam_icp_acquire_dev_info icp_acquire_info;
struct cam_icp_res_info icp_out_acquire_info[2];
uint32_t fw_handle;
};
struct cam_icp_a5_test_irq {
uint32_t test_irq;
};
#endif /* CAM_A5_HW_INTF_H */

View File

@@ -23,9 +23,11 @@
#define CAM_ICP_DUMP_STATUS_REGISTERS BIT(0)
#define CAM_ICP_DUMP_CSR_REGISTERS BIT(1)
#define CAM_ICP_MAX_ICP_DEV_TYPE 2
enum cam_icp_hw_type {
CAM_ICP_DEV_A5,
CAM_ICP_DEV_LX7,
CAM_ICP_DEV_ICP_V1,
CAM_ICP_DEV_ICP_V2,
CAM_ICP_DEV_IPE,
CAM_ICP_DEV_BPS,
CAM_ICP_DEV_MAX,

View File

@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "cam_debug_util.h"
#include "cam_icp_proc.h"
static int cam_icp_get_device_num(uint32_t dev_type, uint32_t *num_dev)
{
int rc = 0;
switch (dev_type) {
case CAM_ICP_DEV_ICP_V1:
*num_dev = cam_icp_v1_get_device_num();
break;
case CAM_ICP_DEV_ICP_V2:
*num_dev = cam_icp_v2_get_device_num();
break;
default:
CAM_ERR(CAM_ICP, "Invalid dev type: %d", dev_type);
rc = -EINVAL;
}
return rc;
}
int cam_icp_alloc_processor_devs(struct device_node *np, int *icp_hw_type,
struct cam_hw_intf ***devices)
{
uint32_t num_icp_found = 0, num_icp_listed;
int rc, i;
if (!np) {
CAM_ERR(CAM_ICP, "Invalid device node");
return -EINVAL;
}
rc = of_property_read_u32(np, "num-icp", &num_icp_listed);
if (rc) {
CAM_ERR(CAM_ICP, "read num-icp failed rc=%d", rc);
return -ENODEV;
}
if (!num_icp_listed) {
CAM_ERR(CAM_ICP, "No ICP device %d", num_icp_listed);
return -EINVAL;
}
for (i = 0; i < CAM_ICP_MAX_ICP_DEV_TYPE; i++) {
rc = cam_icp_get_device_num(i, &num_icp_found);
if (rc)
return rc;
if (num_icp_found) {
*icp_hw_type = i;
break;
}
}
if (i == CAM_ICP_MAX_ICP_DEV_TYPE) {
CAM_ERR(CAM_ICP, "No ICP device probed");
return -ENODEV;
}
if (num_icp_listed != num_icp_found) {
CAM_ERR(CAM_ICP,
"number of ICP devices do not match num_icp_listed: %d num_icp_found: %d",
num_icp_listed, num_icp_found);
return -EINVAL;
}
*devices = kcalloc(num_icp_listed, sizeof(**devices), GFP_KERNEL);
if (!(*devices)) {
CAM_ERR(CAM_ICP,
"ICP device memory allocation failed. Num devices: %u",
num_icp_listed);
return -ENOMEM;
}
CAM_DBG(CAM_ICP, "allocated device iface for %s",
*icp_hw_type == CAM_ICP_DEV_ICP_V1 ? "ICP_V1" : "ICP_V2");
return rc;
}
int cam_icp_get_hfi_device_ops(uint32_t hw_type, const struct hfi_ops **hfi_proc_ops)
{
int rc = 0;
switch (hw_type) {
case CAM_ICP_DEV_ICP_V1:
cam_icp_v1_populate_hfi_ops(hfi_proc_ops);
break;
case CAM_ICP_DEV_ICP_V2:
cam_icp_v2_populate_hfi_ops(hfi_proc_ops);
break;
default:
rc = -EINVAL;
CAM_ERR(CAM_ICP, "Invalid ICP device type: %u", hw_type);
}
return rc;
}

View File

@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "cam_icp_v1_core.h"
#include "cam_icp_v2_core.h"
#include "hfi_intf.h"
#define CAM_ICP_GET_PROC_DEV_INTF(devices) \
(devices[CAM_ICP_DEV_ICP_V1] ? devices[CAM_ICP_DEV_ICP_V1][0] : \
devices[CAM_ICP_DEV_ICP_V2][0])
/**
* @brief : Get ICP device type (ICP_V1/ICP_V2/...)
*/
int cam_icp_alloc_processor_devs(struct device_node *np, int *icp_hw_type,
struct cam_hw_intf ***devices);
/**
* @brief : Get device operations per device type
*/
int cam_icp_get_hfi_device_ops(uint32_t hw_type, const struct hfi_ops **hif_ops);
/**
* @brief : Get number of icp_v2 hw instances
*/
uint32_t cam_icp_v2_get_device_num(void);
/**
* @brief : Get number of icp_v1 hw instances
*/
uint32_t cam_icp_v1_get_device_num(void);

View File

@@ -1,9 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "cam_icp_utils.h"
#include "cam_icp_proc_common.h"
#include "cam_compat.h"
#include "cam_icp_hw_intf.h"
#include "hfi_intf.h"
int32_t cam_icp_validate_fw(const uint8_t *elf,
uint32_t machine_id)
@@ -128,3 +132,97 @@ int32_t cam_icp_program_fw(const uint8_t *elf,
return rc;
}
int cam_icp_proc_cpas_vote(uint32_t cpas_handle,
struct cam_icp_cpas_vote *vote)
{
int rc;
if (!vote)
return -EINVAL;
if (vote->ahb_vote_valid) {
rc = cam_cpas_update_ahb_vote(cpas_handle, &vote->ahb_vote);
if (rc) {
CAM_ERR(CAM_ICP, "AHB vote update failed rc=%d", rc);
return rc;
}
}
if (vote->axi_vote_valid) {
rc = cam_cpas_update_axi_vote(cpas_handle, &vote->axi_vote);
if (rc) {
CAM_ERR(CAM_ICP, "AXI vote update failed rc=%d", rc);
return rc;
}
}
return 0;
}
int cam_icp_proc_mini_dump(struct cam_icp_hw_dump_args *args,
uintptr_t fw_kva_addr, uint64_t fw_buf_len)
{
u8 *dest;
u8 *src;
struct cam_icp_hw_dump_args *dump_args = args;
if (!dump_args) {
CAM_ERR(CAM_ICP, "Invalid param %pK", dump_args);
return -EINVAL;
}
if (!fw_kva_addr || !dump_args->cpu_addr) {
CAM_ERR(CAM_ICP, "invalid params %pK, 0x%zx",
fw_kva_addr, dump_args->cpu_addr);
return -EINVAL;
}
if (dump_args->buf_len < fw_buf_len) {
CAM_WARN(CAM_ICP, "Insufficient Len %lu fw_len %llu",
dump_args->buf_len, fw_buf_len);
return -ENOSPC;
}
dest = (u8 *)dump_args->cpu_addr;
src = (u8 *)fw_kva_addr;
memcpy_fromio(dest, src, fw_buf_len);
dump_args->offset = fw_buf_len;
return 0;
}
int cam_icp_proc_ubwc_configure(struct cam_icp_ubwc_cfg ubwc_cfg,
uint32_t force_disable_ubwc)
{
int i = 0, ddr_type, rc;
uint32_t ipe_ubwc_cfg[ICP_UBWC_CFG_MAX];
uint32_t bps_ubwc_cfg[ICP_UBWC_CFG_MAX];
ddr_type = cam_get_ddr_type();
if (ddr_type == DDR_TYPE_LPDDR5 || ddr_type == DDR_TYPE_LPDDR5X)
i = 1;
ipe_ubwc_cfg[0] = ubwc_cfg.ipe_fetch[i];
ipe_ubwc_cfg[1] = ubwc_cfg.ipe_write[i];
bps_ubwc_cfg[0] = ubwc_cfg.bps_fetch[i];
bps_ubwc_cfg[1] = ubwc_cfg.bps_write[i];
if (force_disable_ubwc) {
ipe_ubwc_cfg[1] &= ~CAM_ICP_UBWC_COMP_EN;
bps_ubwc_cfg[1] &= ~CAM_ICP_UBWC_COMP_EN;
CAM_DBG(CAM_ICP,
"Force disable UBWC compression, ipe_ubwc_cfg: 0x%x, bps_ubwc_cfg: 0x%x",
ipe_ubwc_cfg[1], bps_ubwc_cfg[1]);
}
rc = hfi_cmd_ubwc_config_ext(ipe_ubwc_cfg, bps_ubwc_cfg);
if (rc) {
CAM_ERR(CAM_ICP, "Failed to write UBWC configure rc=%d", rc);
return rc;
}
return 0;
}

View File

@@ -0,0 +1,57 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_ICP_UTILS_H_
#define _CAM_ICP_UTILS_H_
#include <linux/firmware.h>
#include <linux/elf.h>
#include <linux/iopoll.h>
#include "cam_debug_util.h"
#include "cam_cpas_api.h"
#include "cam_icp_hw_mgr_intf.h"
#include "cam_icp_soc_common.h"
#define ICP_FW_NAME_MAX_SIZE 32
#define PC_POLL_DELAY_US 100
#define PC_POLL_TIMEOUT_US 10000
/**
* @brief : Validate FW elf image
*/
int32_t cam_icp_validate_fw(const uint8_t *elf, uint32_t machine_id);
/**
* @brief : Get FW elf size
*/
int32_t cam_icp_get_fw_size(const uint8_t *elf, uint32_t *fw_size);
/**
* @brief : Program FW memory
*/
int32_t cam_icp_program_fw(const uint8_t *elf,
uintptr_t fw_kva_addr);
/**
* @brief : Update ahb and axi votes
*/
int cam_icp_proc_cpas_vote(uint32_t cpas_handle,
struct cam_icp_cpas_vote *vote);
/**
* @brief : dump FW memory into mini dump
*/
int cam_icp_proc_mini_dump(struct cam_icp_hw_dump_args *args,
uintptr_t fw_kva_addr, uint64_t fw_buf_len);
/**
* @brief : Update UBWC configuration for IPE and BPS
*/
int cam_icp_proc_ubwc_configure(struct cam_icp_ubwc_cfg ubwc_cfg,
uint32_t force_disable_ubwc);
#endif /* _CAM_ICP_UTILS_H_ */

View File

@@ -9,28 +9,26 @@
#include "cam_debug_util.h"
#include "cam_soc_util.h"
#include "lx7_soc.h"
#include "hfi_intf.h"
#include "cam_icp_soc_common.h"
static int __ubwc_config_get(struct device_node *np, char *name, uint32_t *cfg)
{
int nconfig;
int i;
int i, rc;
nconfig = of_property_count_u32_elems(np, name);
if (nconfig < 0 || nconfig > UBWC_CONFIG_MAX) {
CAM_ERR(CAM_ICP, "invalid number of UBWC configs[=%d]",
if (nconfig < 0 || nconfig > ICP_UBWC_CFG_MAX) {
CAM_ERR(CAM_ICP, "Invalid number of UBWC configs[=%d]",
nconfig);
return -EINVAL;
}
for (i = 0; i < nconfig; i++) {
int rc;
rc = of_property_read_u32_index(np, name, i, &cfg[i]);
if (rc) {
CAM_ERR(CAM_ICP,
"node %pOF has no valid %s prop at index=%d",
"Node %pOF has no valid %s prop at index=%d",
np, name, i);
return rc;
}
@@ -39,77 +37,120 @@ static int __ubwc_config_get(struct device_node *np, char *name, uint32_t *cfg)
return 0;
}
static int cam_lx7_ubwc_config_get(struct lx7_soc_info *lx7_soc_info,
struct device_node *np)
static int cam_icp_soc_ubwc_config_get(struct device_node *np,
struct cam_icp_soc_info *icp_soc_info)
{
struct cam_icp_ubwc_cfg *ubwc_cfg_ext = NULL;
int rc;
uint32_t dev_type;
rc = __ubwc_config_get(np, "ubwc-ipe-fetch-cfg",
lx7_soc_info->ubwc_cfg.ipe_fetch);
dev_type = icp_soc_info->dev_type;
ubwc_cfg_ext = &icp_soc_info->uconfig.ubwc_cfg_ext;
rc = __ubwc_config_get(np, "ubwc-ipe-fetch-cfg", ubwc_cfg_ext->ipe_fetch);
if (rc) {
if (dev_type == CAM_ICP_DEV_ICP_V1) {
rc = __ubwc_config_get(np, "ubwc-cfg", icp_soc_info->uconfig.ubwc_cfg);
if (rc)
return rc;
icp_soc_info->is_ubwc_cfg = true;
}
return rc;
}
rc = __ubwc_config_get(np, "ubwc-ipe-write-cfg",
lx7_soc_info->ubwc_cfg.ipe_write);
icp_soc_info->uconfig.ubwc_cfg_ext.ipe_write);
if (rc)
return rc;
rc = __ubwc_config_get(np, "ubwc-bps-fetch-cfg",
lx7_soc_info->ubwc_cfg.bps_fetch);
icp_soc_info->uconfig.ubwc_cfg_ext.bps_fetch);
if (rc)
return rc;
rc = __ubwc_config_get(np, "ubwc-bps-write-cfg",
lx7_soc_info->ubwc_cfg.bps_write);
if (rc)
icp_soc_info->uconfig.ubwc_cfg_ext.bps_write);
return rc;
return 0;
}
static inline void cam_lx7_qos_get(
struct lx7_soc_info *lx7_soc_info,
struct device_node *np)
static inline void cam_icp_soc_qos_get(struct device_node *np,
struct cam_icp_soc_info *icp_soc_info)
{
if (of_property_read_u32(np, "qos-val", &icp_soc_info->qos_val)) {
CAM_WARN(CAM_ICP, "QoS not set for device: %d",
icp_soc_info->dev_type);
icp_soc_info->qos_val = 0;
}
}
static int cam_icp_soc_get_hw_version(struct device_node *np,
struct cam_icp_soc_info *icp_soc_info)
{
int rc;
uint32_t version;
rc = of_property_read_u32(np, "qos-val",
&lx7_soc_info->icp_qos_val);
if (rc < 0) {
CAM_WARN(CAM_ICP, "QoS need not be set");
lx7_soc_info->icp_qos_val = 0;
}
rc = of_property_read_u32(np, "icp-version", &version);
if (rc) {
CAM_ERR(CAM_ICP, "read icp-version failed rc=%d", rc);
return -ENODEV;
}
static int cam_lx7_dt_properties_get(struct cam_hw_soc_info *soc_info)
switch (version) {
case CAM_ICP_V1_VERSION:
case CAM_ICP_V2_VERSION:
icp_soc_info->hw_version = version;
break;
default:
CAM_ERR(CAM_ICP, "Invalid ICP version: %u", version);
rc = -ENODEV;
}
return rc;
}
static int cam_icp_soc_dt_properties_get(struct cam_hw_soc_info *soc_info)
{
struct cam_icp_soc_info *icp_soc_info;
struct device_node *np;
int rc;
if (!soc_info->soc_private) {
CAM_ERR(CAM_ICP, "soc private is NULL");
return -EINVAL;
}
icp_soc_info = (struct cam_icp_soc_info *)soc_info->soc_private;
np = soc_info->pdev->dev.of_node;
rc = cam_soc_util_get_dt_properties(soc_info);
if (rc) {
CAM_ERR(CAM_ICP, "failed to get DT properties rc=%d", rc);
return rc;
}
rc = cam_lx7_ubwc_config_get(soc_info->soc_private,
soc_info->pdev->dev.of_node);
rc = cam_icp_soc_ubwc_config_get(np, icp_soc_info);
if (rc) {
CAM_ERR(CAM_ICP, "failed to get UBWC config props rc=%d", rc);
return rc;
}
cam_lx7_qos_get(soc_info->soc_private,
soc_info->pdev->dev.of_node);
cam_icp_soc_qos_get(np, icp_soc_info);
rc = cam_icp_soc_get_hw_version(np, icp_soc_info);
if (rc) {
CAM_ERR(CAM_ICP, "Get ICP HW version failed");
return rc;
}
return 0;
}
int cam_lx7_soc_resources_init(struct cam_hw_soc_info *soc_info,
int cam_icp_soc_resources_init(struct cam_hw_soc_info *soc_info,
irq_handler_t handler, void *data)
{
int rc;
rc = cam_lx7_dt_properties_get(soc_info);
rc = cam_icp_soc_dt_properties_get(soc_info);
if (rc)
return rc;
@@ -123,7 +164,7 @@ int cam_lx7_soc_resources_init(struct cam_hw_soc_info *soc_info,
return 0;
}
int cam_lx7_soc_resources_deinit(struct cam_hw_soc_info *soc_info)
int cam_icp_soc_resources_deinit(struct cam_hw_soc_info *soc_info)
{
int rc;
@@ -135,7 +176,7 @@ int cam_lx7_soc_resources_deinit(struct cam_hw_soc_info *soc_info)
return rc;
}
int cam_lx7_soc_resources_enable(struct cam_hw_soc_info *soc_info)
int cam_icp_soc_resources_enable(struct cam_hw_soc_info *soc_info)
{
int rc = 0;
@@ -147,7 +188,7 @@ int cam_lx7_soc_resources_enable(struct cam_hw_soc_info *soc_info)
return rc;
}
int cam_lx7_soc_resources_disable(struct cam_hw_soc_info *soc_info)
int cam_icp_soc_resources_disable(struct cam_hw_soc_info *soc_info)
{
int rc = 0;
@@ -158,7 +199,7 @@ int cam_lx7_soc_resources_disable(struct cam_hw_soc_info *soc_info)
return rc;
}
int cam_lx7_update_clk_rate(struct cam_hw_soc_info *soc_info,
int cam_icp_soc_update_clk_rate(struct cam_hw_soc_info *soc_info,
int32_t clk_level)
{
int32_t src_clk_idx = 0;
@@ -166,7 +207,7 @@ int cam_lx7_update_clk_rate(struct cam_hw_soc_info *soc_info,
int rc = 0;
if (!soc_info) {
CAM_ERR(CAM_ICP, "Invalid args");
CAM_ERR(CAM_ICP, "Invalid soc_info");
return -EINVAL;
}

View File

@@ -0,0 +1,64 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef CAM_ICP_SOC_COMMON_H
#define CAM_ICP_SOC_COMMON_H
#include "cam_soc_util.h"
#include "cam_icp_hw_intf.h"
#define ICP_UBWC_CFG_MAX 2
#define CAM_ICP_V1_VERSION 0x0100
#define CAM_ICP_V2_VERSION 0x0200
/**
* struct cam_icp_ubwc_cfg - ICP ubwc cfg
* @ipe_fetch: UBWC configuration for IPE fetch.
* @ipe_write: UBWC configuration for IPE write.
* @bps_fetch: UBWC configuration for BPS fetch.
* @bps_write: UBWC configuration for BPS write.
*/
struct cam_icp_ubwc_cfg {
uint32_t ipe_fetch[ICP_UBWC_CFG_MAX];
uint32_t ipe_write[ICP_UBWC_CFG_MAX];
uint32_t bps_fetch[ICP_UBWC_CFG_MAX];
uint32_t bps_write[ICP_UBWC_CFG_MAX];
};
/**
* struct cam_icp_soc_info - ICP soc info
* @dev_type: Device type.
* @qos_val: QOS value.
* @hw_version: hw version.
* @uconfig: union of ubwc_cfg_ext and ubwc_cfg. ubwc_cfg may
* be used in icp_v1 for older chipsets. icp_v2 only
* uses ubwc_cfg_ext.
* @is_ubwc_cfg: indicate if ubwc_cfg is used.
*/
struct cam_icp_soc_info {
enum cam_icp_hw_type dev_type;
uint32_t qos_val;
uint32_t hw_version;
union {
uint32_t ubwc_cfg[ICP_UBWC_CFG_MAX];
struct cam_icp_ubwc_cfg ubwc_cfg_ext;
} uconfig;
bool is_ubwc_cfg;
};
int cam_icp_soc_resources_init(struct cam_hw_soc_info *soc_info,
irq_handler_t irq_handler, void *irq_data);
int cam_icp_soc_resources_deinit(struct cam_hw_soc_info *soc_info);
int cam_icp_soc_resources_enable(struct cam_hw_soc_info *soc_info);
int cam_icp_soc_resources_disable(struct cam_hw_soc_info *soc_info);
int cam_icp_soc_update_clk_rate(struct cam_hw_soc_info *soc_info,
int32_t clk_level);
#endif

View File

@@ -15,82 +15,71 @@
#include <media/cam_icp.h>
#include "cam_io_util.h"
#include "cam_a5_hw_intf.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
#include "a5_core.h"
#include "a5_reg.h"
#include "a5_soc.h"
#include "cam_icp_v1_core.h"
#include "cam_icp_v1_reg.h"
#include "cam_soc_util.h"
#include "cam_io_util.h"
#include "hfi_intf.h"
#include "hfi_sys_defs.h"
#include "cam_icp_hw_mgr_intf.h"
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
#include "cam_icp_utils.h"
#include "cam_icp_proc_common.h"
#include "cam_common_util.h"
#include "cam_compat.h"
#include "cam_icp_soc_common.h"
#define PC_POLL_DELAY_US 100
#define PC_POLL_TIMEOUT_US 10000
static const struct hfi_ops hfi_icp_v1_ops = {
.irq_raise = cam_icp_v1_irq_raise,
.irq_enable = cam_icp_v1_irq_enable,
.iface_addr = cam_icp_v1_iface_addr,
};
#define A5_GEN_PURPOSE_REG_OFFSET 0x40
static int cam_a5_cpas_vote(struct cam_a5_device_core_info *core_info,
static int cam_icp_v1_cpas_vote(struct cam_icp_v1_device_core_info *core_info,
struct cam_icp_cpas_vote *cpas_vote)
{
int rc = 0;
if (!core_info)
return -EINVAL;
if (cpas_vote->ahb_vote_valid)
rc = cam_cpas_update_ahb_vote(core_info->cpas_handle,
&cpas_vote->ahb_vote);
if (cpas_vote->axi_vote_valid)
rc = cam_cpas_update_axi_vote(core_info->cpas_handle,
&cpas_vote->axi_vote);
if (rc)
CAM_ERR(CAM_ICP, "cpas vote is failed: %d", rc);
return rc;
return cam_icp_proc_cpas_vote(core_info->cpas_handle, cpas_vote);
}
static int32_t cam_a5_download_fw(void *device_priv)
static int32_t cam_icp_v1_download_fw(void *device_priv)
{
int32_t rc = 0;
uint32_t fw_size;
const uint8_t *fw_start = NULL;
struct cam_hw_info *a5_dev = device_priv;
struct cam_hw_info *icp_v1_dev = device_priv;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_a5_device_core_info *core_info = NULL;
struct cam_a5_device_hw_info *hw_info = NULL;
struct cam_icp_v1_device_core_info *core_info = NULL;
struct platform_device *pdev = NULL;
struct a5_soc_info *cam_a5_soc_info = NULL;
const char *firmware_name = NULL;
if (!device_priv) {
CAM_ERR(CAM_ICP, "Invalid cam_dev_info");
return -EINVAL;
}
soc_info = &a5_dev->soc_info;
core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
hw_info = core_info->a5_hw_info;
soc_info = &icp_v1_dev->soc_info;
core_info = (struct cam_icp_v1_device_core_info *)icp_v1_dev->core_info;
pdev = soc_info->pdev;
cam_a5_soc_info = soc_info->soc_private;
if (cam_a5_soc_info->fw_name) {
CAM_INFO(CAM_ICP, "Downloading firmware %s",
cam_a5_soc_info->fw_name);
rc = of_property_read_string(pdev->dev.of_node, "fw_name", &firmware_name);
if (rc) {
CAM_INFO(CAM_ICP,
"FW image name not found. Use default name: CAMERA_ICP.elf");
rc = firmware_request_nowarn(&core_info->fw_elf,
cam_a5_soc_info->fw_name, &pdev->dev);
"CAMERA_ICP.elf", &pdev->dev);
if (rc) {
CAM_ERR(CAM_ICP, "Failed to locate fw: %d", rc);
return rc;
}
} else {
CAM_INFO(CAM_ICP, "Downloading firmware %s",
firmware_name);
rc = firmware_request_nowarn(&core_info->fw_elf,
"CAMERA_ICP.elf", &pdev->dev);
firmware_name, &pdev->dev);
if (rc) {
CAM_ERR(CAM_ICP, "Failed to locate fw: %d", rc);
return rc;
@@ -134,9 +123,9 @@ fw_download_failed:
return rc;
}
static int cam_a5_fw_dump(
static int cam_icp_v1_fw_dump(
struct cam_icp_hw_dump_args *dump_args,
struct cam_a5_device_core_info *core_info)
struct cam_icp_v1_device_core_info *core_info)
{
u8 *dest;
u8 *src;
@@ -181,44 +170,25 @@ static int cam_a5_fw_dump(
return 0;
}
static int cam_a5_fw_mini_dump(
struct cam_icp_hw_dump_args *dump_args,
struct cam_a5_device_core_info *core_info)
static int cam_icp_v1_fw_mini_dump(struct cam_icp_hw_dump_args *dump_args,
struct cam_icp_v1_device_core_info *core_info)
{
u8 *dest;
u8 *src;
if (!core_info || !dump_args) {
CAM_ERR(CAM_ICP, "invalid params %pK %pK", core_info, dump_args);
if (!core_info) {
CAM_ERR(CAM_ICP, "Invalid param %pK", core_info);
return -EINVAL;
}
if (!core_info->fw_kva_addr || !dump_args->cpu_addr) {
CAM_ERR(CAM_ICP, "invalid params %pK, 0x%zx", core_info->fw_kva_addr,
dump_args->cpu_addr);
return -EINVAL;
return cam_icp_proc_mini_dump(dump_args, core_info->fw_kva_addr,
core_info->fw_buf_len);
}
if (dump_args->buf_len < core_info->fw_buf_len) {
CAM_WARN(CAM_ICP, "Insufficient Len %lu fw_len %llu",
dump_args->buf_len, core_info->fw_buf_len);
return -ENOSPC;
}
dest = (u8 *)dump_args->cpu_addr;
src = (u8 *)core_info->fw_kva_addr;
memcpy_fromio(dest, src, core_info->fw_buf_len);
dump_args->offset = core_info->fw_buf_len;
return 0;
}
int cam_a5_init_hw(void *device_priv,
int cam_icp_v1_init_hw(void *device_priv,
void *init_hw_args, uint32_t arg_size)
{
struct cam_hw_info *a5_dev = device_priv;
struct cam_hw_info *icp_v1_dev = device_priv;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_a5_device_core_info *core_info = NULL;
struct a5_soc_info *a5_soc_info;
struct cam_icp_v1_device_core_info *core_info = NULL;
struct cam_icp_soc_info *icp_v1_soc_info;
struct cam_icp_cpas_vote cpas_vote;
unsigned long flags;
int rc = 0;
@@ -229,8 +199,8 @@ int cam_a5_init_hw(void *device_priv,
return -EINVAL;
}
soc_info = &a5_dev->soc_info;
core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
soc_info = &icp_v1_dev->soc_info;
core_info = (struct cam_icp_v1_device_core_info *)icp_v1_dev->core_info;
if ((!soc_info) || (!core_info)) {
CAM_ERR(CAM_ICP, "soc_info: %pK core_info: %pK",
@@ -238,14 +208,14 @@ int cam_a5_init_hw(void *device_priv,
return -EINVAL;
}
spin_lock_irqsave(&a5_dev->hw_lock, flags);
if (a5_dev->hw_state == CAM_HW_STATE_POWER_UP) {
spin_unlock_irqrestore(&a5_dev->hw_lock, flags);
spin_lock_irqsave(&icp_v1_dev->hw_lock, flags);
if (icp_v1_dev->hw_state == CAM_HW_STATE_POWER_UP) {
spin_unlock_irqrestore(&icp_v1_dev->hw_lock, flags);
return 0;
}
spin_unlock_irqrestore(&a5_dev->hw_lock, flags);
spin_unlock_irqrestore(&icp_v1_dev->hw_lock, flags);
a5_soc_info = soc_info->soc_private;
icp_v1_soc_info = soc_info->soc_private;
cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
cpas_vote.ahb_vote.vote.level = CAM_LOWSVS_VOTE;
@@ -273,7 +243,7 @@ int cam_a5_init_hw(void *device_priv,
}
core_info->cpas_start = true;
rc = cam_a5_enable_soc_resources(soc_info);
rc = cam_icp_soc_resources_enable(soc_info);
if (rc) {
CAM_ERR(CAM_ICP, "soc enable is failed: %d", rc);
if (cam_cpas_stop(core_info->cpas_handle))
@@ -281,11 +251,11 @@ int cam_a5_init_hw(void *device_priv,
else
core_info->cpas_start = false;
} else {
CAM_DBG(CAM_ICP, "a5_qos %d", a5_soc_info->a5_qos_val);
if (a5_soc_info->a5_qos_val)
cam_io_w_mb(a5_soc_info->a5_qos_val,
soc_info->reg_map[A5_SIERRA_BASE].mem_base +
ICP_SIERRA_A5_CSR_ACCESS);
CAM_DBG(CAM_ICP, "icp_v1_qos %d", icp_v1_soc_info->qos_val);
if (icp_v1_soc_info->qos_val)
cam_io_w_mb(icp_v1_soc_info->qos_val,
soc_info->reg_map[ICP_V1_BASE].mem_base +
ICP_V1_CSR_ACCESS);
if (send_freq_info) {
int32_t clk_rate = 0;
@@ -294,20 +264,20 @@ int cam_a5_init_hw(void *device_priv,
}
}
spin_lock_irqsave(&a5_dev->hw_lock, flags);
a5_dev->hw_state = CAM_HW_STATE_POWER_UP;
spin_unlock_irqrestore(&a5_dev->hw_lock, flags);
spin_lock_irqsave(&icp_v1_dev->hw_lock, flags);
icp_v1_dev->hw_state = CAM_HW_STATE_POWER_UP;
spin_unlock_irqrestore(&icp_v1_dev->hw_lock, flags);
error:
return rc;
}
int cam_a5_deinit_hw(void *device_priv,
int cam_icp_v1_deinit_hw(void *device_priv,
void *init_hw_args, uint32_t arg_size)
{
struct cam_hw_info *a5_dev = device_priv;
struct cam_hw_info *icp_v1_dev = device_priv;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_a5_device_core_info *core_info = NULL;
struct cam_icp_v1_device_core_info *core_info = NULL;
unsigned long flags;
int rc = 0;
bool send_freq_info = (init_hw_args == NULL) ? false : *((bool *)init_hw_args);
@@ -317,25 +287,26 @@ int cam_a5_deinit_hw(void *device_priv,
return -EINVAL;
}
soc_info = &a5_dev->soc_info;
core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
soc_info = &icp_v1_dev->soc_info;
core_info = (struct cam_icp_v1_device_core_info *)icp_v1_dev->core_info;
if ((!soc_info) || (!core_info)) {
CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK",
soc_info, core_info);
return -EINVAL;
}
spin_lock_irqsave(&a5_dev->hw_lock, flags);
if (a5_dev->hw_state == CAM_HW_STATE_POWER_DOWN) {
spin_unlock_irqrestore(&a5_dev->hw_lock, flags);
spin_lock_irqsave(&icp_v1_dev->hw_lock, flags);
if (icp_v1_dev->hw_state == CAM_HW_STATE_POWER_DOWN) {
spin_unlock_irqrestore(&icp_v1_dev->hw_lock, flags);
return 0;
}
spin_unlock_irqrestore(&a5_dev->hw_lock, flags);
spin_unlock_irqrestore(&icp_v1_dev->hw_lock, flags);
if (send_freq_info)
hfi_send_freq_info(0);
rc = cam_a5_disable_soc_resources(soc_info);
rc = cam_icp_soc_resources_disable(soc_info);
if (rc)
CAM_ERR(CAM_ICP, "soc disable is failed: %d", rc);
@@ -346,56 +317,56 @@ int cam_a5_deinit_hw(void *device_priv,
core_info->cpas_start = false;
}
spin_lock_irqsave(&a5_dev->hw_lock, flags);
a5_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
spin_unlock_irqrestore(&a5_dev->hw_lock, flags);
spin_lock_irqsave(&icp_v1_dev->hw_lock, flags);
icp_v1_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
spin_unlock_irqrestore(&icp_v1_dev->hw_lock, flags);
return rc;
}
static int cam_a5_power_resume(struct cam_hw_info *a5_info, bool debug_enabled)
static int cam_icp_v1_power_resume(struct cam_hw_info *icp_v1_info, bool debug_enabled)
{
uint32_t val = A5_CSR_FULL_CPU_EN;
uint32_t val = ICP_V1_CSR_FULL_CPU_EN;
void __iomem *base;
struct cam_hw_soc_info *soc_info = NULL;
struct a5_soc_info *a5_soc_info;
struct cam_icp_soc_info *icp_v1_soc_info;
if (!a5_info) {
CAM_ERR(CAM_ICP, "invalid A5 device info");
if (!icp_v1_info) {
CAM_ERR(CAM_ICP, "Invalid ICP device info");
return -EINVAL;
}
base = a5_info->soc_info.reg_map[A5_SIERRA_BASE].mem_base;
soc_info = &a5_info->soc_info;
a5_soc_info = soc_info->soc_private;
base = icp_v1_info->soc_info.reg_map[ICP_V1_BASE].mem_base;
soc_info = &icp_v1_info->soc_info;
icp_v1_soc_info = soc_info->soc_private;
cam_io_w_mb(A5_CSR_A5_CPU_EN, base + ICP_SIERRA_A5_CSR_A5_CONTROL);
cam_io_w_mb(A5_CSR_FUNC_RESET, base + ICP_SIERRA_A5_CSR_NSEC_RESET);
cam_io_w_mb(ICP_V1_CSR_CPU_EN, base + ICP_V1_CSR_CONTROL);
cam_io_w_mb(ICP_V1_CSR_FUNC_RESET, base + ICP_V1_CSR_NSEC_RESET);
if (debug_enabled)
val |= A5_CSR_FULL_DBG_EN;
val |= ICP_V1_CSR_FULL_DBG_EN;
cam_io_w_mb(val, base + ICP_SIERRA_A5_CSR_A5_CONTROL);
cam_io_w_mb(a5_soc_info->a5_qos_val,
base + ICP_SIERRA_A5_CSR_ACCESS);
cam_io_w_mb(val, base + ICP_V1_CSR_CONTROL);
cam_io_w_mb(icp_v1_soc_info->qos_val,
base + ICP_V1_CSR_ACCESS);
CAM_DBG(CAM_ICP, "a5 qos-val : 0x%x",
cam_io_r_mb(base + ICP_SIERRA_A5_CSR_ACCESS));
CAM_DBG(CAM_ICP, "icp_v1 qos-val : 0x%x",
cam_io_r_mb(base + ICP_V1_CSR_ACCESS));
return 0;
}
static int cam_a5_power_collapse(struct cam_hw_info *a5_info)
static int cam_icp_v1_power_collapse(struct cam_hw_info *icp_v1_info)
{
uint32_t val, status = 0;
void __iomem *base;
if (!a5_info) {
CAM_ERR(CAM_ICP, "invalid A5 device info");
if (!icp_v1_info) {
CAM_ERR(CAM_ICP, "invalid ICP device info");
return -EINVAL;
}
base = a5_info->soc_info.reg_map[A5_SIERRA_BASE].mem_base;
base = icp_v1_info->soc_info.reg_map[ICP_V1_BASE].mem_base;
/**
* Need to poll here to confirm that FW has triggered WFI
@@ -404,107 +375,106 @@ static int cam_a5_power_collapse(struct cam_hw_info *a5_info)
*/
if (cam_common_read_poll_timeout(base +
ICP_SIERRA_A5_CSR_A5_STATUS,
ICP_V1_CSR_STATUS,
PC_POLL_DELAY_US, PC_POLL_TIMEOUT_US,
A5_CSR_A5_STANDBYWFI,
A5_CSR_A5_STANDBYWFI, &status)) {
ICP_V1_CSR_STANDBYWFI,
ICP_V1_CSR_STANDBYWFI, &status)) {
CAM_ERR(CAM_ICP, "WFI poll timed out: status=0x%08x", status);
return -ETIMEDOUT;
}
val = cam_io_r(base + ICP_SIERRA_A5_CSR_A5_CONTROL);
val &= ~(A5_CSR_A5_CPU_EN | A5_CSR_WAKE_UP_EN);
cam_io_w_mb(val, base + ICP_SIERRA_A5_CSR_A5_CONTROL);
val = cam_io_r(base + ICP_V1_CSR_CONTROL);
val &= ~(ICP_V1_CSR_CPU_EN | ICP_V1_CSR_WAKE_UP_EN);
cam_io_w_mb(val, base + ICP_V1_CSR_CONTROL);
return 0;
}
static void prepare_boot(struct cam_hw_info *a5_dev,
static void prepare_boot(struct cam_hw_info *icp_v1_dev,
struct cam_icp_boot_args *args)
{
struct cam_a5_device_core_info *core_info = a5_dev->core_info;
struct cam_icp_v1_device_core_info *core_info = icp_v1_dev->core_info;
unsigned long flags;
core_info->fw_buf = args->firmware.iova;
core_info->fw_kva_addr = args->firmware.kva;
core_info->fw_buf_len = args->firmware.len;
spin_lock_irqsave(&a5_dev->hw_lock, flags);
spin_lock_irqsave(&icp_v1_dev->hw_lock, flags);
core_info->irq_cb.data = args->irq_cb.data;
core_info->irq_cb.cb = args->irq_cb.cb;
spin_unlock_irqrestore(&a5_dev->hw_lock, flags);
spin_unlock_irqrestore(&icp_v1_dev->hw_lock, flags);
}
static void prepare_shutdown(struct cam_hw_info *a5_dev)
static void prepare_shutdown(struct cam_hw_info *icp_v1_dev)
{
struct cam_a5_device_core_info *core_info = a5_dev->core_info;
struct cam_icp_v1_device_core_info *core_info = icp_v1_dev->core_info;
unsigned long flags;
core_info->fw_buf = 0;
core_info->fw_kva_addr = 0;
core_info->fw_buf_len = 0;
spin_lock_irqsave(&a5_dev->hw_lock, flags);
spin_lock_irqsave(&icp_v1_dev->hw_lock, flags);
core_info->irq_cb.data = NULL;
core_info->irq_cb.cb = NULL;
spin_unlock_irqrestore(&a5_dev->hw_lock, flags);
spin_unlock_irqrestore(&icp_v1_dev->hw_lock, flags);
}
static int cam_a5_boot(struct cam_hw_info *a5_dev,
static int cam_icp_v1_boot(struct cam_hw_info *icp_v1_dev,
struct cam_icp_boot_args *args, size_t arg_size)
{
int rc;
if (!a5_dev || !args) {
if (!icp_v1_dev || !args) {
CAM_ERR(CAM_ICP,
"invalid args: a5_dev=%pK args=%pK",
a5_dev, args);
"Invalid args: icp_v1_dev=%pK args=%pK",
icp_v1_dev, args);
return -EINVAL;
}
if (arg_size != sizeof(struct cam_icp_boot_args)) {
CAM_ERR(CAM_ICP, "invalid boot args size");
CAM_ERR(CAM_ICP, "Invalid boot args size");
return -EINVAL;
}
prepare_boot(a5_dev, args);
prepare_boot(icp_v1_dev, args);
rc = cam_a5_download_fw(a5_dev);
rc = cam_icp_v1_download_fw(icp_v1_dev);
if (rc) {
CAM_ERR(CAM_ICP, "firmware download failed rc=%d", rc);
goto err;
}
rc = cam_a5_power_resume(a5_dev, args->debug_enabled);
rc = cam_icp_v1_power_resume(icp_v1_dev, args->debug_enabled);
if (rc) {
CAM_ERR(CAM_ICP, "A5 boot failed rc=%d", rc);
CAM_ERR(CAM_ICP, "ICP boot failed rc=%d", rc);
goto err;
}
return 0;
err:
prepare_shutdown(a5_dev);
prepare_shutdown(icp_v1_dev);
return rc;
}
static int cam_a5_shutdown(struct cam_hw_info *a5_dev)
static int cam_icp_v1_shutdown(struct cam_hw_info *icp_v1_dev)
{
if (!a5_dev) {
CAM_ERR(CAM_ICP, "invalid A5 device info");
if (!icp_v1_dev) {
CAM_ERR(CAM_ICP, "invalid ICP device info");
return -EINVAL;
}
prepare_shutdown(a5_dev);
cam_a5_power_collapse(a5_dev);
prepare_shutdown(icp_v1_dev);
cam_icp_v1_power_collapse(icp_v1_dev);
return 0;
}
irqreturn_t cam_a5_irq(int irq_num, void *data)
irqreturn_t cam_icp_v1_irq(int irq_num, void *data)
{
struct cam_hw_info *a5_dev = data;
struct cam_hw_info *icp_v1_dev = data;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_a5_device_core_info *core_info = NULL;
struct cam_a5_device_hw_info *hw_info = NULL;
struct cam_icp_v1_device_core_info *core_info = NULL;
uint32_t irq_status = 0;
bool recover = false;
@@ -513,95 +483,98 @@ irqreturn_t cam_a5_irq(int irq_num, void *data)
return IRQ_HANDLED;
}
spin_lock(&a5_dev->hw_lock);
if (a5_dev->hw_state == CAM_HW_STATE_POWER_DOWN) {
spin_lock(&icp_v1_dev->hw_lock);
if (icp_v1_dev->hw_state == CAM_HW_STATE_POWER_DOWN) {
CAM_WARN(CAM_ICP, "ICP HW powered off");
spin_unlock(&a5_dev->hw_lock);
spin_unlock(&icp_v1_dev->hw_lock);
return IRQ_HANDLED;
}
spin_unlock(&a5_dev->hw_lock);
spin_unlock(&icp_v1_dev->hw_lock);
soc_info = &a5_dev->soc_info;
core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
hw_info = core_info->a5_hw_info;
soc_info = &icp_v1_dev->soc_info;
core_info = (struct cam_icp_v1_device_core_info *)icp_v1_dev->core_info;
irq_status = cam_io_r_mb(soc_info->reg_map[A5_SIERRA_BASE].mem_base +
core_info->a5_hw_info->a5_host_int_status);
irq_status = cam_io_r_mb(soc_info->reg_map[ICP_V1_BASE].mem_base +
ICP_V1_HOST_INT_STATUS);
cam_io_w_mb(irq_status,
soc_info->reg_map[A5_SIERRA_BASE].mem_base +
core_info->a5_hw_info->a5_host_int_clr);
soc_info->reg_map[ICP_V1_BASE].mem_base + ICP_V1_HOST_INT_CLR);
if ((irq_status & A5_WDT_0) ||
(irq_status & A5_WDT_1)) {
CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5");
if ((irq_status & ICP_V1_WDT_0) ||
(irq_status & ICP_V1_WDT_1)) {
CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from ICP");
recover = true;
}
spin_lock(&a5_dev->hw_lock);
spin_lock(&icp_v1_dev->hw_lock);
if (core_info->irq_cb.cb)
core_info->irq_cb.cb(core_info->irq_cb.data,
recover);
spin_unlock(&a5_dev->hw_lock);
core_info->irq_cb.cb(core_info->irq_cb.data, recover);
spin_unlock(&icp_v1_dev->hw_lock);
return IRQ_HANDLED;
}
void cam_a5_irq_raise(void *priv)
void cam_icp_v1_irq_raise(void *priv)
{
struct cam_hw_info *a5_info = priv;
struct cam_hw_info *icp_v1_info = priv;
if (!a5_info) {
CAM_ERR(CAM_ICP, "invalid A5 device info");
if (!icp_v1_info) {
CAM_ERR(CAM_ICP, "invalid ICP device info");
return;
}
cam_io_w_mb(A5_HOSTINT,
a5_info->soc_info.reg_map[A5_SIERRA_BASE].mem_base +
ICP_SIERRA_A5_CSR_HOST2ICPINT);
cam_io_w_mb(ICP_V1_HOSTINT,
icp_v1_info->soc_info.reg_map[ICP_V1_BASE].mem_base +
ICP_V1_CSR_HOST2ICPINT);
}
void cam_a5_irq_enable(void *priv)
void cam_icp_v1_irq_enable(void *priv)
{
struct cam_hw_info *a5_info = priv;
struct cam_hw_info *icp_v1_info = priv;
if (!a5_info) {
CAM_ERR(CAM_ICP, "invalid A5 device info");
if (!icp_v1_info) {
CAM_ERR(CAM_ICP, "invalid ICP device info");
return;
}
cam_io_w_mb(A5_WDT_WS0EN | A5_A2HOSTINTEN,
a5_info->soc_info.reg_map[A5_SIERRA_BASE].mem_base +
ICP_SIERRA_A5_CSR_A2HOSTINTEN);
cam_io_w_mb(ICP_V1_WDT_WS0EN | ICP_V1_A2HOSTINTEN,
icp_v1_info->soc_info.reg_map[ICP_V1_BASE].mem_base +
ICP_V1_CSR_A2HOSTINTEN);
}
void __iomem *cam_a5_iface_addr(void *priv)
void __iomem *cam_icp_v1_iface_addr(void *priv)
{
struct cam_hw_info *a5_info = priv;
struct cam_hw_info *icp_v1_info = priv;
void __iomem *base;
if (!a5_info) {
CAM_ERR(CAM_ICP, "invalid A5 device info");
if (!icp_v1_info) {
CAM_ERR(CAM_ICP, "invalid ICP device info");
return ERR_PTR(-EINVAL);
}
base = a5_info->soc_info.reg_map[A5_SIERRA_BASE].mem_base;
base = icp_v1_info->soc_info.reg_map[ICP_V1_BASE].mem_base;
return base + A5_GEN_PURPOSE_REG_OFFSET;
return base + ICP_V1_GEN_PURPOSE_REG_OFFSET;
}
int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
void cam_icp_v1_populate_hfi_ops(const struct hfi_ops **hfi_proc_ops)
{
if (!hfi_proc_ops) {
CAM_ERR(CAM_ICP, "Invalid hfi ops argument");
return;
}
*hfi_proc_ops = &hfi_icp_v1_ops;
}
int cam_icp_v1_process_cmd(void *device_priv, uint32_t cmd_type,
void *cmd_args, uint32_t arg_size)
{
struct cam_hw_info *a5_dev = device_priv;
struct cam_hw_info *icp_v1_dev = device_priv;
struct cam_hw_soc_info *soc_info = NULL;
struct cam_a5_device_core_info *core_info = NULL;
struct cam_a5_device_hw_info *hw_info = NULL;
struct a5_soc_info *a5_soc = NULL;
uint32_t ubwc_ipe_cfg[ICP_UBWC_MAX] = {0};
uint32_t ubwc_bps_cfg[ICP_UBWC_MAX] = {0};
uint32_t index = 0;
int rc = 0, ddr_type = 0;
struct cam_icp_v1_device_core_info *core_info = NULL;
struct cam_icp_soc_info *icp_soc_info = NULL;
int rc = 0;
if (!device_priv) {
CAM_ERR(CAM_ICP, "Invalid arguments");
@@ -613,22 +586,21 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
return -EINVAL;
}
soc_info = &a5_dev->soc_info;
core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
hw_info = core_info->a5_hw_info;
soc_info = &icp_v1_dev->soc_info;
core_info = (struct cam_icp_v1_device_core_info *)icp_v1_dev->core_info;
switch (cmd_type) {
case CAM_ICP_CMD_PROC_SHUTDOWN:
rc = cam_a5_shutdown(device_priv);
rc = cam_icp_v1_shutdown(device_priv);
break;
case CAM_ICP_CMD_PROC_BOOT:
rc = cam_a5_boot(device_priv, cmd_args, arg_size);
rc = cam_icp_v1_boot(device_priv, cmd_args, arg_size);
break;
case CAM_ICP_CMD_POWER_COLLAPSE:
rc = cam_a5_power_collapse(a5_dev);
rc = cam_icp_v1_power_collapse(icp_v1_dev);
break;
case CAM_ICP_CMD_POWER_RESUME:
rc = cam_a5_power_resume(a5_dev, *((bool *)cmd_args));
rc = cam_icp_v1_power_resume(icp_v1_dev, *((bool *)cmd_args));
break;
case CAM_ICP_SEND_INIT:
hfi_send_system_cmd(HFI_CMD_SYS_INIT, 0, 0);
@@ -646,7 +618,7 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
return -EINVAL;
}
cam_a5_cpas_vote(core_info, cpas_vote);
cam_icp_v1_cpas_vote(core_info, cpas_vote);
break;
}
@@ -674,12 +646,11 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
}
break;
case CAM_ICP_CMD_UBWC_CFG: {
struct a5_ubwc_cfg_ext *ubwc_cfg_ext = NULL;
uint32_t *disable_ubwc_comp;
uint32_t disable_ubwc_comp;
a5_soc = soc_info->soc_private;
if (!a5_soc) {
CAM_ERR(CAM_ICP, "A5 private soc info is NULL");
icp_soc_info = soc_info->soc_private;
if (!icp_soc_info) {
CAM_ERR(CAM_ICP, "ICP private soc info is NULL");
return -EINVAL;
}
@@ -687,37 +658,13 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
CAM_ERR(CAM_ICP, "Invalid args");
return -EINVAL;
}
disable_ubwc_comp = *((uint32_t *)cmd_args);
disable_ubwc_comp = (uint32_t *)cmd_args;
if (a5_soc->ubwc_config_ext) {
/* Invoke kernel API to determine DDR type */
ddr_type = cam_get_ddr_type();
if ((ddr_type == DDR_TYPE_LPDDR5) ||
(ddr_type == DDR_TYPE_LPDDR5X))
index = 1;
ubwc_cfg_ext = &a5_soc->uconfig.ubwc_cfg_ext;
ubwc_ipe_cfg[0] =
ubwc_cfg_ext->ubwc_ipe_fetch_cfg[index];
ubwc_ipe_cfg[1] =
ubwc_cfg_ext->ubwc_ipe_write_cfg[index];
ubwc_bps_cfg[0] =
ubwc_cfg_ext->ubwc_bps_fetch_cfg[index];
ubwc_bps_cfg[1] =
ubwc_cfg_ext->ubwc_bps_write_cfg[index];
if (*disable_ubwc_comp) {
ubwc_ipe_cfg[1] &= ~CAM_ICP_UBWC_COMP_EN;
ubwc_bps_cfg[1] &= ~CAM_ICP_UBWC_COMP_EN;
CAM_DBG(CAM_ICP,
"Force disable UBWC compression, ubwc_ipe_cfg: 0x%x, ubwc_bps_cfg: 0x%x",
ubwc_ipe_cfg[1], ubwc_bps_cfg[1]);
}
rc = hfi_cmd_ubwc_config_ext(&ubwc_ipe_cfg[0],
&ubwc_bps_cfg[0]);
} else {
rc = hfi_cmd_ubwc_config(a5_soc->uconfig.ubwc_cfg);
}
if (icp_soc_info->is_ubwc_cfg)
rc = hfi_cmd_ubwc_config(icp_soc_info->uconfig.ubwc_cfg);
else
rc = cam_icp_proc_ubwc_configure(icp_soc_info->uconfig.ubwc_cfg_ext,
disable_ubwc_comp);
break;
}
@@ -733,7 +680,7 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
clk_level = *((int32_t *)cmd_args);
CAM_DBG(CAM_ICP,
"Update ICP clock to level [%d]", clk_level);
rc = cam_a5_update_clk_rate(soc_info, clk_level);
rc = cam_icp_soc_update_clk_rate(soc_info, clk_level);
if (rc)
CAM_ERR(CAM_ICP,
"Failed to update clk to level: %d rc: %d",
@@ -748,14 +695,14 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
case CAM_ICP_CMD_HW_DUMP: {
struct cam_icp_hw_dump_args *dump_args = cmd_args;
rc = cam_a5_fw_dump(dump_args, core_info);
rc = cam_icp_v1_fw_dump(dump_args, core_info);
break;
}
case CAM_ICP_CMD_HW_MINI_DUMP: {
struct cam_icp_hw_dump_args *dump_args = cmd_args;
rc = cam_a5_fw_mini_dump(dump_args, core_info);
rc = cam_icp_v1_fw_mini_dump(dump_args, core_info);
break;
}
case CAM_ICP_CMD_HW_REG_DUMP: {

View File

@@ -0,0 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef CAM_ICP_V1_CORE_H
#define CAM_ICP_V1_CORE_H
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include "cam_icp_hw_intf.h"
#include "hfi_intf.h"
#define ICP_V1_QGIC_BASE 0
#define ICP_V1_BASE 1
#define ICP_V1_CSR_BASE 2
#define ICP_V1_HOST_INT 0x1
#define ICP_V1_WDT_0 0x2
#define ICP_V1_WDT_1 0x4
#define ICP_V1_CSR_ACCESS 0x3C
#define ELF_GUARD_PAGE (2 * 1024 * 1024)
/**
* struct cam_icp_v1_device_hw_info
* @icp_v1_hw_info: ICP_V1 hardware info
* @fw_elf: start address of fw start with elf header
* @fw: start address of fw blob
* @fw_buf: smmu alloc/mapped fw buffer
* @fw_buf_len: fw buffer length
* @query_cap: ICP_V1 query info from firmware
* @icp_v1_acquire: Acquire information of ICP_V1
* @irq_cb: IRQ callback
* @cpas_handle: CPAS handle for ICP_V1
* @hw_version: hw version of icp v1 processor
* @cpas_start: state variable for cpas
*/
struct cam_icp_v1_device_core_info {
const struct firmware *fw_elf;
void *fw;
uint32_t fw_buf;
uintptr_t fw_kva_addr;
uint64_t fw_buf_len;
struct cam_icp_irq_cb irq_cb;
uint32_t cpas_handle;
bool cpas_start;
};
int cam_icp_v1_init_hw(void *device_priv,
void *init_hw_args, uint32_t arg_size);
int cam_icp_v1_deinit_hw(void *device_priv,
void *init_hw_args, uint32_t arg_size);
int cam_icp_v1_process_cmd(void *device_priv, uint32_t cmd_type,
void *cmd_args, uint32_t arg_size);
irqreturn_t cam_icp_v1_irq(int irq_num, void *data);
void cam_icp_v1_irq_raise(void *priv);
void cam_icp_v1_irq_enable(void *priv);
void __iomem *cam_icp_v1_iface_addr(void *priv);
void cam_icp_v1_populate_hfi_ops(const struct hfi_ops **hfi_proc_ops);
#endif /* CAM_ICP_V1_CORE_H */

View File

@@ -0,0 +1,279 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 "cam_icp_v1_core.h"
#include "cam_io_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
#include "cam_icp_hw_mgr_intf.h"
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
#include "camera_main.h"
#include "cam_icp_soc_common.h"
#include "cam_icp_v1_dev.h"
static int max_icp_v1_hw_idx = -1;
uint32_t cam_icp_v1_get_device_num(void)
{
return max_icp_v1_hw_idx + 1;
}
static bool cam_icp_v1_cpas_cb(uint32_t client_handle, void *userdata,
struct cam_cpas_irq_data *irq_data)
{
bool error_handled = false;
if (!irq_data)
return error_handled;
switch (irq_data->irq_type) {
case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR:
CAM_ERR_RATE_LIMIT(CAM_ICP,
"IPE/BPS UBWC Decode error type=%d status=%x thr_err=%d, fcl_err=%d, len_md_err=%d, format_err=%d",
irq_data->irq_type,
irq_data->u.dec_err.decerr_status.value,
irq_data->u.dec_err.decerr_status.thr_err,
irq_data->u.dec_err.decerr_status.fcl_err,
irq_data->u.dec_err.decerr_status.len_md_err,
irq_data->u.dec_err.decerr_status.format_err);
error_handled = true;
break;
case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR:
CAM_ERR_RATE_LIMIT(CAM_ICP,
"IPE/BPS UBWC Encode error type=%d status=%x",
irq_data->irq_type,
irq_data->u.enc_err.encerr_status.value);
error_handled = true;
break;
default:
break;
}
return error_handled;
}
int cam_icp_v1_register_cpas(struct cam_hw_soc_info *soc_info,
struct cam_icp_v1_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, "icp", sizeof("icp"));
cpas_register_params.cam_cpas_client_cb = cam_icp_v1_cpas_cb;
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_ICP, "failed: %d", rc);
return rc;
}
core_info->cpas_handle = cpas_register_params.client_handle;
return rc;
}
static inline void cam_icp_v1_soc_info_deinit(struct cam_hw_soc_info *soc_info)
{
kfree(soc_info->soc_private);
}
static int cam_icp_v1_soc_info_init(struct cam_hw_soc_info *soc_info,
struct platform_device *pdev)
{
struct cam_icp_soc_info *icp_soc_info = NULL;
icp_soc_info = kzalloc(sizeof(*icp_soc_info), GFP_KERNEL);
if (!icp_soc_info)
return -ENOMEM;
soc_info->pdev = pdev;
soc_info->dev = &pdev->dev;
soc_info->dev_name = pdev->name;
soc_info->soc_private = icp_soc_info;
icp_soc_info->dev_type = CAM_ICP_DEV_ICP_V1;
return 0;
}
static int cam_icp_v1_component_bind(struct device *dev,
struct device *master_dev, void *data)
{
int rc = 0;
struct cam_hw_info *icp_v1_dev = NULL;
struct cam_hw_intf *icp_v1_dev_intf = NULL;
const struct of_device_id *match_dev = NULL;
struct cam_icp_v1_device_core_info *core_info = NULL;
struct platform_device *pdev = to_platform_device(dev);
icp_v1_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
if (!icp_v1_dev_intf)
return -ENOMEM;
of_property_read_u32(pdev->dev.of_node,
"cell-index", &icp_v1_dev_intf->hw_idx);
icp_v1_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
if (!icp_v1_dev) {
rc = -ENOMEM;
goto icp_v1_dev_alloc_failure;
}
icp_v1_dev_intf->hw_priv = icp_v1_dev;
icp_v1_dev_intf->hw_ops.init = cam_icp_v1_init_hw;
icp_v1_dev_intf->hw_ops.deinit = cam_icp_v1_deinit_hw;
icp_v1_dev_intf->hw_ops.process_cmd = cam_icp_v1_process_cmd;
icp_v1_dev_intf->hw_type = CAM_ICP_DEV_ICP_V1;
CAM_DBG(CAM_ICP, "type %d index %d",
icp_v1_dev_intf->hw_type,
icp_v1_dev_intf->hw_idx);
platform_set_drvdata(pdev, icp_v1_dev_intf);
core_info = kzalloc(sizeof(struct cam_icp_v1_device_core_info),
GFP_KERNEL);
if (!core_info) {
rc = -ENOMEM;
goto core_info_alloc_failure;
}
icp_v1_dev->core_info = core_info;
match_dev = of_match_device(pdev->dev.driver->of_match_table,
&pdev->dev);
if (!match_dev) {
CAM_ERR(CAM_ICP, "No icp_v1 hardware info");
rc = -EINVAL;
goto match_err;
}
rc = cam_icp_v1_soc_info_init(&icp_v1_dev->soc_info, pdev);
if (rc)
goto init_soc_failure;
rc = cam_icp_soc_resources_init(&icp_v1_dev->soc_info, cam_icp_v1_irq,
icp_v1_dev);
if (rc < 0) {
CAM_ERR(CAM_ICP, "failed to init_soc");
goto init_soc_failure;
}
rc = cam_icp_v1_register_cpas(&icp_v1_dev->soc_info,
core_info, icp_v1_dev_intf->hw_idx);
if (rc < 0) {
CAM_ERR(CAM_ICP, "icp_v1 cpas registration failed");
goto cpas_reg_failed;
}
icp_v1_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
mutex_init(&icp_v1_dev->hw_mutex);
spin_lock_init(&icp_v1_dev->hw_lock);
init_completion(&icp_v1_dev->hw_complete);
if ((int)(icp_v1_dev_intf->hw_idx) > max_icp_v1_hw_idx)
max_icp_v1_hw_idx = icp_v1_dev_intf->hw_idx;
CAM_DBG(CAM_ICP, "ICP_V1:%u component bound successfully",
icp_v1_dev_intf->hw_idx);
return 0;
cpas_reg_failed:
cam_icp_soc_resources_deinit(&icp_v1_dev->soc_info);
init_soc_failure:
cam_icp_v1_soc_info_deinit(&icp_v1_dev->soc_info);
match_err:
kfree(core_info);
core_info_alloc_failure:
kfree(icp_v1_dev);
icp_v1_dev_alloc_failure:
kfree(icp_v1_dev_intf);
return rc;
}
static void cam_icp_v1_component_unbind(struct device *dev,
struct device *master_dev, void *data)
{
struct cam_hw_info *icp_v1_dev = NULL;
struct cam_hw_intf *icp_v1_dev_intf = NULL;
struct cam_icp_v1_device_core_info *core_info = NULL;
struct platform_device *pdev = to_platform_device(dev);
icp_v1_dev_intf = platform_get_drvdata(pdev);
icp_v1_dev = icp_v1_dev_intf->hw_priv;
core_info = (struct cam_icp_v1_device_core_info *)icp_v1_dev->core_info;
cam_cpas_unregister_client(core_info->cpas_handle);
cam_icp_soc_resources_deinit(&icp_v1_dev->soc_info);
cam_icp_v1_soc_info_deinit(&icp_v1_dev->soc_info);
max_icp_v1_hw_idx = -1;
kfree(icp_v1_dev->core_info);
kfree(icp_v1_dev);
kfree(icp_v1_dev_intf);
}
static const struct component_ops cam_icp_v1_component_ops = {
.bind = cam_icp_v1_component_bind,
.unbind = cam_icp_v1_component_unbind,
};
int cam_icp_v1_probe(struct platform_device *pdev)
{
int rc = 0;
CAM_DBG(CAM_ICP, "Adding ICP_V1 component");
rc = component_add(&pdev->dev, &cam_icp_v1_component_ops);
if (rc)
CAM_ERR(CAM_ICP, "failed to add component rc: %d", rc);
return rc;
}
static int cam_icp_v1_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &cam_icp_v1_component_ops);
return 0;
}
static const struct of_device_id cam_icp_v1_dt_match[] = {
{.compatible = "qcom,cam-icp_v1",},
{},
};
MODULE_DEVICE_TABLE(of, cam_icp_v1_dt_match);
struct platform_driver cam_icp_v1_driver = {
.probe = cam_icp_v1_probe,
.remove = cam_icp_v1_remove,
.driver = {
.name = "cam-icp_v1",
.owner = THIS_MODULE,
.of_match_table = cam_icp_v1_dt_match,
.suppress_bind_attrs = true,
},
};
int cam_icp_v1_init_module(void)
{
return platform_driver_register(&cam_icp_v1_driver);
}
void cam_icp_v1_exit_module(void)
{
platform_driver_unregister(&cam_icp_v1_driver);
}
MODULE_DESCRIPTION("CAM ICP_V1 driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_ICP_V1_DEV_H_
#define _CAM_ICP_V1_DEV_H_
/**
* @brief : API to register icp_v1 hw to platform framework.
* @return struct platform_device pointer on success, or ERR_PTR() on error.
*/
int cam_icp_v1_init_module(void);
/**
* @brief : API to remove icp_v1 hw from platform framework.
*/
void cam_icp_v1_exit_module(void);
#endif /* _CAM_ICP_V1_DEV_H_ */

View File

@@ -0,0 +1,50 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_ICP_V1_REG_H_
#define _CAM_ICP_V1_REG_H_
#define ICP_V1_CSR_NSEC_RESET 0x4
#define ICP_V1_GEN_PURPOSE_REG_OFFSET 0x40
#define ICP_V1_CSR_FUNC_RESET (1 << 4)
#define ICP_V1_CSR_DBG_RESET (1 << 3)
#define ICP_V1_CSR_CPU_RESET (1 << 2)
#define ICP_V1_CSR_CONTROL 0x8
#define ICP_V1_CSR_DBGSWENABLE (1 << 22)
#define ICP_V1_CSR_EDBGRQ (1 << 14)
#define ICP_V1_CSR_EN_CLKGATE_WFI (1 << 12)
#define ICP_V1_CSR_CPU_EN (1 << 9)
#define ICP_V1_CSR_WAKE_UP_EN (1 << 4)
#define ICP_V1_CSR_FULL_DBG_EN (ICP_V1_CSR_DBGSWENABLE | ICP_V1_CSR_EDBGRQ)
#define ICP_V1_CSR_FULL_CPU_EN (ICP_V1_CSR_CPU_EN | \
ICP_V1_CSR_WAKE_UP_EN | \
ICP_V1_CSR_EN_CLKGATE_WFI)
#define ICP_V1_CSR_A2HOSTINTEN 0x10
#define ICP_V1_WDT_WS1EN (1 << 2)
#define ICP_V1_WDT_WS0EN (1 << 1)
#define ICP_V1_A2HOSTINTEN (1 << 0)
#define ICP_V1_CSR_HOST2ICPINT 0x30
#define ICP_V1_HOSTINT (1 << 0)
#define ICP_V1_HOST_INT_CLR 0x18
#define ICP_V1_HOST_INT_STATUS 0x1c
#define ICP_V1_HOST_INT_SET 0x20
#define ICP_V1_CSR_STATUS 0x200
#define ICP_V1_CSR_STANDBYWFI (1 << 7)
#define ICP_V1_INIT_REQ 0x48
#define ICP_V1_INIT_RESPONSE 0x4c
#define ICP_V1_SHARED_MEM_PTR 0x50
#define ICP_V1_SHARED_MEM_SIZE 0x54
#define ICP_V1_QTBL_PTR 0x58
#define ICP_V1_UNCACHED_HEAP_PTR 0x5c
#define ICP_V1_UNCACHED_HEAP_SIZE 0x60
#endif /* _CAM_ICP_V1_REG_H_ */

View File

@@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_ICP_V2_CORE_H_
#define _CAM_ICP_V2_CORE_H_
#include "cam_hw_intf.h"
#include "cam_icp_hw_intf.h"
#include "hfi_intf.h"
#define UNSUPPORTED_PROC_PAS_ID 30
#define CAM_FW_PAS_ID 33
enum cam_icp_v2_reg_base {
ICP_V2_CSR_BASE,
ICP_V2_CIRQ_BASE,
ICP_V2_WD0_BASE,
ICP_V2_SYS_BASE,
ICP_V2_BASE_MAX,
};
struct cam_icp_v2_core_info {
struct cam_icp_irq_cb irq_cb;
uint32_t cpas_handle;
bool cpas_start;
bool use_sec_pil;
bool is_irq_test;
struct {
const struct firmware *fw_elf;
void *fw;
uint32_t fw_buf;
uintptr_t fw_kva_addr;
uint64_t fw_buf_len;
} fw_params;
};
int cam_icp_v2_hw_init(void *priv, void *args, uint32_t arg_size);
int cam_icp_v2_hw_deinit(void *priv, void *args, uint32_t arg_size);
int cam_icp_v2_process_cmd(void *priv, uint32_t cmd_type,
void *args, uint32_t arg_size);
int cam_icp_v2_test_irq_line(void *priv);
int cam_icp_v2_cpas_register(struct cam_hw_intf *icp_v2_intf);
int cam_icp_v2_cpas_unregister(struct cam_hw_intf *icp_v2_intf);
irqreturn_t cam_icp_v2_handle_irq(int irq_num, void *data);
void cam_icp_v2_irq_raise(void *priv);
void cam_icp_v2_irq_enable(void *priv);
void __iomem *cam_icp_v2_iface_addr(void *priv);
void cam_icp_v2_populate_hfi_ops(const struct hfi_ops **hfi_proc_ops);
#endif /* _CAM_ICP_V2_CORE_H_ */

View File

@@ -0,0 +1,195 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of_device.h>
#include "camera_main.h"
#include "cam_debug_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
#include "cam_icp_hw_intf.h"
#include "cam_icp_v2_core.h"
#include "cam_icp_soc_common.h"
static int max_icp_v2_hw_idx = -1;
uint32_t cam_icp_v2_get_device_num(void)
{
return max_icp_v2_hw_idx + 1;
}
static int cam_icp_v2_soc_info_init(struct cam_hw_soc_info *soc_info,
struct platform_device *pdev)
{
struct cam_icp_soc_info *icp_soc_info = NULL;
icp_soc_info = kzalloc(sizeof(*icp_soc_info), GFP_KERNEL);
if (!icp_soc_info)
return -ENOMEM;
soc_info->pdev = pdev;
soc_info->dev = &pdev->dev;
soc_info->dev_name = pdev->name;
soc_info->soc_private = icp_soc_info;
icp_soc_info->dev_type = CAM_ICP_DEV_ICP_V2;
return 0;
}
static inline void cam_icp_v2_soc_info_deinit(struct cam_hw_soc_info *soc_info)
{
kfree(soc_info->soc_private);
}
static int cam_icp_v2_component_bind(struct device *dev,
struct device *mdev, void *data)
{
int rc = 0;
struct cam_hw_intf *icp_v2_intf = NULL;
struct cam_hw_info *icp_v2_info = NULL;
struct cam_icp_v2_core_info *core_info = NULL;
struct platform_device *pdev = to_platform_device(dev);
icp_v2_intf = kzalloc(sizeof(*icp_v2_intf), GFP_KERNEL);
if (!icp_v2_intf)
return -ENOMEM;
icp_v2_info = kzalloc(sizeof(*icp_v2_info), GFP_KERNEL);
if (!icp_v2_info) {
rc = -ENOMEM;
goto free_hw_intf;
}
core_info = kzalloc(sizeof(*core_info), GFP_KERNEL);
if (!core_info) {
rc = -ENOMEM;
goto free_hw_info;
}
icp_v2_info->core_info = core_info;
rc = cam_icp_v2_soc_info_init(&icp_v2_info->soc_info, pdev);
if (rc)
goto free_core_info;
mutex_init(&icp_v2_info->hw_mutex);
spin_lock_init(&icp_v2_info->hw_lock);
init_completion(&icp_v2_info->hw_complete);
rc = cam_icp_soc_resources_init(&icp_v2_info->soc_info,
cam_icp_v2_handle_irq, icp_v2_info);
if (rc) {
CAM_ERR(CAM_ICP, "soc resources init failed rc=%d", rc);
goto free_soc_info;
}
icp_v2_intf->hw_priv = icp_v2_info;
icp_v2_intf->hw_type = CAM_ICP_DEV_ICP_V2;
icp_v2_intf->hw_idx = icp_v2_info->soc_info.index;
icp_v2_intf->hw_ops.init = cam_icp_v2_hw_init;
icp_v2_intf->hw_ops.deinit = cam_icp_v2_hw_deinit;
icp_v2_intf->hw_ops.process_cmd = cam_icp_v2_process_cmd;
icp_v2_intf->hw_ops.test_irq_line = cam_icp_v2_test_irq_line;
rc = cam_icp_v2_cpas_register(icp_v2_intf);
if (rc) {
CAM_ERR(CAM_ICP, "cpas registration failed rc=%d", rc);
goto res_deinit;
}
if ((int)(icp_v2_intf->hw_idx) > max_icp_v2_hw_idx)
max_icp_v2_hw_idx = icp_v2_intf->hw_idx;
platform_set_drvdata(pdev, icp_v2_intf);
return 0;
res_deinit:
cam_icp_soc_resources_deinit(&icp_v2_info->soc_info);
free_soc_info:
cam_icp_v2_soc_info_deinit(&icp_v2_info->soc_info);
free_core_info:
kfree(core_info);
free_hw_info:
kfree(icp_v2_info);
free_hw_intf:
kfree(icp_v2_intf);
return rc;
}
static void cam_icp_v2_component_unbind(struct device *dev,
struct device *mdev, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
struct cam_hw_intf *icp_v2_intf = platform_get_drvdata(pdev);
struct cam_hw_info *icp_v2_info = icp_v2_intf->hw_priv;
cam_icp_v2_cpas_unregister(icp_v2_intf);
cam_icp_soc_resources_deinit(&icp_v2_info->soc_info);
cam_icp_v2_soc_info_deinit(&icp_v2_info->soc_info);
max_icp_v2_hw_idx = -1;
kfree(icp_v2_info->core_info);
kfree(icp_v2_info);
kfree(icp_v2_intf);
}
static const struct component_ops cam_icp_v2_component_ops = {
.bind = cam_icp_v2_component_bind,
.unbind = cam_icp_v2_component_unbind,
};
static const struct of_device_id cam_icp_v2_match[] = {
{ .compatible = "qcom,cam-icp_v2"},
{},
};
MODULE_DEVICE_TABLE(of, cam_icp_v2_match);
static int cam_icp_v2_driver_probe(struct platform_device *pdev)
{
int rc;
rc = component_add(&pdev->dev, &cam_icp_v2_component_ops);
if (rc)
CAM_ERR(CAM_ICP, "cam-icp_v2 component add failed rc=%d", rc);
return rc;
}
static int cam_icp_v2_driver_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &cam_icp_v2_component_ops);
return 0;
}
struct platform_driver cam_icp_v2_driver = {
.probe = cam_icp_v2_driver_probe,
.remove = cam_icp_v2_driver_remove,
.driver = {
.name = "cam-icp_v2",
.of_match_table = cam_icp_v2_match,
.suppress_bind_attrs = true,
},
};
int cam_icp_v2_init_module(void)
{
return platform_driver_register(&cam_icp_v2_driver);
}
void cam_icp_v2_exit_module(void)
{
platform_driver_unregister(&cam_icp_v2_driver);
}
MODULE_DESCRIPTION("Camera ICP_V2 driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_ICP_V2_DEV_H_
#define _CAM_ICP_V2_DEV_H_
int cam_icp_v2_init_module(void);
void cam_icp_v2_exit_module(void);
#endif /* _CAM_ICP_V2_DEV_H_ */

View File

@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_ICP_V2_REG_H_
#define _CAM_ICP_V2_REG_H_
/* ICP CSR info */
#define ICP_V2_GEN_PURPOSE_REG_OFFSET 0x20
#define ICP_V2_CSR_DBG_STATUS_REG_OFFSET 0xC0
#define ICP_V2_CSR_DBG_CTRL_REG_OFFSET 0xC4
#define ICP_V2_CSR_GP_REG_COUNT 0x18
/* ICP_SYS - Protected reg space defined in AC policy */
#define ICP_V2_SYS_RESET 0x0
#define ICP_V2_SYS_CONTROL 0x4
#define ICP_V2_SYS_STATUS 0xC
#define ICP_V2_SYS_ACCESS 0x10
#define ICP_V2_STANDBYWFI (1 << 7)
#define ICP_V2_EN_CPU (1 << 9)
#define ICP_V2_FUNC_RESET (1 << 4)
#define ICP_V2_CIRQ_OB_MASK 0x0
#define ICP_V2_CIRQ_OB_CLEAR 0x4
#define ICP_V2_CIRQ_OB_SET 0x8
#define ICP_V2_CIRQ_OB_STATUS 0xc
/* ICP WD reg space */
#define ICP_V2_WD_CTRL 0x8
#define ICP_V2_WD_INTCLR 0xC
/* These bitfields are shared by OB_MASK, OB_CLEAR, OB_STATUS */
#define ICP_V2_WDT_BITE_WS1 (1 << 6)
#define ICP_V2_WDT_BARK_WS1 (1 << 5)
#define ICP_V2_WDT_BITE_WS0 (1 << 4)
#define ICP_V2_WDT_BARK_WS0 (1 << 3)
#define ICP_V2_ICP2HOSTINT (1 << 2)
#define ICP_V2_CIRQ_OB_IRQ_CMD 0x10
#define ICP_V2_IRQ_CLEAR_CMD (1 << 1)
#define ICP_V2_IRQ_SET_CMD (1 << 0)
#define ICP_V2_CIRQ_IB_STATUS0 0x70
#define ICP_V2_CIRQ_IB_STATUS1 0x74
#define ICP_V2_CIRQ_HOST2ICPINT 0x124
#define ICP_V2_CIRQ_PFAULT_INFO 0x128
#define ICP_V2_HOST2ICPINT (1 << 0)
#endif /* _CAM_ICP_V2_REG_H_ */

View File

@@ -1,54 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_LX7_CORE_H_
#define _CAM_LX7_CORE_H_
#include "cam_hw_intf.h"
#include "cam_icp_hw_intf.h"
#define UNSUPPORTED_PROC_PAS_ID 30
#define CAM_FW_PAS_ID 33
enum cam_lx7_reg_base {
LX7_CSR_BASE,
LX7_CIRQ_BASE,
LX7_WD0_BASE,
LX7_SYS_BASE,
LX7_BASE_MAX,
};
struct cam_lx7_core_info {
struct cam_icp_irq_cb irq_cb;
uint32_t cpas_handle;
bool cpas_start;
bool use_sec_pil;
bool is_irq_test;
struct {
const struct firmware *fw_elf;
void *fw;
uint32_t fw_buf;
uintptr_t fw_kva_addr;
uint64_t fw_buf_len;
} fw_params;
};
int cam_lx7_hw_init(void *priv, void *args, uint32_t arg_size);
int cam_lx7_hw_deinit(void *priv, void *args, uint32_t arg_size);
int cam_lx7_process_cmd(void *priv, uint32_t cmd_type,
void *args, uint32_t arg_size);
int cam_lx7_test_irq_line(void *priv);
int cam_lx7_cpas_register(struct cam_hw_intf *lx7_intf);
int cam_lx7_cpas_unregister(struct cam_hw_intf *lx7_intf);
irqreturn_t cam_lx7_handle_irq(int irq_num, void *data);
void cam_lx7_irq_raise(void *priv);
void cam_lx7_irq_enable(void *priv);
void __iomem *cam_lx7_iface_addr(void *priv);
#endif /* _CAM_LX7_CORE_H_ */

View File

@@ -1,166 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of_device.h>
#include "camera_main.h"
#include "cam_debug_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
#include "cam_icp_hw_intf.h"
#include "lx7_core.h"
#include "lx7_soc.h"
static int cam_lx7_component_bind(struct device *dev,
struct device *mdev, void *data)
{
int rc = 0;
struct cam_hw_intf *lx7_intf = NULL;
struct cam_hw_info *lx7_info = NULL;
struct lx7_soc_info *lx7_soc_info = NULL;
struct cam_lx7_core_info *core_info = NULL;
struct platform_device *pdev = to_platform_device(dev);
lx7_intf = kzalloc(sizeof(*lx7_intf), GFP_KERNEL);
if (!lx7_intf)
return -ENOMEM;
lx7_info = kzalloc(sizeof(*lx7_info), GFP_KERNEL);
if (!lx7_info) {
rc = -ENOMEM;
goto free_hw_intf;
}
lx7_soc_info = kzalloc(sizeof(*lx7_soc_info), GFP_KERNEL);
if (!lx7_soc_info) {
rc = -ENOMEM;
goto free_hw_info;
}
core_info = kzalloc(sizeof(*core_info), GFP_KERNEL);
if (!core_info) {
rc = -ENOMEM;
goto free_soc_info;
}
lx7_info->core_info = core_info;
lx7_info->soc_info.pdev = pdev;
lx7_info->soc_info.dev = &pdev->dev;
lx7_info->soc_info.dev_name = pdev->name;
lx7_info->soc_info.soc_private = lx7_soc_info;
mutex_init(&lx7_info->hw_mutex);
spin_lock_init(&lx7_info->hw_lock);
init_completion(&lx7_info->hw_complete);
rc = cam_lx7_soc_resources_init(&lx7_info->soc_info,
cam_lx7_handle_irq, lx7_info);
if (rc) {
CAM_ERR(CAM_ICP, "soc resources init failed rc=%d", rc);
goto free_core_info;
}
lx7_intf->hw_priv = lx7_info;
lx7_intf->hw_type = CAM_ICP_DEV_LX7;
lx7_intf->hw_idx = lx7_info->soc_info.index;
lx7_intf->hw_ops.init = cam_lx7_hw_init;
lx7_intf->hw_ops.deinit = cam_lx7_hw_deinit;
lx7_intf->hw_ops.process_cmd = cam_lx7_process_cmd;
lx7_intf->hw_ops.test_irq_line = cam_lx7_test_irq_line;
rc = cam_lx7_cpas_register(lx7_intf);
if (rc) {
CAM_ERR(CAM_ICP, "cpas registration failed rc=%d", rc);
goto res_deinit;
}
platform_set_drvdata(pdev, lx7_intf);
return 0;
res_deinit:
cam_lx7_soc_resources_deinit(&lx7_info->soc_info);
free_core_info:
kfree(core_info);
free_soc_info:
kfree(lx7_soc_info);
free_hw_info:
kfree(lx7_info);
free_hw_intf:
kfree(lx7_intf);
return rc;
}
static void cam_lx7_component_unbind(struct device *dev,
struct device *mdev, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
struct cam_hw_intf *lx7_intf = platform_get_drvdata(pdev);
struct cam_hw_info *lx7_info = lx7_intf->hw_priv;
cam_lx7_cpas_unregister(lx7_intf);
cam_lx7_soc_resources_deinit(&lx7_info->soc_info);
kfree(lx7_info->core_info);
kfree(lx7_info->soc_info.soc_private);
kfree(lx7_info);
kfree(lx7_intf);
}
static const struct component_ops cam_lx7_component_ops = {
.bind = cam_lx7_component_bind,
.unbind = cam_lx7_component_unbind,
};
static const struct of_device_id cam_lx7_match[] = {
{ .compatible = "qcom,cam-lx7"},
{},
};
MODULE_DEVICE_TABLE(of, cam_lx7_match);
static int cam_lx7_driver_probe(struct platform_device *pdev)
{
int rc;
rc = component_add(&pdev->dev, &cam_lx7_component_ops);
if (rc)
CAM_ERR(CAM_ICP, "cam-lx7 component add failed rc=%d", rc);
return rc;
}
static int cam_lx7_driver_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &cam_lx7_component_ops);
return 0;
}
struct platform_driver cam_lx7_driver = {
.probe = cam_lx7_driver_probe,
.remove = cam_lx7_driver_remove,
.driver = {
.name = "cam-lx7",
.of_match_table = cam_lx7_match,
.suppress_bind_attrs = true,
},
};
int cam_lx7_init_module(void)
{
return platform_driver_register(&cam_lx7_driver);
}
void cam_lx7_exit_module(void)
{
platform_driver_unregister(&cam_lx7_driver);
}
MODULE_DESCRIPTION("Camera LX7 driver");
MODULE_LICENSE("GPL v2");

View File

@@ -1,12 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_LX7_DEV_H_
#define _CAM_LX7_DEV_H_
int cam_lx7_init_module(void);
void cam_lx7_exit_module(void);
#endif /* _CAM_LX7_DEV_H_ */

View File

@@ -1,52 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_LX7_REG_H_
#define _CAM_LX7_REG_H_
/* ICP CSR info */
#define LX7_GEN_PURPOSE_REG_OFFSET 0x20
#define LX7_CSR_DBG_STATUS_REG_OFFSET 0xC0
#define LX7_CSR_DBG_CTRL_REG_OFFSET 0xC4
#define LX7_CSR_GP_REG_COUNT 0x18
/* ICP_SYS - Protected reg space defined in AC policy */
#define ICP_LX7_SYS_RESET 0x0
#define ICP_LX7_SYS_CONTROL 0x4
#define ICP_LX7_SYS_STATUS 0xC
#define ICP_LX7_SYS_ACCESS 0x10
#define ICP_LX7_STANDBYWFI (1 << 7)
#define ICP_LX7_EN_CPU (1 << 9)
#define ICP_LX7_FUNC_RESET (1 << 4)
#define ICP_LX7_CIRQ_OB_MASK 0x0
#define ICP_LX7_CIRQ_OB_CLEAR 0x4
#define ICP_LX7_CIRQ_OB_SET 0x8
#define ICP_LX7_CIRQ_OB_STATUS 0xc
/* ICP WD reg space */
#define ICP_LX7_WD_CTRL 0x8
#define ICP_LX7_WD_INTCLR 0xC
/* These bitfields are shared by OB_MASK, OB_CLEAR, OB_STATUS */
#define LX7_WDT_BITE_WS1 (1 << 6)
#define LX7_WDT_BARK_WS1 (1 << 5)
#define LX7_WDT_BITE_WS0 (1 << 4)
#define LX7_WDT_BARK_WS0 (1 << 3)
#define LX7_ICP2HOSTINT (1 << 2)
#define ICP_LX7_CIRQ_OB_IRQ_CMD 0x10
#define LX7_IRQ_CLEAR_CMD (1 << 1)
#define LX7_IRQ_SET_CMD (1 << 0)
#define ICP_LX7_CIRQ_IB_STATUS0 0x70
#define ICP_LX7_CIRQ_IB_STATUS1 0x74
#define ICP_LX7_CIRQ_HOST2ICPINT 0x124
#define ICP_LX7_CIRQ_PFAULT_INFO 0x128
#define LX7_HOST2ICPINT (1 << 0)
#endif /* _CAM_LX7_REG_H_ */

View File

@@ -1,35 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_LX7_SOC_H_
#define _CAM_LX7_SOC_H_
#include <linux/interrupt.h>
#include "cam_soc_util.h"
#define UBWC_CONFIG_MAX 2
struct lx7_soc_info {
uint32_t icp_qos_val;
struct {
uint32_t ipe_fetch[UBWC_CONFIG_MAX];
uint32_t ipe_write[UBWC_CONFIG_MAX];
uint32_t bps_fetch[UBWC_CONFIG_MAX];
uint32_t bps_write[UBWC_CONFIG_MAX];
} ubwc_cfg;
};
int cam_lx7_soc_resources_init(struct cam_hw_soc_info *soc_info,
irq_handler_t irq_handler,
void *irq_data);
int cam_lx7_soc_resources_deinit(struct cam_hw_soc_info *soc_info);
int cam_lx7_soc_resources_enable(struct cam_hw_soc_info *soc_info);
int cam_lx7_soc_resources_disable(struct cam_hw_soc_info *soc_info);
int cam_lx7_update_clk_rate(struct cam_hw_soc_info *soc_info,
int32_t clk_level);
#endif /* _CAM_LX7_SOC_H_ */

View File

@@ -1,31 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_ICP_UTILS_H_
#define _CAM_ICP_UTILS_H_
#include <linux/firmware.h>
#include <linux/elf.h>
#include <linux/iopoll.h>
#include "cam_debug_util.h"
/**
* @brief : Validate FW elf image
*/
int32_t cam_icp_validate_fw(const uint8_t *elf, uint32_t machine_id);
/**
* @brief : Get FW elf size
*/
int32_t cam_icp_get_fw_size(const uint8_t *elf, uint32_t *fw_size);
/**
* @brief : Program FW memory
*/
int32_t cam_icp_program_fw(const uint8_t *elf,
uintptr_t fw_kva_addr);
#endif /* _CAM_ICP_UTILS_H_ */

View File

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_PRESIL_HW_ACCESS_H_
@@ -18,7 +19,7 @@
#define CAM_PRESIL_EVENT_HFI_REG_MSG_Q_IOVA CAM_PRESIL_EVENT_HFI_REG(2)
#define CAM_PRESIL_EVENT_HFI_REG_DBG_Q_IOVA CAM_PRESIL_EVENT_HFI_REG(3)
#define CAM_PRESIL_EVENT_HFI_REG_SFR_LEN CAM_PRESIL_EVENT_HFI_REG(4)
#define CAM_PRESIL_EVENT_HFI_REG_A5_HW_VERSION_TO_START_HFI_INIT CAM_PRESIL_EVENT_HFI_REG(13)
#define CAM_PRESIL_EVENT_HFI_REG_ICP_V1_HW_VERSION_TO_START_HFI_INIT CAM_PRESIL_EVENT_HFI_REG(13)
#define CAM_PRESIL_EVENT_HFI_REG_ON_FIRST_REG_START_FW_DOWNLOAD 0x638 /* write FF to start */

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
#include <linux/build_bug.h>
@@ -26,8 +27,8 @@
#include "cam_tpg_dev.h"
#include "cam_flash_dev.h"
#include "a5_core.h"
#include "lx7_dev.h"
#include "cam_icp_v1_dev.h"
#include "cam_icp_v2_dev.h"
#include "ipe_core.h"
#include "bps_core.h"
#include "cam_icp_subdev.h"
@@ -118,8 +119,8 @@ static const struct camera_submodule_component camera_sensor[] = {
static const struct camera_submodule_component camera_icp[] = {
#ifdef CONFIG_SPECTRA_ICP
{&cam_a5_init_module, &cam_a5_exit_module},
{&cam_lx7_init_module, &cam_lx7_exit_module},
{&cam_icp_v1_init_module, &cam_icp_v1_exit_module},
{&cam_icp_v2_init_module, &cam_icp_v2_exit_module},
{&cam_ipe_init_module, &cam_ipe_exit_module},
{&cam_bps_init_module, &cam_bps_exit_module},
{&cam_icp_init_module, &cam_icp_exit_module},

View File

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef CAMERA_MAIN_H
@@ -47,8 +48,8 @@ extern struct platform_driver cam_flash_platform_driver;
#endif
#endif
#ifdef CONFIG_SPECTRA_ICP
extern struct platform_driver cam_a5_driver;
extern struct platform_driver cam_lx7_driver;
extern struct platform_driver cam_icp_v1_driver;
extern struct platform_driver cam_icp_v2_driver;
extern struct platform_driver cam_ipe_driver;
extern struct platform_driver cam_bps_driver;
extern struct platform_driver cam_icp_driver;
@@ -118,8 +119,8 @@ static struct platform_driver *const cam_component_platform_drivers[] = {
#endif
#endif
#ifdef CONFIG_SPECTRA_ICP
&cam_a5_driver,
&cam_lx7_driver,
&cam_icp_v1_driver,
&cam_icp_v2_driver,
&cam_ipe_driver,
&cam_bps_driver,
&cam_icp_driver,